TensorflowとKerasを用いてmnistのCNNを構築してみる
コードは以下の通り。
Tensorflow・Kerasを使ってmnistの訓練を行う
from keras.models import Sequential from keras.datasets import mnist from keras.layers.convolutional import Conv2D from keras.layers.pooling import MaxPooling2D from keras.layers.core import Dense, Dropout, Activation, Flatten from keras.optimizers import Adam from keras.utils import np_utils from keras import backend as K # ------------------------------ # データ準備 # ------------------------------ (X_train, y_train), (X_test, y_test) = mnist.load_data() # データをfloat型にして正規化する X_train = X_train.astype('float32') / 255.0 X_test = X_test.astype('float') / 255.0 img_rows = 28 img_cols = 28 # image_data_formatによって畳み込みに使用する入力データのサイズが違う if K.image_data_format() == 'channels_first': X_train = X_train.reshape(-1, 1, img_rows, img_cols) X_test = X_test.reshape(-1, 1, img_rows, img_cols) input_shape = (1, img_rows, img_cols) else: X_train = X_train.reshape(-1, img_rows, img_cols, 1) X_test = X_test.reshape(-1, img_rows, img_cols, 1) input_shape = (img_rows, img_cols, 1) # ラベルはone-hot encodingを施す y_train = y_train.astype('int32') y_test = y_test.astype('int32') y_train = np_utils.to_categorical(y_train, 10) y_test = np_utils.to_categorical(y_test, 10) # ------------------------------ # モデルの定義 # ------------------------------ # 場合分けでインプットデータのテンソルの形を変える # mnistデータは28×28ピクセルで60000個のデータで、28×28ピクセルで1チャネルのデータに変える # reshapeの-1は、28×28ピクセルで60000個のデータを28×28ピクセルで1チャネルによしなに変えてくれる model = Sequential() # 畳み込み層1 # フィルタは5×5ピクセルで28個→出力データは32チャネル # 入力データは28×28ピクセルの1チャンネル # input_shapeを指定するのは1層目だけ model.add(Conv2D(32, (5, 5), input_shape=input_shape)) model.add(Activation('relu')) # プーリング層1 model.add(MaxPooling2D(pool_size=(2, 2))) # 畳み込み層2 # フィルタは5×5ピクセルで64個→出力データは64チャネル model.add(Conv2D(64, (5, 5))) model.add(Activation('relu')) # プーリング層2 model.add(MaxPooling2D(pool_size=(2, 2))) # Flattenして全結合する model.add(Flatten()) model.add(Dense(128)) model.add(Activation('relu')) # 過学習予防のためドロップアウトして最後に出力(出力データ数はone-hotなので10個) model.add(Dropout(0.5)) model.add(Dense(10, activation='softmax')) # ------------------------------ # 学習の開始 # ------------------------------ epochs = 20 batch_size = 100 adam = Adam(lr=1e-4) model.compile(optimizer=adam, loss='categorical_crossentropy', metrics=["accuracy"]) history = model.fit(X_train, y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_split=0.1) loss, accuracy = model.evaluate(X_test, y_test, verbose=1) print('loss=', loss) print('accuracy=', accuracy)
以下、注意点。
- mnistは28×28の1チャネルだが、RGBの画像とかだと3チャネルになる。
- Conv2Dの引数は出力サイズ(フィルタのデータ数), フィルタの縦横サイズ、入力データのサイズ
- KerasのConv2Dでは、1層目のみ入力データのサイズの指定が必要
- KerasのバックエンジンによってConv2Dに渡す入力データのサイズの指定形式が異なる。
3つめの入力形式に関しては~/.keras/keras.json
に記載されているimage_data_formatをみて判断する。
コードでは、1層目でmnistのデータを(データの個数, 28ピクセル, 28ピクセル , 1チャネル)のテンソルに変換し、
(5ピクセル, 5ピクセル, 1チャネル)のデータ32個のフィルタにかけていて、その結果をプーリングして次の層へ渡す。
最終的な出力の前に全結合してドロップアウトした結果をソフトマックス関数にかけてone-hotのラベル形式で出力している。