Tensorfrowで画像分類など学習してみる(手書き文字認識編3)


前回の記事「Tensorfrowで画像分類など学習してみる(手書き文字認識編2)」の続きになります。
前回は、データの前処理(スケール変換・1hotベクトル変換と、3層の順伝播型ニューラルネットワークをkerasを用いて構築しました。今回はその続きとしてモデルの学習を進めていきます。

前提/環境

前提となる環境とバージョンは下記となります。
・Anaconda3
・Python3.7.7
・pip 20.0
・TensorFlow 2.0.0

この記事ではJupyter Notebookでプログラムを進めていきます。コードの部分をJupyter Notebookにコピー&ペーストし実行することで同様の結果が得られると思います。前回分のコードは前回の記事を参照してもらえるとありがたいです。

モデルの学習

機械学習では大まかにモデル構築⇒モデルを用いて訓練⇒未知のデータの分類または予測 という流れで進めます。モデルの訓練は次のコードで行います。keras ではfit関数を利用します。fitは固定のエポック数でモデルを訓練するものになります。

code
model.fit(
    x_train,
    y_train,
    batch_size=32,
    epochs=20,
    validation_split=0.2
)

訓練ではデータすべてを使うわけではありません、手書き文字のデータセットの内60000枚を利用します。残りの10000枚のデータは未知のデータへの検証や予測のために利用します。

fit関数を用いるにあたり引数を指定しています。それぞれは下記の意味合いとなります。

x_train
訓練データの画像に手書き文字セットの画像の行列に対応します。
y_train
訓練データのラベルに対応する行列に対応します。
batch_size
整数またはNoneを指定します。動作としては設定したサンプル数ごとに勾配の更新を行います。指定しなければデフォルトで32で更新します。機械学習の原理として与えられた関数の傾き(勾配)を計算して、勾配の傾きが大きいほうへパラメーターをずらしていきます。この動きに対する指定となります。
epochs
整数で,モデルを訓練するエポック数を指定します。
validation_sprit
訓練データ全体を訓練にのみ利用するのではなく、一部を訓練中の検証用データとして用いる場合に設定します。kerasでは0から1までの浮動小数点数で指定します。この設定値は訓練データの中で検証データとして使う割合を示します。この記事では0.2を定していますが、訓練に使われるのは全体の8割、残りの2割は検証用データとして利用するということになります。ここで設定した検証データは訓練には利用されません。

モデルの訓練の実行

fitを実行すると下記のような結果が得られます。(一部抜粋)注:結果中のaccuracyなどの値は全く同じにならない場合があります

Train on 48000 samples, validate on 12000 samples
Epoch 1/20
48000/48000 [==============================] - 230s 5ms/sample - loss: 0.1753 - accuracy: 0.9567 - val_loss: 0.3396 - val_accuracy: 0.9468
Epoch 2/20
48000/48000 [==============================] - 246s 5ms/sample - loss: 0.1696 - accuracy: 0.9575 - val_loss: 0.3084 - val_accuracy: 0.9444



Epoch 20/20
48000/48000 [==============================] - 317s 7ms/sample - loss: 0.1477 - accuracy: 0.9636 - val_loss: 0.4187 - val_accuracy: 0.9446

得られる結果としてデータセット数、loss、accuracy、val_loss、val_accuracyというものが得られます。手書き文字セットの訓練データは60000枚でしたがその8割を利用するので48000枚を利用して訓練をしています。残りの2割データで検証を行っています。
loss、accuracy、val_loss、val_accuracyそれぞれの意味合いは下記になります。

loss
訓練データを用いた場合の損失関数の値。損失関数の値が減少することが望ましい
accuracy
訓練データに対しての分類精度(正解率)この値が高くなることが望ましい。
val_loss
訓練データの一部を検証用データとして利用した場合に得られる。検証用データ(未知のデータ)に対する損失関数の値
val_accuracy
訓練データの一部を検証用データとして利用した場合に得られる。検証用データ(未知のデータ)に対する正解率

基本的にエポックを重ねるごとにlossが減少し、accuracyが増加します。またval_loss,val_accuracyの値に比べ正解率が高く、損失値が小さくなります。訓練用データでのエポックを過剰に進めると、未知のデータに対する正解率が上がらず損失値が減少しない場合があります。これを過学習といいます。

モデルの正解率の評価

code
test_loss, test_acc = model.evaluate(x_test, y_test, verbose=0)
print('\nTest accuracy:', test_acc)

結果
Test accuracy: 0.9414

手書き文字セットの内、10000枚のデータで評価しました。値は訓練データでの正解率に比べ現象しています。

モデルを使い予測してみる。

predict関数を用いて、手書き文字セットの評価用データを用いて予測してみます。

code
predictions = model.predict(x_test)
predictions[0]

結果
array([0.0000000e+00, 1.4220487e-26, 1.4102146e-16, 1.2095399e-13,
5.7181305e-13, 1.5182375e-28, 0.0000000e+00, 1.0000000e+00,
0.0000000e+00, 3.0219263e-18], dtype=float32)

この結果として予測した結果の値が得られます。いくつかの候補に値があります。

code
np.argmax(predictions[0])

結果
7

予測したもので最も可能性が高いと思われるものが7であるという結果が得られました。
ラベルを確認しましょう。

code
y_test[0]

結果
array([0., 0., 0., 0., 0., 0., 0., 1., 0., 0.], dtype=float32)

正解を示すラベルでは7番目の要素が1となっています。この結果から正しいことがわかりました。念のため画像を見ましょう

code
x_test_image = x_test[0].reshape(28, 28) 

plt.figure()
plt.imshow(x_test_image)
plt.colorbar()
plt.grid(False)
plt.show()

ここでは一度784に画像を変更しているので、28×28に再度reshapeしなおして画像として表示しています。
そうすると7という文字の手書き画像が表示されます。

まとめ

ここまで、MNISTの手書きデータセットを用いて順伝播型ニューラルネットワークによる訓練と予測をしてみました。
tensorflowとkerasを用いると簡便にいろいろな機械学習が行えます。
初歩的な内容でしたが、次回以降はCNNによる画像分類を書いていきたいと思います。

2020年7月12日追記
CNNの実装をしてみようということで下記の記事も書き始めました。
Tensorflow・kerasでCNNを構築して画像分類してみる(概要編)