dlshogiの自己対局で生成したデータを学習すると、方策損失がNaNになるというissueをもらった。
自己対局棋譜を用いるとPolicyのlossがNaNになる · Issue #44 · TadaoYamaoka/DeepLearningShogi · GitHub
原因
実際にデータをもらって、調査したところ、強化学習で生成したデータに重複局面が多いとうまく学習できない(方策損失がNaNになる)ということがわかった。
私が行っているdlshogiの強化学習では、約5億局面の初期局面集を使用しているため、重複がほぼないため問題が起きていなかった。
しかし、floodgateの棋譜から作成した26手まで初期局面集を使用して生成したデータの場合、デフォルト設定(--random 4)では33%が重複局面になっていた。
重複を削除して、データをユニークにするとうまく学習できるようになった。
局面の偏りについての考察
機械学習の一般論として、データの偏りが大きすぎる場合は、汎化性能を上げるためにアンダーサンプリングなどの手法がとられる。
同様に、局面の偏りが大きすぎると学習に悪影響があると考えられる。
ただし、将棋の学習では、序盤の頻度が高い局面は、それに応じてサンプル数が多い方が良い可能性はある。
しかし、自己対局で生成した局面は、対局時の出現頻度と生成された局面の頻度が一致する理想的な状態にはならない。
AlphaZero方式の強化学習では、30手までは、ルートの子ノードの訪問数に応じたボルツマン分布で手を選択し、30手目以降はグリーディーに選択する。
30手までの出現頻度が実際の対局時の頻度に近くなる保証はなく、また、30手目までが同一の場合、それ以降の手順も重複する可能性が高い(30手目以降もディリクレ分布によるノイズが加えられるが、同じになる確率の方が高い)。
dlshogiの場合は、初期局面集を使用してデフォルト4手だけルートの子ノードの訪問数に応じたボルツマン分布で手を選択しているため、初期局面集が少ないとAlphaZero方式よりも重複しやすい。
偏りをなくす方法
自己対局の初期局面集を増やす
dlshogiの強化学習のように、5億局面くらい初期局面集を用意すれば、ほぼ重複が起きない。
ランダムを増やす
オプションを変更して、ボルツマン分布で手を選択する手数を増やすことで、偏りを減らすことができる(例:--random 8)。
しかし、それ以降グリーディーで選択する手で重複が起きる問題は解消されない。
ユニークにする
単純に偏りをなくすには、ユニークにすればよい。
hcpeフォーマットの場合、
hcpes = np.fromfile(file1, dtype=HuffmanCodedPosAndEval)
np.unique(hcpes, axis=0).tofile(file2)
のようにすれば、ユニークにできる。
しかし、単純にユニークにすると、局面が同一で、勝敗が異なる場合の勝敗の分布を無視してしまう。
アンダーサンプリングする
局面の出現頻度に応じてサンプリングされる確率を下げることで、偏りをなくすことができる。
しかし、アンダーサンプリングすると全データが使用されなくなる。
重複局面を平均化する
重複局面の方策の分布と勝敗および評価値を平均化して、1サンプルとして学習する。
実装が容易で、偏りをなくして、勝敗の分布が学習に反映されるようになる。
重複局面を平均化する方法の実験
ここでは、実装が容易な重複局面を平均化する方法を試してみた。
floodgateの26手目までから作成した初期局面集を使用して、--random 8で、500万局面を生成した。
8.4%が重複局面であった。
初期値から学習した場合と、学習済みモデルに追加学習した場合の2パターンで、テスト精度を比較した。
テストデータには2017年~2018年6月のfloodgateのR3500以上の棋譜からサンプリングした856,923局面(重複なし)を使用した。
初期値やデータのシャッフルによって、結果がぶれるため10回測定の平均で比較した。
考察
初期値から学習した場合は、方策は平均化なしが良く、価値は平均化ありが良いという結果になった。
方策が下がったのは平均化によりサンプル数が減ったことが起因している可能性がある。
学習済みモデルに追加学習した場合は、方策、価値どちらも、平均化した方が良い結果になった。
まとめ
自己対局で生成した局面に重複局面が多いとうまく学習できない事象の対策として、重複局面を平均化する方法を試した。
実験の結果、学習済みモデルに追加学習する場合は、重複局面を平均化した方が、良さそうという結果が得られた。
序盤の出現頻度が高い局面のサンプル数を増やした方がよいという考えもあるが、自己対局で生成した局面が理想的な出現頻度になっているかは考慮が必要だと考える。
ソース
feature/hcpe3_averageブランチに平均化する処理を実装したソースをプッシュした。
GitHub - TadaoYamaoka/DeepLearningShogi at feature/hcpe3_average
※平均化に対応したのは、方策の分布を学習する場合(train_hcpe3.py)のみである。