深層強化学習でAIマリオのクリアにチャレンジしてみた

![mario_random.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81919/38ab2d9b-0c3a-fc7e-6f4d-55cf93a40846.gif)


# 追記：マリオの全ステージクリアを目指します！(2021/12/30)
　深層強化学習で学習したAIマリオで全ステージクリアを目指すプロジェクトをGitHub Pagesで立ち上げました！参加者募集中です！

https://karaage0703.github.io/mario-ai-challenge/

詳細は以下参照ください

https://karaage.hatenadiary.jp/entry/2022/01/17/073000


# 深層強化学習のPyTorchチュートリアルが日本語訳されて…ない！
　PyTorch勉強中の人にとって助けになるのが公式のチュートリアルです。そんな公式チュートリアル @sugulu_Ogawa_ISID さんが日本語訳して公開してくださっています。

https://yutaroogawa.github.io/pytorch_tutorials_jp/

　今、深層強化学習に興味津々丸なので、早速確認してみました。

　すると…

![rl_none.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81919/f9887945-3e08-71c6-041c-58100205fc99.png)

　ない！

　PyTorchのチュートリアル、マリオをプレイするものあって、めっちゃ面白そうなんですよね。というわけで、訳される前のPyTorchの深層強化学習のマリオチュートリアルをやってみました。

　ちなみに、PyTorchチュートリアル（日本語翻訳版）の深層強化学習のチュートリアルは現在絶賛レビュー中らしいので、期待して公開を待ちましょう！

**追記： [PyTorchチュートリアル（日本語翻訳版）](https://yutaroogawa.github.io/pytorch_tutorials_jp/)にAIマリオの深層強化学習のGoogle Colab ノートブックが追加されていました！なんと本記事へのリンクもしていただいてます。**

この記事より100倍分かりやすい内容ですので、本記事は軽く流して、こちらをじっくり読みましょう！

## マリオのチュートリアルが楽し…くない！
　早速公式のチュートリアルを確認してみます。

[TRAIN A MARIO-PLAYING RL AGENT](https://pytorch.org/tutorials/intermediate/mario_rl_tutorial.html)
　マリオが動くGIF動画があって、テンションマックスです。

![mario.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81919/fabd1c92-3711-9a69-dc7f-b2a0d6bb0ece.gif)
[TRAIN A MARIO-PLAYING RL AGENT](https://pytorch.org/tutorials/intermediate/mario_rl_tutorial.html)より引用

　こんなん楽しいに決まってるじゃん！ご丁寧に、Google Colaboratoryのノートブックへのリンクもあります。Google Colaboratory（Google Colab）が何か分からない人は、以下記事参照ください。

https://karaage.hatenadiary.jp/entry/2018/03/21/073000

　Google Colabなので、セットアップで少し詰まったものの、クリックしていくだけで~~理解していなくても~~サクサク進んでいきます。ただ、一向にマリオが動き出しません。嫌な予感を感じつつも、最後までGoogle Colabノートブックを動かすと…そこで特派員がみたものは！

```
/usr/local/lib/python3.6/dist-packages/gym_super_mario_bros/smb_env.py:148: RuntimeWarning: overflow encountered in ubyte_scalars
  return (self.ram[0x86] - self.ram[0x071c]) % 256
Episode 0 - Step 184 - Epsilon 0.9999540010522275 - Mean Reward 1046.0 - Mean Length 184.0 - Mean Loss 0.0 - Mean Q Value 0.0 - Time Delta 2.062 - Time 2020-12-22T14:09:33
<Figure size 432x288 with 0 Axes>
```

　数字の羅列！マリオは1画素も出てこずでした。初めてMNISTを実行して、何ができたのか訳が分からなかったときの甘酸っぱい思い出が蘇ってきました。

　もっと…チュートリアルの見せ方…あるでしょ！

## マリオのチュートリアルを楽しくしてみた
　せっかくの素晴らしい教材なので、もっと深層強化学習の素晴らしさが分かるように、少しだけGoogle Colabノートブックに手を加えてみました。

　ここで、Google ColabでOpen Gym（スーパーマリオを動かす環境）の画像を表示するテクニックを使います。こちらに関しては、以前ブログに書いた以下記事を参照ください。

https://karaage.hatenadiary.jp/entry/rl-tutorial

　作成したGoogle Colabノートブックは以下です。

[mario_rl_tutorial_custom.ipynb](https://colab.research.google.com/drive/18tTiRxUmZKNCd26pkFnO4Nw8eO5eAHSm?usp=sharing)

　ブログ記事のテクニックを使うことで、実際にマリオがプレイする様子をGoogle Colab上で可視化することができます。

　必要なセットアップをした後、まずはマリオをランダムに動かす様子を保存して可視化します。マリオをランダムに動かすコードは以下のようになります。

```python
EPISODE_NUMB = 1
MAX_TIME = 200

import copy

frames = []
for i in range(EPISODE_NUMB):
    observation = env.reset()  # reset for each new trial
    done = False
    total_reward = 0
    total_time = 0
    time = 0
    while not done and total_time < MAX_TIME: # run for MAX_TIME timesteps or until done, whichever is first
        frames.append(copy.deepcopy(env.render(mode = 'rgb_array')))
        action = env.action_space.sample()  # select a random action
        next_state, reward, done, info = env.step(action)
        total_reward += reward
        total_time += 1
    print('test episode:', i, 'reward:', total_reward, 'time:', total_time)
```

　実行すると`numpy.ndarray`形式の画像が`frames`というリストにどんどん追加されていきます。あとは、この`frames`を動画として可視化すれば、以下のようにマリオが生き生きと動きだします。

![mario_random.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81919/87200e35-eb6f-6010-9f3a-b08d7eb29cb5.gif)

　最初、何故かマリオが死ぬところだけが延々と表示されてハマったのですが`deepcopy`を使って解決しました。原因は、多分[リストのコピーでハマった話](https://qiita.com/kokorinosoba/items/e9ab9398af5b44d2ac9a)に書かれていることと同じだと思います。雰囲気で理解しましたが、マリオでなくCart Poleだと`deepcopy`しなくても大丈夫な理由とか、実際良く分かってないです（ソフト初心者です）。

　その後、深層強化学習でAIマリオを学習させるためのコードが続きます。ただ、難しくてよく分かりません（深層強化学習初心者です）。手法としては「Double Deep Q-Networks」らしいです。コードをみていくと`MarioNet`なるものが定義されています。

```python
class MarioNet(nn.Module):
    """mini cnn structure
  input -> (conv2d + relu) x 3 -> flatten -> (dense + relu) x 2 -> output
  """

    def __init__(self, input_dim, output_dim):
        super().__init__()
        c, h, w = input_dim

        if h != 84:
            raise ValueError(f"Expecting input height: 84, got: {h}")
        if w != 84:
            raise ValueError(f"Expecting input width: 84, got: {w}")

        self.online = nn.Sequential(
            nn.Conv2d(in_channels=c, out_channels=32, kernel_size=8, stride=4),
            nn.ReLU(),
            nn.Conv2d(in_channels=32, out_channels=64, kernel_size=4, stride=2),
            nn.ReLU(),
            nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, stride=1),
            nn.ReLU(),
            nn.Flatten(),
            nn.Linear(3136, 512),
            nn.ReLU(),
            nn.Linear(512, output_dim),
        )

        self.target = copy.deepcopy(self.online)

        # Q_target parameters are frozen.
        for p in self.target.parameters():
            p.requires_grad = False
```

　ここがキモだと思うのですが、パッとみた感じは、画像認識で使うようなCNN(Convolutional Neural Network)ですね。ネットワークも凄く小さいです。

　そして、このネットワーク（`MarioNet`）を学習させます。学習のところで、デフォルトのエピソード数は10が設定されていますが、注意書きとして「マリオをクリアしたければ40,000エピソード学習させろ！（意訳）」と鬼畜なことが書かれています。もちろんGoogle Colabじゃ四万エピソードを学習させるのは無理なので、デフォルトの10だけ学習させました。

　「たった10エピソードの学習でマリオさん大丈夫かなぁ」と心配しつつ、学習したAIマリオでプレイしてみます。ダメでも死ぬのはマリオなので安心（？）ですね。

　学習済みのAIマリオにゲームをプレイさせるためには、さきほどのランダムプレイのコードの`action`を以下に変えるだけです。

```python
action = mario.act(state)
```

　マリオの動きを可視化すると、AIマリオがプレイする様子が表示されます。

![mario_rl.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81919/0bcd55ba-e608-09cb-50f0-cfa0672ccf64.gif)

　10エピソード分の学習にもかかわらず、かなり賢い動きですね。

　実行するたびに、プレイは変化します。何回か試してみましたが、残念ながら1面をクリアできるAIマリオは生まれませんでした。やはりクリアのためには四万エピソード分の尊いマリオの犠牲が必要なのかもしれません。

## まとめ
　PyTorchのマリオの深層強化学習のチュートリアル、楽しく学習できるように少しだけ工夫してみました。

　小さいネットワークで、10エピソードでそれなりに学習できているのは凄いですね。深層強化学習興味あるので、このチュートリアルをベースに色々勉強してみたいなと思っています。

　強化学習初心者なので、詳しい方は色々アドバイスいただけると嬉しいです。
　
## 宣伝「からあげ先生のとにかく楽しいAI自作教室」
　この記事のように、Google Colabratoryを使って、初心者でも楽しみながらAIを学べるチュートリアル盛りだくさんの本を執筆しました。強化学習は扱っていませんが、その前段階の基礎知識となる画像認識を中心に、自然言語処理、画像生成、姿勢推定、エッジコンピューティングと幅広く学べる内容になっています。この記事でも少し出てきたCNNといったニューラルネットワークも自分で作りながら理解していく形になっていて、楽しく学べると思います。

　書籍の詳細は以下ブログ記事に書いています。紙の書籍は来年1月発売ですが、電子書籍は販売開始していてすぐ読めます。興味ある方は是非！

https://karaage.hatenadiary.jp/entry/2020/12/11/073000

https://karaage.hatenadiary.jp/entry/2020/12/23/073000