前回、対局プログラムを探索と評価の直列化することによって高速化を行ったが、自己対局プログラムについても探索と評価の直列化を行った。
以前は、探索を複数スレッドで行って、ニューラルネットワークを計算をキューにためて専用のスレッドでバッチ処理を行っていたが、スレッドの同期がボトルネックになっていた。
2枚のGPUのPCで、GPUごとに180スレッドと140スレッドという大量のスレッドで探索を行い、ニューラルネットワークの計算完了を探索スレッドでビジーウェイトで待機していた。
ニューラルネットワークの計算が完了すると同時に、大量スレッドが一斉に動き始めるため、CPUを奪い合う状況が発生しており、性能低下を起こしていた。
Windowsではそれなりの速度で動いていたが、LinuxではWindowsの3割程度の性能になっていた。
このようなマルチスレッドの問題は、コンピュータサイエンスではThundering herd problem(大群の問題)と呼ばれている。「Optimized C++」にも記述されていた。
この問題を避けるため、一つのスレッドで探索をバッチサイズ分繰り返した後、評価(ニューラルネットワークの計算)を同一のスレッドでバッチ処理するように変更を行った。ニューラルネットワークの計算中にも探索を行えるように、2つのスレッドで探索を行うようにした。
自己対局プログラムでは、バッチサイズ分の対局を並行で進行し、各対局のシミュレーションを1回実行し、各対局の評価要求を1つずつキューにためてバッチで処理するようにした。
局面生成速度比較
変更前後で局面の生成速度は、以下のようになった。
GPUの2枚(Titan V+1080Ti)のPCで測定した。スレッド数、バッチサイズは生成速度が最大になるように調整している。
スレッド数 | 生成速度(node/sec) | |
---|---|---|
変更前 | 180+140 | 11.26+8.53=19.79 |
変更後 | 2+2(バッチサイズ:192+176) | 14.17+11.35=25.52 |
生成速度が変更前から1.29倍になった。