TadaoYamaokaの日記

山岡忠夫Homeで公開しているプログラムの開発ネタを中心に書いていきます。

PythonでAlphaZero Shogiを実装する その3

技術書典6の本を執筆しながらAlphaZero Shogiを実装したPythonプログラムの修正も行っている。
プログラムの方はほぼ完成しているが、自己対局を数時間実行すると途中で評価済みのはずのノードが未評価になっているため例外になる問題が発生している。
原因を探すために、デバッガで動かしたいが、再現性が低いため、デバッガだと実行速度が1/10くらいになるため長時間実行しても再現しない。

Pythonで再現性の低いコードのデバッグ

C++のプログラムであれば、例外発生時点でデバッガをアタッチできるが、Pythonの場合後からPythonデバッガをアタッチできない。
調べたところ、Pythonでは以下のような方法で、途中からデバッガを起動できることがわかった。

import pdb; pdb.set_trace()

公式マニュアルに書かれていた。

例外が起きる位置で、発生条件をif文でチェックして、上記のコードを実行するようにすればよい。
こうすればエラー条件の発生までは通常に実行できるため、実行速度が落ちることはない。

上記の方法で、再現させてデバッガで調べたところ、千日手に関係する局面で問題が起きていた。

AlphaZeroでは、局面の繰り返し数が入力特徴量になっているため、ハッシュに登録する際に繰り返し数もキーの一つとしていた。
そうすることで、繰り返し数が異なる局面は別のエントリになるため、うまく千日手が処理できると考えていた。
しかし、繰り返し数が同じ同一の局面でも、次の手を指した後の局面の繰り返し数が同じになるとは限らない。
その局面の繰り返し数が同じでも、局面に至る経路が異なれば、同じ手を指しても次の局面が千日手になる場合とならない場合がある。
そのため、先に千日手になる方を調べた場合、別の経路で探索された場合に、局面がニューラネットワークで評価されていない状態になっていた。

ハッシュの仕組みの変更

AlphaZeroの方式では、経路が異なる同一局面を別の局面として扱う必要があるため、経路を考慮しないとハッシュの仕組みが使えないということになる。
ルートからの経路をハッシュのキーとすることもできるが、ハッシュを使う意味がなくなるため、ハッシュを使わずに、ゲーム木をノードのリンクで表現する実装に変更した。
ノードが合流する場合の効率が多少変わるだけなので、探索速度にはそれほど影響しない。
ニューラネットワークの入力特徴量は、経路が異なっても局面と繰り返し数が同一であれば再利用可能だが、複雑になるため実装しないことになる。

上記の問題を修正したことで、長時間の自己対局が可能になったので、ゼロからの学習を開始した。
技術書典までに多少は学習できそうだ。

なお、実行速度は、C++で作成したdlshogiでは、GPU3枚使って45局面/秒くらいの生成速度だが、Pythonで実装したdlshogi-zeroでは、GPU1枚で1.6局面/秒になる。
GPU1枚あたりでは、1/10程度といったところだ。