[python3 / gymnasium] Colaboratory上で強化学習ライブラリgymnasiumの出力を描画 / 録画

# ※注意 *(2024/10/26 更新)*

最近触ってみたら、古い記述のままでは動かなくなってました。
`FileNotFoundError: [Errno 2] No such file or directory: 'Xvfb'` などのエラーが発生する。

そのため、大幅に加筆 / 修正を行いました。


# 1. 概要

最初はこの記事の方法に従っていたのだけど、

https://qiita.com/ymd_h/items/c393797deb72e1779269

もう色々を古くなっていたので、調べた方法を記事にした。


# 2. 環境

gymnasium のバージョンによって、動作させるためのコードの書き方が異なるようです。
今回は、2つのバージョンにおけるそれぞれの書き方を別々に記載し~~ます。~~ようと思ったのですが、沼にハマってしまったので、最低限自分が必要な方 (gymnasium=1.0.0) だけを残しておきます。

gym をご利用の方は、申し訳ないですが、参考程度にこの記事を参照してください。

## 1つ目 (本記事では動作未確認)

||versionなど|
|:--|:--|
|実行環境|colaboratory|
|Python|3.10.12|
|gym|0.??.??|

## 2つ目

||versionなど|
|:--|:--|
|実行環境|colaboratory|
|Python|3.10.12|
|gymnasium|1.0.0|

違うのは、 `gymnasium` のバージョン。


# 3. ~~ソースコード (gym==0.??.?? を使用している場合)~~

以前はこれで動いていたのですが、現在はこの部分「3.」は工事中です。


## 3-1. colaboratory 上に実行結果を描画する場合

### 3-1-1. モジュール類のインストール

```bash: colaboratory
# NOTE: gymnasium[box2d] を install するために必要
#   swig がないと、"ERROR: Could not build wheels for box2d-py, which is required to install pyproject.toml-based projects" が発生する
# https://stackoverflow.com/questions/76222239/pip-install-gymnasiumbox2d-not-working-on-google-colab
!pip install -q swig

!pip install -q gymnasium[box2d]
```

### 3-1-2. 実行コード

この「3-1-2」については、ほぼ以下の記事を参考にした。

https://qiita.com/engbJapans/items/1e2f0d4c60012ee92a7e

この部分が役に立ったという方は、上記記事にも「いいね」して下さると嬉しいです(*´ｖ｀)

```python: colaboratory
import time
from IPython import display
from PIL import Image

import gym


env = gym.make("LunarLander-v2")
env.reset(seed=42)

for _ in range(300):
    observation, reward, done, info = env.step(
        env.action_space.sample()
    )

    # 描画処理
    display.clear_output(wait=True)
    img: Image = Image.fromarray(env.render(mode='rgb_array'))
    display.display(img)

    time.sleep(0.05)
    if done:
        env.reset()

env.close()
```

これで、宇宙船の着陸トライアルの様子を見ることができる\\( ˙꒳˙ \三/ ˙꒳˙)/わーい


## 3-2. colaboratory 上には描画せずに録画ファイルを作る場合

### 3-2-1. モジュール類のインストール

```bash: colaboratory
# NOTE: gymnasium[box2d] を install するために必要
#   swig がないと、"ERROR: Could not build wheels for box2d-py, which is required to install pyproject.toml-based projects" が発生する
# https://stackoverflow.com/questions/76222239/pip-install-gymnasiumbox2d-not-working-on-google-colab
!pip install -q swig==4.2.1

!pip install -q gymnasium[box2d]==1.0.0
```

```python:colaboratory
# colabortory 上で gymnasium のゲーム実行結果を録画するためのモジュールインストール
!apt-get -qq -y install xvfb freeglut3-dev ffmpeg
!pip install -q pyvirtualdisplay
```


### 3-2-2. 実行コード

```python:colaboratory
# Colab上で仮想ディスプレイを使用するための設定
from pyvirtualdisplay import Display
display = Display(visible=0, size=(1400, 900))
display.start()

import gym
from gym.wrappers import RecordVideo
from IPython import display as ipythondisplay
from IPython.display import HTML

# LunarLander環境の作成
env = gym.make("LunarLander-v2")

# 録画用の RecordVideo ラッパーの作成
video_path = "/content/lunar_lander_video"  # 保存先のpath
env = RecordVideo(env, video_path)

# 5回分のエピソードの実行
num_episodes = 5
for episode in range(num_episodes):
    observation = env.reset()
    done = False
    total_reward = 0

    while not done:
        action = env.action_space.sample()  # ランダムな行動の選択
        observation, reward, done, _ = env.step(action)
        total_reward += reward

    print(f"Episode {episode + 1}, Total Reward: {total_reward}")


# 動画の保存先の表示
video_path
```

これを実行すると、以下に動画ファイルが保存される。

![スクリーンショット 2024-01-27 211101.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327407/5b68fab1-651b-adaa-7625-0c380005f8a0.png)

![240127_lunarrander_sample.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327407/40371d44-72e9-16c2-6f5b-95da931d6ee8.gif)

中身はこんな感じ。いたそう...(｡ŏ﹏ŏ)


# 4. ソースコード (gymnasium==1.0.0 の場合) *(2024/10/26 更新分)*

## 4-1. colaboratory 画面上に実行結果を描画


```bash:colaboratory
# この apt-get install はいらないかも
!apt-get -qq -y install xvfb freeglut3-dev ffmpeg

!pip install swig==4.2.1
!pip install gymnasium[box2d] pyvirtualdisplay
```


```python:colaboratory
import time
from IPython import display
from PIL import Image

import gymnasium


env = gymnasium.make("LunarLander-v3", render_mode="rgb_array")
env.reset(seed=42)

for _ in range(300):
    observation, reward, terminated, truncated, info = env.step(
        env.action_space.sample()
    )

    # 描画処理
    display.clear_output(wait=True)
    img: Image = Image.fromarray(env.render())
    display.display(img)

    time.sleep(0.03)
    if terminated or truncated:
        env.reset()

env.close()
```

## 4-2. 実行結果を mp4 に録画する場合

```bash:colaboratory
!apt-get -qq -y install xvfb freeglut3-dev ffmpeg

!pip install swig==4.2.1
!pip install gymnasium[box2d] pyvirtualdisplay
```

```python:colabortaory
# Colab上で仮想ディスプレイを使用するための設定
from pyvirtualdisplay import Display
display = Display(visible=0, size=(1400, 900))
display.start()

import gymnasium
from gymnasium.wrappers import RecordVideo
from IPython import display as ipythondisplay
from IPython.display import HTML



# LunarLander環境の作成
env = gymnasium.make("LunarLander-v3", continuous=True, render_mode="rgb_array")

# 録画用の RecordVideo ラッパーの作成
video_path = "/content/lunar_lander_video"  # 保存先のpath
env = RecordVideo(env, video_path)

# 5回分のエピソードの実行
num_episodes = 3
for episode in range(num_episodes):
    observation, info = env.reset()
    terminated, truncated = False, False
    total_reward = 0

    while not (terminated or truncated):
        action = env.action_space.sample()  # ランダムな行動の選択
        observation, reward, terminated, truncated, _ = env.step(action)
        total_reward += reward

    print(f"Episode {episode + 1}, Total Reward: {total_reward}")


# 動画の保存先の表示
video_path + "フォルダ内に録画結果を保存しました"
```


# 5. 参考にした記事

## 5-1. リアルタイム描画について

https://qiita.com/engbJapans/items/1e2f0d4c60012ee92a7e

上記の記事の方法のままでは動かなかったが、以下の stackoverflow の回答を参照し、

https://stackoverflow.com/questions/76222239/pip-install-gymnasiumbox2d-not-working-on-google-colab

以下のように修正したところ、動いた。

```python:colaboratory
# package install
!pip install -q swig

# !pip install pygame  # pygame はもうだめぽ
!pip install -q gymnasium[box2d]
```

上記の install を済ませておけば、 python のコードの方はそのままでも動いた。
本記事の「3-1-2」は、ほぼこの記事を参考にして書かれている。ありがたし...。


## 5-2. gymの出力を動画にする

https://zenn.dev/ymd_h/articles/36eff0de1ee5ed

この記事の方法のままだと、`gym.wrappers.RecordVideo`を使ったとしても、`AttributeError: 'CartPoleEnv' object has no attribute 'videos'`というエラーが発生していた。

同エラーへの対応を、本記事で行った。

## 5-3. RecordVideo についての解説 (gymnasium 公式)

https://gymnasium.farama.org/api/wrappers/misc_wrappers/#gymnasium.wrappers.RecordVideo


# あとがき

[OpenAI Gym サポート終わった](https://zenn.dev/ymd_h/articles/dd3bce4199e2ba)りして色々変動あったから、多分色々動かなくなってるんだと思う。

今後は安定するといいな...|дﾟ)