hcpe3 は、dlshogi 系で使われる教師データ形式の一つである。Huffman Coded Pos and Eval 系の形式を拡張し、自己対局や MCTS で得られる候補手分布を、学習に使いやすい形で保存する。
従来の hcpe は、局面、評価値、最善手、勝敗結果を局面単位で保持する形式である。一方 hcpe3 は、一局の開始局面を基準に、各手の選択手、探索評価、候補手数、候補手ごとの訪問回数を順に記録する。これにより、AlphaZero 型の MCTS の訪問回数分布を方策教師にする 学習と相性がよい。
hcpe3 は、単なる棋譜保存形式というより、教師データ生成と学習処理の間をつなぐ中間形式である。棋譜のように指された手だけを保存するのではなく、探索で得た候補手分布も保存できるため、方策ネットワークに どの手がどれくらい探索されたか を学習させられる。
TadaoYamaoka 氏の開発日記では、2021 年に hcpe3 関連ブランチが master に統合され、hcpe と hcpe3 を同じ学習スクリプトで読めるようになったこと、重複局面の平均化や評価値補正をオプション化したことが説明されている。
DeepLearningShogi の実装では、hcpe3 は主に次の構造体で構成される。
HuffmanCodedPosAndEval3
一局のヘッダ。開始局面 hcp、手数 moveNum、終局結果 result、対戦相手種別 opponent を持つ。MoveInfo
各手の情報。実際に選ばれた手 selectedMove16、探索評価 eval、候補手数 candidateNum を持つ。MoveVisits
候補手の情報。候補手 move16 と訪問回数 visitNum を持つ。HuffmanCodedPosAndEval3 の result には、勝敗だけでなく千日手、入玉宣言、最大手数到達などを表すビットも含まれる。opponent は、自己対局、先手 USI エンジン、後手 USI エンジンなど、データの由来を区別するために使われる。
hcpe や HuffmanCodedPosAndEval2 は、局面に対して最善手、評価値、結果を対応させる形式である。これは教師局面をランダムアクセスしやすく、従来型の評価関数学習や教師あり学習に向いている。
hcpe3 は、一局単位で開始局面から手を進めながら局面を復元し、候補手分布を読み出す形式である。局面ごとに候補手の訪問回数を持てるため、最善手だけでなく複数候補手の確率分布を方策教師にできる。
この違いにより、hcpe3 は MCTS で生成した自己対局データを表現しやすい。ただし、ファイル内の各局面を読むには一局の手順をたどる必要があるため、学習時には読み込み時にランダムアクセスしやすい内部表現やキャッシュへ変換される。
dlshogi.data_loader.Hcpe3DataLoader は、hcpe3 ファイルを読み込み、学習用のミニバッチとして入力特徴量、方策分布、勝敗結果、価値を返す。
C++ 側の読み込み処理では、候補手の訪問回数を確率分布に変換する。温度 temperature が 1 の場合は訪問回数に比例した分布になり、0 の場合は最大訪問回数の手だけを one-hot にする。それ以外の場合は、訪問回数に 1 / temperature 乗をかけた分布に変換する。
また、use_average を有効にすると重複局面をまとめ、評価値、結果、候補手分布を加算して平均化できる。use_evalfix を有効にすると、評価値から勝率への変換スケールをデータに合わせて補正する。TadaoYamaoka 氏の比較では、重複が多いデータでは平均化が学習安定化に重要で、評価値補正は価値側の損失を下げる傾向があると説明されている。
大量の hcpe3 を毎回ファイルから復元すると、局面復元や候補手分布変換のコストが大きい。そのため dlshogi には make_hcpe3_cache.py、merge_hcpe3_cache.py、stat_hcpe3_cache.py、hcpe3_cache_re_eval.py などの補助スクリプトが用意されている。
PyTorch Lightning 対応の記事では、マルチ GPU 学習時にはデータローダが複数プロセスで作成されるため、前処理済みキャッシュを作っておくとよいと説明されている。これは、hcpe3 が豊かな情報を持つ一方で、学習時には効率よくランダムアクセスできる形にしておく必要があるためである。
dlshogi の dlshogi/utils には、hcpe3 を扱う補助ツールが多数含まれる。
csa_to_hcpe3.py
CSA 棋譜から hcpe3 を作る。aoba_to_hcpe3.py
AobaZero 系のデータから hcpe3 を作る。hcpe3_to_hcpe.py
hcpe3 を従来の hcpe 形式へ変換する。hcpe3_to_psv.py
hcpe3 を Packed SFEN Value 系の形式へ変換する。hcpe3_to_csa.py
hcpe3 を確認用に CSA 棋譜へ戻す。split_hcpe3.py、stat_hcpe3.py、clean_hcpe3.py
分割、統計、クリーニングを行う。make_hcpe3_cache.py、merge_hcpe3_cache.py
学習用キャッシュを作成・結合する。candidateNum == 0 の手は、方策分布を持たない局面として扱われる。hcpe3 と棋譜変換由来の hcpe3 では、候補手分布の意味が異なる場合がある。hcpe3 は豊かな形式だが、そのままではランダムアクセスしにくいため、大規模学習ではキャッシュ利用が重要になる。hcpe3_to_hcpe.py のような変換では、複数候補手の分布情報が失われる可能性がある。opponent、開始局面、探索 playout 数、モデル世代などの由来情報を意識する必要がある。