TadaoYamaokaの開発日記

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

将棋でディープラーニングする その47(全結合)

AlphaGo Zeroでは、policy networkの出力ラベルを石の色×座標+passで表しており、全結合層で出力を行っている。
Fan Hui版AlphaGoでは1×1フィルターの畳み込み層を出力層としていた。
出力層を全結合にした理由は、論文では説明されていないが、精度が上がるため、もしくは単にpassを出力するためと思われる。

将棋AIでは、passがないため、1×1フィルターの畳み込み層で全候補手を出力できる。
全結合にすると計算量が増えるため、精度があがる効果がなければ、全結合にする必要はない。

そこで、出力層を1×1フィルターの畳み込み層とした場合と全結合層にした場合で精度の比較を行った。

1×1フィルターの畳み込み層の枚数は、前回の日記で説明した通り、駒の種類×移動方向+持ち駒の種類だけの枚数(101)とする。
全結合層のノード数は、駒の種類によって移動できない座標を除外したノード数(5839)とする。

以下のパターンで比較を行う。

パターン 出力層
1 1×1フィルターの畳み込み層
2 全結合層
3 1×1フィルターの畳み込み層の後に全結合層

比較結果

測定条件
  • 5ブロックのWide ResNet、3×3フィルター、192枚
  • 訓練データ:4000万局面
  • テストデータ:100万局面
  • 学習率:0.01
  • 最適化:MomentumSGD
  • ミニバッチサイズ:64
  • 訓練局面elmoの自己対局で生成
  • value networkとマルチタスク学習

policy networkの学習結果

train loss test accuracy 学習時間/1000万局面
1×1フィルターの畳み込み層 1.0002 0.4065 1:08:57
全結合層 1.0318 0.3957 2:17:10
1×1フィルターの畳み込み層の後に全結合層 1.0545 0.3926 1:39:37

考察

精度

全結合層のノード数は、移動できない座標を除外しているので、1×1フィルターの畳み込み層のラベル数(8181)よりもラベル数(5839)は少なくなくなっている。
そのため、精度が向上する効果があると予測したが、逆に精度が悪くなるという結果になった。
出力ラベルを減らす効果よりも、全結合にすることの影響が大きかったようだ。

全結合よりも、1×1フィルターの畳み込み層の方が精度が高くなる理由については、全結合は位置の情報が失われるためという説明をどこかで読んだような記憶がありますが、どなたかご存知でしたら教えてください。

このページとかには、パフォーマンスが改善するという記述がありますが、精度が上がる理由を説明している資料を探し中。

学習時間

全結合よりも、1×1フィルターの畳み込み層の方が計算量が少なくなり学習時間が短くなる。
測定結果でも、1×1フィルターの畳み込み層の学習時間が最も短かった。
全結合のみ(パターン2)の場合は、全結合への入力が192枚の画像となっており入力ノード数が多いため、学習時間が1×1フィルターの畳み込み層の約2倍になった。


前回の結果と合わせると、

  • 出力層は、1×1フィルターの畳み込み層
  • 出力ラベルは、移動先と移動方向で表現(移動する駒の種類は不要)

が、将棋AIのpolicy networkの出力層に最適と言えそうです。

なお、今回の実験の際に、今まで使っていたネットワークの出力層の直前の活性化層が漏れてたことに気づいたので修正しました。これも精度を落とす要因になっていました。

2017/11/21 追記

全結合よりも1×1フィルターの畳み込み層の方が精度が上がる理由を、はっきり説明できる資料は見つかりませんでしたが、以下のredditのスレッドで議論されている内容から、1×1フィルターの畳み込み層は空間の次元を保持して、色の次元を削減するために使用するようです。
www.reddit.com
全結合に比べて次元を削減できることで学習効率が上がるのか、空間の次元を保持することで将棋という位置が重要となるゲームで有効に働くかのどちらかではないかと思います。

将棋でディープラーニングする その46(出力ラベルの表現方法)

開発してるdlshogiでは、出力ラベルを(駒の種類×移動方向+持ち駒の種類)×座標で表現し、出力層にAlphaGoを参考に1×1の畳み込み層を使用している。
AlphaGo Zeroでは、出力ラベルを石の色×座標+passで表しており、全結合層で出力を行っている。
1×1の畳み込み層から全結合層に変えた理由は、論文では特に説明されていない。
精度を上げるため、もしくは単にpassを表現したかったためと思われる。

dlshogiでは、出力層に1×1の畳み込み層を使っているため、駒の種類によっては、移動できない座標にもラベルを割り当てている。
出力を全結合層にすると、移動できない座標にラベルを割り当てる必要はなくなり、割り当てるラベルを減らすことができる。
全結合層に変更することで精度があがるか検証してみたい。

今回は、全結合層の検証の前に、出力ラベルの表現方法について、以前から気になる点があったので検証を行った。

出力ラベルの表現方法の検証

将棋では、駒の移動があるため、座標だけでは、移動元が一意に決められない。
移動元も座標で表すと、移動先との組み合わせが多くなる。
そこで、dlshogiでは、以前に書いた通り、移動元は方向だけで表現している。
また、移動する駒の種類にもラベルを割り当てている。
移動方向は、駒の種類ごとに移動できる方向だけにラベルを割り当て、駒の成りも移動方向の一種として表現する。
出力ラベルは(駒の種類×移動方向+持ち駒の種類)×座標で表現される。
出力ラベルの合計は8181になる。(詳細は以前の日記を参照)

比較対象

元々、移動元を方向で表すアイディアは、not522/CNNShogiからヒントを得たものであった。
not522/CNNShogiでは、移動する駒の種類にはラベルを割り当てていないため、出力ラベルは、(移動方向(桂馬の動き含む)×成りの有無+持ち駒の種類)×座標となり、合計で(10×2+7)×9×9 = 2187となる。

dlshogiで駒の種類にもラベルを割り当てた理由は、異なる駒の移動を同じラベルとして学習すると、モデルに与える情報量が減るため、精度も落ちると考えたためである。

どちらの表現がよいか以前から気になっていたので比較実験してみた。

比較結果

測定条件
  • 5ブロックのWide ResNet
  • 訓練データ:3000万局面
  • テストデータ:100万局面
  • 学習率:0.01
  • 最適化:MomentumSGD
  • ミニバッチサイズ:64
  • 訓練局面elmoの自己対局で生成
  • value networkとマルチタスク学習

policy networkの学習結果

train loss test accuracy
駒の種類あり 1.0487 0.3824
移動方向のみ 1.0470 0.3889

考察

予測に反して、精度はほぼ同じとなった。
対局時に使用したときのレーティングに影響があるかも調べたいが、モデル学習に時間がかかりすぎるので検証はここまでにする。

出力層を全結合層にした場合でも、駒の種類ありと移動方向のみを比較してみたい。

2017/11/18 追記

訓練データを1億局面にして比較してみた。

train loss test accuracy
駒の種類あり 0.9990 0.4081
移動方向のみ 0.9957 0.4087

上記と同様に精度はほとんど変わらなようだ。

2017/11/19 追記

出力層の前の活性化関数が漏れているバグがあったため、修正して再測定した。

train loss test accuracy
駒の種類あり 0.9676 0.4150
移動方向のみ 0.9637 0.4174

※訓練データ:7000万局面
移動方向のみの方が良いという結果になった。

dlshogiのバグ報告

電王トーナメントバージョンを公開しましたが、致命的なバグがありました。

移動を表すラベルにバグがあり、いくつかの異なるラベルが同じラベルに割り振られていました。
このバグのため学習の精度がかなり落ちていたと思われます。

モデルの学習からやり直しが必要になるのでバイナリ公開は、電王トーナメントのままとします。
ソースを参考にしたい方は、masterのソースを参考にしてください。

バグ修正箇所

github.com

将棋でディープラーニングする その45(高速化)

現在のdlshogiの実装では、NPSが2500程度しかでていないため、高速化できる箇所がないかを検討している。

モンテカルロ木探索でpolicyとvalueGPUで計算すると、GPUの実行時間が処理時間のほとんどを占めているため、CPUの論理コア数以上のスレッドで並列に探索を行い、policyとvalueの計算要求をキューにためて、GPUは繰り返し溜まったキューをバッチ処理している。
dlshogiのモンテカルロ木探索の実装では、1つのスレッドはGPUに計算要求したら計算が終わるの待つため、ほとんどの時間CPUは遊んでいる状態になる。

開始局面で探索したときのGPUのバッチサイズを調べたところ、スレッド数36の設定の場合、平均で22.4 となっていた。
GPUは並列計算が可能なためバッチサイズが増えてもGPUの計算時間は変わらないため、バッチサイズは、スレッド数36と同じになっている方が効率がよい。
そこで、GPUの処理開始時に溜まっているキューのサイズが閾値未満の場合、1回だけ1msスリープする処理を入れてみた。

測定結果

閾値 平均キューサイ NPS
なし 22.4 2522
スレッド数×0.5 25.3 2680
スレッド数×0.6 30.9 3201
スレッド数×0.7 35.2 3286
スレッド数×0.8 35.6 3333
スレッド数×0.9 35.8 3458
スレッド数 35.7 3314

閾値をスレッド数×0.9にしたときに、平均キューサイズが35.8とほぼスレッド数と同じになった。
NPSは、閾値なしの1.37倍になった。

閾値なしだと論理スレッド数は36が最適だったが、閾値ありだと論理スレッド数をさらに増やせる可能性があるので、調整を行う予定。

2017/11/14 追記

スレッド数の調整を行った結果、スレッド数を128にしたときに、NPSが7027、平均キューサイズが119.5となった。
それ以上スレッド数を増やすと、NPSが低下した。
CPU使用率を見ると100%になっていたが、スレッド36で確認しても100%だった。
GPUの計算をスピンロックで待機しているためと思われる。
CPU使用率からは、はっきりわからなかったが、NPSがピークになっていることから、CPUが効率的に働いている状態になっていると思われる。
NPSは元の状態から、2.78倍になった。

NPSが上がっても、Root並列化の特性から、そのまま線形に強さにつながるわけではない。
どれだけ強さに影響があるか、GPSFishと1手3秒で10局ほど対局させてみたが、勝率は効率化前と変わらなかった(勝率4割)。
やはりDNNの予測精度が上がらないと高速化では強くするのは難しそうだ。

それでも自己対局で強化学習を行うことを計画しているので、できるだけ高速化はしておきたい。

dlshogiのビルド済みファイル公開

dlshogiの第5回将棋電王トーナメントバージョンのビルド済みファイルを公開しました。

elmoで生成した35.8億局面を学習済みモデルと、モンテカルロ木探索で事前探索した定跡も含んでいます。

CUDA、Pythonの環境構築が必要になるので、なるだけ丁寧に説明を記述しました。
この手順で実行できない場合は、ご連絡いただければ対応します。

Release 第5回将棋電王トーナメントバージョン · TadaoYamaoka/DeepLearningShogi · GitHub

第5回将棋電王トーナメント 出場結果

第5回将棋電王トーナメントに参加しました。

本日は予選が行われ、dlshogiは3勝5敗という結果で、予選落ちとなりました。
3回戦と6回戦は、秒読みに入ってから将棋所のinfo stringの出力に時間がかかり、優勢にかかわらず時間切れ負けとなってしまうという残念な結果でした。

infor stringはバッファリングされずに出力仕切るまで処理を返さないという仕様になっており、探索時間の制御は正しかったにも関わらずinfo stringの出力に5秒以上かかって時間切れを起こしていました。
info stringの表示が遅いのは認識していましたが、バッファリングして出力しているだろうと思い込んでいました。
テスト不足でしたorz

まあその問題がなくても、実力的に予選通過はほぼ無理でしたので、次回にチャレンジしたいと思います。


参加して他の開発者の方と意見を交わすことができて楽しい一日を過ごすことができました。
明日も観戦のため現地には行こうと思っています。


info stringの出力を抑止したバージョンを公開しました。
近々ライブラリ登録する予定です。
github.com

将棋でディープラーニングする その44(L2正則化)

将棋AIのPolicy NetworkとValue Networkのマルチタスク学習でのL2正則化の効果を測定してみた。

正則化なし

loss

f:id:TadaoYamaoka:20171108225146p:plain

policy accuracy

f:id:TadaoYamaoka:20171108225221p:plain

value accuracy

f:id:TadaoYamaoka:20171108225349p:plain

L2正則化係数10^{-4}

loss

f:id:TadaoYamaoka:20171108224557p:plain

policy accuracy

f:id:TadaoYamaoka:20171108224625p:plain

value accuracy

f:id:TadaoYamaoka:20171108225416p:plain

考察

正則化なしでも、trainとlossにそれほど差がないが、L2正則化を行うとtrainとtestの差が縮まっている。
その代わりに、policy、vlaueともに2%くらい一致率が下がっている。

この結果から汎化が行われていると考えらるが、一致率が下がった分で実際の対局でプラスに働くかは検証が必要そうだ。

AlphaGo Zeroのように自己対局のみで学習する場合は、局面の偏りが心配なのでL2正則化は行った方がよいだろう。


なお、L2正則化係数を10^{-6}にした場合は、正則化なしとほぼ同じグラフになった。
正則化の効果を得るには、L2正則化係数10^{-4}くらいが適している。