256chでの教師あり学習

 普段使っているネットワークがそこまで大きくはないのでもっと大きいネットワークを試したいと思って実験したが、ブログを見るとほとんど同じような実験を以前にもしていた。自分で書いた記事を自分で忘れている。


 上の記事と同様に、普段128chである残差ブロック中のCNNを256chに増やして学習を行った。学習データはAobaZeroの棋譜、検証データはfloodgate2015年の棋譜を使っている。

 上の記事では1,000,000ステップしか学習を回していないところを、今回は3倍の3,000,000ステップまで回した。学習率の減衰は0.6Mステップごとに1/10にする形で行った。つまり学習が終わるまでに等間隔で計4回減衰が発生する。

Policy損失

f:id:tokumini:20210128104326p:plain

 Policyの検証損失はほぼ変わらない。が、点線の方であるtrain損失ではそこそこ差がある点は気になる。AobaZero棋譜への適応はチャンネル数を増やした分良くなったが、floodgateの棋譜はまた性質が異なるので検証損失は伸びなかったと解釈するのが普通だろうか。

Value損失

f:id:tokumini:20210128104333p:plain

初期局面での5秒検討

f:id:tokumini:20210128113128p:plainf:id:tokumini:20210128113143p:plain
左:128ch 右:256ch

 NPSは128chのとき8100.6、256chのとき5457.6

 探索深さにやや差が出ているのは気になるが、偶然の範囲内かどうか。

対局@2080tiマシン

~/Miacis/scripts/vsYaneuraOu.py --time1=250 --time2=250 --NodesLimit=400000 --game_num=1000

f:id:tokumini:20210128104318p:plain

 なぜか128chは途中からしか計測していなかったが、まぁ学習序盤はどうせ弱いのでどうでもいいだろう。

 最終的な対局による性能はほとんど変わらなかった。NPSの低下とValueの精度向上がちょうど打ち消し合うくらいだったということだろう。冒頭の記事でもだいたい同じ感じだったので128ch ~ 192ch ~ 256chでは同じ持ち時間での性能はほとんど変わらないというのがここまでの結果になる。

 では結局どのチャンネル数が良いかというと、それぞれのメリットを考えると

  • 128chにすると学習・生成が速いので実験サイクルは回しやすい
  • 256chの方が対局時のGPU依存部分が多いので、強力なGPUを使った場合での伸びが期待できる
  • 256chの方が探索ノード数が少なく、持ち時間を長くしたときの伸びは低ノード帯の方がやや大きいはず

(三番目の根拠についてはMuZeroの論文のFigure.3)

f:id:tokumini:20210128114702p:plain

という感じなので、大雑把にいろいろ実験するなら128ch、最高性能を目指すなら256chという感覚。

Transformerを用いた探索的NNの学習(成功?編)

 以下の続き。

 前回は上手くいかなかった学習をなんとか多少は改善することができた。修士論文としてはとりあえずこの方針の結果で許してもらいたい、という気持ちです。

 基本的な手法は冒頭で示した前回と変わらず、事前学習したモデルのPolicyが示す確率に従って行動をサンプリングし、局面の系列を得る。このときルート局面から3回動かしたらまたルート局面まで戻す。全体の系列長は10で行ったため、3回動かした局面の系列が3個+1回動かした局面という10個の表現ベクトルがTransformerのEncoder側に入力される。TransformerのDecoder側には常にルート局面の表現ベクトルが入力される。

 前回から変えた点は、

  • LibTorchの1.7.0リリースにより公式のTransformerが使えるようになったのでそれを利用するようにした
  • Positional Encodingをランダム初期化した学習可能な値を用いるようにした
  • 損失計算で今までは10回の系列入力について毎回損失を計算していたが、10系列まとめて入力した最後にだけ損失を計算するように変更した

の3点である。おそらく重要だったのが一番最後の点であり、これにより一気に傾向が変わったような印象がある。また損失計算を最後だけにすると計算も速くなり、事前学習のない場合もなんとか2日程度で学習ができるようになった。

結果

 実験はどれもオセロで行った。

事前学習あり

 まずシミュレータを行うための普通のFeedforwardネットワークを教師あり学習で学習させた。検証損失は以下の通り。

f:id:tokumini:20201115130907p:plain

 最終的に値は0.774083となった。

 パラメータを固定したこのモデルを用いて局面系列のサンプリングおよび入力する局面のエンコードをし、Transformerを学習させた結果が以下となる。(これらは同じ棋譜を用いて同じように検証損失を計算している)

f:id:tokumini:20201115131103p:plain

 オレンジ色の線が事前学習で得られたモデルであり、それより性能が良くなった。

 学習後、最終ステップ時点のモデルにおいて各系列長(探索回数)の時点で切り上げてTransformerに損失を計算させると次のようになった。

f:id:tokumini:20201115132815p:plain

 わりと最後の方でも系列が増えることによる性能向上が見られているので悪くないように思える。

事前学習なし

 事前学習なく、Transformerの学習と同時にサンプリング、エンコード用のモデルも学習させ、Transformerの勾配もエンコーダ側まで流すようにして実験を行った。

f:id:tokumini:20201115133142p:plain

 先程と異なり探索なしのオレンジ線も学習に伴って下がっていくが、事前学習よりも少し悪い程度で留まった(これは事前学習の方がステップ数が多かったという理由が大きそうではある)。Transformerの方の学習も事前学習ありの場合とそこまで変わらない。

 同様に学習済みモデルについて、各系列長(探索回数)の時点でTransformerに損失を計算させると次のようになった。

f:id:tokumini:20201115150650p:plain

 0回の時点でもそこまで悪くないのが多少異なる点ではある。単なる学習のブレか、本質的な違いかはわからない。

 ちなみに事前学習ありのものでも同様だが、系列長10で学習させたものに、学習後無理やり系列長20までサンプリングして与えてみたところ、当然のように性能は悪化した。

f:id:tokumini:20201115150855p:plain

 Positional Encodingのランダムなところが学習されてないので当たり前なのだが、これは本家Transformerの三角関数を用いたPositional Encodingに戻せば汎化できるのだろうか。

今後やること

  • 系列長を20で学習した場合にどうなるか(学習コストが大きいのでやれても30くらいまでかなというところ)
  • そもそもTransformerではなくてLSTMではダメなのか
  • Positional Encodingを三角関数を利用するものに戻してやりなおす

 なにか疑問点があればコメントいただければ僕の修士論文が少しだけ良くなるかもしれません。

教師あり学習をした後の強化学習

 カテゴリカルモデルで教師あり学習をすると勝ち負け引分に相当する値の領域にしか教師信号が発生しないため分布が有効活用できない問題がある。

 (無理やり割引率を導入すれば初期局面に対しても値を与えられるが、それは恣意的なのでできるだけしたくない)

 強化学習ではTD(λ)を用いることでこれを回避できるため、教師あり学習をした後に強化学習を用いて追加学習することを試みた。

教師あり学習

 AobaZeroの棋譜を用いて教師あり学習を行った(具体的な手順などは以前の記事を参照)

 Vadlidationにはfloodgate2015年の棋譜から片方の対局者のレート2800以上のものを抽出し、利用した。

結果

f:id:tokumini:20201106164704p:plainf:id:tokumini:20201106164707p:plain
左:Policy損失 右:Value損失

 以前行ったスカラーモデルでの結果と比べて、Policy損失はほぼ変わらず、Value損失はやや悪化となった。

 参考:同条件で学習した場合の最終ステップでの損失値

モデル Policy損失 Value損失
スカラー 1.949150 0.618593
カテゴリカル 1.949936 0.645331

強化学習

 AlphaZeroとほぼ同等の800回探索の自己対局を教師とする強化学習を行った。教師信号を作る際にTD(λ)を用いている。学習は継続中だが、とりあえず50000ステップでの結果が出たのでそれをまとめておく。

結果

 50000ステップでの損失値(この検証データは教師あり学習のときと完全に同一のfoodgate2015年データを用いて行っている)

モデル Policy損失 Value損失
強化学習 1.949936 0.645331
強化学習 1.902164 0.693806

 Policy損失はやや改善したが、Value損失がかなりはっきり悪化している。

初期局面での推論結果

f:id:tokumini:20201106171844p:plainf:id:tokumini:20201106171840p:plain
左:強化学習前 右:強化学習

 AobaZeroの棋譜教師あり学習を行うと初期局面での評価値がやけに先手に大きく振れるのだが、それが是正されている。また、分布の形状もかなり想定に近いものになっている。

検証対局

 持ち時間0.25秒でYaneuraOu(評価パラメータはKristallweizen・NodesLimit400000)と1000局の対局を行った結果

モデル 勝ち 引分 負け 勝率 Eloレート差
強化学習 433 131 436 49.85% -1.0
強化学習 348 1 651 34.85% -108.7

 レートが100以上下がった。探索込みではやはりValue損失が大きく効いてくる印象ではある。

 他に目を引くのが引分数の大幅な減少で、ほぼ引分が起こらないというのはゼロから強化学習をした場合とほぼ同じ傾向である。

 全体的にもとのパラメータの影響がかなり薄れている印象を受けた。もとの教師あり学習が300万ステップであるのに対して、5万ステップの強化学習をするだけでこれだけ変わってしまうのは学習率が大きすぎたのかもしれない。

Transformerを用いた探索的NNの学習(失敗編)

 以下の続き。

 前回までの手法では多少改善は得られたものの、探索回数を増やすほど性能が良くなるような性質は得られなかった。またこのやり方では本質的にゲームであることを利用しておらず、一般的に画像認識等でも利用できるものになっており、スコープが広すぎる気がしていた。よってここのところはシミュレータを利用してきちんと盤面遷移を含める手法について検討している(単に迷走中と言ったほうが適切かもしれない)。

f:id:tokumini:20201019095735p:plain

 この雑な図で伝わるかはわからないが、今は赤枠のあたりを探っている。

 問題を簡単にするため、探索部分は事前学習したモデルを用いることにした。

f:id:tokumini:20201019102446p:plain

f:id:tokumini:20201019102514p:plain

 注意点として、このやり方だと一つの読み筋を突き進んでいくことしかできない。よって行動はSoftmax層の出力から確率的にサンプリングすることにし、数手(今回は3手)進むごとにルート局面に強制的に戻すことで深さ3の読み筋をたくさん並べることにした。

f:id:tokumini:20201019102809p:plain

 これを時系列モデル、今回はTransformerに入力することで推論をする。src側に探索の系列、target側にルート局面の分散表現を入れて、ルート局面に対するPolicyを推論させる。

f:id:tokumini:20201019103033p:plain

実験

 オセロにおける教師あり学習で実験を行った。事前学習ではPolicy損失は0.776090になった。

 Transformerの学習推移は次のようになった。

f:id:tokumini:20201019103215p:plain

 n回探索は、src側の系列長がn個であることを意味する。

 線が重なっていてさっぱり違いがわからない。つまりsrc側の情報を有効活用できていないということなのだろう。

 最終ステップでの損失を取り出してプロットすると次のようになった。

f:id:tokumini:20201019103219p:plain

 探索しないほうがマシという結果になっている。

所感

 そこまで大幅な改善を期待していたわけではないが、少しくらいは良くなるのではないかと思っていたのでこの結果は意外だし、何か実装ミスがないか不安になるところではある。特にTransformer部分は

などからコピペして、LibTorch1.6.0環境ではそのままでは動かなかったのでちょっと改造して実装したわけだが、そのあたりでミスしている可能性がなくはない。特にLibTorch1.6.0ではMultiheadattentionモジュールにバグがあり、そこも手動で直したのでそのあたりがどうか……。

 LibTorch1.7.0では直っていると思われるのでそれを待ちたいところでもあるが、修論締め切りは待ってくれない。

AobaZeroの棋譜を用いた教師あり学習 192ch

 今回は普段128chである残差ブロック中のCNNを192chに増やして学習を行った。

学習結果

f:id:tokumini:20201005082025p:plainf:id:tokumini:20201005082029p:plain
左:Policy損失 右:Value損失

 どちらも学習損失では192chの方がやや良いのだが、検証損失ではそこまで差が出ていない。

 学習時間はやや長くなり45時間、約二日であった。

検証対局

Miacis側0.25秒-Kristallweizen側200Kノード

f:id:tokumini:20201005082125p:plain

 192chにするとNPSも落ちるので総合的に見て棋力が向上している感じはあまりしない。しかし学習量を増やした分の影響で少しだけレートが高くなっていそうではある。

Miacis側1秒-Kristallweizen0.4秒

 基本的にMiacisのパラメータはCategoricalモデルでチューニングしたものであり、Scalarモデルではもっと良いパラメータがある可能性が残されていたため、今回は特に C _ {PCUT}についていくつかの値を試してみた。

 C _ {PCUT} 勝数 引分数 負数 勝率 相対Eloレート
2000 262 101 637 31.2% -137.0
2500 159 76 341 34.2% -113.7
3000 315 132 553 38.1% -84.3
3500 331 117 552 39.0% -78.1
4000 315 168 517 39.9% -71.2
4500 309 153 538 38.6% -81.0

 MiacisではValueの学習をtanhを使い-1から1で学習していて、探索中も0から1に正規化することはなくそのまま使用しているため、正規化しているAlphaZeroに比べれば C _ {PCUT}は2倍になっていておかしくない。AlphaZeroで C _ {PCUT} = 2000と考えると、少し大きい気はするがそんなもんかなという気もする。

 最も良かった結果について、強化学習モデルとの比較をすると

 C _ {PCUT} 勝数 引分数 負数 勝率 相対Eloレート
教師あり学習モデル 315 168 517 39.9% -71.2
強化学習モデル 530 1 469 53.0% 21.2

となる。レート差は90ちょいといったところで、まだ同等というには少し遠い。

 注目すべきは引分数で、極端に異なっている。入玉形を目指しやすいかどうかというあたりの差だと予想しているが、検証対局はAyaneでの自動対局で行っており棋譜も残していなかったので正確なことはまだ不明。

Miacisを用いた教師あり学習の実行手順

 AobaZeroの棋譜を用いて学習し、floodgateの棋譜を用いて検証する場合を説明します。

前提

 Ubuntu 18.04でのみ検証ができています。おそらくUbuntu 16.04や20.04でも大丈夫だとは思いますが、未検証です。Windowsでも最近のWSL2やDocker for Windowsでできるかもしれませんが、未検証です。

環境構築

1) Nvidia Driverのインストール

 ここの手順は半年も経てば変わっていそうなので、とりあえず2020年6月時点でのQiitaの記事をリンクするにとどめます。

2) CUDA,cuDNNのインストールからMiacisのビルドまで

2-a) Dockerを使う場合

 Dockerfileを公開しているのでDockerを用いることをおすすめします。検証したDockerのバージョンは19.03.12で、nvidia-dockerの拡張を入れます。そのあたりについては

などを参考にしてください。

 Dockerが使える状態になったら適当にビルド用ディレクトリを作り、公開されているDockerfileをダウンロードしてきてビルドします。コマンドとしては

mkdir miacis_build
cd miacis_build
wget https://raw.githubusercontent.com/SakodaShintaro/Miacis/master/scripts/Dockerfile
docker build -t miacis .
docker run --gpus all -it --name miacis miacis bash

2-b) Dockerを使わない場合(未検証)

 CUDA10.2とそれに対応したcuDNN7.5~をインストールしてください。それができたら後の手順は先のDockerfileと同じなので、そこに記載してあるコマンドを上からコピペして実行していけばできると思います。

注意

 以下ではMiacisリポジトリ~/にあると仮定してコマンドを記述していきます(Dockerで環境構築した場合そうなっています)。

3) 棋譜のダウンロード

 検証損失を計算するためにfloodgateの棋譜をダウンロードします(7zipの展開に数時間かかります)。スクリプトを用意してあるのでそれを実行します。

~/Miacis/scripts/download_floodgate_kifu.sh

 学習用の棋譜としてAobaZeroの棋譜をダウンロードします(回線環境に応じてそれなりに時間がかかります)。同様にスクリプトを実行します。

~/Miacis/scripts/download_AobaZero_kifu.sh

 これらのスクリプトにより

~/data/floodgate/train
~/data/floodgate/valid
~/data/aobazero/data

のというディレクトリができ、そこにCSA形式の棋譜が保存されます。

学習

 学習の設定ファイルをMiacis実行ファイルと同階層にコピーしてきます。

cd ~/Miacis/src/cmake-build-release/
cp ~/Miacis/settings/supervised_learn_settings.txt .

 Miacisを実行します。

./Miacis_shogi_categorical

 実行するとCUDA is available.またはCUDA is not available.という表示が出て、その後コマンド受付状態になります。CUDA is not available.という表示が出た場合はCUDAが認識できていないので環境を見直してください。

 コマンド受付状態ではusiなどのUSIプロトコルに対応したコマンドを受付けますが、それらに加えて学習コマンドも実行できます。まずはinitParamsコマンドを入力し、ランダム初期化したパラメータを準備します。その後supervisedLearnコマンドを入力することで、同階層にあるsupervised_learn_settings.txtを読み込んでそこで指定された設定のもとに学習を始めます。

 学習が終わるとfinish supervisedLearnの表示が出たあと、コマンド受付状態に戻ります。終了したい場合はCtrl + Cquitコマンド入力で抜けます。

 一連の手順を1コマンドにまとめると

echo -e "initParams\nsupervisedLearn\nquit\n" | ./Miacis_shogi_categorical

とすればパラメータ初期化、学習、終了を一気に自動的に行ってくれます。

検証対局

 学習した結果はsupervised_train_log.txtsupervised_valid_log.txtとして残されますが、損失値の計算だけでなく実際の対局により棋力を検証したい場合もあります。

 まずはYaneuraOu(評価関数はKristallweizen)をダウンロード、構築します。スクリプトとして手順をまとめており、

~/Miacis/scripts/download_YaneuraOu.sh

を実行することで~/YaneuraOuというディレクトリができ、そこに実行ファイルが作られます。

 YauenuraOuが取得できたら対局を行います。学習を行ったディレクト~/Miacis/src/cmake-build-releaseにおいて

~/Miacis/scripts/vsYaneuraOu.py --time1=250 --time2=250 --NodesLimit=200000 --game_num=250

を入力します。

 対局数が250とやや少なめなので確実な値ではありませんが

158勝  25引き分け  67敗 勝率 68.2% 相対レート  132.5

が2020年9月26日時点で最も良かった値となります。

発展

ハイパーパラメータを変更する

 学習のハイパーパラメータ等を変更したい場合はsupervised_learn_settings.txtの内容を変更します。これは空白区切りで設定項目とその値を1行に書いていく形式になっており、詳しくは~/Miacis/src/supervised_learn.cpp等を見てください。

ネットワークを変更する

 ネットワークを変更したい場合、Miacis/src/neural_network.cppを編集することになると思います。たとえば残差ブロックの数を増やしたければ7行目の

static constexpr int32_t BLOCK_NUM = 10;

というところを変更してからMiacis/src/cmake-build-releaseディレクトリでmakeをするとビルドが行われます。

LSTMを用いた探索的NNの学習:単純なLSTM

 以下の続き。

 前回はLSTMによくわからない工夫を入れることで探索(?)回数が増えると損失が落ちる結果を得ることができた。

 今回はもっと単純に本当にLSTMだけを使うものと比較する。

手法

 余計な部分を加えず、LSTMで単純に規定回数だけ推論してから出力する。便宜上、LSTMで推論させる回数を探索回数と呼ぶことにする。

 PyTorchにおいてLSTMはnum_layersという引数でLSTMの層をどれだけ重ねるか制御できるが、今回はnum_layers=2で実験を行った。

 入力としては常にルート局面を事前学習したEncoderにかけて得られた同じ表現ベクトルを与える。

f:id:tokumini:20200924094730p:plain

 以下の論文でやっていることに近いと思われる。現状で相違点としては

  • Conv-LSTMではなく単純なLSTMであること
  • LSTM内の一番奥から手前へのTop-down skip connectionがないこと
  • LSTMの状態を前状態から引き継がないこと

があると認識している。1,2個目はあまり重大ではないかもしれないが、3つ目はやや大きい違いかもしれない。

 以前読んだときのメモ

実験結果

f:id:tokumini:20200924075202p:plain

 綺麗に層が分かれて、なかなか良い結果に見える。

 10回探索後の検証損失を前回の手法(LSTM+α)と比較すると次のようになった。

f:id:tokumini:20200924075217p:plain

 終始、今回の単純なLSTMモデルの方が良い値となった。

 横軸に学習時間を取ってプロットしても以下のように前回の手法よりも短い時間で済んでいることがわかるので、計算量が増えているということもない。

f:id:tokumini:20200924080115p:plain

 最終ステップでの検証損失を比較すると

f:id:tokumini:20200924075237p:plain

となり、単純なLSTMではなだらかに下がっていっていることがわかる。

検証対局

 Edax Level1と1000局やった勝率を前回の結果も含めて掲載。

手法 探索回数 勝率 レート差 参考(損失値)
MCTSNet 0 35.6% -102.6 0.833593
MCTSNet 10 37.9% -86.0 0.812401
LSTM 0 36.0% -100.0 0.784351
LSTM 10 39.9% -71.5 0.661252
SimpleLSTM 0 33.9% -116.4 0.701362
SimpleLSTM 10 37.6% -87.6 0.658220

 探索回数0→10で改善はしているが、損失値のわりには弱い。やっぱり検証対局が損失と相関しない印象がある。

所感

 入力に常に同じものを与えるLSTMというのは結局SkipコネクションがあるフィードフォワードNNと変わらないようにも思える。「探索回数を増やす=ネットワークの層を増やす」ということになっているならばそれに伴って損失が小さくなることも納得できる。となると単純に層を増やした探索なしモデルと比較してみるべきか。

 手法のところで挙げた論文を読んだメモでは、プランニングの特徴として

  1. 様々な状況に対して簡単に一般化可能
  2. 少量のデータから効率的に学習可能
  3. 思考時間が伸びるほど性能向上

というものを挙げている。個人的には3が一番重要だと思っているが、今回の結果ではわりと早い段階で頭打ちになっている。今後はそこの改善を目指していきたい。

LSTMを用いた探索的NNの学習

 以下の続き。

 前回はMCTSNetの学習方法を工夫することで上手く学習できた。

 今回はそれに対する提案手法に近いものとして、LSTMを用いてGPU上のみで探索的な振る舞いを可能にするモデルについて実験を行った。

手法

f:id:tokumini:20200923143240p:plain

 Simulation Policyに相当するLSTMは状態の表現ベクトルを系列的に受け取り、探索する行動の表現ベクトルを出力する。行動の表現ベクトルというのはただの個人的な解釈であり、特定の行動と結びつくようになにか制約を入れているわけではない。

 Env Model(環境モデル)は全結合NNであり、状態表現ベクトルと行動表現ベクトルを連結したものを入力して次の状態表現ベクトルを出力する。これもまた個人的な解釈であり、再構成誤差等の制約を導入しているわけではない。

f:id:tokumini:20200923143226p:plain

 最終決定はSimulation Policy用LSTMとはまた別のReadout用LSTMにより、状態表現ベクトルの系列を入力して最後に方策を出力する。

実験設定

 オセロでの学習を施行した。

 EncoderはMCTSNetの学習と同様に、普通のMLPモデルで事前学習したパラメータを用いて、学習しないように凍結した。

 MCTSNetに比べて高速なので10倍のステップ数で学習を行った。

実験結果

f:id:tokumini:20200923143823p:plain

 1回探索した時点で大きく下がり、学習後半では2回探索した時点でもやや下がる。それ以降ではほぼ変わらない。

 最終ステップ時点での検証損失をプロットすると次のようになる。

f:id:tokumini:20200923143832p:plain

 見事に2回目以降はX軸に並行となっている。

 興味深い点として、事前学習での最終的なPolicy損失が0.853867であったのに対して、今回の学習では0回目時点で0.784351とそれより小さくなっている。事前学習はややチューニング不足ではあるので、しっかりやればこの程度はいくかもしれないが、今回の学習の2回探索時点では0.661485となっており、ここまで通常のMLPで学習させるのは困難に思える。つまり、損失値としては非常に良い値が出た。

検証対局

 前回のMCTSNetと合わせてEdax Level1と対局した。それぞれ1000局行った。

手法 探索回数 勝率 レート差 参考(損失値)
MCTSNet 0 35.6% -102.6 0.833593
MCTSNet 10 37.9% -86.0 0.812401
LSTM 0 36.0% -100.0 0.784351
LSTM 10 39.9% -71.5 0.661252

 一応どちらも探索を入れた方が勝率は上がっているが、それほど損失値と対応したレート値にはなっていない。EdaxのLevelも1という低いものであり、この検証対局での勝率が指標として良いものかどうかはわからない。

 (AlphaZeroのように強化学習してMCTSを行う手法では800回の探索でEdaxのLevel 6と同程度の性能になる)。

分析

 今回の学習で得られたパラメータについて探索中に得られた表現ベクトルについて値を検証した。

 初期局面に対する探索について、表現ベクトルを1回前の探索時点の表現ベクトルからどの程度変わったかを調べた。

f:id:tokumini:20200923150007p:plain

 Y軸は対数となっており、要するに探索すればするほど表現ベクトルが大きく変わっていくということになっている。要素平均値が1000も変わるというのは尋常ではない変わり方であり、まともな挙動とは言い難いように思える。

 それだけ変わると状態表現ベクトルもおかしい値になっていそうだが、Policyに影響は出ていない。おそらくLSTM部分でほとんど入力が受け付けられていない(Input gateがほとんど0になっている)のではないか。

所感

 上手くいっているんだかいってないんだかよくわからない結果となったが、可能性はありそうに感じる。いろいろ正則化を入れてどうなるか、モデルの構造を工夫してどうなるかといったところを検証してみたい。

 一応、今回の結果を信頼するならば、AlphaZeroモデルの評価関数部分をこのLSTM的なもので置き換えるだけで性能向上ということがあり得るのかもしれない。評価する時点でネットワークで小探索をして、その出力を使ってさらにMCTSするという感じになるのか?

AobaZeroの棋譜を用いた教師あり学習

 前回、AobaZeroの棋譜を取得できるようになった。floodgateの棋譜についてもダウンロードスクリプトを整備し、実験手順を再現しやすいように仕組みをやや変えたので教師あり学習をやり直すことにした。

棋譜について

floodgateの棋譜(いつも通りの設定)

 2016年~2019年の棋譜を学習用、2015年の棋譜を検証用として利用する。学習結果は古いものを使ったので厳密にはやや異なっている部分もあるが、学習に使う棋譜はおおむね以下の条件を満たすものとなる。

  • %TORYO,%SENNICHITE,%KACHIのいずれかで終わっている
  • 手数が60手以上である
  • 対局者のレートの高い方が2800以上である(レートが不明な対局者はレート0として扱う)

 学習データ数は約31,000,000局面, 検証データ数は約2,000,000局面である。重複局面の削除等はしていない。

 ダウンロードスクリプト

AobaZeroの棋譜

 AobaZeroの棋譜もfloodgateの棋譜と同様に以下の条件でフィルタをかけた。

  • %TORYO,%SENNICHITE,%KACHIのいずれかで終わっている
  • 手数が60手以上である

 AobaZeroの棋譜にレートについての制約はかけていない。

 AobaZeroの棋譜はこの一つでおおよそ3,000,00弱程度の局面があり、今回は13300000から14300000までの101個をダウンロードしたので約300,000,000局面ほどになる。(これはfloodgate側の約10倍の量であり、今回の学習設定では1エポックも回りきらない)

 ダウンロードスクリプト

実験設定

  • OptimizerはMomentum(0.9)付きSGD
  • バッチサイズ : 512
  • 初期学習率 : 0.025
    • 200,000、300,000ステップ時点で学習率を1/10
  • 学習ステップ数 : 400,000
  • 検証損失の計算はどちらもfloodgate2015年のデータに対して実行
  • 左右反転によるデータ拡張を実行
  • 使用したモデルはCategoricalモデル

 実験設定はできるだけ揃えたつもりだったが、AobaZeroの方でのみL2正則化があり(係数1e-4)になっていた。

実験結果

floodgateの棋譜からの学習

f:id:tokumini:20200915090809p:plainf:id:tokumini:20200915090813p:plain
左:Policy損失 右:Value損失

  • Policyについて、学習損失と検証損失の乖離が小さい
  • Valueについて、検証損失は200,000ステップ以降上がっていってしまう
    • 60,548ステップで1エポックであり、3エポック目あたりから過学習

AobaZeroの棋譜からの学習

f:id:tokumini:20200915091123p:plainf:id:tokumini:20200915091126p:plain
左:Policy損失 右:Value損失

  • Policyについて、学習損失と検証損失の乖離が大きい
  • Valueについて、検証損失も下がり続ける
    • 200,000ステップまではやや振動している感じがある?
    • 学習率の設定はfloodgateと同じだが、大きすぎる?
  • Valueの学習損失の挙動が奇妙?

検証損失を比較

f:id:tokumini:20200915091517p:plainf:id:tokumini:20200915091520p:plain
左:Policy損失 右:Value損失

  • Policy損失は明らかにfloodgateの方が小さい
  • Value損失は最終的にAobaZeroの方が小さくなる

対局による比較

 Kristallweizenの4スレッド、NodesLimit200,000と対局を行った。Miacis側は1手0.25秒である。 使用したスクリプト、使用したコマンドは以下

~/Miacis/scripts/vsYaneuraOu.py --time1=250 --time2=250 --NodesLimit=200000 --game_num=250

f:id:tokumini:20200916103925p:plain

 AobaZeroが200,000ステップ以降で大きく伸びた。両者、最も良かった点を比較するとAobaZeroが380,000ステップ時点のR+13.9、floodgateが280,000ステップ時点のR-243.0なので256.9ほどの差が出たことになった。

 追加のデータとして、Miacisの強化学習で1,000,000ステップ回したものをこの条件で対局させるとR+232.3となった。AobaZeroの学習よりもさらにR+220ほど強い。

所感

 学習設定が揃っていないことに記事を書いている途中で気づいたのでどうしようか悩んだが、とりあえずこの状態で一度公開する。AobaZeroの棋譜からの学習はもっとチューニングできそうなので、整えきってからまた公平な比較ができれば。

 今後は

  • 学習率を下げる
  • AobaZeroの利用する棋譜をもっと増やす
  • Scalarモデルでの学習
  • Swish, Mishなどの活性化関数

あたりを試してみたい。

付録

 L2正則化(Weight Decay : 以下WD)の有無による差は、古いデータだったり学習率減衰の設定が異なっていたり対局結果はなかったりするが一応損失推移のデータはあったので載せておく。

floodgate

f:id:tokumini:20200916110356p:plainf:id:tokumini:20200916110400p:plain
左:Policy損失 右:Value損失

 明らかにWDありの方がValue損失が小さくなっている。こちらで検証対局をするべきだった。4ヶ月以上前に行った実験なので、現在の設定でやり直して対局までやってみたい。

AobaZero

f:id:tokumini:20200916110609p:plainf:id:tokumini:20200916110613p:plain
左:Policy損失 右:Value損失

 これは最近取ったデータであり、これでWDありの方がやや良かったのでAobaZeroの検証対局はWDありの方でやってしまった。損失から見るとWDなしでもそこまで大きな差があるわけではないように感じられるが……。

 気になる点としては、WDなしの場合でもValueの学習損失が学習率を下げた200,000ステップ以降で上昇傾向にあることであり、これがどういう理由で起こっていることなのかよくわからない。

WDあり同士での比較

f:id:tokumini:20200916112029p:plainf:id:tokumini:20200916112033p:plain
左:Policy損失 右:Value損失

 これで見るとほとんど差はないかもしれない。しかしこうして見てもAobaZeroの棋譜を用いたときのValue学習損失の挙動が気になる。

 自分が想像していた以上にL2正則化が強力なのではないかと感じてきた。強化学習へ導入したときは学習序盤であまり効果がないと打ち切ってしまっておりL2正則化に対する信頼感がなかったのだが、学習率を下げた後半で強く効いてくるとしたら話は変わってくる。強化学習の方でも追加でやってみるべきかもしれない。

MCTSNetの学習結果(Simulation Policyの廃止)

 以下の続き。

 前回はMCTSNetの学習式に従って実験したが、結果は振るわなかった。学習の挙動などを見ていて、個人的な印象としてはSimulation Policyを方策勾配法のような形で学習していくのは難しいように感じている。

 具体的な要因としては、特に学習序盤でSimulation Policyが変に学習されてしまうと考えている。Simulation Policyは0回目からm回目までの探索で損失が改善した量を報酬として学習するわけだが、学習序盤では損失値はたいてい次のようになる。(以下は実際の学習で得られた値)

0回後 1回後 2回後 3回後 4回後 5回後 6回後 7回後 8回後 9回後 10回後
1.862 1.911 2.014 2.197 2.435 2.735 3.104 3.492 3.783 3.983 4.137

 Policyを事前学習しているので0回後の損失値はそこそこ良いものになっている一方で、Backupネットワークは事前学習できないので探索すればするほど損失値は悪くなる。つまり序盤ではどんな探索行動を取っていても悪化するというシグナルしか与えられない。

 方策勾配法が必要になるのはSimulation Policyを学習させるためだが、つまりSimulation Policyなんてものがなければ妙なことはしなくて済む。探索中に用いるSimulation Policyと最終決定で用いるReadout Policyが異なるというのは納得できる話なのだが、実践的に学習を安定化させるためには両者に同一のものを使ってしまうのが良いと考えた。

 まとめると改善案として次の2つの工夫を加えた。

  • Simulation PolicyとReadout Policyに同じパラメータを用いる
  • 学習方法を0回目からm回目までの各探索後のReadout結果と教師の交差エントロピーのみに変更する

実験

  1. 教師あり学習でEmbedネットワークおよびPolicyネットワークを事前学習
  2. Backupネットワークを追加して学習(このときEmbedネットワークは凍結する)

という手順で実験を行った。将棋ではfloodgateの棋譜を用い、オセロでは以前山岡さんが記事に書いていたサイトの棋譜を利用した。

将棋

 検証損失の推移は以下のようになった。

f:id:tokumini:20200914103128p:plain

 6万ステップを超えたタイミングで学習率を1/10にしており、そこからの減少で本当に少しだけ損失が改善するようになった。

 一番最後の検証損失は横軸に探索回数を取ってプロットすると次のようになっている。

f:id:tokumini:20200914103113p:plain

 3回目までは下がっていき、それ以降は上がってしまっている。

 MCTSNetの学習により0回目の損失値がやや悪化しているのだが、事前学習での検証損失は1.877444であるのに対して3回目での損失値は1.877302なので一応小さいことは小さい。しかし誤差レベルか。

オセロ

 検証損失の推移は以下のようになった。

f:id:tokumini:20200914103039p:plain

 オセロの方が学習が上手くいっている。3万ステップを超えたタイミングで学習率を1/10にしてからかなり差が出た。

 一番最後の検証損失は横軸に探索回数を取ってプロットすると次のようになっている。

f:id:tokumini:20200914103252p:plain

 とても綺麗な形で右肩下がりになっている。疑わしいくらいに理想的な結果だ。

 事前学習との比較では、オセロでの事前学習の検証損失は0.853867なのでそもそも0回後の時点で改善がされている。事前学習のチューニングが甘く、収束しきっていない状態からMCTSNetの学習を始めてしまっているかもしれない。

まとめ

 将棋では微妙だがオセロでは効果がありそうだという結果が得られた。以前も少し考察した通り、10回程度の探索が有効に機能するシーンが多そうなのは将棋よりもオセロのように感じている。将棋でも大駒をタダで捨ててしまう局面などでは有効かもしれないが、全体から見てそういう局面があまり多くないのではないか。オセロは最終盤でほぼ毎回有効に機能すると思われる。

 上手くいったとはいえ今回の手法はかなりMCTSNetの主張を無視しているのでこれで再現できたと言い張ってよいものかどうか。むしろこれで上手くいくならなぜMCTSNetはSimulation Policyを導入して複雑化したのだろうという気にもなるが、Simulation Policyを用いてランダムプレイアウトする由緒正しいMCTSの影響が強かったということなのだろうか。

 今後はオセロで実際に対局してみて性能が上がっているかどうかの検証や、どういう局面で損失が改善されているかなどの分析を行っていきたい。