1
0

MNISTで文字判定プログラムを作ってCNNの基本を知る

Last updated at Posted at 2024-04-27

概要

  • 手書きの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アプリ上で手書き文字の入力と、結果の出力とかしてみたい
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0