Deep Learning 脱初心者めざして

主にDeepLearningや画像処理について扱います

DNNを実装してみた ( 2 )

前回の続きで、転移学習を扱っていこうと思います。

ちなみに↓が前回の記事です。

mamomamoru.hatenablog.com

前回の記事をみてもらえればわかると思いますが、前回はMNISTデータの0〜4までの数字を使ってDNNを作成しました。今回は、そのモデルを再利用して、残りの5〜9の数字についての学習をしたいと思います。

前問の全ての訓練済み隠れ層(5層)を再利用

隠れ層を全て凍結し、新しいソフトマックス出力層を追加

プレトレーニング済み層の再利用
reset_graph()

restore_saver = tf.train.import_meta_graph("./my_best_mnist_model_0_to_4.meta")

X = tf.get_default_graph().get_tensor_by_name("X:0")
y = tf.get_default_graph().get_tensor_by_name("y:0")
loss = tf.get_default_graph().get_tensor_by_name("loss:0")
Y_proba = tf.get_default_graph().get_tensor_by_name("Y_proba:0")
logits = Y_proba.op.inputs[0]
accuracy = tf.get_default_graph().get_tensor_by_name("accuracy:0")

(./my_best_mnist_model_0_to_4.metaに前回作成したモデルが保存されています。)

隠れ層の凍結

重みを凍結するとは、下位層の重みが固定することであり、無駄な訓練をしなくて済むため上位層の重みの訓練が簡単になる。

  • tf.get_collection()関数
    • 下位層の変数を除外して、オプティマイザに訓練する変数のリストを渡す
learning_rate = 0.01

output_layer_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope="logits")  # logitsの下位層は除外
optimizer = tf.train.AdamOptimizer(learning_rate, name="Adam2")
training_op = optimizer.minimize(loss, var_list=output_layer_vars)

correct = tf.nn.in_top_k(logits, y, 1)
accuracy = tf.reduce_mean(tf.cast(correct, tf.float32), name="accuracy")

init = tf.global_variables_initializer()
five_frozen_saver = tf.train.Saver()

数字1つあたり100個の画像で5から9までの数字について新しいDNNを訓練

学習

n_epochs = 1000
batch_size = 20

max_checks_without_progress = 20
checks_without_progress = 0
best_loss = np.infty

with tf.Session() as sess:
    init.run()
    restore_saver.restore(sess, "./my_best_mnist_model_0_to_4")
        
    for epoch in range(n_epochs):
        rnd_idx = np.random.permutation(len(X_train2))
        for rnd_indices in np.array_split(rnd_idx, len(X_train2) // batch_size):
            X_batch, y_batch = X_train2[rnd_indices], y_train2[rnd_indices]
            sess.run(training_op, feed_dict={X: X_batch, y: y_batch})
        loss_val, acc_val = sess.run([loss, accuracy], feed_dict={X: X_valid2, y: y_valid2})
        if loss_val < best_loss:
            save_path = five_frozen_saver.save(sess, "./my_mnist_model_5_to_9_five_frozen")
            best_loss = loss_val
            checks_without_progress = 0
        else:
            checks_without_progress += 1
            if checks_without_progress > max_checks_without_progress:
                print("Early stopping!")
                break
        print("{}\tValidation loss: {:.6f}\tBest loss: {:.6f}\tAccuracy: {:.2f}%".format(
            epoch, loss_val, best_loss, acc_val * 100))

with tf.Session() as sess:
    five_frozen_saver.restore(sess, "./my_mnist_model_5_to_9_five_frozen")
    acc_test = accuracy.eval(feed_dict={X: X_test2, y: y_test2})
    print("Final test accuracy: {:.2f}%".format(acc_test * 100))
結果
Total training time: 2.2s
Final test accuracy: 74.04%

重みの計算の部分を全て凍結しているから、学習速度はめちゃくちゃはやくなっている。各画像100枚ずつの学習だからなんとも言えないが、それにしても74%は低い。まあ、前回作成したモデルの隠れ層をそのまま使ってるから当たり前なんだけど...

再利用する隠れ層の数を変更(5 -> 4)

これ以降は上記のコードを少しいじればできるので、コードは省略します。前回と同じようにGitHubに置いてあるので、興味のある方は見てください。

github.com

Final test accuracy: 75.77%

まあ、さっきよりはほんの少し良くなったくらい。

上位2層の凍結を解除(隠れ層1,2のみを凍結)

Final test accuracy: 81.92%

少ない学習データに関わらず、そこそこの精度は得られてるけど前回ほど高い数値はでないなあ

最後に

今回はそこまで良い結果が得られなかったが、転移学習は深層学習に必須の知識なので、ぜひ使えるようになりたい。転移学習ができるようになれば、わざわざ下位層の重みの計算をしなくて済み、実行時間が大幅に短縮できるので非常に便利だと思った。

scikit-learnとTensorFlowによる実践機械学習

scikit-learnとTensorFlowによる実践機械学習