一般的な方策勾配法では、選択した行動aに対して、損失を計算するが、
AlphaZeroでは、方策の損失は、探索から求めた方策の確率分布を使用している。
dlshogiでは、前者をベースにしたActor-Criticで更新を行っている。
後者の確率分布を学習する場合と、どちらが良いのか比較してみた。
実装
損失関数
選択した行動を学習する場合は、方策がソフトマックス関数で、出力がロジットの場合は、PytorchのCrossEntropyLossを使用して損失が計算できる。
確率分布を学習する場合は、組み込みの損失関数がないため、以下のように損失関数を定義した。
def cross_entropy_loss_with_soft_target(pred, soft_targets): return torch.sum(-soft_targets * F.log_softmax(pred, dim=1), 1)
教師データ
方策の確率分布が教師データに必要になるため、dlshogiで使用しているhcpeフォーマットでは対応できない。
また、合法手ごとの訪問回数を記録するため、局面により合法手の数が異なるため可変長フォーマットになる。
hcpeを拡張して、以下のようなフォーマットにした。
HuffmanCodedPosAndEval3 = np.dtype([ ('hcp', dtypeHcp), ('eval', dtypeEval), ('bestMove16', dtypeMove16), ('result', np.uint8), ('seq', np.uint8), # 開始局面からの手数/2(今のところ使わない) ('candidateNum', np.uint16), ]) MoveVisits = np.dtype([ ('move16', dtypeMove16), ('visits', np.uint16), ])
MoveVisitsはcandidateNumの数だけ繰り返す。
可変長フォーマットの場合は、今までの固定長のようにディスク上のデータすべてをメモリにそのまま読み込んで使用することができないので、シーケンシャルに読み込む処理が必要になる。
その場合は、開始局面のhcpと指し手のみ記録した方がデータサイズを節約できる。
また、resultを全局面に記録する必要もなくなるので、フォーマットはもう少しスリムにできる。
とりあえず実験したかったので、上記のような冗長なフォーマットになっている。
測定方法
強化学習で新たに教師データを生成するには時間がかかるため、方策の分布が記録されているAobaZeroの棋譜を使用した。
棋譜はarch000015000000からarch000015190000を使用し、合計19,695,636局面を学習した。
テストデータには、floodgateのレート3500以上の対局の棋譜からサンプリングした856,923局面を使用した。
比較対象のActor-Criticは、dlshogiで使用している式を使用した。
これはエントロピー正則化も含んでいる。
比較結果
訓練損失
訓練平均方策損失 | 訓練平均価値損失 | |
---|---|---|
Actor-Critic | 0.90724320 | 0.58483684 |
分布を学習 | 1.97043909 | 0.58462431 |
テスト損失
テスト方策損失 | テスト価値損失 | |
---|---|---|
Actor-Critic | 0.98559491 | 0.57659638 |
分布を学習 | 0.93136043 | 0.56870430 |
テスト正解率
テスト方策正解率 | テスト価値正解率 | |
---|---|---|
Actor-Critic | 0.40432432 | 0.68084011 |
分布を学習 | 0.41709992 | 0.68707843 |
考察
方策の訓練損失は式が異なるため直接は比較できない。
テスト損失は、dlshogiの損失計算に合わせている。
テスト損失、テスト正解率どちらも、分布を学習した方が、方策、価値どちらも良い値になっている。
ただし、価値については初期値の影響による誤差の範囲かもしれない。
また、方策のエントロピーが分布を学習した方が高く、より偏りの少ない方策になっていることがわかる。
まとめ
方策をActor-Criticで学習する場合と、探索後のルートノードの訪問数を使用した確率分布を学習する場合の比較を行った。
実験結果から、方策は分布を学習した方がよさそうということがわかった。
結果を受けて、dlshogiの強化学習でも分布を学習可能にする予定である。
教師データのフォーマットの見直しから行うことにする。