TadaoYamaokaの開発日記

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

将棋でディープラーニングする その11(Kerasの実装)

将棋でのディープラーニングをChainerを使って検証していたが、Kerasでも試してみた。

13層のDCNNを学習するには、少なくとも全パラメータ数の数倍の訓練データで学習する必要がある。
保存したmodelファイルをzipで解凍したファイルの合計サイズが約25MB(numpyのヘッダーも含むがおよそのオーダーは合っているはず)であることから、1データが32bit(4byte)なので、パラメータ数は約650万(25×1024×1024÷4)ある。

その10倍の局面を用意するとすると、6,500万局面が必要となる。
1局平均140手とすると、46万局ほど対局データが必要である。

なお、AlphaGoの論文では、SL policy networkの学習に、16万局から2億9400万局面を学習データに使用し、ミニバッチサイズ16で3億4000万ステップ(延べ54億4000万局面、185エポック)を学習している。パラメータ数は、約360万で盤は大きいが駒の種類がない分、将棋より少ない。

前回までの検証では、プロの棋譜3744局、422852局面を使用しており、学習時間は、49分15秒かかっている。

6,500万局面を学習データとすると、1エポックの見積もり時間は、5日6時間10分36秒となる。

収束するまでエポックを回すと相当な時間がかかるので、できるだけ時間を短縮したい。

そこで、バックグラウンドでC言語ベースのTensorFlowを使用しているKerasと学習時間を比較を行ってみた。

Kerasの実装

Kerasのfit関数を使うと、学習データと教師データを全てメモリに乗せる必要がある。
1サンプルあたり、入力特徴数105×9×9と、教師データ8181分類なので、約65KBが必要になる。
422852局面には、26GB必要になる。
これではメモリが不足する。(実際に試して、MemoryErrorとなった。)
そこで、fit_generatorを使い、ミニバッチ単位に動的にビットボードデータから入力特徴、出力クラス分類データに展開するようにした。
fit_generatorは、ミニバッチデータの準備を、GPUによる学習とは別スレッドで並列に行うので、速度アップも期待できる。

また、KerasのConv2Dはデフォルトでは、データ形式が、(batch, height, width, channels)になっており、そのままでは入力できない。
オプションで変更できることが分かったので、data_format='channels_first'を指定した。
その場合、BatchNormalizationのオプションもaxis=1にする必要がある。

また、Chainerの実装では、持ち駒の入力特徴の畳み込みのカーネルサイズを1にしてパディングの悪影響を減らすことを行ったが、fit_generatorを使う場合は、入力の種類を2つにすることはできない。
そこで、カーネルサイズ、パディングは盤面と同じにした。

また、出力層はAlphaGoの論文を参考にして、全結合ではなく1×1の畳み込みに位置ごとのバイアスをかけている。ChainerにはBiasリンクがあるが、Kerasにはそれに相当するLayerがなかった。そのため、AlphaGoクローンの実装を参考に、Bias Layerを実装した。

測定結果

学習時間は以下の通りとなった。

学習時間
Chainerの実装 0:49:15
Kerasの実装 1:22:50

期待に反して、Kerasの方が多く時間がかかった。

精度の比較は以下の通りであった。

train loss test accuracy
Chainerの実装 2.13 0.43
Kerasの実装 2.32 0.38

Kerasの方が精度が悪くなったが、持ち駒のパディングの影響と、デフォルトのパラメータの初期値が異なることが影響していると思われる。
パラメータの初期値はChainerではデフォルトでHeNormalが使われるが、KerasではGlorotUniformがデフォルトになっている。
初期値は変更できるが、デフォルトのまま測定した。

この測定結果から、自分の環境ではChainerの方が実行時間が速かったので、今後もChainerの実装を使うことにする。
(時間を見積もってみて収束するまでの学習は諦め気味・・・)

Kerasでの実装はGitHubのkerasブランチで公開した。
github.com