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

DeepLearningによる将棋の学習5~損失の配分を変更~

 前回はフィルタサイズを変更してもうまくいかないことを確認しました。

 個人的にはDeepLearningによる学習でValueの学習がなかなかうまくいかないという点が気になっています。マルチタスク学習をさせているので損失は指し手の一致具合とValueの一致具合の和を取っている

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

のですが、ここの配分を変えてみることで何か知見が得られないかと考えました。

 小さいデータ(訓練用1000局、テスト用100局)でいくらか試してみたところ、Value側の損失を大きくしても(定数100をかけても)そこまでValue予測の質は改善されない一方、指し手予測の方はひどい性能になりました。

 もともとValueだけを学習するネットワークでもそこまでの精度になっていないことを考えると、これは当たり前なのかもしれません。

 一方で逆にValueの損失を小さくするとValue予測の方は多少質が悪化した一方で指し手予測の精度は上がったため、これで全データを使って実験してみました。正確にはvalue側の損失に0.1をかけて学習させました。

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

 Residualブロック数は5、optimizerはSGD、early stoppingのpatienceは7で実験した結果が以下となります。

epoch Loss Move Accuracy Value Accuracy
1 3.5121 0.2691 0.6114
2 3.0486 0.3111 0.6389
3 2.8629 0.3315 0.6432
4 2.7399 0.3454 0.6505
5 2.6606 0.3545 0.6572
6 2.6133 0.3587 0.6618
7 2.5537 0.3667 0.6635
8 2.5361 0.3689 0.6647
9 2.5160 0.3707 0.6698
10 2.4973 0.3730 0.6707
11 2.4876 0.3743 0.6689
12 2.4843 0.3759 0.6745
13 2.4760 0.3783 0.6731
14 2.4844 0.3774 0.6744
15 2.4794 0.3795 0.6742
16 2.4832 0.3790 0.6717
17 2.4864 0.3799 0.6747
18 2.4926 0.3797 0.6761

f:id:tokumini:20180420095852p:plain

 学習に必要なエポック数は伸びていますが特に性能は上がっていません。損失の合計が小さくなっているので収束が遅いのは当然なのでしょうか。それならばValue側の損失の寄与も十分に意義あるものだった、ということになると思えます。

 学習自体が不安定なのではないかという説も自分の中で起こっています。同じ条件で何度も実験してみないと何も言えないのかもしれません。

 実験とは本質的に関係のないことかもしれませんが、ログファイルから表の作成、グラフの作成あたりは自動化しておいたほうが良さそうですね。山岡さんの本でもいくらか記述があったので、それを参考に頑張ってみたいと思います。

DeepLearningによる将棋の学習4~フィルタサイズの変更2~

 前回はフィルタサイズを5にして実験してみました。その結果性能は下がり、学習時間も多くなるということがわかりました。単純に考えれば増やしてもダメだということになるのですが、念のため今回はさらにフィルタサイズを7にして実験を行いました。結果は以下の通りです。

epoch Loss Move Accuracy Value Accuracy
1 3.5894 0.3014 0.6561
2 3.2799 0.3346 0.6786
3 3.2016 0.3457 0.6791
4 3.2024 0.3553 0.6773
5 3.2453 0.3565 0.6728
6 3.4741 0.3611 0.6501
7 3.3973 0.3579 0.6676
8 3.5083 0.3570 0.6656
9 3.5896 0.3581 0.6662
10 3.6940 0.3570 0.6682

f:id:tokumini:20180419105101p:plain

 今までの結果とまとめると次のようになります。

フィルタサイズ Loss Move Accuracy Value Accuracy 1エポックあたりの学習時間
3 2.9753 0.3879 0.6853 約40分
5 3.1447 0.3643 0.6744 約47分
7 3.2016 0.3457 0.6791 約49分

 やはりフィルタサイズは3が良いようです。

DeepLearningによる将棋の学習3~フィルタサイズの変更~

 前回はブロック数を10、optimizerをAdamにして実験してみましたが良い結果は得られませんでした。

 今回はブロック数ではなくフィルタサイズを3→5に変更して学習させてみました。ブロック数は5、optimizerはSGD、patienceは7です。下の表が結果となります。

epoch Loss Move Accuracy Value Accuracy
1 3.6433 0.2979 0.6583
2 3.2917 0.3352 0.6791
3 3.1746 0.3504 0.6803
4 3.1395 0.3576 0.6763
5 3.1447 0.3643 0.6744
6 3.1594 0.3686 0.6778
7 3.1695 0.3709 0.6735
8 3.2584 0.3708 0.6730
9 3.3467 0.3706 0.6707
10 3.3977 0.3705 0.6708
11 3.4479 0.3679 0.6675

 グラフとして描くと下の様になります。

f:id:tokumini:20180418095416p:plain

 フィルタサイズ3のものに比べると以下のようになります。

フィルタサイズ Loss Move Accuracy Value Accuracy 1エポックあたりの学習時間
3 2.9753 0.3879 0.6853 約40分
5 3.1447 0.3643 0.6744 約47分

 性能が悪化していることがわかります。また学習時間も伸びているため良いとこなしです。

 これを書く段階で気づきましたがoptimizerはフィルタサイズ3のときに合わせてNesterovにするべきでした。ここが統一されていない時点で今回の実験は比較に値しないものかもしれません。

 学習曲線の気になるところとしてはロスが下がらなくなったあともMove Accuracyは少し上がっていることでしょうか。しかしValue Accuracyは下がっているため、良い学習ができているわけでもなさそうです。

 この実験に限らずDeepLearningではValueの学習がなかなか難しいという印象を持っており、2駒関係などでそれなりな性能が出ることを考えると少し意外だと感じます。なにか実装を間違えているのではないかという気にもなりますが、山岡さんの本でもあまりValue Accuracyは高くなっておらず、これくらいなものなのかもしれません。

DeepLearningによる将棋の学習2~Adamによる学習~

 前回の続き。

 patienceを7にしてAdamでもやってみました。

optimizer = tf.train.AdamOptimizer(learning_rate=0.001)

 結果は次の通りです。

epoch Loss Move Accuracy Value Accuracy
1 4.4521 0.2929 0.6807
2 4.1956 0.3232 0.6873
3 4.1133 0.3335 0.6898
4 4.0703 0.3424 0.6890
5 4.0683 0.3443 0.6880
6 4.1143 0.3480 0.6846
7 4.1600 0.3477 0.6800
8 4.1749 0.3476 0.6822
9 4.2409 0.3456 0.6787
10 4.2836 0.3483 0.6772
11 4.2952 0.3469 0.6761
12 4.3597 0.3464 0.6791

 5epochで損失が下がりきっており、収束は速いのですが、収束した値の性能はあまり良さそうではありません。

 またここから損失が再び下がっていくということはないように思えます。

 今までの結果をグラフ化すると f:id:tokumini:20180417101518p:plain f:id:tokumini:20180417101529p:plain f:id:tokumini:20180417101537p:plain f:id:tokumini:20180417101634p:plain

 となります。patienceが小さすぎるということはないのかなぁと思えるのですが、もっとやったら違うのかもしれません。またそもそも学習データ量が少なすぎる可能性もあり、たとえば2015年の棋譜を使う、あるいはやねさんが公開されている(まだ公開されているのでしょうか?)ものを使うなどのことをしなければならないのかもしれません。

DeepLearningによる将棋の学習1

 山岡さんの本を参考にtensorflowを用いてDeepLearningを用いた将棋ソフトを作ってみています。

将棋AIで学ぶディープラーニング

将棋AIで学ぶディープラーニング

 ResidualNetを実装しているところなのですが、実装がまずいのかブロック数を増やすと上手く学習してくれないという事態が起こりました。現在の実装は以下の通りです。山岡さんの本をそのまま模倣しようとしているので、そうなっていない部分があったら指摘していただけると幸いです。

ch = 192
kernel = 3


def ResidualBlock(inputs):
    conv1 = tf.layers.conv2d(inputs=inputs, filters=ch, kernel_size=kernel, padding="same", use_bias=False)
    bn1 = tf.layers.batch_normalization(inputs=conv1, training=True)
    relu1 = tf.nn.relu(bn1)
    conv2 = tf.layers.conv2d(inputs=relu1, filters=ch, kernel_size=kernel, padding="same", use_bias=False)
    bn2 = tf.layers.batch_normalization(inputs=conv2, training=True)
    return tf.nn.relu(inputs + bn2)


def policy_value_func(features):
    # Input Layer
    # featuresのshapeは9×9マスが104チャネル ([-1, 9, 9, 104])
    input_layer = features

    # ResidualBlock
    conv1 = tf.layers.conv2d(inputs=input_layer, filters=ch, kernel_size=3, padding="same", activation=tf.nn.relu)
    res1 = ResidualBlock(conv1)
    res2 = ResidualBlock(res1)
    res3 = ResidualBlock(res2)
    res4 = ResidualBlock(res3)
    res5 = ResidualBlock(res4)
    res6 = ResidualBlock(res5)
    res7 = ResidualBlock(res6)
    res8 = ResidualBlock(res7)
    res9 = ResidualBlock(res8)
    res10 = ResidualBlock(res9)

    # policy_network用
    conv13p = tf.layers.conv2d(inputs=res10, filters=MOVE_DIRECTION_LABEL_NUM, kernel_size=1, padding="same",
                               activation=tf.nn.relu)
    policy = tf.reshape(conv13p, shape=[-1, 9 * 9 * MOVE_DIRECTION_LABEL_NUM])

    # value_network用
    conv13d = tf.layers.conv2d(inputs=res10, filters=MOVE_DIRECTION_LABEL_NUM, kernel_size=1, padding="same",
                               activation=tf.nn.relu)
    # 1次元化する
    flat = tf.reshape(conv13d, [-1, 9 * 9 * MOVE_DIRECTION_LABEL_NUM])

    # 全結合層
    dense = tf.layers.dense(inputs=flat, units=256, activation=tf.nn.relu,)
    # 出力値はスカラ1つ
    value = tf.layers.dense(inputs=dense, units=1)
    # サイズ1のベクトルになっているのでsqueezeで直す
    value = tf.squeeze(value, axis=1)

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

 学習はfloodgateの2016年の棋譜を山岡さんの本の通りに学習用3,711,167局面、テスト用414,677局面に分け、early stoppingをpatience = 3でやっています。

 5ブロックで行った場合の結果が以下

epoch Loss Move Accuracy Value Accuracy
1 3.6427 0.3086 0.6702
2 3.2474 0.3481 0.6825
3 3.1120 0.3646 0.6899
4 3.0099 0.3765 0.6882
5 2.9835 0.3807 0.6913
6 2.9768 0.3865 0.6861
7 2.9753 0.3879 0.6853
8 3.0051 0.3903 0.6839
9 2.9959 0.3927 0.6816
10 3.0267 0.3927 0.6815

 10ブロックで行った場合の結果が以下のようになります。

epoch Loss Move Accuracy Value Accuracy
1 5.0812 0.2416 0.6547
2 4.6445 0.2853 0.6804
3 4.4765 0.3042 0.6877
4 4.3976 0.3153 0.6901
5 4.3842 0.3237 0.6883
6 4.3915 0.3265 0.6866
7 4.3952 0.3267 0.6836
8 4.4427 0.3301 0.6837

 5ブロックのときと比べて損失が大きい段階で学習が終了しています。指し手の一致率も6%以上低いです。今冷静に見返すとやはりもっとpatienceを大きくするべきなのでしょうか……。

 上の二つの実験はoptimizerをNesterovありのmomentum

optimizer = tf.train.MomentumOptimizer(learning_rate=0.01, momentum=0.9, use_nesterov=True)

で行っており、普通のSGD

optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)

にしたところ5ブロックの場合にやや劣る程度になりました。

epoch Loss Move Accuracy Value Accuracy
1 3.9261 0.2829 0.6452
2 3.4671 0.3243 0.6741
3 3.2671 0.3472 0.6791
4 3.1414 0.3597 0.6859
5 3.0936 0.3697 0.6810
6 3.0394 0.3727 0.6882
7 3.0323 0.3789 0.6845
8 3.0575 0.3811 0.6798
9 3.0550 0.3833 0.6842
10 3.0771 0.3852 0.6813

 表にして最終結果をまとめると以下のようになります。

model Loss Move Accuracy Value Accuracy
5ブロック(Nesterov) 2.9753 0.3879 0.6853
10ブロック(Nesterov) 4.3842 0.3237 0.6883
10ブロック(SGD) 3.0323 0.3789 0.6845

 patienceが小さいと鞍点にハマってしまうかどうかに大きく左右され、運次第になってしまうということでしょうか。それぞれ1回の実験だけではなんとも言えないという気もします。optimizerとの相性の問題だとするとかなり大変なことだなと思えるのですが、何はともあれもっと実験を重ねてみるしかなさそうです。

AtCoderRegularContest095 参加ログ

結果

 C,D,Eの3完で112位。後述するがE問題はほぼ不正のような解き方をしている。高順位となったが実力ではない。

 今回の結果によって青コーダーになれてしまったが、今後も精進を重ねていかなければいきたい。 f:id:tokumini:20180415094204p:plain

C問題

 配列Aを違う配列BにコピーしておいてBをソートし、各A[i]に対してB[N / 2]かB[N / 2 - 1]を出力していけばいいだろうというところまで考えてコードを書き始め、条件分岐はサンプルに合うようにした。こういうところを最後まで考え切ってから実装し始めるか、サンプルに頼るかは悩むところ。なんとかWAなく4分50秒でAC。

D問題

 知識として、nに対してコンビネーションが大きくなるのはだいたいn/2個選ぶときであるというのは知っていたが、nに最大のものを選んでいいということに気づくのがちょっと遅れた。それさえわかってしまえば、と思って2分探索で出したがWA。別に10の5乗くらいなら全部舐めてしまえばいいなと気づいて21分41秒でAC。もうちょっとスマートに解いていきたい。

E問題

 上の人と同じことをした。

 各操作において、行・列についてどの文字が何個含まれるようなものがあるかということは変わらない。よってそれをmapで取っておき、H,Wの偶奇に合わせてペアがうまく作れるか、そして真ん中が回文になるかという条件を考えた。上の通りこれは必要条件にすぎないのでダメだろうと思いつつ提出したらWAが1個だけだった。assertで範囲を絞りつつ、一応はなんで間違っているのかを考えていたが、最終的にはWAのケースを特定できてしまったのでそこだけ"NO"を出力するようにしてAC。6WAで74分17秒。まぁひどい解き方ですね。

 しかし他の人の提出を見ても乱択? っぽいのとか焼きなましだったりとか、わりと想定とは違う解法がびゅんびゅん飛んでいるように思える。だからといってassert二分探索の罪が軽くなるわけではないが、まぁやっぱり制約が小さいといろいろ起きるのかなとも。

総括

 何はともあれ青コーダーになったのはなったのだ。これからはちゃんと青を安定させられるように頑張っていきたい。

将棋ウォーズで二段になったので採用している序盤作戦について書いてみた

 先日将棋ウォーズで二段になりました。将棋を始めたきっかけは電王戦FINALなので、将棋歴は約3年ということになりますね。ちょうど区切りも良いということで、今回は二段になったタイミングで採用していた序盤作戦についてまとめてみたいと思います。

 局面図もいくらか載せてみますが、手順とかは正確ではないことをご了承ください。

居飛車

 相居飛車は基本的に横歩取り、角換わりを目指します。相手の変化によっては雁木や、その他力戦という感じになります。

1.角換わり

 角換わりは基本的に先手でも後手でも腰掛銀で4八金2九飛車の形を目指します。もちろん駒組の段階でも仕掛けを考えはしますが、大抵は図のように自陣を組んでから相手の形に応じて考えることになります。

 一番気分として楽なのは相手が5二金、8二飛車の形で4四歩と突いてくれている形(下図)で、これなら4五歩から仕掛けて良いんじゃないかなぁという感じです。形勢としては別に差はないとは思いますが、先攻できるならまぁ不満なしです。f:id:tokumini:20180208133423j:plain

 一番嫌なのは同型(下図)になることで、そうなるともう仕掛けがわからないので先手でも千日手やむなしの姿勢で、多少待機気味に玉を動かしたりして相手に隙ができるのを待つしかなくなります。しかし意外と千日手にはならないもので、こっちがバランス崩したり相手が崩したりしてなんだかんだ決着はつくものです。多分あまり僕の勝率は高くないと思います……。f:id:tokumini:20180208133724j:plain

 相手が早繰銀ならば腰掛けるのを急いで6五歩で相手の銀を追っ払う形(下図)を目指します。しかしこれ棒銀に切り替えられたりしたときにちゃんと受かるのかは自信がありません。f:id:tokumini:20180208134048j:plain

2. 横歩取り

 横歩取りは先手なら勇気流、後手なら斎藤流を目指します。といっても特に研究しているわけではないので、形とか狙い筋だけをちょっと真似している程度ですね。

 当然、勇気流は相手にやられることもあって、その時には飛車をぶつける作戦(下図)をやっています。これはプロで前例があったやつで、初出がどの対局かは知りませんが僕が記憶しているのは去年の羽生-村山戦ですね。一度だけ40手くらいこの前例をなぞりあう展開になったことがあり、その時は僕が先に手順を忘れていて負けにしたので、特に記憶に残っていますね。f:id:tokumini:20180208135832j:plain

 後手では斎藤流(下図)を目指します。斎藤流は神崎蘭子さんの将棋グリモワールを読んで知ったもので、まだちゃんと変化とかを全部覚えているわけではないんですが相手よりは多少知識はあって有利かなぁというくらいです。f:id:tokumini:20180208140038j:plain

 横歩取りの後手を持っていて気になるのはときどき8七歩と受けるのが早い(下図)人がいることですね。これは一応2四飛と回れば先手は歩で謝るしかなくて多少指しやすいと思っているんですが、まぁめちゃくちゃ有利というわけでもありませんか。f:id:tokumini:20180208135903j:plain

3.対雁木

 最近はプロの影響なのか、相手が角道を止めてくる居飛車力戦みたいな形がちょっと増えた気がします。しかしこれは叡王戦本戦の丸山-小林戦のように船囲い+早繰銀というような形にすれば互角以上の形勢で先攻できる(下図)ことが多いので特に不満はないという感じですかね。f:id:tokumini:20180208140818j:plain

 これは銀を2六と4六のどっちにあがるべきなのかなぁとかちょっと迷いますが、うーんまぁよくわかりません。

振り飛車

 対振り飛車では対抗形が苦手なので相振り飛車を目指すようにしています。特に向飛車に振って相居飛車の左右反転した局面としてとらえていきたいところです。手数の関係で相振りにしにくい先手の時だけはちょっと対抗形も指すように変えつつあるタイミングで二段になりました。

4.対四間飛車

 先手だと3手目に2六歩と突いてしまうのが相振りを目指すうえでネックとなります。特に最近は雁木が増えたこともあって、角と左銀だけ動かされると雁木か四間飛車か判別できないことが多いく、困りどころです。雁木には居飛車を、四間飛車には相振りをやりたいのですが、どちらでも対応できるようにしても下図くらいが限界なので最近は諦めて対抗形をやるようにしています。2五歩まで指してしまうと相振りにはしづらい気がしているのですが、2六歩は許容しているのに一貫性がないかもしれません。f:id:tokumini:20180208141820j:plain

 とりあえず最近の対四間飛車先手番では対抗形、急戦を目指します。穴熊はさっぱり得意ではないので急戦で頑張ります。よくやるのは下図のような形で、飛車角銀桂でなんとか攻めていきたいところですが、やっぱり自玉が薄くて大変なことが多いですね。f:id:tokumini:20180208150353j:plain

 後手だとほぼ相振りにします。これは8四歩の一手を省略できることが多いからです(下図)。しかし雁木に警戒しつつの駒組となるので、厳密には相手に上手くやられると不利な展開になる気がしています。f:id:tokumini:20180208142301j:plain

 具体的には相手に囲いよりも攻めを重視されると嫌で、下の局面は5五銀が見えてても受からないような気がします。しかし個人的な印象としてはそこまでこうやられる頻度は高くなく、四間飛車を指すような人はあまりこういうことはしない性格なのかな……? とか思います。f:id:tokumini:20180208142813j:plain

5.対三間飛車

 あまり三間飛車には当たらない気がしているんですが、結構やられて嫌な作戦ではあります。大抵は対四間飛車と同じように先手なら対抗形、後手では相振りを目指します。しかし後手で対四間飛車と同じように相振りを目指すと時々いきなり突っかけらて、そこでなんとなく7二飛車とぶつけるのが何度か経験した局面です(下図)。f:id:tokumini:20180208144010j:plain

 別に飛車交換する一手ではないと思いますが、今までのところは交換になることが多い感じですかね。こうなれば互いに飛車を持ち合っての戦いになるのでまぁ対抗形よりは好みの将棋になります。

6.対中飛車

 対中飛車でも相手の態度が早いなら相振り、そうでなかったら対抗形という感じになっています。対抗形になるのは大抵相手の後手ゴキゲン中飛車なので主に超速で対応します。対中飛車の相振りはツノ銀雁木のような形にしていきます(下図)。他のよくわからない相振りよりは隙がない感じに組めることが多く、これはこれで一局になっているという気がします。f:id:tokumini:20180208144744j:plain

7.その他振り飛車

 角交換振り飛車は対抗形にすることが多いのですが苦手な戦型ですね。

 向飛車も逆棒銀の筋をそのまま食らって負けるということを何度かやらかしている気がします。

 この辺のちょっと遭遇頻度が低い振り飛車は苦手で、対抗形の指し方、考え方が根本的に身についていないという気がします。

終わりに

 特に相居飛車ではプロが指す戦型を真似をするというのが僕の好みとなっています。対抗形はよくわからなくて変な相振りに逃げたりしていますが、三段を目指すとしたら対抗形をきちんと見つめ直す機会が必要なのだろうなぁと感じているところです。

 三段になれる気はさっぱりしないのですが、初段になったときも二段になれる気は全くしなかったなぁということを思い出すとそういうものなのかもしれません。