概要
- 手書きの0~9の数字を判定するプログラムを実装して、画像分類するCNNモデルの概略をつかむ
- データセットはmnistを使う
- CNNモデルはkerasで作成する
補足
- 勉強中の知識のアウトプットなので間違いがあるかもしれません。ご承知おきください。
環境等
- Google Colab
- keras version: 2.15.0
実装
- 学習して数字を判定するまでの大まかな流れ
- step1 : 学習に使うデータの準備
- step2 : 学習
- step3 : 推論(学習で得られたモデルで判定する)
step1 学習に使うデータの準備
mnistからデータセットをダウンロードする
-
keras.load_data
でmnistのデータセットをダウンロードする - ダウンロードしたデータセットは トレーニング用とバリデーション用に分かれている
- データセットは 画像データ(x)と 正解ラベル(y)を持つ。正解ラベルは画像が示す数字である。
import keras
import keras.datasets import mnist
# mnist からトレーニングデータセットとバリデーションデータセットをダウンロードする
# xは画像データ、yは画像の判定ラベル
# x_trainデータは28*28ピクセル画像が60000枚 (60000, 28, 28)
# x_testデータは28*28ピクセル画像が10000枚 (10000, 28, 28)
(x_train, y_train), (x_test, y_test) = mnist.load_data()
load_dataの中身
- x_train[0]

- この画像の正解ラベル y_train[0] は
1
データの前処理
- 正解ラベル(y)を 10個の確率データ の形式に変換する。今の正解ラベルは 1~9のラベルになっており、学習モデルの出力形式である10個の確率データに合わないため。
- 例: [0, 1, ..., 0]。左から数字1,2, ... 9の確率
- 画像データ(x)は扱いやすいように 0~1の間の数値にする。今は min:0(白) ~ max:255(黒)を表す。
from keras.utils import to_categorical
# mnistの画像データはグレースケール画像であり、min:0(白)~max:255(黒)を表す。入力を0~1の範囲にした方が都合がよいので255で割る。
X_train = x_train.reshape(60000, 28,28,1)/255
X_test = x_test.reshape(10000, 28,28,1)/255
# 学習モデルの出力が 10個の確率データ(例: [0, 1, ..., 0])になるので、今の形式(画像が0~9のうちのどの数字か)はかみ合わない。そこで形式をそろえるために変換する
Y_train = to_categorical(y_tr, 10)
Y_test = to_categorical(y_te, 10)
step2 学習
学習モデルを用意する
- kerasの
Sequential
モデルを使って学習モデルを作成する-
Sequential
モデルはニューラルネットワークを構築するための1つの方法 - ニューラルネットワークは複数の層(レイヤー)で構成される。
Sequential
では層を1つずつ積み重ねて構築していく。
-
from keras.models import Sequential
from keras.layers import Dense , Activation, Convolution2D , MaxPooling2D, Flatten
model = Sequential()
model.add(Convolution2D(10, (5,5), input_shape=(28,28,1), activation="relu")) # 2D畳み込み層
model.add(MaxPooling2D(2,2)) # Maxプーリング層
model.add(Convolution2D(10, (5,5), padding="same"))
model.add(MaxPooling2D(2,2))
model.add(Convolution2D(10, (5,5), padding="same"))
model.add(MaxPooling2D(2,2))
model.add(Flatten()) # 平坦化層。入力画像を1次元配列に変換して出力する。全結合層に接続する前に使われる。
model.add(Dense(10, activation="softmax")) # 全結合層
畳み込み層(Convolution)とは
- 画像の特徴点を見つけること
- 画像にカーネルを充てることで特徴点(特徴マップ)を得る
- カーネルの数字によって抽出できる特徴が変わる。
- CNNにおいてカーネルが重みであり、よいCNNモデルとは最適なカーネルを持ったモデルのことを言う。

プーリング層(Pooling)とは
- 識別に不必要な特徴量をそぎ落とす。識別に必要な特徴量を抽出する処理

全結合層(Dense)とは
- 畳み込み層も、プーリング層も、出力は画像のまま(特徴マップ)である。
- 最終的には画像を与えると、1~9のように識別したいので、出力を1次元にしたい。そのために全結合層がある。
- 全結合層の前にFlatten層で平坦化する
Sequentialモデルを使って学習済みモデルを作成する
- 前段で作ったSequentialモデルにデータセットを渡して学習を開始する
- 学習モデルができたら評価してみる
- lossはモデルの出力値と、教師データの結果の誤差。0に近いほど良い。
- accuracyはモデルの出力値の正答率。1に近いほどよい。
from keras.callbacks import EarlyStopping
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics="accuracy")
# 学習
model.fit(X_train, Y_train, epochs=1, batch_size=100, validation_data=(X_test, Y_test), callbacks=[EarlyStopping()])
# モデル評価
score = model.evaluate(X_test, Y_test, verbose=0)
print("loss:", score[0])
print("accuracy:", score[1])
"""出力
loss: 0.10847385227680206
accuracy: 0.9653000235557556
"""
step3 推論してみる
from keras.models import load_model
# 学習済みモデルを保存しておく
model.save('MNIST_NN.h5')
MNIST_NN = load_model('MNIST_NN.h5')
# 学習済みモデルに、mnistのバリデーション画像を渡して推論してみる
predicted = MNIST_NN.predict(x_test[0].reshape(1, 28, 28, 1))
print("判定結果=" np.argmax(predicted)) # 最も確率の高い数字を出力する
plt.imshow(x_test[0], cmap=plt.cm.gray_r)
plt.show
結果
- 結果は
1
- 判定できた。
- 何度か試したが時々間違える

感想など
- kerasのsequentialを使ってCNNモデルを構築。手書き文字の判定プログラムを作った。
- sequentialで層やその他のオプションを調整することで、判定精度などあげられるかもしれない。
- 今回は判定にmnistのバリデーションデータを使ったが、mnist以外の手書き文字を渡して判定してみたい
- mnistの文字判定はチュートリアルレベルの内容なので、他の画像を使ったCNNモデルを組んでみたい
- Google colabでAPIサーバを立てられる方法があるみたいなので、webアプリ上で手書き文字の入力と、結果の出力とかしてみたい