将棋でのディープラーニングを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