TadaoYamaokaの開発日記

個人開発しているスマホアプリや将棋AIの開発ネタを中心に書いていきます。

将棋AIモデルのテストデータの作り方

dlshogiで以前から使用しているテストデータと、GCTのノートブックのテストデータで、テスト損失と正解率の違いがあるため、テストデータの作成方法によってどう違いがでるのかを検証した。

テストデータの比較

まず、dlshogiのテストデータとGCTのテストデータの作成条件と、それぞれで同一モデルで測定したテスト損失と正解率について整理すると以下の通りになる。

dlshogiのテストデータ

2018/6/17に作成したテストデータを使い続けている。
これはfloodgateの2017年から2018年6月までの棋譜を元に、csa_to_hcpe.pyで、レーティング双方3500以上、評価値3000を超えたら打ち切りという条件で作成している。
千日手、最大手数による引き分けは出力していない。
また、hcpe_uniqで、局面と指し手が重複するデータを除外している。
局面数は、856,923局面ある。

モデルごとの精度は以下の通り。

モデル 方策損失 価値損失 方策正解率 価値正解率 方策エントロピー
GCT電竜 1.78864127 0.53541758 0.46435664 0.72764303 1.26309002
dlshogi with GCT(model-0000225kai) 1.77482759 0.49535870 0.49073551 0.74466278 1.02956448
dlshogi dr2_exhi 1.41893253 0.46856942 0.52342348 0.76075737 1.35510777
GCTのノートブックのテストデータ

使用しているツール(csa_to_hcpe.py、hcpe_uniq)は同じものを使用している。
使用している棋譜は、floodgateの2008年から2019年の棋譜で、レーティングは双方3500以上、評価値は5000を超えたら打ち切りという条件で作成している。
局面数は、2,414,974局面ある。

上記dlshogiのテストデータとの差分は、floodgateの使用している期間と、評価値の閾値である。

モデルごとの精度は以下の通り。

モデル 方策損失 価値損失 方策正解率 価値正解率 方策エントロピー
GCT電竜 1.83690576 0.51293612 0.46163161 0.73495564 1.24398525
dlshogi with GCT(model-0000225kai) 1.82079209 0.47346048 0.48964214 0.75278598 1.00554464
dlshogi dr2_exhi 1.42115222 0.44965372 0.52322546 0.76564239 1.36627845
比較

上記の2つのテストデータの精度を比較すると、方策についてはdlshogiのテストデータが良い値になり、価値についてはGCTのテストデータが良い値になっている。
floodgateの期間の違いはあるが、主な差分は評価値の閾値の差である。
終盤の局面(評価値3000以上5000以下)まで含む場合、方策の精度は低くなり、価値の精度は高くなるという傾向があることが分かった。
終盤ほど読みの比重が高くなるため方策の正解率が下がって、評価値の差が広がるほど勝敗が明確なため価値の正解率が上がるということだと理解できる。

重複局面の条件変更

np.unique

上記のテストデータは、重複局面を除外する条件として、局面と指し手が一致していることを条件としている。
これを、評価値と勝敗まで含めて一致という条件にしてみた(hcpeを単純にnp.uniqueでユニークにした)。
元データは、floodgateの2017年から2019年の棋譜で、レーティングは双方3500以上、評価値は5000を超えたら打ち切りという条件で作成した。

局面数は、重複削除前:2798640、重複削除後:2551507となった。

モデルごとの精度は以下の通り。

モデル 方策損失 価値損失 方策正解率 価値正解率 方策エントロピー
GCT電竜 1.81846763 0.51962999 0.46602104 0.72777115 1.25068274
dlshogi with GCT(model-0000225kai) 1.80058509 0.48026565 0.49412886 0.74460519 0.99275402
dlshogi dr2_exhi 1.40826132 0.45623083 0.52678000 0.75692493 1.36271331

方策が高くなり、価値は低い値になった。
評価値まで一致しないと別のデータになるため、序盤の局面の数が多くなることが原因と考えられる。
同一局面で評価値がわずかに違うだけのデータが増えると、データが偏るため、局面と指し手の一致を重複の条件とする方が適切と考える。

結果の最頻値化と評価値平均化

局面と指し手の一致で除外すると、最初に読み込んだデータの勝敗結果が使用されて、残りのデータの結果が無視されてしまう。
これは適切ではないため、結果の最頻値を採用し、評価値については平均化を行うようにした。

実装は、pandasのgroupbyを使用して行った。

    df = pd.concat([pd.DataFrame(hcpes['hcp']), pd.DataFrame(hcpes[['eval', 'bestMove16', 'gameResult', 'dummy']])], axis=1)

    # hcpとbestMove16でグループ化して平均を算出
    df2 = df.groupby(list(range(32)) + ['bestMove16'], as_index=False).mean()

    # gameResultは最頻値に変換
    df2.loc[df2['gameResult'] >= 1.5, 'gameResult'] = 2
    df2.loc[(df2['gameResult'] > 0) & (df2['gameResult'] < 2), 'gameResult'] = 1

    hcpes2 = np.zeros(len(df2), HuffmanCodedPosAndEval)
    hcpes2['hcp'] = df2[list(range(32))]
    hcpes2['eval'] = df2['eval']
    hcpes2['bestMove16'] = df2['bestMove16']
    hcpes2['gameResult'] = df2['gameResult']

元データは先ほどと同じく、floodgateの2017年から2019年の棋譜で、レーティングは双方3500以上、評価値は5000を超えたら打ち切りという条件で作成した。
局面数は、重複削除前:2798640、重複削除後:2383564となった。

モデルごとの精度は以下の通り。

モデル 方策損失 価値損失 方策正解率 価値正解率 方策エントロピー
GCT電竜 1.84447462 0.50861321 0.46116580 0.73828041 1.24337653
dlshogi with GCT(model-0000225kai) 1.82565162 0.46669739 0.48931699 0.75633276 1.00591798
dlshogi dr2_exhi 1.42368041 0.44125965 0.52300734 0.76926015 1.37016454

GCTのノートブックのテストデータに比較的近い値になっている。
重複のない局面の方が多いため傾向としては同じで、重複のある局面での勝敗がより統計的に正しく測れるようになったと考える。

さらに統計的に測りたければ、勝敗結果を分布するのがよいが、その場合、正解率という指標は使えなくなるので、正解率を使うなら最頻値を使うのが良いと考える。

同一局面で指し手ごとにデータを分けるのも、数が多い指し手と少ない指し手を同様に扱っているので良くないが、指し手の方は最頻値を採用すると、序盤は一手のみが正解とも言えないので、指し手ごとにデータを分けるようにしている。

まとめ

テストデータの作成条件による精度の傾向を調べた。
また、重複削除の方法として、局面の指し手が一致するデータの勝敗結果の最頻値を使用するという方法を試した。

棋譜から条件を指定してhcpeを作成する方法と、最頻値を使う重複削除はツール化しているので活用して欲しい(今回の調査中にcsa_to_hcpe.pyにバグが見つかったので修正している)。