前回の記事「Tensorfrowで画像分類など学習してみる(手書き文字認識編2)」の続きになります。
前回は、データの前処理(スケール変換・1hotベクトル変換と、3層の順伝播型ニューラルネットワークをkerasを用いて構築しました。今回はその続きとしてモデルの学習を進めていきます。
前提/環境
前提となる環境とバージョンは下記となります。
・Anaconda3
・Python3.7.7
・pip 20.0
・TensorFlow 2.0.0
この記事ではJupyter Notebookでプログラムを進めていきます。コードの部分をJupyter Notebookにコピー&ペーストし実行することで同様の結果が得られると思います。前回分のコードは前回の記事を参照してもらえるとありがたいです。
モデルの学習
機械学習では大まかにモデル構築⇒モデルを用いて訓練⇒未知のデータの分類または予測 という流れで進めます。モデルの訓練は次のコードで行います。keras ではfit関数を利用します。fitは固定のエポック数でモデルを訓練するものになります。
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の値に比べ正解率が高く、損失値が小さくなります。訓練用データでのエポックを過剰に進めると、未知のデータに対する正解率が上がらず損失値が減少しない場合があります。これを過学習といいます。
###モデルの正解率の評価
test_loss, test_acc = model.evaluate(x_test, y_test, verbose=0)
print('\nTest accuracy:', test_acc)
結果
Test accuracy: 0.9414
手書き文字セットの内、10000枚のデータで評価しました。値は訓練データでの正解率に比べ現象しています。
###モデルを使い予測してみる。
predict関数を用いて、手書き文字セットの評価用データを用いて予測してみます。
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)
この結果として予測した結果の値が得られます。いくつかの候補に値があります。
np.argmax(predictions[0])
結果
7
予測したもので最も可能性が高いと思われるものが7であるという結果が得られました。
ラベルを確認しましょう。
y_test[0]
結果
array([0., 0., 0., 0., 0., 0., 0., 1., 0., 0.], dtype=float32)
正解を示すラベルでは7番目の要素が1となっています。この結果から正しいことがわかりました。念のため画像を見ましょう
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を構築して画像分類してみる(概要編)