GPUが2つになったので、dlshogiをマルチGPUに対応させました。
ニューラルネットワークの計算要求をキューにためてミニバッチで推論を行う仕組みにしていたので、キューをGPUごとに用意して、探索スレッドを一方のキューに対応させて、キューを監視してニューラルネットワークの予測を行うスレッドをそれぞれのGPUごとに用意する仕組みにしました。
はじめ、単にニューラルネットワークの計算用のスレッドを2つにしてそれぞれが、Pythonの処理を呼び出してChainerに推論を行わせればよいと考えていましたが、Pythonの処理はマルチスレッドで呼び出すとメモリ例外が起きてうまくいきませんでした。
調べたところ、昨日の日記に書いた通りC/C++側のプログラムでもGILを制御する必要がありました。
Pythonの処理はGILがロックされている間は同時には1つしか動かせないので、推論中もGILがロックされていると、マルチGPUにしてもパフォーマンスは上がらないことになります。
GILはIO処理中は解放するのがお作法なので、Chainerも当然GPUで計算中はGILを解放しているはずです。
CuPyのソースを調べたところ、ちゃんとnogilブロックで囲われていました。
Python経由でマルチスレッドの処理を行うと、Pythonの処理中は一つのスレッドしか動作できないため多少効率が落ちますが、ほとんどはGPUで計算している時間なので、影響はそれほどでもないと思います。
TensorFlowを使えば、直接C/C++で推論が行えるのでマルチスレッドでもGILに悩まされることはなくなりますが、ChainerのGPUメモリとCPUメモリのやりとりはかなり効率よくおこなわれているので、TensorFlowで同等の性能をだすにはノウハウがいりそうです。
GPU処理のチューニングまわりでがんばりたくないのでChainerを使っていくつもりです。
マルチGPUの効果
マルチGPUで探索した場合と、シングルGPUで探索した場合で比較を行いました。
測定条件
初手開始局面での、プレイアウト数/秒の測定結果
シングルGPU | 5591 |
マルチGPU | 8028 |
マルチGPUにすることで、1.44倍 プレイアウト数/秒が増えました。
マルチGPUの効果があることが確かめられました。
モンテカルロ木探索でプレイアウト数が増えることは棋力向上につながるはずです。
CPUが合計500スレッド動いているのでCPUボトルネックになっている気もするので、チューニングすればもう少し効率を上げられそうです。
なお、デフォルトの設定ではシングルGPUで動くようにしています。
UCT_Threads2に0以上を設定するとマルチGPUで動きます。
自己対局で局面生成するプログラムもマルチGPUに対応させる予定です。