2021年11月13日土曜日

順調に育つエージェントができた

とりえあずのお祝いを。

前回の記事の終わりで、さもパフォーマンスが落ちる原因がわかったかのような口を聞いたが、仮説検証のために色々と実装をしたものの結局のところパフォーマンスが落ちる原因はわからなかった。しかもコードの重要な部分にバグがあるのも見つかり、しっちゃかめっちゃかになった。バグの修正後に比較的安全なパラメータ調整をして臨んだところ安定して成長するようになったのである。今回の記事はそのあたり(10月上旬あたりから約1ヶ月程度)のまとめになる。長くなることを最初にお伝えしておく。

過学習と正則化

前回の最後に立てた仮説は「過学習によってそれまでと少しでも違う動きをする相手に対応できなくなっている」というものであった。過学習とはデータの中の一般化できない部分にまで適応してしまう現象のことである。深層学習では過学習をどのようにして避けるかが一つの大きなテーマにもなっており、様々な手法が開発されている。データの数が少なければ少ないほど過学習のリスクも高まる。こちらの記事に詳しく解説されている。

深層強化学習の場合はデータを常に作り続けるために他の深層学習の分野と比較して過学習に対する対応が薄い。このプロジェクトで使っているRainbowというモデルでも明示的に過学習を防ぐ方法は取られていない。Rainbowの論文ではAtariのゲームのシミュレータを用いているので、データ取得と学習のステップをどの程度の比にするかを選べるようになっている。ここでデータ取得の頻度を比較的大きくしておけば過学習を防ぐことができる仕組みになっている。

AIガオガエンの場合は実機を用いるためデータ取得の頻度が実時間で決めらている。一方学習は別スレッドで動いているためステップ数はCPUに可能な最大値となっている。LSTM2枚程度のモデルではだいたいRainbow論文と同程度、つまり4ステップごとに1回程度のペースで学習をする。一回の学習で32ステップを読み込むため、実時間に対して8倍程度の速度で学習をすることになる。これもRainbow論文と同程度である。

これだけ聞くと過学習の心配はなさそうに感じるがもちろん環境が違うためちゃんと成長するために必要なデータの分量も変わってくる。LSTM1枚のモデルが2枚のものより早くパフォーマンスが落ちるのを観測したとき、過学習の可能性を疑ったのである。

過学習が起こったらどうすればいいのか。先述の記事にもあるように、「正則化」を行うのが順当な手法である。このプロジェクトでは最適化の手法であるAdamにWeight Decayを加えたAdamWというものを使った。

もうお分かりかと思うが、これで問題は解決しなかった。詳細は割愛するが、Weight Decayを導入してもパフォーマンスの低下は防げず、逆にWeight Decayを弱めたところから成長を始めるエージェントなどもいて、かえって邪魔になっている印象であった。

次に試されたのが色が見えるエージェントである。Rainbow論文にならってAIガオガエンは白黒の映像を与えられていたが、ステージが緑色、ガオガエンが赤、マルスが青で、それぞれのカラーチャンネルにうまく対応していたため色が見えるエージェントは物の識別が用意になるのではないか、という仮説があったからである。色を導入するとデータ量が増えるため、今までよりも少ない数のリプレイメモリしか保存できなくなるのがトレードオフである。

これも試されたものの、白黒のエージェントに勝ることはなく、短期間で実験を終えることになった。

ハイパーパラメータチューニング

試せる案が減ってきたので、ノイズを増やす、マルチステップの数を変える、などの妙な変更を始めた。ここで試したかったことは、「パフォーマンスの低下は過学習の結果ではなく、ガオガエンが成長する上で必要なステップで、それを越えた先に成長がある」という仮説の検証であった。このエージェントでは成長速度を上げるため、裏でやっていたAtariのパラメータを一部ひっぱってきてやっていた。つまり、バッチサイズを大きく(32→128)し、学習率を上げる(1e-5→1e-4)という方法だったのだが、どういうきまぐれからかLSTMレイヤーの数は3枚にしてみた。

蓋を開けてみると、このエージェントの成長はとても遅かった。バッチサイズを大きくし、ネットワークを重くした結果、データ取得に対する学習ステップが100ステップに1,2回程度まで下がってしまい、結果Lossの現象は今までのLSTMモデルより随分ゆっくりになった。次のグラフはLSTM1枚のモデルと今回のモデルの比較である。両方Lv3スタートである。


Lossが2.0程度に戻ってくるまでに先のモデルは500エピソード程度だったが、今回のモデルは3000エピソード近くかかっている。そしてこのエージェントはその後もゆっくりと成長を続け、Lv3をクリアする直前まで来た。ここまでにおよそ5日程度かかっている。

ここで一度クラッシュしたのと、メモリ構造を書き換えるために止めたため、クリア前ではあるがLv4に移行することにした。以下がLv4の経過である。
しばらく走らせたものの、クリア目標である70%に到達するのは遠いように見えたので、クリア条件を60%に改めてクリアしたことにした。次がLv5の経過である。

ここに来て減速を始めたのである。結局駄目だったかと落胆したものである。パフォーマンスが下がるにつれてガードが増え、クラッシュするまで守るようになったのが印象的であった。パフォーマンスが落ちつつも試合時間が長くなっているあたりにその様子が間接的に伺える。

未来予測型

その次に試されたのが未来予測型のネットワークである。情報を処理するLSTMの前に未来を予測する部分を並列で作り現在の情報と予測された未来の情報の両方を使って最適な行動を選べる(はずの)エージェントである。次の図の左側の水色の線の部分が未来予測の部分である。

着想はSSBMの深層強化学習を行ったFiroiu氏のこの論文からである。AIガオガエンの約300msの入力遅延を未来予測でごまかせないかという話である。

結果から言うと、未来予測型がしっかり完成する前に、回帰ネットワークまわりのバグが見つかったので保留になった。なのでこの部分は未完成である(一応完成はしているが未検証、といったところか)。

回帰ネットワークのバグ

問題は「トレーニングの最中に同じネットワークを2回使ってしまっていた」というものであった。回帰ネットワークでなければ何度使おうが同じ入力には同じ結果を返すので問題ないのだが、回帰ネットワークは内部状態を持つため2回使うと違う結果が出るし、その次のステップ移行にも影響してくる。トレーニングにおいても同じネットワークは一度しか使ってはいけないのだ(内部状態を元に戻すという処理も可)。今回は2回使わなければいけない場面でネットワークを2つ用意するという対応をとった。

このバグに間してはバッチサイズを大きくすることによってもある程度対策が可能なため、バッチサイズの大きくした時にパフォーマンスが低下しにくくなる1つの理由となり得た。

GRU vs LSTM

回帰ネットワークのバグを修正するついでに計算を軽くしたい欲求も出てきた。もし今まで成長していなかったのが回帰ネットワークのバグのせいならばLSTM1枚でもちゃんと成長する可能性がまだ残っている。

それと同時に、今までのLSTMの知見が眉唾ものになったために、少し他の事を試すいい機会になった。GRUというLSTMと同等の性能でパラメータが少なく計算と学習が少し早い回帰層があり、これとLSTMのどちらを使うか迷った結果今まではLSTMを使っていたのだが、ろえを機会にGRUを試してみることにした。以下がGRUでLv3から学習を始めたときの結果である。

最初大きなバッチサイズ(4096だったか)で始めて、2200epあたりで成長の遅さにしびれを切らしてバッチサイズを小さく(128)した。そこからしばらく走らせたものの、パフォーマンスの低下が見られたので仕方なく打ち切った。LSTM3枚のモデルがうまくいっていたため、このままここで時間を使うのは勿体ないかと思い、これも一旦保留にしてLSTM3枚のモデルに戻ることにした。

最後の変更:バッチサイズをランダムに

結局まともに動いているならいいかということでLSTM3枚でLv5で調子がよかったあたりから再開した。次のグラフの14000epあたりから修正されたLSTM(バッチサイズ大)が始まる。
バッチサイズの変更の伴って報酬は急上昇し(QもLossも)あっさりとLv5をクリアした。Lv6も同様でさほど苦労せずに攻略した。Lossはバッチサイズを大きくして以来増え続けている。
Lv7の途中で少し成長に鈍化が見られた。
上昇を続けていたLossもここで現象に転じ、過学習の様相を見せ始めた。ここで、新たな正則化の手法を導入した。バッチサイズを固定された数からランダムに変更したのである。

学習に用いるデータは1試合ずつ取り出して使われるのだが、バッチサイズを固定しておくと、同じ試合を取り出した時に切り分け方がいつも同じになる。これをランダムにすることで、同じ試合でも別の切り方になり、ネットワークにとって少しずつ違うデータに見えて、正則化が働くのではないかという算段である。

そのランダム化を3700epあたりで導入した結果、以下の図のようにパフォーマンスがまた回復してLv7をクリアすることができた。最後急激に報酬が落ちたが、あまり気にしないことにした。その後もこのエージェントは順調に成長し、ついに当初の目標であるLv8のCPUマルスを攻略した。

これで少なくとも安定して成長するエージェントができたことになり、いよいよAI同士によるセルフプレイの準備を始められる段階に入った。

確認事項1: クイックモードをやめたらどうなるのか

今までのトレーニングの大部分はデータが速くとれるクイックモードでやっていたが、通常モードと比べると入力遅延がやや大きい、フレームスキップがより頻繁に起こる、FPSが微妙に違うなどの問題があって通常モードに戻したときにどうなるかという検証が行われていなかった。人間は通常の時間でプレイしているため、通常モードで動かせないのは致命的になる。セルフプレイを本格的に始める前に通常モードに移行できるかを確かめることにした。

クイックモードでLv8マルス攻略まで鍛えたガオガエンを通常モードで戦わせた結果がこちらである。

ご覧の通り、最初こそ少しパフォーマンスを落とすものの、比較的簡単に順応することがわかる。

確認事項2: 終点から戦場にするとどうなるか

もう1つ確認しておきたかったのが台の有無にどう対応していくかである。スマブラは縦にも横にもキャラが動くゲームで、ステージ上の浮遊する台の存在によって戦術の幅が大きく広がる。もし実戦を意識するのなら、台有りでの戦いは避けられない。セルフプレイを始めるにあたって、台なしの環境で育ててしまった場合、台ありにシフトしたかったら両方のエージェントを同時に鍛えなおす必要がある。ゲーム内CPUが使えるうちに台の有無に適応できるかの確認をしておきたい。

次の図は、Lv8CPUマルスを終点で倒したガオガエンが戦場(両方エレクトロプランクトンではあるが…)を使った時の結果である。

クイックから実時間に変更した時と比べて最初のパフォーマンスの落ち込みは大きかった。ほぼ全然勝てない状態に戻ったものの、そこそこの時間で勝率を5割程度まで戻すことができた。

この挑戦中にセルフプレイ用の機材が届いたので、このエージェントを叩き台としてセルフプレイを開始することにした。

続きは次の記事で…。