前回の日記で、ブートストラップについて少し書いたが、1000万局面では効果がわからなかったので、局面を増やして再度検証した。
ブートストラップ
前回も書いたが、本来の報酬(勝敗)とは別の推定量(探索結果の評価値)を用いてパラメータを更新する手法をブートストラップという。
elmo_for_learnで生成したデータには、局面の探索結果の評価値が含まれているので、バリューネットワークの値をその評価値に近づけるように学習することで、学習の効率を上げることができると思われる。
経験的にブートストラップ手法は、非ブートストラップ手法より性能が良いことが知られている。
ブートストラップ項を加えた損失関数
elmoと同様に、ブートストラップ項の損失には、2確率変数の交差エントロピーを使用する。
バリューネットワークの値を、探索結果の評価値をシグモイド関数で勝率に変換した値をとした場合、交差エントロピーは以下の式で表される。
交差エントロピーの偏微分は、
となるが、Chainerで実装する場合、backwardの処理をGPUで計算できるように、cudaの処理を記述する必要がある。
技量不足でその部分を実装できなかったため、交差エントロピーを以下のように計算して、微分は計算グラフの処理に任せることにした。
def cross_entropy(p, q): return F.mean(-p * F.log(q) - (1 - p) * F.log(1 - q))
このブートストラップ項に係数を掛けて、元の損失関数に加える。
損失関数は以下の通りになる。
loss1 = F.mean(F.softmax_cross_entropy(y1, t1, reduce='no') * z) loss2 = F.sigmoid_cross_entropy(y2, t2) loss3 = cross_entropy(F.sigmoid(y2), value) loss = loss1 + loss2 + args.val_lambda * loss3
loss1は指し手予測(policy network)の損失、loss2は勝率予測(value policy)の損失、loss3がブートストラップ項である。
測定結果
ブートストラップなしで2億局面学習したモデルから、ブートストラップなし/ありで、8000万局面を学習して精度を比較した。
train loss1 | train loss2 | train loss3 | test acc.(policy) | test acc.(value) | |
ブートストラップ項なし | 0.8883 | 0.4638 | 0.4439 | 0.7651 | |
ブートストラップ項あり | 0.8853 | 0.4741 | 0.4427 | 0.4444 | 0.7658 |
train loss2(value networkの損失)は、ブートストラップ項のなしの方が減少しているが、test accuracyはブートストラップ項ありの方がわずかに良い。
train loss3はブートストラップ項ありの場合のみ測定しているが、初期から減少を続けており、value networkの予測が評価値に近づいている。
GPSfishとの対局
ブートストラップ項ありで学習したモデルで、GPSfishと対局させた。
GPSfishに勝つことができた。
評価値はGPSfishとほぼ同じ傾向だが、GPSfishより早く評価値が付いている。
ブートストラップ項なしで学習したモデルでは以前と同様に、評価値がGPSfishより遅れて不利を判断しており、勝つことができなかった。
ブートストラップ項を追加することで、バリューネットワークの学習効率が上がることが確かめられた。
これで、ディープラーニングのみでも(GPSfishよりも)強いソフトが作れることが確認できた。
この方法で、さらに学習を進める予定。