前回サンプルで扱うデータを眺めてみたので、今回は実際にサンプルを動かして画像の分類をしてみたい
サンプルはこれ
keras/cifar10_cnn.py at master · keras-team/keras · GitHub
colab
https://colab.research.google.com/drive/1oCHanNltHykuY2R89lUFYY90cLyIKBrv
基本的にサンプルをそのまま動かしていくだけ コメントもcolabの方に書いていく
一層目は
# 一層目を追加 model.add(Conv2D(32, (3, 3), padding='same', input_shape=x_train.shape[1:])) model.add(Activation('relu'))
Conv2Dのドキュメントを見ると
keras.layers.Conv2D(filters, kernel_size, strides=(1, 1), padding='valid', data_format=None, dilation_rate=(1, 1), activation=None, use_bias=True, kernel_initializer='glorot_uniform', bias_initializer='zeros', kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None, kernel_constraint=None, bias_constraint=None)
32(filters)は出力される画像の枚数、(3, 3) (kernel_size) はフィルタのサイズとのこと
また
x_train.shape[1:] → (32, 32, 3)
でinput_shape には画像1枚のデータの形を渡している
あと、現在の出力のshapeはmodel.output_shape で見れるみたい
model.output_shape → (None, 32, 32, 32)
2層目もほぼ同じ
# 二層目を追加 model.add(Conv2D(32, (3, 3))) model.add(Activation('relu'))
このあとMaxPooling2Dで画像のサイズを小さくしている
# pooling で画像を縮小 model.add(MaxPooling2D(pool_size=(2, 2))) model.output_shape → (None, 16, 16, 32)
Dropoutは指定した割合のノードを非活性化させて過学習を抑えるやつ
# Dropout model.add(Dropout(0.25))
3層目(と数えるのか? poolingが3層目?)以降も1~2層目と同じ感じ
model.add(Conv2D(64, (3, 3), padding='same')) model.add(Activation('relu')) model.add(Conv2D(64, (3, 3))) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25))
つぎにFlattenを挟んでいる これは (50000, 32, 32, 3) とかを (50000, 32323) みたいな形に変形するやつ
model.add(Flatten())
フラットにした出力を512個のノードを持つ層に全連結する
model.add(Dense(512)) model.add(Activation('relu')) model.add(Dropout(0.5))
最後に、10種類の分類問題なので10個のノードを持つ層に全連結、活性化関数はsoftmax
model.add(Dense(num_classes)) model.add(Activation('softmax'))
ここまででレイヤの設定は終了
次にオプティマイザの設定
# パラメータの更新に使うオプティマイザを指定 opt = keras.optimizers.rmsprop(lr=0.0001, decay=1e-6)
SGDとかAdagradとかは知ってたけど RMSPropって初めて知った
損失関数とかを設定してコンパイル
model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])
画像データは0~255の整数値だけど 0~1.0の実数にしたいので変換
# データの準備 x_train = x_train.astype('float32') x_test = x_test.astype('float32') x_train /= 255 x_test /= 255
ImageDataGenerator が何かよくわかっていないけど、学習データにノイズをのせたりちょっと変形させたりして学習データを増やすやつ?? あとで調べる
データの拡張をしないなら
model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, validation_data=(x_test, y_test), shuffle=True)
で学習できます
今回は拡張しないでやりました
Google Colaboratory の GPU ランタイムで、およそ1時間ほどで学習が完了しました (結構早い段階でloss, accは変わらなくなってたみたいです)
Train on 50000 samples, validate on 10000 samples Epoch 1/100 50000/50000 [==============================] - 34s 678us/step - loss: 1.7920 - acc: 0.3452 - val_loss: 1.5589 - val_acc: 0.4344 Epoch 2/100 50000/50000 [==============================] - 33s 669us/step - loss: 1.4828 - acc: 0.4602 - val_loss: 1.3297 - val_acc: 0.5235 Epoch 3/100 ... Epoch 99/100 50000/50000 [==============================] - 33s 667us/step - loss: 0.6290 - acc: 0.7919 - val_loss: 0.7397 - val_acc: 0.7645 Epoch 100/100 50000/50000 [==============================] - 33s 667us/step - loss: 0.6290 - acc: 0.7928 - val_loss: 0.6674 - val_acc: 0.7836 <keras.callbacks.History at 0x7f5460e23a20>
最終的に80%程度の精度で判別できるようになったみたいです
本当に判別できるようになっているのか、確認してみます
model.predict(x_train[0:1]) → array([[5.1839565e-05, 9.5230262e-06, 4.2473815e-02, 1.3438360e-01, 1.5156801e-02, 4.1686233e-02, 7.6447803e-01, 1.6840984e-03, 4.3788212e-05, 3.2197495e-05]], dtype=float32) y_train[0] → array([0., 0., 0., 0., 0., 0., 1., 0., 0., 0.], dtype=float32)
学習データに使ったデータで確認するべきではないとは思いますが、とりあえず最初の画像は 7番目のラベルが 0.764で一番大きな値になっていて、y_train[0]と一致しているようです
model.predict(x_train[1:2]) → array([[3.8416937e-07, 4.2660031e-05, 4.9953406e-09, 4.7760366e-08, 1.3378058e-10, 6.4784986e-09, 4.5471082e-11, 1.5476447e-08, 1.4176493e-06, 9.9995542e-01]], dtype=float32) y_train[1] → array([0., 0., 0., 0., 0., 0., 0., 0., 0., 1.], dtype=float32)
2つ目の画像も10番目のラベルが99.99でy_train[1]と一致していますね
ということでサンプルを実際に動かしてみることができました
次回はこれを応用して独自の画像分類器を作って見たいと思っています。