前回の記事でTensorflow2をインストールしました。 早速これを使って何かしてみましょう✊
初心者向けチュートリアル
Tensorflowの公式マニュアルを見ると、初心者向けのチュートリアルがあります。
最初は、"Hello, world!"代わりに、画像を分類するニューラルネットワークを構築して学習させ、正解率の評価を行うようです。 題材は有名なMNIST。手書き文字認識のデータセットですね。 学習用の手書き文字画像が6万枚、テスト用の画像が1万枚も入っています。縦横28ピクセルのグレースケール画像です。
早速やってみよう
といっても、公式のソースをそのまま写すだけです😅
import tensorflow as tf mnist = tf.keras.datasets.mnist (x_train, y_train), (x_test, y_test) = mnist.load_data() x_train, x_test = x_train / 255.0, x_test / 255.0 model = tf.keras.models.Sequential([ tf.keras.layers.Flatten(input_shape=(28, 28)), tf.keras.layers.Dense(128, activation='relu'), tf.keras.layers.Dropout(0.2), tf.keras.layers.Dense(10, activation='softmax') ]) model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy']) model.fit(x_train, y_train, epochs=5)
チュートリアルですし、深くはないニューラルネットワークを使うようです。 入力層は画像の画素の28x28=784ノード、出力層は0~9までの数字をあらわす10ノードになっていますね。
これを実行するとどうなるのでしょうか。
上記ソースをmnist_test.py
というファイルに保存して実行します。
> venv\Scripts\python.exe mnist_test.py (略) Train on 60000 samples Epoch 1/5 60000/60000 [==============================] - 3s 57us/sample - loss: 0.2966 - accuracy: 0.9125 Epoch 2/5 60000/60000 [==============================] - 3s 49us/sample - loss: 0.1426 - accuracy: 0.9582 Epoch 3/5 60000/60000 [==============================] - 3s 49us/sample - loss: 0.1089 - accuracy: 0.9678 Epoch 4/5 60000/60000 [==============================] - 3s 49us/sample - loss: 0.0887 - accuracy: 0.9722 Epoch 5/5 60000/60000 [==============================] - 3s 49us/sample - loss: 0.0758 - accuracy: 0.9756 10000/10000 - 0s - loss: 0.0844 - accuracy: 0.9751
MNISTのデータセットをダウンロードしていなくても、初回実行時に自動でダウンロードしてくれます。至れり尽くせりなフレームワークですね☺️
30秒もしないうちに学習が終わり、評価結果が出ました。 6万枚ある学習用画像を5周分学習し、その後1万枚のテスト画像を分類した結果、accuracyが0.9751、すなわち約97%で正解する分類器が作れたことになります🎉
公式のチュートリアルはここで一区切りし、次のチュートリアルに移ります。
………。
…何かあっさりしていますね。本当にニューラルネットワークが学習したのか実感がわかない…🤔
ということで、もう少しいじってみることにしました。
データを見てみる
そもそもどんな画像が入っているのか見てみましょう。
import tensorflow as tf mnist = tf.keras.datasets.mnist (x_train, y_train), (x_test, y_test) = mnist.load_data() print(x_train.shape) print(y_train.shape) print(x_test.shape) print(y_test.shape) print(x_train[0]) print(y_train[0])
上記スクリプトをmnist_shape.py
という名前で保存して実行してみます。
> .\venv\Script\python.exe mnist_shape.py (60000, 28, 28) (60000,) (10000, 28, 28) (10000,) [ (中略) [ 0 0 0 0 0 0 18 171 219 253 253 253 253 195 80 9 0 0 0 0 0 0 0 0 0 0 0 0] [ 0 0 0 0 55 172 226 253 253 253 253 244 133 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0] (中略) ] 5
画像のほうは28x28ピクセルの画像がそれぞれ6万枚、1万枚、それに対応する教師データは、正解の数字がそのまま入っています。 一番最初の学習用画像の正解は、5のようです。 画像データは背景の部分は0、何か書かれている部分は1~255までの数字で表されています。
画像データを実際に表示させてみましょう。 次のチュートリアルで出てきますが、matplotlibを使うと簡単に可視化👀できます。pipで簡単にインストールできます。
> .\venv\Script\pip.exe matplotlib
そして、先ほどのmnist_shape.py
の最後に次のスクリプトを付け加えます。
import matplotlib.pylab as plt plt.figure(figsize=(10, 9)) plt.subplots_adjust(hspace=0.5) for n in range(30): plt.subplot(6, 5, n+1) plt.imshow(x_train[n], cmap="Greys") plt.title(y_train[n]) plt.axis('off') plt.show()
学習用画像の最初30個を表示します。こんな画像が出てきました。
なんか、えらく下手な?文字も混ざっているように見えますが😅ともかく手書き文字です。
自分の手書き文字も認識させたい!
ここまで来たら、自分の手書き文字も認識させたいですよね😆早速やってみましょう。
データ作成
私はWindows10に付属のペイントで、マウスを使って28x28ピクセルの画像データを作成しました。
注意点としては、MNISTのデータは背景が0、文字の部分が0以外になっていますので、ペイントで描く際は黒背景に白文字で書くと良いでしょう。 あとでグレースケール画像に変換すると、MNISTデータと同じようになります。
画像はpng形式で保存し、ファイル名は0.png
などとします。
学習させたモデルの保存
その前に、学習したニューラルネットワークを保存しておきましょう。 いろんな画像を試すのに、毎回学習していては不便です。
最初に作成した、mnist_test.py
の最後に、次の1行を付け加えて実行します。
model.save("mnist_model.h5")
これで、学習したニューラルネットワークがmnist_model.h5
という名前で保存されました。
認識するときは、そのデータを読み込めばよいというわけです。
認識させてみよう
`0.png
~9.png
まで用意し、次のスクリプトを実行します。
import tensorflow as tf import numpy as np def load_imgset(filename): img = tf.io.decode_image(tf.io.read_file(filename)) img = tf.image.rgb_to_grayscale(img) img = tf.image.resize(img, [28, 28]) img = np.reshape(img, (28, 28)) img / 255.0 img_set = np.expand_dims(img,0) # Create dataset from one image return img_set model = tf.keras.models.load_model("mnist_model.h5") for i in range(10): img = load_imgset("%d.png" % i) pred = model.predict(img) pred_num = pred.argmax() print(i, "-->", pred_num)
実行結果は次の通りです。
0 --> 0 1 --> 1 2 --> 2 3 --> 3 4 --> 4 5 --> 3 6 --> 8 7 --> 7 8 --> 3 9 --> 9
左側が正解、右側が認識結果ですが…5,6,8が正しく認識できていないです。 正解率約97%のはずが、なぜかこんな結果に。実質2値画像だからでしょうか🤔??
ともあれ、ひとまずここまでで一区切りとします😌