TadaoYamaokaの開発日記

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

【dlshogi】軽量価値ネットワーク その2(Stockfishの探索)

前回試した軽量価値ネットワークをStockfishの探索に組み込むことを検討している。
最終的には、dlshogiのMCTSベースの探索とStockfishベースの探索を組み合わせることを構想しているが、まずは、単体で動作するStockfishベースのプログラムを作りたい。

実装方針

今後、dlshogiの探索と組み合わせる際に、効率的に組み合わせるには、一つのプログラムで局面の情報を共有したいため、現在のAperyベースのdlshogiの局面管理(Positionクラス)や、指し手生成(MoveListクラス)などは、共通化したい。

既存のPositionやMoveListなどは、Stockfishの探索部にそのまま適用することができない部分があるため、接合する仕組みが必要になる。

その方法として、以下の案を考えた。
1. 既存のクラスをStockfishベースに置き換える
2. まったく別に作成して、情報を受け渡す際の変換処理を実装する
3. 既存のクラスを継承して、不足部分と置換する部分のみを開発する

1.は、今後Stockfishのソースを流用しやすくなるメリットがあるが、将棋特有の処理を一から実装する必要があり、既存のdlshogiにも影響するので、作業量が多い。
2.は、既存のdlshogiには影響しないが、やはり将棋特有の処理を実装するのが大変である。
3.は、不足部分と置換する部分のみを開発すれば良く、既存のdlshogiへの影響も小さい。

作業量を優先して、3.の方法で実装することにする。

既存のクラス・構造体を継承して実装する場合、既存のクラス・構造体のメモリ配置は変えられないため、既存のクラス・構造体に一部フィールドを追加することになる。
dlshogi側のメモリ消費が無駄に増えるため、できれば影響がない方法で実装したいが、いったん気にせず後で考えることにする。

既存のクラス継承したクラス

Stockfishの名前空間で、既存のクラスを継承して同名のクラスを定義する。
いったん継承しただけのクラスを定義して、Stockfishから流用した探索の処理で、コンパイルエラーになる箇所について、追加実装する。

名前のみの違いの場合は、Stockfishのコードを修正しないで良いように、別名で定義し直す。
追加で必要なメソッドは追加で実装する。

Positionクラスの例:

class Position : public ::Position {
    ...

    // Doing and undoing moves
    void do_move(Move m, StateInfo& newSt) { doMove(m, newSt); } // 名前変換
    void undo_move(Move m) { undoMove(m); } // 名前変換
    void do_null_move(StateInfo& newSt, const TranspositionTable& tt); // 追加実装
    void undo_null_move(); // 追加実装

    // Static Exchange Evaluation
    bool see_ge(Move m, int threshold = 0) const; // 追加実装

    ...
};

Stockfishのコード流用

Stockfishのコードをコピーして、既存クラスから継承したクラスに置き換えたことで、コンパイルエラーになる箇所を修正する。
また、チェス固有の処理を将棋固有の処理に置き換える。

推論処理

前回試した軽量の畳み込みニューラルネットワークの推論を効率的に探索に組み込には、NNUEのように入力層の差分更新を行おうとすると、実装が大変になる。
いったん、差分更新は実装しないで、毎回特徴量を作成して、入力層を計算することにする。
入力層はEmbeddingを使うので、辞書引きと加算なので、そこまで遅くはならない見込みである。

推論処理は、いったんLibTorchを使って独自実装を省くことにする。
CPUで高速に推論するには量子化が必要なため、PyTorchで量子化認識トレーニング量子化する。
torch.compileでモデルを最適化して、MKLをバックエンドに使えば、独自実装するよりも速い可能性もあるが、パフォーマンスがでなければ後で考える。

実装

実装に着手したが、1日、2日では終わらない作業量である。
将棋固有の処理は、やねうら王の実装も参考にしながら実装している。

実装中に、やねうら王のバグを見つけて、PRを上げた。
最下位ビット以外が1になる場合があるバグ修正 by TadaoYamaoka · Pull Request #297 · yaneurao/YaneuraOu · GitHub

SEE (Static Exchange Evaluation)の処理で、連続した駒の交換を評価する際に、桂馬の交換時に2枚以上の桂馬の効きがあると1つしか考慮されない場合があるというバグである。
PRマージ後に、やねうらお氏が計測したところ、頻度が少ないため棋力にはほぼ影響はなかったようである。

まとめ

軽量価値ネットワークをStockfishの探索に組み込むために、Stockfishベース探索の実装を始めた。
最小限の作業量でいったん完成させるつもりだが、それでもまだ時間はかかりそうである。
Stockfishの探索について理解を深めたいという目的もあるので、実装しながら理解していくつもりである。