前回は損失の配分を調整して学習をさせてみましたが思わしい結果は得られませんでした。しかし、これは指し手予測の精度だけを見た場合の話であり、損失について考えると実は良い結果になっているともいえるかもしれないことに記事を書いてから気づきました。
というのも前回の結果をPolicyとValueそれぞれの損失まで描くと下のようになり
配分を1:1にしていたときのグラフは
のようになっていらからです。配分が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 |
一番損失が小さいタイミングを抜き出すと
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を用いて自動化しました。まだ使い方がよくわからず苦労するところも多いのですが……。