Gymで強化学習①準備編
Gymnasium(競技場)は強化学習エージェントを訓練するためのさまざまな環境を提供するPythonのオープンソースのライブラリです。
もともとはOpenAIが開発したGymですが、2022年の10月に非営利団体のFarama Foundationが保守開発を受け継ぐことになったとの発表がありました。
Farama FoundationはGymをフォーク(独自の変更や改善を行うためにGithub上のリポジトリを複製)してGymnasiumと名付けました。ここでは単にGymと呼びます。
今後、いくつかの記事にわたってGymの環境での強化学習について理論とコードの両方で解説していきます。今回は、環境の準備と説明を行います。
Pythonの環境を準備
まずは、Gymを使える環境を準備します。今回はBox2Dという2次元ゲームの環境を使います。以下の手順に従って必要なライブラリをインストールしてください。
# テスト用のフォルダを作る
mkdir rl_test
cd rl_test
#Pythonの環境を作る
python3 -m venv venv
source venv/bin/activate
# Pipを最新のものにしておく
pip install --upgrade pip
# ジムと2Dゲーム環境の依存関係をインストール
pip install gymnasium[box2d]
なお、テスト用のフォルダ名は上記と同じでなくとも構いません。
インストール中に、私の環境では以下のような注意が出ました。とりあえず無視しても問題はありません。これはbox2dのセットアップの問題ですが、そのうち改善されると思われます。
月着陸ゲームを実行
月面着陸(Lunar Lander)ゲームをランダムに行動するエージェントを使って実行します。
以下のPythonのコードをagent.pyとして保存します。他の名前でも構いません。
import gymnasium as gym
# 月着陸(Lunar Lander)ゲームの環境を作成
env = gym.make("LunarLander-v2", render_mode="human")
# ゲーム環境を初期化
observation, info = env.reset()
# ゲームのステップを1000回プレイ
for _ in range(1000):
# 環境からランダムな行動を取得
# これがエージェントの行動になるので、本来はAIが行動を決定するべきところ
action = env.action_space.sample()
# 行動を実行すると、環境の状態が更新される
observation, reward, terminated, truncated, info = env.step(action)
# ゲームが終了したら、環境を初期化して再開
if terminated or truncated:
observation, info = env.reset()
env.close()
これを以下のように実行します。
python agent.py
初回は環境が立ち上がるまで数秒かかるかもしれません。2回目からはスムーズに立ち上がります。宇宙船がランダムに噴射している以下のような映像が見えれば環境の準備は成功です。
このゲームの目的は宇宙船を上空中央の位置から二つの旗の間へとスムーズに着陸させることです。
次にコードを順番に解説します。
環境オブジェクトを作る
以下のコードではLunar Lander-v2(月面着陸バージョン2)の環境オブジェクト(env)を作成しています。
# 月着陸(Lunar Lander)ゲームの環境を作成
env = gym.make("LunarLander-v2", render_mode="human")
render_mode="human"とすると上記のような画像が見えます。render_modeは描画のモードを指定するのですが、"human"と人間が見てわかるように上記のように動画として表示するという意味です。
環境をリセットする
まずゲーム環境を初期化します。これによって現在の観測値(observation)と情報(info)を得ることができます。
# ゲーム環境を初期化
observation, info = env.reset()
観測値は八個の値があるベクトル形式になっています。
宇宙船のx軸の位置(-1.5 ~ 1.5)
宇宙船のy軸の位置(-1.5 ~ 1.5)
宇宙船のx軸の速度(-5 ~ 5)
宇宙船のy軸の速度(-5 ~ 5)
宇宙船の角度(-3.14 ~ 3.14)
宇宙船の角速度(-5 ~ 5)
左の足が地面についているか(0か1)
右の足が地面についているか(0か1)
具体的には以下のような数値が返されます。
[ 0.01344519 1.40932 0.6799792 -0.04843535 -0.01540422 -0.15244037
0. 0. ]
情報はディクショナリ形式ですが、このゲームでのinfoは空なので使いません。
エージェントの行動
エージェントは、以下の4つの行動(action)を取ることができます。
0: 何もしない
1: 右へ噴射
2: 下へ噴射
3: 左へ噴射
上記のコードではランダムな行動を選択しています。
# 環境からランダムな行動を取得
# これがエージェントの行動になるので、本来はAIが行動を決定するべきところ
action = env.action_space.sample()
Gymにあるどの環境オブジェクト(env)でも、action_spaceというプロパティがあります。action_spaceのsampleメソッドを呼び出すことでランダムな行動の値を得ることができます。
行動を実行するには、環境オブジェクト(env)のstepメソッドに選ばれた行動(action)を渡します。
# 行動を実行すると、環境の状態が更新される
observation, reward, terminated, truncated, info = env.step(action)
行動が環境に作用した結果として宇宙船の位置や速度が変わるので、更新された観測値(observation)が環境オブジェクトから返されます。
エージェントへの報酬
行動実行の返り値として報酬(reward)があります。報酬の数値は0より大きい方が良く、0より低い場合はペナルティ(penalty)です。0の場合はどちらでもありません。
報酬の値は以下の要因で増減が決まります。
着陸地点に近づくと増える。遠のくと減る。
スピードが遅いと増える。速いと減る。
宇宙船の角度が水平線と平行でないと減る。
片方の足が地面につくと10ポイント。両方で20ポイント。
左右エンジンが噴射していると0.03ポイント減る。
下のエンジンが噴射していると0.3ポイント減る。
エピソードが終了した時(次のセクションを参照)は、安全な着陸に対して+100ポイント、墜落に対して-100 ポイントの追加報酬を受け取ります。
最終的に報酬の総和が100以上ならば着陸成功となります。200以上ならばエージェントによる宇宙船のコントロールの問題は解決されたとみなされます。
エピソードの終了
このサンプルコードでは1000回のステップを繰り返すと終了になっています。
# ゲームのステップを1000回プレイ
for _ in range(1000):
...行動と観察を繰り返す
しかし、1000回のステップに到達する前に、宇宙船は何度も着陸や墜落を繰り返します。その度に、上空中央の位置に戻ってゲームが再開されます。
ゲームが開始され着陸あるいは墜落するまでの過程をエピソード(episode)と呼びます。
宇宙船が墜落した(船体が月面に触れた)
宇宙船が視界の外に出た(宇宙船のx軸の位置が1以上離れた)
宇宙船が静止した
エピソードが終了するとterminatedはTrueになります。
# 行動を実行すると、環境の状態が更新される
observation, reward, terminated, truncated, info = env.step(action)
なお、このゲームにおいては、truncatedは常にFalseです。他のゲームで最大ステップ数に上限がある場合は、上限に達したときにtruncatedがTrueになります。
なので、コードの処理としてはterminateあるいはtruncatedがTrueならば、エピソードが終了したとして環境の初期化(リセット、reset)を行います。
# ゲームが終了したら、環境を初期化して再開
if terminated or truncated:
observation, info = env.reset()
このゲームではtruncatedがTrueになることはありませんが上記のように書いておくと環境を変えても適応できるのでそうしています。
環境を閉じる
使わなくなった環境オブジェクトは以下のように閉じることができます。不要なメモリなどのリソースを開放できます。
env.close()
ただし、このプログラムでは一番最後に呼んでいるのであまり意味はありません。
まとめ
以上で月着陸ゲームにおけるGymの環境の解説が終わりました。
次回は強化学習の一般論の解説になります。
(続く)
この記事が気に入ったらサポートをしてみませんか?