DeepLearningによる将棋の学習8~元のモデル~

 前回はフィルタ数を変更して実験をしてみました。

 今回はいろんな実験をしすぎて情報が取っ散らかってきたように思えるのでここらで一度標準的なものを再実験してみることにしました。

 ResidualBlock5つ、フィルタ数192、optimizerはSGD、patienceは10、損失の比は1:0.1、バッチサイズは256での実験です。

Epoch Total Loss Policy Loss Value Loss Move Accuracy Value Accuracy
1 3.6851 3.6216 0.6356 0.2560 0.6093
2 3.1959 3.1348 0.6113 0.2961 0.6300
3 2.9791 2.9188 0.6023 0.3167 0.6368
4 2.8631 2.8040 0.5909 0.3305 0.6466
5 2.7799 2.7218 0.5808 0.3386 0.6529
6 2.7272 2.6693 0.5789 0.3459 0.6553
7 2.6715 2.6144 0.5709 0.3515 0.6621
8 2.6428 2.5854 0.5744 0.3550 0.6591
9 2.6117 2.5546 0.5711 0.3588 0.6622
10 2.5974 2.5408 0.5668 0.3607 0.6651
11 2.5806 2.5243 0.5625 0.3628 0.6691
12 2.5684 2.5122 0.5620 0.3637 0.6688
13 2.5526 2.4967 0.5589 0.3675 0.6706
14 2.5516 2.4957 0.5589 0.3669 0.6712
15 2.5524 2.4965 0.5590 0.3689 0.6710
16 2.5471 2.4910 0.5612 0.3682 0.6693
17 2.5485 2.4926 0.5587 0.3691 0.6727
18 2.5504 2.4949 0.5548 0.3679 0.6752
19 2.5531 2.4974 0.5568 0.3681 0.6729
20 2.5573 2.5017 0.5550 0.3689 0.6741
21 2.5650 2.5095 0.5557 0.3697 0.6737
22 2.5775 2.5218 0.5566 0.3676 0.6734
23 2.5813 2.5259 0.5543 0.3694 0.6755
24 2.5850 2.5295 0.5548 0.3689 0.6762
25 2.5995 2.5441 0.5534 0.3671 0.6765
26 2.6024 2.5469 0.5556 0.3689 0.6748

f:id:tokumini:20180425131349p:plain

 思ったよりも精度が出ませんでした。指し手を検証してみても初期局面で▲1八香、▲9八香などが高い確率で示されていてあまり上手くいっているようには見えません。損失の比をいじると見た目の数字だけ改善されている可能性があります。

 損失の減少具合と指し手の自然さがあまり一致しない場合、学習の進行度合いを確認する指標がなくなり、苦しい事態となるのですが……。

 確認できることとして、patienceは相当小さくても良いのではないかということがあります。そもそもテストデータに対する損失で学習終了を決定して良いのかという疑問はありますが、これを正しいとすると、一度損失が増加し始めると改善されることはないような結果が今のところ得られています。

 収束まで16エポックかかっていることも気になります。特に変な実験条件ではないはずなので、こんなにかかる原因がよくわかりません。今回からバッチサイズを倍にしていることが効いているのでしょうか。時間がかかるわりに性能がよくなっているということがあればいいのですが、あまりその傾向はみられないようにも思えます。

 5ブロックではNesterovが良いということもあるのかもしれません。ブロック数によって最適なoptimizerが異なると膨大な実験が必要になってしまうようにも思えるのですが……。

 一度性能まとめ記事を作らないと自分でもなにをやっているのか少しわからなくなってきています。うまく実験をデザインしていきたいです。

DeepLearningによる将棋の学習7~フィルタ数の変更~

 フィルタ数を256にして実験してみました。

 損失の比が1:1の場合

Epoch Total Loss Policy Loss Value Loss Move Accuracy Value Accuracy
1 3.9012 3.3180 0.5833 0.2844 0.6544
2 3.4626 2.8997 0.5630 0.3194 0.6710
3 3.2766 2.7227 0.5539 0.3407 0.6819
4 3.1787 2.6200 0.5587 0.3514 0.6841
5 3.1518 2.5581 0.5938 0.3606 0.6776
6 3.1222 2.5166 0.6057 0.3661 0.6785
7 3.1237 2.4928 0.6309 0.3681 0.6770
8 3.1259 2.4712 0.6547 0.3718 0.6764
9 3.1711 2.4665 0.7046 0.3728 0.6740
10 3.1869 2.4692 0.7177 0.3742 0.6748
11 3.2392 2.4728 0.7664 0.3733 0.6735
12 3.2619 2.4747 0.7872 0.3741 0.6717
13 3.2887 2.4768 0.8119 0.3761 0.6696

 損失の比が1:0.01の場合

Epoch Total Loss Policy Loss Value Loss Move Accuracy Value Accuracy
1 3.3156 3.3090 0.6593 0.2834 0.5909
2 2.8898 2.8834 0.6388 0.3241 0.6097
3 2.7190 2.7127 0.6262 0.3418 0.6196
4 2.6072 2.6010 0.6199 0.3549 0.6245
5 2.5365 2.5303 0.6135 0.3603 0.6298
6 2.4879 2.4818 0.6082 0.3686 0.6344
7 2.4555 2.4495 0.6045 0.3722 0.6367
8 2.4368 2.4307 0.6018 0.3753 0.6388
9 2.4318 2.4259 0.5982 0.3756 0.6418
10 2.4138 2.4078 0.5952 0.3798 0.6441
11 2.4311 2.4251 0.5946 0.3785 0.6441
12 2.4338 2.4278 0.5929 0.3803 0.6452
13 2.4469 2.4410 0.5937 0.3783 0.6453
14 2.4570 2.4511 0.5925 0.3789 0.6469
15 2.4788 2.4729 0.5911 0.3769 0.6468
16 2.4921 2.4862 0.5890 0.3783 0.6484
17 2.5086 2.5027 0.5892 0.3781 0.6487

 グラフでは

 損失が1:1の場合 f:id:tokumini:20180423151142p:plain

 損失が1:0.01の場合 f:id:tokumini:20180423151205p:plain

損失最小の時点での結果

比(Move:Value) Total Loss Policy Loss Value Loss Move Accuracy Value Accuracy
1:1 3.1222 2.5166 0.6057 0.3661 0.6785
1:0.01 2.4138 2.4078 0.5952 0.3798 0.6441

 損失が1:1のとき、PolicyとValueでピークがあってないように見えるのが気になるんですね。その点1:0.01にすると無理やりValueの変化を小さくできているような……。しかしValueがまだ学習できるような感じにも見えます。この中間くらいでしょうかね。

 澤田さんの本を読んでも思ったのですが、目的意識もないままによくわからない実験を繰り返しているのは良くないですね。何かしらの仮説があって、それを検証するような実験を行いたいです。

 まぁしかしいろいろなネットワークを試していた結果、結局5ブロックのCNNで良いんじゃないかとわかってきたのは成果なのかもしれません。

 そろそろ強化学習の方に手を付けていきたいと思っていますが……。

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を用いて自動化しました。まだ使い方がよくわからず苦労するところも多いのですが……。