kerasで手書き数字の判定

f:id:hanamichi_sukusuku:20210205194734p:plain

実行結果

f:id:hanamichi_sukusuku:20210205194801p:plain

このプログラムではTensorFlowを用いて手書き数字の判定を行っていく。

 

MNISTデータの読み込み

 

import keras
from keras.datasets import mnist
from matplotlib import pyplot

(X_train, y_train), (X_test, y_test) = mnist.load_data()

for i in range(0, 32):
pyplot.subplot(4, 8, i+1)
pyplot.imshow(X_train[i], cmap='gray')
 
pyplot.show()

 

MNISTのデータは、白黒画像の手書き数字のデータセットで、学習用の画像は6万枚、テスト用の画像は1万枚もの画像が用意されている。それぞれの画像は28✖️28ピクセル、グレースケールのデータ。グレースケールというのは0(白)~255(黒)の範囲の値で構成されている画像のこと。kerasには、機械学習で使える様々なデータセットが用意されており、MNISTデータもkerasのデータセットに含まれている。

よってfrom keras.datasets import mnistでmnistモジュールをインポートし、load_data()関数でMNISTデータを読み込む。それを学習用、テストように分割。

 

for文ではMNISTデータの中身を確認している。

range(0, 32)では0~31の値を順にiに格納している。

pyplot.subplot()では複数の描画を一つの画像に描くた目のもので、第一引数に行数、第二引数に列数、第三引数にどこに描画するかを指定している(左上から0)。

pyplot.imshow()で学習用のデータの一部を描画。

pyplot.show()で表示。

 

データを一次元に変換

X_train = X_train.reshape(-1, 784).astype('float32') / 255
X_test = X_test.reshape(-1, 784).astype('float32') / 255

 

X_trainのデータを確認してみると

f:id:hanamichi_sukusuku:20210205200919p:plain

三次元の配列であり、一つの画像が25✖️25個の二次元配列となっていることが確認できる。

画像一つが二次元なので28✖️28で784の一次元配列に変換するためreshape()の第一引数に-1を指定し、行数が1、列数が784の一次元配列にする。astype()でデータ型変換。float32では6桁で収まるときはこの方が早いらしい。それ以外はfloat64を指定する方が無難っぽい。255で割るのはモデルを学習させるときのために正規化する必要があるので色の最大値である255で全体を割ることで0.0~1.0の値で表現することができる。

 

ラベルデータ、ohe-hotベクトルに変換

y_train = keras.utils.to_categorical(y_train.astype('int32'), 10)
y_test = keras.utils.to_categorical(y_test.astype('int32'), 10)

 

以前はmap関数で変換したがkerasの機能を使って変換することができる。

keras.utils.to_categorical()で第一引数に処理するデータ、第二引数に10を指定しているがこれは例えば出力結果が「0.1,0,0,0,0,0,0.8,0,0.1,0」(0の確率10%。6の確率80%。10の確率10%)を得られるような形でone-hotベクトルに変換する。

 

モデルの構築

in_size = 28 * 28
out_size = 10

Dense = keras.layers.Dense
model = keras.models.Sequential()
model.add(Dense(512, activation='relu', input_shape=(in_size,)))
model.add(Dense(out_size, activation='softmax'))

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

inpu_shape()では入力値が784なので28✖️28を格納したin_sizeを設定。

out_sizeでは10を指定しているが、0~9までの数字を判定するため出力のユニット数を10にしている。

 

学習と評価

model.fit(X_train, y_train,batch_size=20, epochs=20)

score=model.evaluate(X_test, y_test, verbose=1)
print('正解率=', score[1], 'loss=', score[0])

 

fit()で学習。evaluate()で評価。