TadaoYamaokaの開発日記

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

将棋でディープラーニングする その43(ValueNetの出力をtanhにする2)

前回Value Networkの出力をtanhにした場合とsigmoidにした場合で比較を行ったが、マルチタスク学習を行っているため、はっきりした結果がわからなかった。

今回は、Value Networkのみの学習で比較を行った。
以下の2パターンで比較した。

出力関数 損失関数
1 tanh 平均二乗誤差(MSE)
2 sigmoid 交差エントロピー

tanhとsigmoidの比較

測定条件
  • 5ブロックのWide ResNet
  • 訓練データ:7000万局面
  • テストデータ:100万局面
  • 1000万局面ごとに評価
  • 学習率:0.001
  • 最適化:SGD
  • ミニバッチサイズ:64
average train loss

f:id:TadaoYamaoka:20171108205522p:plain

test loss

f:id:TadaoYamaoka:20171108205552p:plain

test accuracy

f:id:TadaoYamaoka:20171108205618p:plain

考察

train lossはスケールが違うため比較できない。どちらも減少している。
test lossはtanhは1000万局面でほぼ減少が止まっている。
sigmoidはわずかに減少している。
test accuracyは、tanhの方が一致率が高い。

以上の結果から、tanhの方が学習効率が高いと言えそうだ。

前回と今回の実験結果からtanhの方が良さそうなので、Value Networkの出力はtanhに変更することにする。


なお、1000局面でtest lossがほぼ下げ止まっているのは、elmo_for_learnでの局面生成時に初期局面(1000万局面くらい)から数手のランダムムーブを行っているとは言え、似たような局面が大量に生成されているためと思われる。
AlphaGoでもValue Networkの学習には1ゲームから1局面しか使っていないので、Value Networkの汎化性能を上げるには、局面のバリエーションがもっと必要と思われる。
AlphaGo Zeroでは、自己対局のみで学習しているので、局面が偏りそうだが実際に強くなっているので不思議な気がしている。AlphaGo ZeroでL2正則化を行っているのは、それが理由かもしれない。
将棋でAlphaGo Zeroと同じように自己対局のみで学習した場合にもうまくいくのかはやってみないとわからない。

tanh vs sigmoid

AlphaGoのValue Networkの出力にはtanhが使用されている。
一方、将棋AIでは評価関数から勝率に変換する際、sigmoidが使われている。

tanhとsigmoidのどちらがよいか、dlshogiの学習で検証してみたが、Policy NetworkとValue Networkのマルチタスク学習を行っているためはっきりした結果が得られなかった。

そこで、MNISTのデータセットで多層パーセプトロンを学習するというシンプルなケースで比較を行ってみた。

MNISTは0から9の数値分類のデータセットだが、tanhとsigmoidを比較するため、偶数か奇数かの2値分類を行う。

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

出力関数 損失関数
1 tanh 平均二乗誤差(MSE)
2 sigmoid 交差エントロピー
3 sigmoid 平均二乗誤差(MSE)

比較結果

測定条件
average train loss

f:id:TadaoYamaoka:20171107213115p:plain

test loss

f:id:TadaoYamaoka:20171107213131p:plain

test accuracy

f:id:TadaoYamaoka:20171107213207p:plain

考察

train lossは、それぞれスケールが異なるため大小では比較できないが、sigmoid+MSEは、lossの減少が他に比べて遅い。
test accuracyは、tanhが最も高くなっている。

このことから、MNISTの多層パーセプトロンによる2値分類では、tanh+MSEが最も効率よく学習できることがわかった。
また、出力関数がsigmoidならば、損失関数は平均二乗誤差より交差エントロピーにした方が良い。

他のデータセットや、深層畳み込みニューラルネットワークでも同じ傾向かは実験してみないとわからない。

検証に使用したソース

github.com

将棋でディープラーニングする その42(ValueNetの出力をtanhにする)

将棋AIでは、評価関数をsigmoid関数で[0,1]の範囲で勝率にすることが行われている。
elmoの損失関数には、勝率の交差エントロピーと、浅い探索と深い探索の評価値から求めた勝率の交差エントロピーの和が使われている。

一方、AlphaGoでは報酬に[-1,1]が使用されており、ValueNetworkの出力にはtanhが使われている。
損失関数には、平均二乗誤差(MSE)が使用されている。

tanhを使用している理由は論文では特に説明されていないが、tanhの方が強い勾配が得られるそうだ。
machine learning - tanh activation function vs sigmoid activation function - Cross Validated

そこで、ValueNetworkの出力をtanhにして損失関数をMSEした場合と、出力をsigomidにして損失関数を交差エントロピーとした場合で比較してみた。
tanhの場合、ブートストラップ項(ValueNetworkの出力と深い探索の評価値の差)の損失関数もMSEとした。

tanhとsigmoidの比較

測定条件
  • 訓練データ:7000万局面
  • テストデータ:100万局面
  • 1000万局面ごとに評価
  • 学習率:0.01、0.001
  • モーメントパラメータ:0.9
  • ミニバッチサイズ:64
  • policyとvalueマルチタスク学習
  • policyは勝敗をアドバンテージにした強化学習
  • valueは勝敗をelmoの探索結果でブートストラップして学習

※評価関数からtanhへの変換はこの記事を参照

average train loss

f:id:TadaoYamaoka:20171106214552p:plain
※policyとvalueの損失の合計

test loss

f:id:TadaoYamaoka:20171106214621p:plain
※policyとvalueの損失の合計

test accuracy policy

f:id:TadaoYamaoka:20171106214637p:plain

test accuracy value

f:id:TadaoYamaoka:20171106214654p:plain

考察

tanhの場合、学習率が0.01の場合、発散して学習できなかった。
学習率を0.001として測定した。
sigmoidも併せて学習率0.01の他に0.001でも測定した。

train loss、test lossはtanhの方が、sigmoidの場合より大きくなっているが、値の範囲が[-1,1]になったことで、損失関数のスケールが2倍になっていることが影響している。

policyのtest accuracyは、tanhの方がsigmoidの場合より大きくなっている。
valueのtest accuracyは、tanhの方がsigmoidの場合より小さくなっている。
tanhの場合、policyの損失関数は交差エントロピーで、valueの損失関数がMSEなので、policyとvalueの損失の比率が、sigmoidのときと変わったことが影響していると思われる。

どちらが良いともはっきりと言えない結果だが、同じ学習率(0.001)では、valueのtest accuracyがほぼ同じなのに対して、policyのtest accuracyはtanhの方が良くなっている。

sigmoidとtanhどちらがよいかは、別のデータセットを使って別途検証してみたい。

将棋でディープラーニングする その41(モーメントありSGD)

AlphaGo Zeroニューラルネットワークの学習の最適化に使用されているモーメントありSGDを将棋AIで試してみた。

以前に、最適化手法を比較した際、Adamのような学習率を自動で調整する手法よりSGDの方が学習効率が高かった。
AlphaGo FanバージョンでもSGDが使われている。

AlphaGo Zeroでは、SGDにモーメントを付けた、モーメントありSGDが使われている。
そこで、SGDとモーメントありSGDの比較を行った。

SGDとモーメントありSGDの比較

測定条件
  • 訓練データ:7000万局面
  • テストデータ:100万局面
  • 1000万局面ごとに評価
  • 学習率:0.01
  • モーメントパラメータ:0.9
  • ミニバッチサイズ:64
  • policyとvalueマルチタスク学習
  • policyは勝敗をアドバンテージにした強化学習
  • valueは勝敗をelmoの探索結果でブートストラップして学習
average train loss

f:id:TadaoYamaoka:20171103094720p:plain
※policyとvalueの損失の合計

test loss

f:id:TadaoYamaoka:20171103094740p:plain
※policyとvalueの損失の合計

test accuracy policy

f:id:TadaoYamaoka:20171103094758p:plain

test accuracy value

f:id:TadaoYamaoka:20171103094812p:plain

考察

比較結果から、モーメントありSGD(MomentumSGD)の方がSGDより、policy、valueともに学習効率が高いことがわかった。


電王トーナメント向けに35.8億局面学習したモデルでは3エポックの途中でtest accuracyが飽和したが、モーメントありにして3エポックをやり直したところ、SGDで飽和した値より学習が進むようになった。
現在、policyの一致率:46.1%、valueの一致率:78.2%になっており、約0.1%程改善している(学習継続中)。
SGDでは3エポックの途中で飽和した後さらに学習を続けると発散したが、モーメントありSGDでは発散していないので、間に合えば4エポック目の学習もできそうである。
※追記
とおもったが、やはり3エポック目の途中で飽和した後、発散した。

将棋でディープラーニングする その40(入力特徴に履歴追加)

その39からずいぶん期間が空きましたが、AlphaGo Zeroの論文を読んで試したいことができたので、AlphaGo Zeroの論文の方法が将棋AIに応用が可能か少しずつ試していこうと思います。

AlphaGo Zeroの特徴については、別の記事に記載していますので、参照してください。

AlphaGo Zeroでは、入力特徴は現局面を含む8手までの履歴局面の石の座標になっています。
入力特徴に履歴が必要な理由は、論文では囲碁にはコウがあるためと説明されています。

将棋にはコウはありませんが、駒の取り合いや千日手があるため、履歴の情報は有用と思われます。

前回までに作成したニューラルネットワーク(Wide ResNet、5ブロック、PolicyとValueの同時出力)の入力特徴に履歴を追加して試してみました。

入力特徴は、前回までと同様に駒の配置と持ち駒、王手がかかっているか、効き数の情報を8手まで持たせます。

学習局面は、elmo_for_learnで履歴も出力できるようにして探索の深さ8で生成しました。学習前に重複を排除してシャッフルしています。

※2017/11/3 データに誤りがあったので修正しました。

履歴あり/なしの比較結果

測定条件
  • 訓練データ:7000万局面
  • テストデータ:100万局面
  • 1000万局面ごとに評価
  • SGD(学習率:0.01)
  • ミニバッチサイズ:64
  • policyとvalueマルチタスク学習
  • policyは勝敗をアドバンテージにした強化学習
  • valueは勝敗をelmoの探索結果でブートストラップして学習
average train loss

f:id:TadaoYamaoka:20171103143117p:plain
※policyとvalueの損失の合計

test loss

f:id:TadaoYamaoka:20171103143137p:plain
※policyとvalueの損失の合計

test accuracy policy

f:id:TadaoYamaoka:20171103143210p:plain

test accuracy value

f:id:TadaoYamaoka:20171103143233p:plain

学習時間
時間/1000万局面
履歴あり 1:46:33
履歴なし 1:21:41

考察

予想に反して、履歴ありの方がpolicy、valueともにtest accuracyが小さくなっている。
将棋では囲碁のコウのように履歴の情報が重要になることが少ないことが関係しているかもしれない。
駒の取り合いや千日手となる局面においては精度がどう影響しているかは気になるが、今回の結果からは履歴は入れない方がよさそうである。

また、学習時間は、履歴を増やしたことで約1.3倍になった。

WindowsにChainer v3+CUDA9+cuDNN7をインストールする

Chainer v3(cupy v2)がCUDA9に対応したので、バージョンアップしました。
Chainer v3はcuDNNも最新のバージョン7に対応しているので、cuDNNも7にしました。

インストール手順は、以前のバージョンと同様です。

chainerをバージョンアップする際は、chainerとcupyをアンインストールしてからインストールします。

pip uninstall chainer
pip uninstall cupy
pip install cupy --no-cache-dir
pip install chainer --no-cache-dir

性能比較

CUDA8+cuDNN5.1と学習速度を比較しました。

比較対象として、将棋AIのResNet(5ブロック)の1000万局面の学習時間で比較しました。

CUDA8+cuDNN5.1 1:09:18
CUDA9+cuDNN7 1:07:16

※2回測定の平均
GPUは、GeForce 1080Ti

約3%学習速度が速くなりました。

なお、速度向上の要因がCUDA9によるものか、cuDNN6によるものか、cuDNN7によるものかは分かりません。

WindowsにAnaconda3でPython 3.6をインストールする

以前はChainerとTensorflowがPython3.6に対応していなかったため、Anaconda3のPython3.5系を使用していた。
現在は、ChainerもTensorflowもPython3.6に対応しているため、Python3.6に入れ替えを行った。

Anaconda | Individual Edition
から、Python 3.6 version(Anaconda3 5.0.1)をダウンロードして、インストールするだけだが、Python3.5系のAnaconda3 4.2.0との違いで戸惑った点を記載しておく。

スタートメニューに「Jupyter QTConsole」がなくなった

以前からWebベースのJupyer Notebookより、GUIで軽い「Jupyter QTConsole」を使用していた。
Anaconda3 5.0.1にしたところ、スタートメニューから「Jupyter QTConsole」がなくなってしまった。

対処

ファイル名を指定して実行から、「jupyter-qtconsole」を指定することで、起動できる。
f:id:TadaoYamaoka:20171027222241p:plain:w300

なお、裏でコマンドプロンプトが同時に起動するが気にしないようにする。

グラフがプロットできない

「Jupyter QTConsole」で、matplotlibでグラフを描画しようとしたら、

Out[2]: [<matplotlib.lines.Line2D at 0x1aa221a2550>]

とだけ表示されて、グラフが描画されない。

対処
%matplotlib

と入力すると、

Using matplotlib backend: Qt5Agg

と表示され、バックエンドが初期化されて描画できるようになる。

以下のようなスクリプトを実行すると、

import numpy as np
import matplotlib.pyplot as plt
x = np.arange(-3, 3, 0.1)
y = np.sin(x)
plt.plot(x, y)

別ウィンドウでグラフが表示される。
f:id:TadaoYamaoka:20171027215936p:plain:w300

cupyのインストールで、UnicodeDecodeErrorが発生

pipでcupyをインストールしようとすると以下のエラーが発生した。

>pip install cupy
Collecting cupy
  Using cached cupy-2.0.0.tar.gz
Exception:
Traceback (most recent call last):
  File "C:\Anaconda3\lib\site-packages\pip\compat\__init__.py", line 73, in console_to_str
    return s.decode(sys.__stdout__.encoding)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x83 in position 0: invalid start byte

(省略)
対処

以下のページを参考に、「C:\Anaconda3\lib\site-packages\pip\compat\__init__.py」を修正した。
Win + Python3.6で「pip install」を実行したときに「UnicodeDecodeError: 'utf-8' codec can't decode byte 0x83」と表示される。 - Qiita

修正後は正常にインストールできた。

※2018/4/23 追記
Anaconda 5.1で、pipをアップデートすると上記の問題が発生しなくなっていました。
Windows環境でもPython3.6が問題なく利用できるようになっています。