Exploration by Random Network Distillation の効果を MountainCar で試した。

強化学習を実際にやってみようと思った人なら、誰でも(?)知っている Atari の Motezuma's Revenge 。

ランダムプレイでは攻略のヒントがつかめないので、強化学習で攻略するには難しいタイプの問題として有名なゲームですね。

この Montezuma's Revenge が、かなり簡単な工夫で攻略されているという記事が興味を引いたので、実際に自分でも試してみました。

gigazine.net blog.openai.com

テスト問題

テスト問題には、OpanAI gym の MountainCar-v0 を選びました。

強化学習をやろうとしている人なら MountainCar は知っていると思うので説明はいらないと思うけど、 この問題は、非力な車を前後に加速して山を登り切ったら完了、というものです。

この車には停止状態から坂を上りきるだけの推力がないので、前後に動きながら勢いを増していかないと坂を上りきることができません。
複雑な問題ではけれど、ゴールにたどり着くまでは意味のある報酬が得られない疎な報酬設定の問題で、CartPoleより難しい問題になっています。 MountainCar は、強化学習界での Hello World 的な CartPole 問題ほど有名ではないけど、教科書などでも取り上げられているため、強化学習を始めたばかりの人もチャレンジするのではないでしょうか。

しかし! OpenAI Gym で提供されている MountainCar-v0 を試すと、結構難しい問題だということに気づくはずです。
今提供されているバージョンは、設定が以前よりかなりシビアになっているんです。
昔のバージョンでは、ステップ数に限界がなく、車が目的地につくまでは done の判定がされなかったのですが、
現在のバージョンでは、エピソードの終了条件が、 目的地到着または200ステップ経過、になっています。
これは、かなりキツイ。

初期のエージェントは馬鹿なので、ほぼランダムプレイしかできません。 ランダムプレイでは、200ステップ以内に目的地に到着する確率は非常に小さいのにもかかわらず、報酬を得るのは目的に到着した時だけなので、学習の最初の手がかりを得ることが異常に難しい。
というわけで、このバージョンは全然初心者向きでないというより、難しい部類に入ってしまうのではないかと感じています。
(余談:なんでOpenAI はこんな変更したんだろう。強化学習の練習問題のはずだったのに。)

逆に言うと、このように正規の報酬が得られにくい状況は、内発的報酬を与えるこの論文の手法検討には適していると考えました。
Atariのゲームでの検証は、GPUも積んでない自宅の貧弱PCでは満足な学習ができないってのも理由のひとつ。)

手法について

元論文はこちら

[1810.12894] Exploration by Random Network Distillation

この論文で提案されている手法は、いわゆる Curiosity Driven 方式です。 エージェントが経験したことがない状況に対して高い内発的報酬を与えることで、未知の状態の探索行動を促進します。

この論文で提案されている手法の良い点は、その内発的報酬を与える仕組みが非常に簡単なことです。 普通の発想だと、今まで経験したことのある状態を記憶したりカウントしたりして、経験したことがない状況を判定しようというアルゴリズムを作りたくなってしまいますが、この論文では、ある意味、逆の発想をしています。

彼らの提案した方法は、いわば、スクラッチ形式の地図のようなものだと、私はとらえました。
クラッチって、あの、宝くじとかで使われている、あのスクラッチです。
状態空間の地図全体がスクラッチ前の銀紙で覆われていて、どこに何が埋まっているか分からないけれど、状態を経験するたびに、それに相当する部分だけが徐々に削れて浮かび上がってくる感じです。 スクラッチが削れてしまったところは十分に経験したことがある状態で、まだ隠れている部分はまだ未経験の状態です。 もし、十分に銀紙がはがれていない状態を経験したら、その時には、不透明度の度合いで報酬を与えることにします。(透明で見えてしまっているところは零点です。)

論文では、もちろん、上のような述べ方はしていません。 論文では、Random Network Distillation (RND)と命名してきちんとした説明がされています。

エッセンスを伝えると、 まず、2種類のネットワーク( \hat{f}, f)を用意します。  \hat{f} : s \rightarrow R^k は、target network、 f : s \rightarrow R^k は、prediction network と呼びます。 ここで  \hat{f} は最初にランダムに初期化した後は、手を付けずそのまま固定します。 target network によって、状態 sはある埋め込み空間のベクトル  e_s \in R^k に移ります。

一方で、もう一つの prediction network は ランダムに初期化された後、target network の出力を予想するように徐々にチューニングしていきます。 つまり、ある状態  sを経験するたびに、予測のずれ   L := \left | \hat{f}(s) - f (s) \right |^2 を小さくするように、 f を、少しずつ勾配降下法でチューニングいきます。

そして、この 誤差  L を、そのまま内発的報酬としてしまうのです。

似たような状態を経験するたびに、その状態に関して勾配降下法でネットワークの予測誤差が減っていきますので、内的報酬も減っていきます。 一方で、まだ経験したことのない状態に関しては prediction network 出力のチューニングは不十分で予測誤差が大きいままですので、大きな内発的報酬が与えられるという仕組みです。

内発的報酬の計算方法に関する提案ですので、様々な既存の強化学習アルゴリズムに適用することが可能です。

テスト結果

RNDを利用した内発的報酬を加えた場合と、加えない場合とで、(外発的)報酬の上がり方を示したのが下のグラフです。 学習手法には Double Deep Q-Learning を使用しました。 RNDを用いたほうが、早くゴールにたどり着いて外発的報酬を得ることに成功していますので、問題を解くまでにかかる試行回数が少なくなっています。
というか、500試行程度では素のDouble DQNでは解けていません。
RNDの効果アリでした。 f:id:FakeOwl:20181126213957p:plain

チューニング

ただし、この結果になるまでには少々工夫も必要でした。 論文でも書かれているように、内発的報酬のスケーリングを工夫しないと、予測誤差を素直に内発的報酬にするだけでは上手くいきませんでした。
RNDの更新の頻度や学習率なども上手く調整する必要がありそうです。 また、内発的報酬を大きくしすぎると、おそらく Exploration/Exploitation バランスが崩れてしまうため、適度の内部報酬となるようにチューニングが必要であると思われます。
最終的には、今回の形式での内発的報酬は経験を積むにつれてゼロに近づくので、本来の外発的報酬だけが残るとは思いますが、それまでのスケジューリングを決めるのは大切なチューニング項目になりそうです。

MountainCar 程度でも試行錯誤が必要でしたので、Atari のゲームのように学習が重たいものを相手にするには、結構な計算リソースが必要になりそうな予感がします。