はっきり言って、Fine-Tuningも随分進化している。
今回は、VGG16モデルのFine-TuningでMNISTを学習し、val_acc99.70%を達成した。
先日、【Fine-Tuning】Base-modelにInput-modelを追加して学習する新しいスタイルの提案♬について記載したが、以下の参考でさらにバージョンアップしてモデルを構築できるというので、今までの知見を合わせて再構築してMNISTの学習に適用してみた。
得られた精度は事前処理は画像拡大だけで、MNISTのトップデータに迫るval_accで99.70%を得たので一定の成果だと思う。また、今回のネットワーク作成方法は汎用的なので他のモデルへの流用もできる手法である。
(以下のKaggleのDate: 7/25/2012 8:43 PM UTCで283位だし、BenchmarkAIだと過去データしか掲載されていないけど。。今は何か事前に学習データ処理すれば100%認識できるんだろね)
MNIST@Benchmarks.AI
Digit Recognizer Learn computer vision fundamentals with the famous MNIST data
参考②にKerasDocumentationにある学習済モデルのFine-Tuningなど使い方をリンクしています。
【参考】
・①Kerasで学習済みモデルに任意のレイヤー(BatchNorm、Dropoutなど)を差し込む方法
・②Usage examples for image classification models@KerasDocumentation
苦労したこと
・入力チャンネルを3チャンネルから1チャンネルにしFine-Tuningする
・入力画像の大きさを適当に変更できるようにする
・callbackを工夫する
・入力チャンネルを3チャンネルから1チャンネルにしFine-Tuningする
モデルの作成方法は、上記の参考記事を読んでください。
ある意味まんまです。
ただ、入力チャンネルを1チャンネルにする部分は以前のFine-Tuningの前段にinput_modelを追加する方法を採用しました。
この部分のコードは以下のとおりです。
def create_normal_model():
input_tensor = x_train.shape[1:]
input_model = Sequential()
input_model.add(InputLayer(input_shape=input_tensor))
input_model.add(Conv2D(3, (3, 3),activation='relu', padding='same'))
ここで重要な変更は、Finetuningなのに上記でConv2D層を追加して全体の層数を変更したため、この段階ではweights=Noneとしたことです。
これは、モデル構築した後、
model.load_weights('vgg16_weights.hdf5',by_name=True)
で読み込むことにより通常のFine-Tuningと同じように、学習済みWeightsによりFine-Tuningすることができるようになります。
※予めvgg16のWeightsをvgg16_weights.hdf5として保存しておく必要があります
※ただし、その他のLayerが変わっているのでFine-Tuningが必要になります
model = VGG16(include_top=False,weights=None, input_tensor=input_model.output) #weights='imagenet'
x = Flatten()(model.layers[-1].output)
x = Dense(num_classes, activation="softmax")(x)
return Model(model.inputs, x)
以下が参考にある、BachNormalizationなどの差し込みをやっているモデルです。
※このコードは汎用性が高く(差し込み自由で)他のモデルでも(Layerの名称などを分析すれば)同じように使えます
def create_batch_norm_model():
model = create_normal_model()
for i, layer in enumerate(model.layers):
if i==0:
input = layer.input
x = input
else:
if "conv" in layer.name:
layer.activation = activations.linear
x = layer(x)
x = BatchNormalization()(x)
x = Activation("relu")(x)
else:
x = layer(x)
bn_model = Model(input, x)
return bn_model
model=create_batch_norm_model()
model.summary()
・入力画像の大きさを適当に変更できるようにする
img_rows, img_cols, ch=128,128,1
num_classes = 10
# データをロード
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# サイズ変更
X_train =[]
X_test = []
for i in range(50000):
dst = cv2.resize(x_train[i], (img_rows, img_cols), interpolation=cv2.INTER_CUBIC)
X_train.append(dst)
for i in range(10000):
dst = cv2.resize(x_test[i], (img_rows, img_cols), interpolation=cv2.INTER_CUBIC)
X_test.append(dst)
以下で、読み込んでサイズ変更したデータをreshapeして形を整えます。
X_train = np.array(X_train).reshape(50000,img_rows, img_cols,ch)
X_test = np.array(X_test).reshape(10000,img_rows, img_cols,ch)
あとは、通常のシークエンスです。
y_train=y_train[:50000]
y_test=y_test[:10000]
x_train = X_train.astype('float32')
x_test = X_test.astype('float32')
x_train /= 255
x_test /= 255
# Convert class vectors to binary class matrices.
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
・callbackを工夫する
一応載せておきます。
callbackはいろいろ工夫できますが、今回は以下のように関数で別だししました。
※とにかくepoch毎にweightsを保存し、一枚(何枚でも可ですが)でも分類クラスと確率を出力する。
後者はおまけにも掲載しましたが、だんだん確率が上がっていく様子が見えて臨場感がでます(特にcifar10,100など。。)
class Check_layer(keras.callbacks.Callback):
def on_epoch_end(self, epoch, logs={}):
model.save_weights('./cifar10/mnist_cnn128_' + str(epoch)+'_g.hdf5', True)
check_layer(img=x_test[1],epoch=epoch)
def check_layer(img=x_test[1],epoch=0):
predictions = model.predict(img.reshape(1,128,128,1))
index_predict=np.argmax(predictions)
print('Predicted class:',index_predict)
print(' Probability: {}'.format(predictions[0][index_predict]))
ch_layer = Check_layer()
callbacks = [ch_layer]
history = model.fit(x_train, y_train,
batch_size=32,
epochs=20,
verbose=1,
callbacks=callbacks,
validation_data=(x_test, y_test))
コード
コード全体は以下のリンクのとおり
・DL-FineTuning/train_mnist_by_vgg16.py
まとめ
・VGG16の学習済モデルでMNISTのFine-Tuningが出来るようになった
・BatchNormalizationなどの層を自由に追加できるようになった
・入力画像のサイズも自由に変更できる
・複合的なモデルでさらなる精度向上を目指す
おまけ
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) (None, 128, 128, 1) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 128, 128, 3) 30
_________________________________________________________________
batch_normalization_1 (Batch (None, 128, 128, 3) 12
_________________________________________________________________
activation_1 (Activation) (None, 128, 128, 3) 0
_________________________________________________________________
block1_conv1 (Conv2D) (None, 128, 128, 64) 1792
_________________________________________________________________
batch_normalization_2 (Batch (None, 128, 128, 64) 256
_________________________________________________________________
activation_2 (Activation) (None, 128, 128, 64) 0
_________________________________________________________________
block1_conv2 (Conv2D) (None, 128, 128, 64) 36928
_________________________________________________________________
batch_normalization_3 (Batch (None, 128, 128, 64) 256
_________________________________________________________________
activation_3 (Activation) (None, 128, 128, 64) 0
_________________________________________________________________
block1_pool (MaxPooling2D) (None, 64, 64, 64) 0
_________________________________________________________________
block2_conv1 (Conv2D) (None, 64, 64, 128) 73856
_________________________________________________________________
batch_normalization_4 (Batch (None, 64, 64, 128) 512
_________________________________________________________________
activation_4 (Activation) (None, 64, 64, 128) 0
_________________________________________________________________
block2_conv2 (Conv2D) (None, 64, 64, 128) 147584
_________________________________________________________________
batch_normalization_5 (Batch (None, 64, 64, 128) 512
_________________________________________________________________
activation_5 (Activation) (None, 64, 64, 128) 0
_________________________________________________________________
block2_pool (MaxPooling2D) (None, 32, 32, 128) 0
_________________________________________________________________
block3_conv1 (Conv2D) (None, 32, 32, 256) 295168
_________________________________________________________________
batch_normalization_6 (Batch (None, 32, 32, 256) 1024
_________________________________________________________________
activation_6 (Activation) (None, 32, 32, 256) 0
_________________________________________________________________
block3_conv2 (Conv2D) (None, 32, 32, 256) 590080
_________________________________________________________________
batch_normalization_7 (Batch (None, 32, 32, 256) 1024
_________________________________________________________________
activation_7 (Activation) (None, 32, 32, 256) 0
_________________________________________________________________
block3_conv3 (Conv2D) (None, 32, 32, 256) 590080
_________________________________________________________________
batch_normalization_8 (Batch (None, 32, 32, 256) 1024
_________________________________________________________________
activation_8 (Activation) (None, 32, 32, 256) 0
_________________________________________________________________
block3_pool (MaxPooling2D) (None, 16, 16, 256) 0
_________________________________________________________________
block4_conv1 (Conv2D) (None, 16, 16, 512) 1180160
_________________________________________________________________
batch_normalization_9 (Batch (None, 16, 16, 512) 2048
_________________________________________________________________
activation_9 (Activation) (None, 16, 16, 512) 0
_________________________________________________________________
block4_conv2 (Conv2D) (None, 16, 16, 512) 2359808
_________________________________________________________________
batch_normalization_10 (Batc (None, 16, 16, 512) 2048
_________________________________________________________________
activation_10 (Activation) (None, 16, 16, 512) 0
_________________________________________________________________
block4_conv3 (Conv2D) (None, 16, 16, 512) 2359808
_________________________________________________________________
batch_normalization_11 (Batc (None, 16, 16, 512) 2048
_________________________________________________________________
activation_11 (Activation) (None, 16, 16, 512) 0
_________________________________________________________________
block4_pool (MaxPooling2D) (None, 8, 8, 512) 0
_________________________________________________________________
block5_conv1 (Conv2D) (None, 8, 8, 512) 2359808
_________________________________________________________________
batch_normalization_12 (Batc (None, 8, 8, 512) 2048
_________________________________________________________________
activation_12 (Activation) (None, 8, 8, 512) 0
_________________________________________________________________
block5_conv2 (Conv2D) (None, 8, 8, 512) 2359808
_________________________________________________________________
batch_normalization_13 (Batc (None, 8, 8, 512) 2048
_________________________________________________________________
activation_13 (Activation) (None, 8, 8, 512) 0
_________________________________________________________________
block5_conv3 (Conv2D) (None, 8, 8, 512) 2359808
_________________________________________________________________
batch_normalization_14 (Batc (None, 8, 8, 512) 2048
_________________________________________________________________
activation_14 (Activation) (None, 8, 8, 512) 0
_________________________________________________________________
block5_pool (MaxPooling2D) (None, 4, 4, 512) 0
_________________________________________________________________
flatten_1 (Flatten) (None, 8192) 0
_________________________________________________________________
dense_1 (Dense) (None, 10) 81930
=================================================================
Total params: 14,813,556
Trainable params: 14,805,102
Non-trainable params: 8,454
_________________________________________________________________
Train on 50000 samples, validate on 10000 samples
Epoch 1/20
50000/50000 [==============================] - 311s 6ms/step - loss: 0.0850 - acc: 0.9776 - val_loss: 0.0256 - val_acc: 0.9915
Predicted class: 2
Probability: 0.9992223978042603
Epoch 2/20
50000/50000 [==============================] - 306s 6ms/step - loss: 0.0178 - acc: 0.9944 - val_loss: 0.0196 - val_acc: 0.9939
Predicted class: 2
Probability: 0.999985933303833
Epoch 3/20
50000/50000 [==============================] - 309s 6ms/step - loss: 0.0116 - acc: 0.9964 - val_loss: 0.0195 - val_acc: 0.9936
Predicted class: 2
Probability: 0.9999558925628662
Epoch 4/20
50000/50000 [==============================] - 308s 6ms/step - loss: 0.0084 - acc: 0.9975 - val_loss: 0.0170 - val_acc: 0.9939
Predicted class: 2
Probability: 0.9999535083770752
Epoch 5/20
50000/50000 [==============================] - 309s 6ms/step - loss: 0.0066 - acc: 0.9978 - val_loss: 0.0154 - val_acc: 0.9948
Predicted class: 2
Probability: 0.9999960660934448
。。。
50000/50000 [==============================] - 268s 5ms/step - loss: 1.4046e-05 - acc: 1.0000 - val_loss: 0.0166 - val_acc: 0.9968
Epoch 00006: val_acc improved from 0.99670 to 0.99680, saving model to ./cifar10/mnist_cnn_128.hdf5
Epoch 7/100
50000/50000 [==============================] - 268s 5ms/step - loss: 1.1672e-05 - acc: 1.0000 - val_loss: 0.0162 - val_acc: 0.9970
Epoch 00007: val_acc improved from 0.99680 to 0.99700, saving model to ./cifar10/mnist_cnn_128.hdf5