DeepLearningによる将棋の学習6~全結合型NN~

 前回は損失の配分を調整して学習をさせてみましたが思わしい結果は得られませんでした。しかし、これは指し手予測の精度だけを見た場合の話であり、損失について考えると実は良い結果になっているともいえるかもしれないことに記事を書いてから気づきました。

 というのも前回の結果をPolicyとValueそれぞれの損失まで描くと下のようになり

f:id:tokumini:20180421105706p:plain

 配分を1:1にしていたときのグラフは

f:id:tokumini:20180421105943p:plain

 のようになっていらからです。配分が1:1だとValueの損失がすぐ上がっていってしまう(精度はそれほど悪化しない)という問題があり、それが緩和されていた可能性があります。Valueは精度よりも損失の方が重視されるべき指標にも思えますし、配分を変更させるのは良かったのかもしれません。

 この辺りは対局させてみないとわからないということになるのかもしれません。また今後はPolicyとValueのそれぞれの損失も表示するようにします。

 今回はそもそもCNNではなく全結合にしてみたらどの程度の性能になるのかを実験してみました。基本的に畳み込み層をそのまま全結合層に置き換えただけの構成になっています。全結合層を使う場合でもResidual Blockを作るのはおそらく効果あるのだと思いますが正確なことはわかりません。以下はその実装となります。

unit_size = 2048

def ResidualBlock(inputs):
    dense1 = tf.layers.dense(inputs=inputs, units=unit_size)
    bn1 = tf.layers.batch_normalization(inputs=dense1, training=True)
    relu1 = tf.nn.relu(bn1)
    dense2 = tf.layers.dense(inputs=relu1, units=unit_size)
    bn2 = tf.layers.batch_normalization(inputs=dense2, training=True)
    return tf.nn.relu(inputs + bn2)

def policy_value_func(features):
    # featuresのshapeは9×9マスが104チャネル ([-1, 9, 9, 104])
    # ResidualBlock
    flat = tf.reshape(features, [-1, 9 * 9 * 104])
    layer1 = tf.layers.dense(inputs=flat, units=unit_size, activation=tf.nn.relu)
    res1 = ResidualBlock(layer1)
    res2 = ResidualBlock(res1)
    res3 = ResidualBlock(res2)
    res4 = ResidualBlock(res3)
    res5 = ResidualBlock(res4)

    # policy_network用
    dense_policy = tf.layers.dense(inputs=res5, units=9 * 9 * MOVE_DIRECTION_LABEL_NUM)
    policy = tf.reshape(dense_policy, shape=[-1, 9 * 9 * MOVE_DIRECTION_LABEL_NUM], name="policy")

    # value_network用
    dense_value = tf.layers.dense(inputs=res5, units=unit_size, activation=tf.nn.relu)
    # 出力値はスカラ1つ
    value = tf.layers.dense(inputs=dense_value, units=1, name="value")
    # サイズ1のベクトルになっているのでsqueezeで直す
    squeezed_value = tf.squeeze(value, axis=1, name="squeezed_value")

    # policyとvalueの二つを返す
    return policy, squeezed_value

 ユニット数は2048、損失の比は1:0.01、

loss_op = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=policy, labels=teacher_for_move)
                         + 0.01 * tf.nn.sigmoid_cross_entropy_with_logits(logits=value, labels=teacher_for_win))

optimizerはSGD、patienceは5で実験を行いました。以下が結果となります。

Epoch Total Loss Policy Loss Value Loss Move Accuracy Value Accuracy
1 4.5123 4.5054 0.6939 0.2024 0.5642
2 4.0329 4.0262 0.6781 0.2430 0.5753
3 3.7613 3.7545 0.6757 0.2654 0.5781
4 3.5761 3.5695 0.6654 0.2796 0.5897
5 3.4540 3.4474 0.6595 0.2906 0.5929
6 3.3782 3.3717 0.6588 0.2955 0.5938
7 3.3175 3.3109 0.6586 0.3035 0.5938
8 3.2783 3.2717 0.6581 0.3075 0.5960
9 3.2539 3.2473 0.6587 0.3105 0.5942
10 3.2397 3.2331 0.6556 0.3137 0.5960
11 3.2226 3.2160 0.6535 0.3152 0.5993
12 3.2501 3.2436 0.6512 0.3160 0.6003
13 3.2673 3.2608 0.6493 0.3148 0.6012
14 3.2725 3.2660 0.6483 0.3161 0.6008
15 3.3043 3.2977 0.6508 0.3160 0.6009
16 3.3179 3.3115 0.6473 0.3170 0.6024

f:id:tokumini:20180421103818p:plain

 一番損失が小さいタイミングを抜き出すと

Epoch Total Loss Policy Loss Value Loss Move Accuracy Value Accuracy
11 3.2226 3.2160 0.6535 0.3152 0.5993

 であり、畳み込み層を使う場合より性能は低いことがわかりました。

 結果で気になる点は、損失が下がらなくなってからも精度は上がっていることでしょうか。この実験に限らず損失のピークと精度のピーク、あるいはPolicyのピークとValueのピークなどの間にズレがあり、どれを信じるものなのかよくわかりません。

 今回からグラフの作成をmatplotlibを用いて自動化しました。まだ使い方がよくわからず苦労するところも多いのですが……。