シミュレーションコンペで強化学習を始める時のTips
はじめに
この記事はKaggle Advent Calender 2021の17日目の記事です。この記事はKaggleで開催されるシミュレーションコンペに、強化学習アプローチで取り組もうと思った時に役立つ情報をまとめたものです。強化学習に初めて取り組む方を基本的には想定しており内容もそちらに合わせています。
初めに自己紹介させていただくと、私はkutoというアカウントでKaggleに取り組んでおり、今年Kaggle Masterになることができました。過去に2つのシミュレーションコンペに参加し強化学習アプローチで取り組みました。過去のコンペ参加の振り返りは以下に書いてますので興味があればご覧ください。 kutohonn.hatenablog.com kutohonn.hatenablog.com
これらの経験を通して得た強化学習の知見を共有できればと思います。なおここでいうシミュレーションコンペとはゲームAIコンペを想定しており、ヒューリスティック・最適化要素の強いコンペ(ex;サンタコンペ)はここでは想定していないことをご了承ください。またこの記事では強化学習アルゴリズムの説明などはおこないません。
目次
シミュレーションコンペの基本知識
チュートリアル
シミュレーションコンペにまだ参加されたことがなく、勘所がいまいち分からないという方はまず初めにこちらのnotebookを読まれることをお勧めします。 www.kaggle.com こちらはkaggle days championship finalのワークショップでkaggle Grand Masterのdott氏が講演してくださったものです。ConnectXというシンプルなゲームを題材にルールベース、ゲーム木アルゴリズム、教師あり学習(模倣学習)、そして強化学習というシミュレーションコンペでとりうるアプローチを順序立てて説明してくださっており雰囲気が掴めると思います。
必要となる計算資源
シミュレーションコンペに強化学習で取り組もうと思った時に大きなハードルとなるのがこの点だと思います。 まず前提として、通常の機械学習と比べると強化学習は明示的に教師データを与えて学習するわけでないため学習効率が非常に悪いです。機械学習だと大抵の場合数時間で1つの学習が終わると思うのですが、強化学習の場合は一定の水準まで学習するのにも日単位の時間がかかることが多いです。この問題に対する1つのアプローチとして後述の分散強化学習というものがあるのですが、そのためには特にCPUの数が重要となります。参考までに今年開催されたHungry Geeseコンペで1stだったチームは、1GPUと64CPUで3週間+1GPUと288CPUで4日学習させていたようです。
このように聞くと計算資源のない人が強化学習で勝つのは難しいのではと思われるかもしれません。ただ先日終了したLuxAI Challengeというコンペで1stだったチームは2GPU+8CPUという強化学習では決して十分とは言えない計算資源で素晴らしい成果を残されました。以降のTipsでは計算資源が少ない状態で戦う方法についても説明しようと思います。
評価方法
通常のコンペはコンペごとの評価指標が設定されており、PublicデータとPrivateデータに対する推論結果を規定の指標で評価しスコアを算出します。一方、シミュレーションコンペの場合はコンペごとの評価指標というものはなく、代わりに他の参加者が提出したsubmissionとの対戦結果から評価されます。対戦相手は自分と同等のスコア帯の人とランダムに当たるようになっています。ただし提出してすぐは自分のsubmissionがどれくらいのスコア帯かというのが分かりません。そこでKaggleでは、序盤は対戦相手のスコア帯の幅を大きくとってたくさん対戦させ、徐々に対戦相手のスコア帯の幅を小さく減衰させることで適切なスコアに収束させる仕組みをとっています。 これは妥当な評価方法であるとは思いますが、一方で序盤の対戦結果のスコアへの影響が大きく、同じsubmissionでも順位が+-30程度変動することもあるのでそこには注意が必要です。
submission形式
シミュレーションコンペではagentという関数を持った.pyファイルをsubmissionすることでスコアが評価されます。この提出形式はコンペによって仕様が異なりますが大抵の場合コンペごとにsubmissionのテンプレートが共有されているのでそちらを参考にすれば良いと思います。
# agent.py def agent(observation, configuration): # observation(ゲームの状態)からaction(とる行動)を算出する処理(ex;モデルの推論) return action
一例として直近で行われていたLuxAIコンペでは独自の処理を上記のようにagent.pyのagent関数内に記述し、
①ホストが用意したそのほかのスクリプト
②agent.py
③(使う場合は)学習済みモデル
を圧縮ファイルとして提出するという方式でした。
強化学習の概要
ここでは用語の説明も兼ねて強化学習の基本的な概要について多くの方がイメージしやすいサッカーゲームを例にして説明したいと思います。
環境(Environment)
環境とはゲームルールなども含むゲームエンジンのようなもので、 この環境から現在のゲーム状態を受け取って後述するAgentを動かし対戦したり学習させたりします。
エージェント(Agent)
プレイヤーが操作する対象のことです。サッカーゲームではアクティブプレイヤーがこれに該当します。
状態(State)
選手の位置や向き、ボールの位置、速度などのゲームの状態を表すもので、環境から出力されます。 状態の形式は画像であったりベクトルであったりと様々です。この状態をAgentに入力として渡します。ちなみに強化学習ではこの状態の価値を計算することがあります。状態の価値とは現在のゲーム状態がプレイヤーにとってどの程度有利かあるいは不利かを表すものと思ってください。この状態の価値を強化学習では状態価値(State Value)あるいは単に価値(Value)といったりします。
行動(Action)
行動はAgentへの操作のことで右に走る、パスを出すなどが行動に当たります。 強化学習ではこの行動を学習・推論することになります。 Agentが状態を入力として行動を出力し、環境がAgentの行動を入力とするとゲーム状態が遷移して新しい状態が環境から出力される、というサイクルにより対戦が行われます。ちなみにある状態における行動確率を方策(Policy)といったりします。最適なPolicyを得るのが強化学習の目的でもあります。
報酬(Reward)
機械学習でいう目的関数に該当するもので、最大化したいものを自分で設定します。 報酬として考えられる例を以下に示します。
報酬 | 説明 |
---|---|
勝敗 | 勝ったら+1, 負けたら-1 |
得点 | 1点入れたら+1, 取られたら-1 |
ゴールまでの距離 | 相手ゴールに10m近づくたびに+0.1 |
報酬に関しては次の項目でもう少し詳しく触れようと思います。
強化学習に取り組む際のTips
ここでは強化学習に取り組む際に最初にすべきことや工夫の余地がある点をまとめています。
1. 模倣学習(Imitation Learning)
シミュレーションコンペのアプローチとして模倣学習というものがあります。 模倣学習とは名前の通り行動を模倣するように学習する教師あり学習です。 シミュレーションコンペでは参加者が提出したAgentの対戦ログがMeta Kaggleに格納されるようになっています。 ここから上位チームの対戦ログを取得し、状態を特徴量、行動を正解ラベルとして教師あり学習をすることで上位チームの方策を模倣することができます。もちろん完全に模倣することはできないのですがこれだけでも良いAgentが作れるケースが多いです。模倣学習にはGBDTやNNが使われるケースがありますがここではNNによる模倣学習を想定しています。 個人的には強化学習に取り組む前にまず模倣学習に取り組むのが良いと考えています。そのように考える理由は以下の3つです。
初手で取り組みやすい 模倣学習は通常の教師あり学習と同じなので、シミュレーションコンペが初めての方にも取り組みやすいアプローチだと思います。また強化学習はKaggle Notebookで実施されることは少ないので共有されているコードが少ない一方、模倣学習はnotebookで完結することもあり過去コンペで有益なnotebookが共有されています。そちらを参考にするとスムーズに取り組むことができると思います。
事前学習モデルとして強化学習への転移学習が可能
強化学習はそこそこ強いAgentを作るのにもかなりの学習コストを要します。一方模倣学習は数時間の学習でそこそこ強いAgentを作ることができるので、模倣学習で学習したネットワークを強化学習モデルに引き継ぎfine-tuningすることで序盤の学習を省略することができます。こうすることにより学習効率の悪い強化学習の欠点を補うことができます。ただしfine-tuning時にうまくAgentの方策を引き継げず弱体化する場合もあるのでその場合は強化学習のハイパーパラメータを調整するor何らかの工夫が必要かもしれません。モデル・データの試行錯誤がしやすい 強化学習は学習効率が悪いのでモデルがうまく学習できているかの評価にも時間がかかってしまいます。そのため新しい特徴量やモデルのアーキテクチャを選定するための試行錯誤をするのが難しいです。一方模倣学習は数時間で学習を終えることができるため試行錯誤しやすく、模倣学習で有用な特徴量やアーキテクチャは強化学習でも有用であると考えられます。なので模倣学習で試行錯誤をして、強化学習を実施するというフローをとれるのが模倣学習から取り組む利点だと思います。
関連するリンク
Simulations Episode Scraper Match Downloader
Meta Kaggleにある参加者の対戦ログから上位チームのデータを取得する方法についてのnotebookです。 模倣学習や後述する対戦結果のEDAを行う際に有用です。Lux AI with Imitation Learning | Kaggle
Lux AIで共有された模倣学習のnobteookです。非常に綺麗に整理されたコードで模倣学習に取り組む際に参考になると思います。
2. 強化学習フレームワークを使用する
強化学習の実装は結構複雑なので、既存の強化学習フレームワークを使用するのが良いと思います。ただし最新の強化学習アルゴリズムが実装されていない場合もあるのでそれらを利用する際は論文実装を参照する必要がありそうです。 以下で私が知っている範囲で主要なフレームワークを紹介します。
Stable baselines
HandyRL
PFRL
RLLib(Ray)
- PyTorch, Tensorflowに対応
- 分散強化学習, Multi-Agent, 模倣学習など多様な機能
- configファイルを用意して動かす
3. 分散強化学習を行う
Agentを強くするためには対戦数が重要なので分散環境で並列に学習ができる分散強化学習を採用するのが良いと思います。強化学習の有名なアルゴリズムとしてDQN(Deep Q Network)がありますが、通常のDQNは分散学習ができないので分散学習に対応したものを使うことで学習効率を上げることができます。過去の上位解法(Football2nd, HungryGeese1st, LuxAI1st)を見るとIMPALAという分散強化学習手法を利用しているケースをよく見かけるためこちらを初手で考えてみるのも良いと思います。 ただし分散強化学習はCPU数が多いほど効果を発揮するのでKaggle環境やColab環境で行う際は注意が必要です。
4. 報酬設計
報酬設計は強化学習において非常に重要なポイントです。
先ほどのサッカーゲームを例に説明します。
報酬は通常勝敗などのシンプルなものが良いとされています。
ただし勝敗を報酬とするとまだ何も学習していないAgentはゴールまでたどり着くことが難しく、学習初期は報酬を得ることができず学習が進まないことが考えられます。そのような時に補助的な形で「ボールと相手ゴールまでの距離」などを報酬として追加してやることでボールを相手ゴールに近づければ良いことを学習することができます。ただし「ボールと相手ゴールまでの距離」のようにゲームの目的とは異なる報酬はAgentにとって欲しい行動を誘発するのに重要ですが、Agentの学習が進んでいくとノイズとなり学習を阻害することがあります。この例で言うと本来はゴールをすることが目的なのに遠い位置からボールをとりあえず相手ゴールの向かった大きく蹴ったり、パスをせずにゴールに向かってずっと走ったりなどです。
こういったことからAgentが弱い段階では補助的に即時報酬を与え、そこそこ強いAgentができたらシンプルな報酬に切り替えるというのが1つの報酬の戦略と言えそうです。また学習を安定させるために報酬をclipingするケースもあります。reward clipingで調べると関連する情報が見つかると思います。
5. 学習する行動を工夫
Agentが取ることのできる行動は通常ゲーム環境で予め設定されています。ただし戦略上あまり必要のない行動であれば省略したり、行動空間を階層化することで学習効率を高めることができます。例えば過去にFootballコンペの6位解法では17個あるAgentの行動のうち、8方向の移動行動(4方向と斜め4方向)を1つの移動行動として扱い、移動行動が選ばれたら次にどの方向かを決定するという行動空間を階層化させるアプローチをとっていました。逆に行動を細分化するアプローチも考えられます。LuxAIコンペの1位解法ではTransfer Actionという元から与えられている1つの行動を扱う資源の種類(3種類)や方角(4方向)で細分化し3×4=12個の行動として扱うようにしていました。 このようにAgentが学習する行動をどのように扱うかというのも工夫する点となります。
関連するリンク
- A way to boost your learning
LuxAIで使われていた移動行動を学習させるための工夫に関するdiscussionです。 移動行動を1つの行動にまとめて学習するというもので模倣学習、強化学習で使えるようです。ゲームAIコンペの場合離散的な移動行動を扱う場合が多いのでこの手法はこれから出てくるシミュレーションコンペでも使えるかもしれません。
6. モデルのアーキテクチャを工夫
ここは基本的に機械学習と同じと考えていただいて構いません。ただし強化学習でpretrained modelや大規模モデルを使うケースは私が知る範囲ではほとんどなくResNetベースのモデルがよく使われている印象です。
7. 入力特徴量を工夫
こちらも基本的に機械学習と同じと考えていただいて構いません。 ゲーム状態を十分に表現できる形式であれば良いと思います。 基本的にはNNで特徴抽出するので凝った特徴量を作る必要はないと思いますが、過去コンペでは特徴量エンジニアリングにより学習効率をあげてスコアが伸びた事例もあるようです。 また強化学習にはstackという過去の状態を現在の状態に重ねてそれをモデルに入力する手法も存在しています。(DQNの論文とかに使われています。)
8. ハイパーパラメータのチューニング
強化学習は学習が不安定であるためタスクに応じてアルゴリズムのパラメータチューニングが必要なケースがあります。上位チームはモデルの挙動を考え、適切なパラメータになるように実験してチューニングしている印象です。とはいえパラメータのチューニングは強化学習アルゴリズムの知識が必要となるため、初心者がいきなりここに取り組むのは難しいと思います。なのでデフォルト値でとりあえずは試してみて、どうしても学習がうまくいっていない様子であればチューニングするというのが1つの手だと思います。
関連するリンク
- PPO Hyperparameters and Ranges. Proximal Policy Optimization (PPO) is… | by AurelianTactics | aureliantactics | Medium
- PPO/best-practices-ppo.md at master · EmbersArc/PPO · GitHub
強化学習アルゴリズムの一つであるPPO(Proximal Policy Optimization)のハイパーパラメータをチューニングする際のエッセンスがまとめられた記事です。
9. 対戦回数を増やす
強化学習は対戦型ゲームAIの場合対戦を行うことで良い方策をAgentが学んでいきます。強化学習は学習のパラメータが正しく設定されている場合は対戦を多く積み重ねることがAgentの性能向上に直結します。 対戦回数を増やすには以下のような方法があります。
- 計算資源を用意し分散環境で並列に対戦させる
- 対戦相手の推論を高速化させる
- 検証用の対戦の頻度・回数を減らす
1つ目は前述のように分散強化学習を使う方法です。
2つ目は学習に必要なデータを生成するための対戦時に、対戦相手の推論速度が学習速度のボトルネックとなるケースがあるので、そのような時は例えば対戦相手がPyTorchやTensorflowなどの深層学習ライブラリを使用したものであればjitやonnxruntimeを使用して推論を高速化させることで時間当たりの対戦回数を増やすことができます。
3つ目については強化学習の場合、学習のための対戦とは別に現在のモデルがどの程度育ったかを評価するために評価用の環境で特定の対戦相手と戦わせます。(機械学習で言うところのvalidationに該当)この対戦の勝率などをチェックして学習がうまくいっているかなどをチェックするのですがこの対戦自体は学習には利用されずあくまで評価用であるためこの頻度を少なくする、または1回当たりの対戦回数を減らすことで学習にリソースを割くというものです。ただし評価のための対戦もモデルが正しく学習されているかのモニタリングのためには重要なのでここは自分の状況を見て判断するのが良いと思います。
10. 対戦相手の調整
強化学習では対戦相手を誰にするかも重要です。 単一のAgentを対戦相手として学習するとその相手にだけ過学習してしまい多様なAgentと対戦するLBではスコアが伸びなくなってしまうため、複数の多様なAgentを用意する必要があります。 以下のような対戦相手を用意して複数の敵と対戦することで汎用的に強いAgentを作ることができるようになります。
- 公開notebookのAgent
- ゲームエンジンに用意されているAgent(ない場合もある)
- 自分と同じAgent(自己対戦, self-playと呼ばれる)
- 過去の自分のAgent
self-playは過去コンペの上位解法でもよく使われており、同じレベル帯の相手と対戦でき、現状の自分より強くなるポテンシャルを持っているので 有用な場合が多いです。ただしself-playの場合、自分と敵が同じ戦略のため方策の更新がサイクルしてしまい学習が進まないケースもあるようです。その場合はハイパーパラメータや学習方法を見直す必要もありそうです。
11. ログをとる
強化学習は機械学習と比べて学習が不安定なため複数の評価指標をモニタリングすると改善策が取りやすいです。
一番わかりやすい指標として対戦時の報酬や勝率がありこれらをモニタリングすることでAgentの学習が順調に進んでいるかを確認することができます。またそのほかにも学習時のLossや状態価値などモニタリングすべき指標は複数存在しており、それらを観察することで現状の学習方法の問題点などを見つけることにつながります。これらの指標はフレームワークであらかじめ記録されるものもあればそうでないものもあるので適宜自身で実装する必要があります。
(指標のモニタリングの一例)
12. 対戦結果のEDA&対戦の様子を見る
これは強化学習に限った話ではなくシミュレーションコンペで重要な点だと思います。 他のコンペと違い、シミュレーションコンペでは提出後に対戦というアウトプットがあるのでその結果を注意深く観察することで、上位チームがどういう戦略をとっているかを理解することにつながると思います。 対戦の様子はLBの右側にある再生ボタンを押すと対象チームのBest ScoreのAgentの過去の対戦結果を動画で見ることができます。
またそれ以外の対戦結果はKaggle DatasetのMeta Kaggleに全参加者の対戦ログがjson形式で格納されているのでそのデータを取得しEDAをすることで上位チームや自分のAgentの分析が可能です。
13. モンテカルロ木探索(MCTS)
モンテカルロ木探索とは効率的にゲーム状態を探索して有効な手を決定する探索アルゴリズムです。 Alpha Zeroで使われていることで有名でKaggleでもHungry GeeseやLuxAIの上位解法で利用されています。モンテカルロ木探索は模倣学習や強化学習の出力と組み合わせて使用されるケースが多い印象です。
関連するリンク
- 10th Place Solution
Hungry Geese10位のsazumaさんのnotebookです。模倣学習とモンテカルロ木探索(MCTS)によるアプローチがとても綺麗なコードでまとまっている貴重なnotebookだと思います。
- 8th place solution: Deep Neural Networks & Tree Search
Lux AI 8位のsaitoさんの解法です。MCTSをC++で実装し探索の高速化を図ったことで探索数を増やすことができスコアを伸ばすことができたようです。
おわりに
Kaggleで強化学習に取り組む際に役立つ情報をまとめてみました。私は2度シミュレーションコンペに参加していますがシミュレーションコンペ、そして強化学習はとても面白いです! なかなかとっつきづらい領域ではありますがこの記事がシミュレーションコンペや強化学習に関心を持つきっかけになると嬉しいです。 読んでいただきありがとうございました。