TadaoYamaokaの日記

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

cuDNNでTensorCoreを有効にする

将棋AIの強化学習にTitan Vを使用しているが、今までTitan Vに搭載されているTensorCoreを使えていなかった。
cuDNN 7.1以前では、TensorCoreを有効にするにはプログラムをFP16に対応させる必要があった。
cuDNN 7.2で、FP32でもTensorCoreが使えるようになったので、どれくらい速くなるか試してみた。

TensorCoreを有効にする

畳み込み演算(Convolution)で、TensorCoreを有効にするには、ディスクリプタに対して、

cudnnSetConvolutionMathType(convDesc, CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION)

をコールすればよい。
GPUにTensorCoreがない場合も、TensorCoreが使われないだけなのでコールしても問題ない。

アルゴリズムの選択には、cuDNN v7のAPIを使う必要がある。

cudnnGetConvolutionForwardAlgorithm_v7(handle, xDesc, wDesc, convDesc, yDesc, 1, &returnedAlgoCount, &algo_perf)

自動的にTensorCoreが有効になるアルゴリズムが選択される。

ベンチマークプログラム

将棋AI用のResNet 10ブロックの推論の速度を以下のベンチマークプログラムで比較した。
DeepLearningShogi/gpubenchmark.cpp at master · TadaoYamaoka/DeepLearningShogi · GitHub

速度比較

CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSIONあり/なしで、推論の速度を比較した。
TensorCoreを搭載していないGeforce 1080 Tiでも測定した。

結果は以下の通り。

  • 10万局面推論の平均時間
  • バッチサイズ128

単位:ms

なし あり 比率(なし/あり)
Titan V 17.697 6.888 2.57
1080 Ti 16.218 16.201 1.00

精度比較

TensorCoreを有効にすると、内部的にFP16に変換が行われる。
そのため、計算の精度が低くなる。
指し手と勝率の予測の結果にどれだけ影響があるか確認した。
floodgateの棋譜との指し手の一致率、勝敗の一致率、評価値の誤差で確認した。

なし あり
指し手一致率 0.43797 0.43799
勝敗一致率 0.708297 0.708287
評価値誤差(MSE) 0.0199915 0.0199915

考察

TensorCoreを有効にすると、2.57倍高速になった。
TensorCoreを搭載していない1080 Tiでは、CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSIONを設定しても処理時間が変わっていない。
TensorCoreを有効にすることで、CUDAコアで計算するよりも高速になることが確認できた。

TensorCoreを使わない場合は、1080 Tiの方がわずかに速い。
ベースクロックが1080 Tiの方が高いためと思われる。
TensorCoreを使わなければ、Titan Vの性能は活かせないと言える。

計算の精度について、畳み込み演算が内部的にFP16に変換されるが、最終結果にほとんど影響していない。


cuBlasでもTensorCoreを有効にできるので、全結合の速度が改善できるはずなので次に試す予定。


今月発売されるGeforce 2080 Tiでも、TensorCoreが544個搭載されるので、機械学習目的でも使えそうです。
Titan Vの640個よりは少ないですが、コストパフォーマンスはよさそうですね。

2018/9/23 追記

実際にTensorCoreが利用されているかプロファイラ(nvprof)で調べてみた。
f:id:TadaoYamaoka:20180923163529p:plain

volta_s884cudnn_fp16_256x64_ldg8_relu_exp_small_nhwc2nchw_tn_v1
という項目があり、以下のページによるとs884cudnnはTensorCoreのオペレーションを表しているようだ。
Mixed precision training using float16 — mxnet documentation
実際にTensorCoreが使われているようである。

将棋AIの進捗 その25(自己対局による強化学習の経過)

前回からだいぶ期間が空きましたが、自己対局による強化学習で、教師ありで収束するまで学習したモデルより有意に強くすることができました。前回は、19イテレーションでほぼ互角の強さでしたが、38イテレーションまで自己対局を行うことで有意に強くなりました。

自己対局における探索延長

強化学習の方法は前回までの方法とほとんど同じですが、途中から探索延長を行うように変更しました。
探索延長は、固定回数シミュレーションの結果、1番目に訪問回数が多い手が2番目に訪問回数が多い手の1.2倍未満の訪問回数のときに、シミュレーション回数を1.5倍にするという実装です。
シミュレーション回数を増やすことで、生成される教師データの精度をあげることができますが、計算時間が増えてしまいます。
結果がわかりきった局面に対してもシミュレーション回数を増やすと無駄があるので、探索延長を行うことでより計算効率を上げることができます。

強さの測定方法

前回までは、平手の初期局面から対局を行っていましたが、多少ランダムは入れていますがソフト同士の対局ではゲームの進行が偏る傾向があるので、24手までは「やねうら互角局面集」を使うようにしました。

教師ありで収束するまで学習したモデルとの対局結果

100回対局の結果は以下の通りです。

対局数100 先手勝ち47(47%) 後手勝ち49(49%) 引き分け4
selfplay038
勝ち63(63%) 先手勝ち31(31%) 後手勝ち32(32%)
model110
勝ち33(33%) 先手勝ち16(16%) 後手勝ち17(17%)

selfplay038が自己対局で38イテレーション学習したモデルで、model110が、elmoで生成した11億局面を学習したモデルです。
100回対局で有意水準を5%とすると、臨界値は58.2%なので、有意に強くなっています。

floodgateの棋譜に対する一致率

イテレーション回数 policyの一致率 valueの一致率
19(前回) 0.4090266 0.68762606
38 0.437221587 0.706173778

イテレーションごとのfloodgate棋譜との一致率グラフ
f:id:TadaoYamaoka:20180826213515p:plain

GPSFishとの対局結果

GeForce 1080を搭載したノートPCでの対局結果です。
GPSFishとはほぼ互角になりました。教師ありで学習したモデルよりも勝率が上がっています。
eloレーティングで言うと、GPSFishのと対局を基準として前回から35.6の向上です。
GeForce 1080 TiだとGPSFishに勝ち越せそうですが、未測定です。

38イテレーション自己対局で学習したモデルとGPSFishの対局結果
対局数100 先手勝ち50(50%) 後手勝ち47(47%) 引き分け3
selfplay038
勝ち45(45%) 先手勝ち24(24%) 後手勝ち21(21%)
GPSfish 0.2.1+r2837 gcc 4.8.1 osl wordsize 32 gcc 4.8.1 64bit
勝ち52(52%) 先手勝ち26(26%) 後手勝ち26(26%)
教師ありで学習したモデルとGPSFishの対局結果
対局数100 先手勝ち50(50%) 後手勝ち47(47%) 引き分け3
model110
勝ち40(40%) 先手勝ち21(21%) 後手勝ち19(19%)
GPSfish 0.2.1+r2837 gcc 4.8.1 osl wordsize 32 gcc 4.8.1 64bit
勝ち57(56%) 先手勝ち29(28%) 後手勝ち28(28%)

自己対局にかかった時間と電気代

前回から、2GPUのPCを2ヵ月以上動かし続けました。
去年の同じ時期よりも、1月あたり200kWhくらい消費電力が増えて、電気代は8000円くらい増えました(´;ω;`)

今後の見通し

20イテレーションで、レーティング35.6の向上なので、現在のトップが4300くらいなので、GPSFishと同じ3100とすると、あと1200必要です。
楽観的に線形にレーティングが伸びるとすると、674イテレーションは必要です(実際はlogの形なのでもっとかかる)。
1ヵ月10イテレーションとすると、67.4ヵ月=5.6年以上かかる見込みです。

今後も継続するつもりですが、より短時間で学習できる方法を見つけたいところです。
もしくは他力本願でGPUの性能が数十倍になってくれることを祈っています。

Protocol BuffersをTensorBoardでグラフ表示

バリューネットワークにはプーリング層が有効らしく、AQでもバリューネットワークはプーリング層を使っているようなので、AQのニューラルネットワークの構成を調べてみた。

GitHubで公開されているソースでは、ニューラルネットワーク構成は、Protocol Buffersの形式で保存されていたので、TensorBoardで可視化してみた。

TensorBoardでProtocol Buffersのグラフを表示する方法

Protocol Buffers形式は、TensorBoardで直接開くことができない。
一旦ログ形式にする必要がある。

やり方はここに書かれていた方法を参考にした。
tensorboard: view graph from saved_model.pb file [feature request] · Issue #8854 · tensorflow/tensorflow · GitHub

import tensorflow as tf
from tensorflow.python.platform import gfile
with tf.Session() as sess:
    model_filename ='AQ/pb/vl.pb'
    with gfile.FastGFile(model_filename, 'rb') as f:
        graph_def = tf.GraphDef()
        graph_def.ParseFromString(f.read())
        g_in = tf.import_graph_def(graph_def)
LOGDIR='log'
train_writer = tf.summary.FileWriter(LOGDIR)
train_writer.add_graph(sess.graph)

logディレクトリにログ形式で保存されるので、

tensorboard --logdir log

のように実行する。

ブラウザでコントロールに表示されたURLを開くとニューラルネットワーク構成をグラフで表示できる。

f:id:TadaoYamaoka:20180801084253p:plain

AlphaZeroの価値関数の目標をQ値にすると改善する

この記事で、AlphaZeroの再実装を試した際に、価値関数の学習目標をゲームの結果からQ値に変更することで、エラー率が低下するという報告がされています。
medium.com

ゲームの結果とQ値の平均を目標とするとさらにエラー率が低下し、ゲームの結果からQ値に段階的に変更することでさらにエラー率が低下しています。
https://cdn-images-1.medium.com/max/1600/1*oaJL2jbtwOcZrb7mB6hgOA.png

Q値について

Q値には、シミュレーションをおこなった後の、ルートノードにバックアップされた価値の平均が使用されています。

考察

ゲームの結果だけでなく、探索の評価値から予測した勝敗を学習目標とする考え方は、コンピュータ将棋の学習でもelmoが導入して以来、普及しています。
実際の結果の推定値を使用して学習する方法は、ブートストラップ法とも呼ばれています。

私が開発しているdlshogiの強化学習でも、価値関数の学習に、ゲームの結果とシミュレーション後のルートノードのQ値の平均を使用しています。
ただし、Q値は、最善応手にバックアップされた価値の平均としています。
第 28 回世界コンピュータ将棋選手権dlshogiアピール文章

私も以前に、価値関数の学習にブートストラップ法が効果があることを確認していましたが、実験数が少なく客観的な検証はできていませんでした。
上記の記事の実験では、AlphaZero方式の学習でもブートストラップ法が有効であることが実験で示されています。

dlshogiでは、AlphaZeroの学習はGoogleのマシンパワーがないと不可能と思われていますが、学習の工夫で個人レベルでもなんとかなることを示せたら良いと思っています(できるかどうかはわかりませんが・・・・)。

【Androidアプリ】電卓アプリをアップデート

ほぼ自分用のアプリですが、電卓アプリをアップデートしました。
play.google.com

累乗と階乗の演算子の優先順位が除算と同じになっていたというバグの修正です。
JavaCCで文法を定義していましたが、編集ミスで階乗と除算が逆になっていました。

電卓アプリはごまんとありますが、式を編集してボタンに割り当てできる機能があります。
料理で、塩の量は食材の0.8%がベストらしいので、「×0.8%」を割り当てて使ったりできます。
広告なしの無料アプリです。

将棋AIの進捗 その24(自己対局による強化学習)

これまではAperyの初期局面集にfloodgateの棋譜を加えたものを初期局面集として自己対局を行っていたが、中終盤のバリエーションを増やすため、

という方法で、初期局面集を作成した。
出来上がった初期局面集は、重複なしで394,003,767局面になった。
これだけあれば、自己対局で局面が重複することはないため、自己対局の効率を上げることができる。

自己対局による重複局面数の比較

初期局面集を変更する前後で、自己対局の結果生成された局面の重複率は以下の通りであった。

条件
  • 自己対局で500万局面生成したときの重複率
  • 初期局面集からランダムに局面を選択し、1手ランダムで指した局面を初期局面として自己対局
重複率
変更前 0.1869%
変更後 0.0767%

変更後の初期局面集を使うことで、重複率が変更前の41%に減っている。

自己対局による強化学習の進捗

elmoで深さ8で生成した教師局面4.9億局面で事前学習したモデルから、自己対局で1イテレーション500万局面生成を19イテレーション繰り返して学習したモデルで、教師ありで収束するまで学習したモデル(11億局面)とだいたい同じ強さになった。

事前学習したモデルでは、教師ありで収束するまで学習したモデルとの1手3秒の対局で、2勝8敗(勝率20%)でだったが、19イテレーション強化学習したモデルでは、5勝5敗(勝率50%)とほぼ同じ強さになった。
GPSFishとの対局でも、5勝5敗(勝率50%)となっている。

対局数が少なく検証が不十分だが、自己対局による強化学習で教師あり学習より強くできることがある程度確認できた。
しばらくこの方法で強化学習を続ける予定である。

モデルの検証

いままではelmoで深さ8で生成した教師局面を学習局面とテスト局面に分けて、モデルの検証を行っていたが、自己対局による強化学習を行うとelmoで生成した局面に対して、policyの一致率もvalueの一致率も低下する傾向にあった。
これでは学習が進んでいることがわかりにくいため、テスト局面を2017年以降のfloodateのレート3500以上の棋譜から作成するようにした。
以下のツールで、CSA形式のファイルから評価値と対局ソフトのレートを条件を指定してhcpe形式で局面を抽出した。
ElmoTeacherDecoder/csa_to_hcpe.py at master · TadaoYamaoka/ElmoTeacherDecoder · GitHub
重複局面を除いて856,923局面が抽出できた。

このテスト局面を使用すると、自己対局による強化学習で学習したモデルのpolicyの一致率もvalueの一致率は以下のようになった。

イテレーション policyの一致率 valueの一致率
1 0.41755396 0.6928097
2 0.42115012 0.69208926
3 0.42269236 0.69095576
4 0.42438433 0.6935829
5 0.42493716 0.69430405
6 0.42519188 0.6961772
7 0.42581162 0.6924004
8 0.42696634 0.6953033
9 0.42807713 0.6971584
10 0.42900684 0.6960269
11 0.42939773 0.69955724
12 0.4297164 0.6982497
13 0.430544 0.69985163
14 0.43124306 0.6994239
15 0.43179193 0.6997897
16 0.43170047 0.7023887
17 0.4324307 0.70205444
18 0.43276954 0.70325536
19 0.43360597 0.70227855

floodgateの棋譜に対しては、policyとvalueどちらも一致率が上昇傾向にあることが確かめられた。

2018/6/20追記

自己対局による強化学習の学習開始モデルとした事前学習(49億局面)したモデルと、教師ありで収束するまで(11億局面)学習したモデルで、floodgateのレート3500以上の棋譜に対して一致率がどうなっているかを検証した。

policyの一致率 valueの一致率
事前学習(4.9億局面) 0.4090266 0.68762606
教師ありで収束するまで(11億局面) 0.41536444 0.6936132

事前学習したモデルは自己対局による強化学習を行ったモデルよりも、policy、valueともに一致率が低い。
自己対局による強化学習を行ったモデルは、教師ありで収束するまで学習したモデルよりもpolicy、valueともに一致率が高くなっている。
自己対局による強化学習で、教師ありよりも強くできることが裏付けられた。

詰み探索の高速化

前回までに作成したdf-pnによる詰み探索を自己対局に組み込んでみたが、探索速度が遅くあまり実用にならなかった。

これまでは、モンテカルロ木探索の先端ノードで全探索の7手詰めを行っていたが、それと同じ時間になるようにdf-pnの探索ノード数を調整すると、150ノードしか探索できない。

150ノードでは、7手詰め以上の詰みを見つけられるときもあるが、7手詰めを見逃すことがあり、単純には置き換えることができない。
インライン化やテンプレート化をして高速化を行ったが、改善は数%程度で、なかなか高速化できずに困っている。

ハッシュのサイズを小さくするほど探索速度が上がるので、CPUのキャッシュヒット率が関係していそうだが、df-pnで優越関係を使用しているため、ハッシュエントリサイズが大きく、キャッシュに載せるのが難しい。
詰み探索に特化したハッシュ構造を考える必要がありそうだが、今のところ良い案が浮かばないので、詰み探索を組み込むのは宿題としておく。

github.com

バグ修正

テストしているときに、また王手のバグ修正が見つかった。
玉で開き王手する場合に、玉の自殺手を除外していなかった。