【Python】初心者でもできる画像識別(fashion_MNIST)をコピペコードで深層学習する方法

スポンサーリンク
Python

今回は、以前使用したコードをそのままコピペしてみたら、どんな結果になるかを試していきます。
コピペもとのコードは、MNIST(手書き文字識別)に対するDNN(畳み込みニューラルネットワーク)です。

【初心者】はじめての深層学習による手書き文字認識(MNIST)
今回は、機械学習を学び始めるなら、必ず通る道である「手書き文字認識」です。 手書き文字認識は、MNIST(Modified National Institute of Standards and Technology database...

このコードを試すのは、MNIST_fashionです。コピペもとであるMNISTは、0~9までの手書き文字を識別する問題です。MNIST_fashionは、ファッション品の識別問題です。

Pythonによる機械学習や深層学習を学び始めの方や、ほんとにコードはコピペでいいのかが疑問に感じている方は参考になると思います。

Pythonの環境構築は、以下の過去記事を参照してください。

【2021年最新】WindowsでAnacondaをインストールする方法、初心者がPythonの環境を構築する
Pythonの環境構築におすすめなのが、「anaconda」です。anacondaのなかにある、Jupyter Labはデータ解析や機械学習に非常に相性がいいです。理由は、コードを実行すると結果を返してくれます。その結果をみて、新たなコード
M1 mac でanacondaをインストールし、Pythonを動作確認
M1 mac miniを購入したので、anacondaのインストールし、Pythonの動作を確認しました。 以前はWindowsでのanacondaのインストール方法を提示しました。 macでのイ...

必要なライブラリをインポート

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
sns.set_style('whitegrid')
import tensorflow as tf
from tensorflow import keras
import warnings
warnings.filterwarnings('ignore')
print(tf.__version__)
print(keras.__version__)

出力:
2.3.0
2.4.0
ファッション品の識別をkerasのデータセットからインポートしましょう。
ファッションのデータセットは訓練用とテスト用のデータに分かれています。

from keras.datasets import fashion_mnist
#学習データとテストデータをKerasが用意しているFashion-MNISTデータ・セットから読み込む
(X_train, y_train), (X_test, y_test) = fashion_mnist.load_data()

print(X_train.shape)
print(X_test.shape)
print(y_train.shape)
print(y_test.shape)

出力:
(60000, 28, 28)
(10000, 28, 28)
(60000,)
(10000,)
ファッショントレーニングセットは、70,000枚の画像から構成され、60,000枚のトレーニングデータと10,000枚のテストデータに分割されています。データセットは、10のクラスからのラベルに関連付けられた28×28のグレースケール画像から構成されています。

10クラスは以下の通りです。
0 => Tシャツ/トップス
1 => ズボン
2 => プルオーバー
3 => ワンピース
4 => コート
5 => サンダル
6 => シャツ
7 => スニーカー
8 => バッグ
9 => アンクルブーツ
では、これを指定していきます。

class_names = ['T_shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 
               'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']

日本語で指定したほうが分かりやすいかもしれませんが、うまく表示されなかったりと、いろいろ面倒です。なので、基本的に英語で指定しましょう。

データの中身を確認する

plt.figure(figsize=(9, 7))
for i in range(20):
plt.subplot(4, 5, i + 1)
plt.xticks([])
plt.yticks([])
plt.grid(False)
plt.imshow(X_train[i].reshape((28,28)), cmap=plt.cm.binary)
label_index = int(y_train[i])
plt.title(class_names[label_index])
plt.show()

出力:

こんな感じで、ファッション品の画像データと、そのラベル(ファッション品の名前)があります。
各画像は縦28ピクセル、横28ピクセル、合計784ピクセルです。

各ピクセルには、それに関連付けられた1つのピクセル値があり、そのピクセルの明暗を示し、数字が大きいほど暗いことを意味します。このピクセル値は0から255までの整数です。
左上のデータをcsvファイルにして確認してみましょう。

X0=X_train[0]
X0_square=X0.reshape(28,28)
df=pd.DataFrame(X0_square)
df.to_csv("employee.csv")

出力:

なんとなく、形が見えますね。数字が大きくなると色が濃くなします。
では、画像を確認してみましょう。

plt.imshow(X0_square , cmap = plt.cm.binary) 
label_index = y_train[0]
plt.title(f"{class_names[label_index]}")

出力:

csvファイルのデータと同じような形で、「Ankle boot」であることが確認できました。

つぎにデータの各クラスの数を確認します。

import japanize_matplotlib

plt.figure(figsize=(12,8))

plt.subplot(2,2,1)
sns.countplot(y_train)
plt.title('訓練データのクラス分類')

plt.subplot(2,2,2)
sns.countplot(y_test)
plt.title('テストデータのクラス分類')

出力:

すべてほぼ同じ数ですね。

データの形を整える

もともと訓練データとテストデータに分かれていますが、訓練データを訓練データと検証データに分割します。

from sklearn.model_selection import train_test_split

X_train, X_valid, y_train, y_valid = train_test_split(
    X_train, y_train, test_size=0.2, random_state=0)

各データの中身を確認しましょう。

print("X_train.shape = {}".format(X_train.shape))
print("y_train.shape = {}".format(y_train.shape))
print("X_valid.shape = {}".format(X_valid.shape))
print("y_valid.shape = {}".format(y_valid.shape))
print("X_test.shape = {}".format(X_test.shape))
print("y_test.shape = {}".format(y_test.shape))

出力:
X_train.shape = (48000, 28, 28)
y_train.shape = (48000,)
X_valid.shape = (12000, 28, 28)
y_valid.shape = (12000,)
X_test.shape = (10000, 28, 28)
y_test.shape = (10000,)

たとえば、X_trainは48,000のデータ数があります。1つのデータは28✕28の形のデータという意味です。

# 28x28x1のサイズへ変換し、数値を0~1に変換するために、255で割る
X_train = X_train.reshape(X_train.shape[0], 28, 28, 1)/255.
X_valid = X_valid.reshape(X_valid.shape[0], 28, 28, 1)/255.
X_test = X_test.reshape(X_test.shape[0], 28, 28, 1)/255.

データを変換したので、確認してみましょう。

print("X_train.shape = {}".format(X_train.shape))
print("y_train.shape = {}".format(y_train.shape))
print("X_valid.shape = {}".format(X_valid.shape))
print("y_valid.shape = {}".format(y_valid.shape))
print("X_test.shape = {}".format(X_test.shape))
print("y_test.shape = {}".format(y_test.shape))

出力:
X_train.shape = (48000, 28, 28, 1)
y_train.shape = (48000,)
X_valid.shape = (12000, 28, 28, 1)
y_valid.shape = (12000,)
X_test.shape = (10000, 28, 28, 1)
y_test.shape = (10000,)

画像はグレースケール(白黒)なので、データを3次元にします。X_trainでは、48000が行数、28が縦列、28が横列、1がグレースケールという意味です。この1が3の場合はカラーです。3とはRGB(Red, Green, Blue)です。

つぎに、どのファッション品であるかのラベル(label)を確認します。

# 訓練データを確認してみる
for i in range(5):
    print(y_train[i])

出力:
7
8
9
0
6
このデータをダミー変数に変換します。

from keras.utils import np_utils

# ターゲットとなる yをダミー変数(one-hot-encode)にする
y_train = np_utils.to_categorical(y_train, 10)
y_valid = np_utils.to_categorical(y_valid, 10)
y_test = np_utils.to_categorical(y_test, 10)

データを確認してみましょう。

# ダミー変数化した訓練データを確認してみる
for i in range(5):
    print(y_train[i])

出力:
[0. 0. 0. 0. 0. 0. 0. 1. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 1. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]
[1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]
1列目のダミー変数前は7でした。ダミー変数後は0から数えて7番目が1になっていますね。3列目のダミー変数前は9でした。ダミー変数後は0から数えて9番目が1になっています。これが、ダミー変数です。
※ 1からではなく、0から数えましょう。

コピペで、深層学習(畳み込みニューラルネットワーク)を実行する

import keras

model = keras.models.Sequential([
    keras.layers.Conv2D(32, kernel_size=3, padding="same", activation="relu"),
    keras.layers.Conv2D(64, kernel_size=3, padding="same", activation="relu"),
    keras.layers.MaxPool2D(),
    keras.layers.Flatten(),
    keras.layers.Dropout(0.25),
    keras.layers.Dense(128, activation="relu"),
    keras.layers.Dropout(0.5),
    keras.layers.Dense(64, activation="relu"),
    keras.layers.Dropout(0.5),
    keras.layers.Dense(10, activation="softmax")
])

model.compile(loss='categorical_crossentropy',
              optimizer='nadam',
              metrics=['accuracy'])

ディープラーニングを実行します。

%%time
# モデルの訓練(エポック 10)
model.fit(X_train, y_train,
          epochs=10,
          validation_data=(X_valid,y_valid))

出力:

深層学習による検証データでは91.9%です。
学習するのにかかった時間は、26分以上です。手書き文字とほぼ同じでしたね。
では、学習に使っていないデータであるテストデータで、正解率を確認してみましょう。

model.evaluate(X_test, y_test)

出力:

正解率は91.6%でしたね。ここでも手書き文字よりは正解率が悪いです。でも、悪くはない結果ではないでしょうか。

深層学習の結果確認

from sklearn.metrics import accuracy_score

y_pred = model.predict(X_test)

y_test = np.argmax(y_test, axis=1)
y_pred = np.argmax(y_pred, axis=1)

from sklearn.metrics import classification_report
print("Classification report for classifier %s:\n%s\n"
      % (model, classification_report(y_test, y_pred)))

出力:

もう少し分かりやすくしてみましょう。
縦軸が実際の結果で、横軸は深層学習モデルによる予測です。それらの正解率を表しています。

from sklearn.metrics import confusion_matrix

confusion_mtx = confusion_matrix(y_test, y_pred)

f, ax = plt.subplots(figsize=(10, 8))
sns.heatmap(confusion_mtx, annot=True, linewidths=0.01,
            cmap="Greens",linecolor="gray", fmt= '.1f',ax=ax)

plt.xlabel("Predicted Label")
plt.ylabel("True Label")
plt.title("Confusion Matrix")
plt.show()

出力:

いかがですね。手書き文字より悪いですが、コピペだけで簡単にできます。
手書き文字もファッション品の識別も同じ28✕28ピクセルのデータであるため、コードの相性は良かったですね。
しかし、ピクセルの違う画像でも、前処理(データを整える)をするだけで、同じようにコピペで深層学習が可能です。
正解率を上げるためには、コードを少し変える必要があります。その場合は、難しい知識が必要ですが、まずはコピペだけで大枠を作ってからでいいです。
とりあえず、コピペで機械学習する方法を身に付けましょう。

コメント

タイトルとURLをコピーしました