こぼれネット

Stable-Baselines3 とは何ですか?

Stable-Baselines3 とは何ですか?

Stable-Baselines3(SB3)は、PyTorchで実装された強化学習アルゴリズムの信頼性重視の実装集。OpenAI Baselines系の後継にあたる Stable Baselines の次世代版。研究・実務で再現性よく比較・活用できるよう、統一APIと豊富なドキュメント・テストを備える。

Stable-Baselines3 を使ったサンプルを記載してください

以下に Stable-Baselines3 (SB3) を用いた最小限のサンプルコードを記載します。
例として、OpenAI Gym の CartPole 環境を使い、PPO (Proximal Policy Optimization) で学習します。

import gym
from stable_baselines3 import PPO

# 環境の作成
env = gym.make("CartPole-v1")

# モデルの作成(PPOを使用)
model = PPO("MlpPolicy", env, verbose=1)

# 学習 (1万ステップ)
model.learn(total_timesteps=10000)

# 学習したモデルを保存
model.save("ppo_cartpole")

# 保存したモデルを読み込み
model = PPO.load("ppo_cartpole", env=env)

# 学習済みモデルで推論(テスト実行)
obs = env.reset()
for _ in range(1000):
    action, _states = model.predict(obs, deterministic=True)
    obs, reward, done, info = env.step(action)
    env.render()
    if done:
        obs = env.reset()

env.close()

ポイント

このプログラムは何をするものですか。実行方法も教えて下さい

このプログラムの内容を整理すると、以下のようになります。


1. プログラムがやること

  • CartPole-v1 環境(倒立振子:カートの上に立てた棒を倒れないように制御する課題)を使います。
  • Stable-Baselines3 の PPOアルゴリズムで、この棒を倒さずにバランスを取り続ける方策(制御ルール)を学習します。
  • 学習が終わったら、学習済みモデルを保存し、保存したモデルを読み込んで実際に動かしてみます。
  • 実行中は env.render() によって、画面上にカートと棒の動きが表示されます。

2. 実行方法

(1) 必要なライブラリのインストール

ターミナル(Linux/Mac)または PowerShell(Windows)で以下を実行してください。

pip install stable-baselines3[extra] gym

[extra] を付けると、依存関係(atari, mujoco以外の基本環境)が一括で入ります。
(もし OpenAI Gym が gymnasium に置き換わっている環境なら、pip install gymnasium[classic-control] を追加してください)


(2) プログラムを保存

任意のファイル名(例: ppo_cartpole.py)で先ほどのコードを保存します。

nano ppo_cartpole.py   # Linux/Mac の場合
notepad ppo_cartpole.py # Windows の場合

(3) プログラムを実行

保存したディレクトリで次を実行します。

python ppo_cartpole.py

(4) 実行結果

  • 学習中は「timesteps」などがログとして表示されます。
  • 学習後に画面が立ち上がり、カートと棒(倒立振子)が動きます。
  • 学習が進むと、棒を長時間倒さずに維持できるようになります。

👉 確認ですが、環境は Windows + Python ですか? それとも WSL / Linux / macOS でしょうか。
それによって render() の挙動(ウィンドウ表示 or headless実行)が少し変わるので、そちらに合わせた実行手順を補足できます。

WSL / Linux です。 ebata@DESKTOP-1QS7OI7:~/trial_rl/ai-rescheduling/GDC/RL/src/railway_training$ python ppo_cartpole.py Traceback (most recent call last): File "ppo_cartpole.py", line 2, in <module> from stable_baselines3 import PPO ModuleNotFoundError: No module named 'stable_baselines3' ebata@DESKTOP-1QS7OI7:~/trial_rl/ai-rescheduling/GDC/RL/src/railway_training$ と言われています。

 

なるほど、ModuleNotFoundError: No module named 'stable_baselines3' が出ているので、WSL上に Stable-Baselines3 がインストールされていないのが原因です。

対処手順(WSL / Linux環境)

1. 必要パッケージの確認・インストール

まず Python と pip が正しく動作するか確認してください。

python3 --version
pip3 --version

もし python コマンドが python3 を指していない場合は、以下のように実行する必要があります。

python3 ppo_cartpole.py

2. Stable-Baselines3 のインストール

以下を実行してください。

pip3 install stable-baselines3[extra] gym

補足:

  • gym が新しい環境では gymnasium に置き換わっている場合があります。その場合は次も必要です。
pip3 install gymnasium[classic-control]

3. 実行

再度プログラムを実行してみてください。

python3 ppo_cartpole.py

4. 画面表示(render)の注意点

WSL 環境だと、env.render() がそのままでは画面に出ないことがあります。

  • WSLg対応の Windows 11 + WSL2 → そのまま GUI が出る(Ubuntu のウィンドウとして表示される)
  • 古い WSL → X11 サーバ(VcXsrv など)が必要

もし実行後に

cannot connect to display

のようなエラーが出た場合、GUI出力がWSLで無効な状態です。その場合は対処方法を案内します。


👉 まず試しに pip3 install stable-baselines3[extra] gym を実行してもらえますか?
その後 python3 ppo_cartpole.py を再実行して、どんなエラーや挙動になるか教えてください。

python3 ppo_cartpole.py Using cpu device Traceback (most recent call last): File "/home/ebata/.pyenv/versions/3.8.10/lib/python3.8/site-packages/stable_baselines3/common/vec_env/patch_gym.py", line 40, in _patch_env import shimmy ModuleNotFoundError: No module named 'shimmy' The above exception was the direct cause of the following exception: Traceback (most recent call last): File "ppo_cartpole.py", line 8, in <module> model = PPO("MlpPolicy", env, verbose=1) File "/home/ebata/.pyenv/versions/3.8.10/lib/python3.8/site-packages/stable_baselines3/ppo/ppo.py", line 109, in __init__ super().__init__( File "/home/ebata/.pyenv/versions/3.8.10/lib/python3.8/site-packages/stable_baselines3/common/on_policy_algorithm.py", line 86, in __init__ super().__init__( File "/home/ebata/.pyenv/versions/3.8.10/lib/python3.8/site-packages/stable_baselines3/common/base_class.py", line 169, in __init__ env = self._wrap_env(env, self.verbose, monitor_wrapper) File "/home/ebata/.pyenv/versions/3.8.10/lib/python3.8/site-packages/stable_baselines3/common/base_class.py", line 216, in _wrap_env env = _patch_env(env) File "/home/ebata/.pyenv/versions/3.8.10/lib/python3.8/site-packages/stable_baselines3/common/vec_env/patch_gym.py", line 42, in _patch_env raise ImportError( ImportError: Missing shimmy installation. You provided an OpenAI Gym environment. Stable-Baselines3 (SB3) has transitioned to using Gymnasium internally. In order to use OpenAI Gym environments with SB3, you need to install shimmy (pip install 'shimmy>=2.0').

はい、これは Stable-Baselines3 の最近の仕様変更によるものです。

SB3 は内部的に gymnasium を使うようになったので、古い gym を使うときには変換ライブラリ shimmy が必要になります。


解決方法

エラーメッセージにもある通り、次を実行してください。

pip3 install "shimmy>=2.0"

その上で、OpenAI Gym の CartPole を使う場合は動くはずです。


代替(推奨方法)

最近は gym よりも gymnasium が推奨されているので、次のように書き換えるのも良い方法です。

インストール

pip3 install gymnasium[classic-control]

コード修正例

import gymnasium as gym
from stable_baselines3 import PPO

# 環境を gymnasium で作成
env = gym.make("CartPole-v1")

model = PPO("MlpPolicy", env, verbose=1)
model.learn(total_timesteps=10000)

obs, _ = env.reset()
for _ in range(1000):
    action, _states = model.predict(obs, deterministic=True)
    obs, reward, terminated, truncated, info = env.step(action)
    done = terminated or truncated
    env.render()
    if done:
        obs, _ = env.reset()

👉 まずは pip3 install "shimmy>=2.0" を実行して、再度 python3 ppo_cartpole.py を試してみるのが一番早いです。
試してみますか?

途中に、 /home/ebata/.pyenv/versions/3.8.10/lib/python3.8/site-packages/stable_baselines3/common/vec_env/patch_gym.py:49: UserWarning: You provided an OpenAI Gym environment. We strongly recommend transitioning to Gymnasium environments. Stable-Baselines3 is automatically wrapping your environments in a compatibility layer, which could potentially cause issues. warnings.warn( Wrapping the env with a Monitor wrapper Wrapping the env in a DummyVecEnv. Traceback (most recent call last): File "/home/ebata/.pyenv/versions/3.8.10/lib/python3.8/site-packages/gym/envs/classic_control/rendering.py", line 15, in <module> import pyglet ModuleNotFoundError: No module named 'pyglet' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "ppo_cartpole.py", line 24, in <module> env.render() File "/home/ebata/.pyenv/versions/3.8.10/lib/python3.8/site-packages/gym/core.py", line 295, in render return self.env.render(mode, **kwargs) File "/home/ebata/.pyenv/versions/3.8.10/lib/python3.8/site-packages/gym/envs/classic_control/cartpole.py", line 179, in render from gym.envs.classic_control import rendering File "/home/ebata/.pyenv/versions/3.8.10/lib/python3.8/site-packages/gym/envs/classic_control/rendering.py", line 17, in <module> raise ImportError( ImportError: Cannot import pyglet. HINT: you can install pyglet directly via 'pip install pyglet'. But if you really just want to install all Gym dependencies and not have to think about it, 'pip install -e .[all]' or 'pip install gym[all]' will do it. が出てきました。

ありがとうございます。状況はこうです。

以下のどちらかで解決できます。


方式A(推奨): gymnasium へ移行(描画は pygame)

インストール

pip3 install "shimmy>=2.0" gymnasium[classic-control] pygame

サンプルコード(置き換え版)

# ppo_cartpole_gymnasium.py
import gymnasium as gym
from stable_baselines3 import PPO

# gymnasium は render_mode を明示
env = gym.make("CartPole-v1", render_mode="human")

model = PPO("MlpPolicy", env, verbose=1)
model.learn(total_timesteps=10_000)

# 学習済みモデルで試走
obs, info = env.reset(seed=0)
for _ in range(1000):
    action, _ = model.predict(obs, deterministic=True)
    obs, reward, terminated, truncated, info = env.step(action)
    env.render()  # human レンダラ(pygame)で表示
    if terminated or truncated:
        obs, info = env.reset()
env.close()

実行

python3 ppo_cartpole_gymnasium.py

※ Windows 11 + WSL2(WSLg)ならそのままウィンドウが出ます。古い WSL の場合は X サーバ(VcXsrv 等)が必要です。


方式B(現行の gym を継続利用): pyglet を入れる

インストール

pip3 install "shimmy>=2.0" "pyglet<2"

pyglet 2.x は旧 gym の classic_control と相性が悪いことが多いので 1.5.27 など 1.x 系を指定します。

いまのコードのまま再実行

python3 ppo_cartpole.py

補足(描画なしで動かしたい場合)

補足(動画として記録したい場合)

WSL で GUI を出さず、あとから動画だけ確認したい場合は gymnasium.wrappers.RecordVideo を使います(要 ffmpeg)。

sudo apt-get update && sudo apt-get install -y ffmpeg

コードでは学習終了後にラップして評価します(必要なら追記します)。


まずは「方式A(推奨)」のコマンドを実行してから、置き換えコードでお試しください。
エラーメッセージが出た場合は、その全文を貼っていただければ、そこから詰めます。

「サンプルコード(置き換え版)」の内容を、各行単位で教えて下さい

了解しました。置き換え版サンプルを 行ごと に説明します。

  1. # ppo_cartpole_gymnasium.py ― スクリプト名のコメント。
  2. import gymnasium as gym ― Gymnasium を gym という短名で読み込む。
  3. from stable_baselines3 import PPO ― SB3 から PPO アルゴリズムを読み込む。
  4. (空行)― 可読性のための区切り。
  5. # gymnasium は render_mode を明示 ― Gymnasium では描画方式を render_mode で指定する旨のメモ。
  6. env = gym.make("CartPole-v1", render_mode="human") ― CartPole 環境を生成し、GUI 描画(human)を有効化。
  7. (空行)― 可読性のための区切り。
  8. model = PPO("MlpPolicy", env, verbose=1) ― 多層パーセプトロン方策で PPO モデルを作成(ログ出力あり)。
  9. model.learn(total_timesteps=10_000) ― 1 万ステップ学習を実行。
  10. (空行)― 可読性のための区切り。
  11. # 学習済みモデルで試走 ― 学習後に推論で動作確認する旨のコメント。
  12. obs, info = env.reset(seed=0) ― 環境を初期化(乱数シード固定)、初期観測とメタ情報を取得。
  13. for _ in range(1000): ― 最長 1000 ステップまでエピソードを進めるループ。
  14. action, _ = model.predict(obs, deterministic=True) ― 観測から決定論的に行動を推論。
  15. obs, reward, terminated, truncated, info = env.step(action) ― 行動を環境へ適用し、次観測・報酬・終了フラグ(成功/時間切れ)等を取得。
  16. env.render() # human レンダラ(pygame)で表示 ― 現在の状態をウィンドウ描画(pygame ベース)。
  17. if terminated or truncated: ― 成功終了または打ち切り(最大ステップ到達など)を判定。
  18. obs, info = env.reset() ― エピソード終了時は環境をリセットして再開可能にする。
  19. env.close() ― 環境と描画リソースを明示的に解放。

補足:

CartPole-v1 とはどういうものですか?

CartPole-v1 は、カート上の棒(倒立振子)を左右どちらかに一定の力を加えるだけでできるだけ長く直立維持する課題。強化学習の標準ベンチマークとして用いられる。

用途はアルゴリズム比較・デバッグ・入門実験。Gymnasium では step()terminatedtruncated を分けて返すため、実装時は両方を考慮する。

CartPole-v1 以外には、どのような課題がありますか

主な強化学習ベンチマーク(SB3で扱いやすい代表例)を用途別に列挙する。

クラシック制御(軽量・入門)

  • MountainCar-v0 / MountainCarContinuous-v0:谷から山を登る(離散/連続)。
  • Acrobot-v1:二重振子を振り上げる(離散)。
  • Pendulum-v1:倒立振子の安定化(連続)。

Box2D(2D物理・中量級)

  • LunarLander-v2 / LunarLanderContinuous-v2:月面着陸(離散/連続)。
  • BipedalWalker-v3:二足歩行(連続)。
  • CarRacing-v2:自動走行(連続)。

Atari / ALE(画像入力・フレームスタックが前提)

  • ALE/Pong-v5、ALE/Breakout-v5、ALE/SpaceInvaders-v5 など(Gymnasium系ID)。
  • 旧来の PongNoFrameskip-v4 等も存在するが、新規は ALE/…-v5 を推奨。

MuJoCo(連続制御・ロコモーション)

  • HalfCheetah-v4、Hopper-v4、Walker2d-v4、Ant-v4、Humanoid-v4(連続)。

ロボティクス(Gymnasium-Robotics)

  • FetchReach-v3、FetchPush-v3、FetchSlide-v3、HandManipulate 系(連続)。

そのほかの代表的スイート

  • Minigrid:MiniGrid-Empty-8x8-v0 などのグリッド迷路(疎報酬・探索検証向け)。
  • Procgen:procgen-coinrun、procgen-caveflyer など(汎化性能評価)。
  • PyBullet:AntBulletEnv-v0、HumanoidBulletEnv-v0 等(MuJoCo代替の無料物理)。

典型的なインストール(WSL想定)

  • クラシック制御
    pip3 install gymnasium[classic-control]
    
  • Box2D
    pip3 install gymnasium[box2d]
    
  • Atari(ROM 使用許諾込み)
    pip3 install gymnasium[atari,accept-rom-license]
    
  • MuJoCo
    pip3 install mujoco gymnasium[mujoco]
    
  • Robotics
    pip3 install gymnasium-robotics
    
  • Minigrid / Procgen / PyBullet
    pip3 install minigrid procgen pybullet pybullet_envs
    

※ 画像系(Atari)や MuJoCo は計算負荷が高く、学習可視化には WSLg か X サーバが必要。描画不要なら render() を外して学習のみ実行で可。


環境ID差し替え例(PPOで共通)

env = gym.make("LunarLander-v2")         # Box2D
# env = gym.make("ALE/Pong-v5", frameskip=1, repeat_action_probability=0.0)  # Atari
# env = gym.make("HalfCheetah-v4")        # MuJoCo
# env = gym.make("MiniGrid-Empty-8x8-v0") # Minigrid(観測が辞書→Wrapperで画像化が必要)

必要に応じて、対象タスクとアルゴリズム(DQN=離散、PPO/SAC/TD3=連続)を組み合わせればよい。

これらの環境モデルはGivenで使用することが前提なものですか

 

短答:いいえ。列挙した環境は Gym/Gymnasium が提供する “汎用ベンチマーク” で、SB3はそれらを“そのまま使える”ようにしているだけです。自作の環境を定義して学習させることも前提機能として完全にサポートされています。


自作環境の最小サンプル(Gymnasium形式)

# my_env.py
import numpy as np
import gymnasium as gym
from gymnasium import spaces

class MyToyEnv(gym.Env):
    metadata = {"render_modes": ["human"], "render_fps": 30}

    def __init__(self, render_mode=None, max_steps=200):
        self.render_mode = render_mode
        self.max_steps = max_steps
        # 観測: 連続3次元ベクトル [-1,1]
        self.observation_space = spaces.Box(low=-1.0, high=1.0, shape=(3,), dtype=np.float32)
        # 行動: 2値(例: 0/1)
        self.action_space = spaces.Discrete(2)
        self.state = None
        self.steps = 0

    def reset(self, seed=None, options=None):
        super().reset(seed=seed)
        self.state = self.np_random.uniform(low=-0.1, high=0.1, size=(3,)).astype(np.float32)
        self.steps = 0
        info = {}
        return self.state, info

    def step(self, action):
        # ダミー力学:actionに応じて状態を微調整
        delta = (1 if action == 1 else -1) * 0.01
        self.state = np.clip(self.state + delta, -1.0, 1.0)

        # 目標: 原点に近づくほど良い(報酬はマイナス距離)
        reward = -float(np.linalg.norm(self.state, ord=2))

        self.steps += 1
        terminated = bool(np.linalg.norm(self.state) < 0.05)   # 目標到達
        truncated  = bool(self.steps >= self.max_steps)        # ステップ上限
        info = {}
        return self.state, reward, terminated, truncated, info

    def render(self):
        if self.render_mode == "human":
            # 必要なら可視化(printでも可)
            print(f"step={self.steps}, state={self.state}")

SB3で学習

# train_my_env.py
import gymnasium as gym
from stable_baselines3 import PPO
from my_env import MyToyEnv

env = MyToyEnv(render_mode=None)  # ヘッドレス学習
model = PPO("MlpPolicy", env, verbose=1)
model.learn(total_timesteps=10_000)

# 学習後の試走(必要なら描画ON)
test_env = MyToyEnv(render_mode="human")
obs, info = test_env.reset(seed=0)
for _ in range(300):
    action, _ = model.predict(obs, deterministic=True)
    obs, reward, terminated, truncated, info = test_env.step(action)
    if terminated or truncated:
        obs, info = test_env.reset()
test_env.close()

自作環境の要件(SB3互換チェックリスト)

  • APIreset()(obs, info)step()(obs, reward, terminated, truncated, info) を返す(Gymnasium仕様)。
  • spacesobservation_spaceaction_spacegymnasium.spaces で定義(Box/Discrete など)。
  • 決定性reset(seed=...) を受け取り、super().reset(seed=seed) を呼ぶ。
  • 終了判定:学習成功等は terminated、時間切れ等は truncated
  • ベクトル化:高速化したい場合は SubprocVecEnv/DummyVecEnv で並列化可能(SB3がラップ)。

既存ベンチマークの位置づけ

  • 研究・検証・比較用の 標準課題(CartPole, LunarLander, MuJoCo系など)。
  • 「それを使わねばならない」制約はない。ドメイン固有のシミュレータをGymnasium APIに合わせれば、そのままSB3で学習可能。

必要であれば、貴プロジェクトの観測・行動の型(連続/離散、次元)に合わせた設計案に落とし込みます。

「自作環境の最小サンプル(Gymnasium形式)」で記載されている内容を教えて下さい

概要

「自作環境の最小サンプル(Gymnasium 形式)」は、自作の強化学習環境 MyToyEnv を定義し、Stable-Baselines3(SB3)の PPO で学習→試走する一連の最小構成です。
環境は 3 次元の連続観測・2 値行動を持つ「おもちゃ問題」で、原点に近づくほど良いという単純な報酬設計になっています。


ファイル1:my_env.py の内容

  • インポート
    numpygymnasium as gymgymnasium.spaces(観測・行動空間の型)。
  • class MyToyEnv(gym.Env)
    • metadatarender_modesrender_fps の宣言(Gymnasium の慣例)。
    • __init__(render_mode=None, max_steps=200)
      • render_mode を保存。
      • 観測空間:spaces.Box(low=-1, high=1, shape=(3,), dtype=float32)(連続3次元)。
      • 行動空間:spaces.Discrete(2)(0/1 の2値)。
      • 内部状態 self.state、ステップ数 self.steps を初期化。
    • reset(self, seed=None, options=None)
      • super().reset(seed=seed) で乱数系列の決定性を確保。
      • 初期状態を小さい乱数で生成(例:±0.1 の一様乱数)。
      • steps=0 に戻し、(obs, info) を返す(Gymnasium 仕様)。
    • step(self, action)
      • action==1 なら +0.01、action==0 なら −0.01 を全成分に加算(簡易ダイナミクス)。
      • 状態を [-1,1] にクリップ。
      • 報酬:原点からの距離のマイナス(-‖state‖₂)=原点に近いほど高報酬
      • steps += 1
      • 終了判定
        • terminated‖state‖ < 0.05(目標達成)。
        • truncatedsteps >= max_steps(上限到達)。
      • (obs, reward, terminated, truncated, info) を返す(Gymnasium 仕様)。
    • render(self)
      • render_mode=="human" のとき、print で状態を表示(コンソール出力。GUI不要)。

ポイント:Gymnasium の新APIreset→(obs, info), step→(obs, reward, terminated, truncated, info))に準拠。observation_space/action_space を正しく定義しているので SB3 でそのまま学習可能


ファイル2:train_my_env.py の内容

  • インポートgymnasium as gymstable_baselines3.PPO、自作環境 MyToyEnv
  • 学習
    env = MyToyEnv(render_mode=None)  # 学習はヘッドレス
    model = PPO("MlpPolicy", env, verbose=1)
    model.learn(total_timesteps=10_000)
    
    • MLPポリシで PPO を構築し、1万ステップ学習。
  • 試走(推論)
    test_env = MyToyEnv(render_mode="human")  # コンソール表示
    obs, info = test_env.reset(seed=0)
    for _ in range(300):
        action, _ = model.predict(obs, deterministic=True)
        obs, reward, terminated, truncated, info = test_env.step(action)
        if terminated or truncated:
            obs, info = test_env.reset()
    test_env.close()
    
    • 学習済みモデルで 300 ステップ走行。
    • エピソード終了時はリセット。render()print なので WSL でも追加の GUI 設定不要

実行手順(WSL / Linux)

  1. 依存のインストール
pip3 install stable-baselines3 gymnasium

(このサンプルは GUI を使わず print だけなので pygame/pyglet 不要)

  1. 上記 2 ファイルを保存(カレントに my_env.pytrain_my_env.py)。
  2. 学習・試走
python3 train_my_env.py

設計意図と拡張ポイント

  • 観測:3次元連続ベクトル(実タスクでは任意次元に変更)。
  • 行動:2 値(実タスクに合わせて Discrete(n)Box へ変更)。
  • 報酬設計:原点距離の負を採用(目的に応じて最小限の差し替えで運用可能)。
  • 終了条件:目標達成(terminated)と打切り(truncated)を分離。
  • 互換性:Gymnasium 仕様に従うことで SB3 の全アルゴリズム(PPO/A2C/SAC/TD3/DQN 等)が利用可能。

必要であれば、貴プロジェクトの観測・行動・報酬に即した雛形へ具体的に落とし込みます。

「環境は 3 次元の連続観測・2 値行動を持つ「おもちゃ問題」で、原点に近づくほど良いという単純な報酬設計になっています。」の意味が分かりかねます。内容を1フレーズでお願いします

観測は3次元連続ベクトル、行動は0/1の二択で、状態が原点(0,0,0)に近いほど報酬が高くなる最小構成のテスト用環境です。

初期値は、乱数の3次元座標として、0/1の行動で座標はどのように動くのですか?

以下の極簡潔モデルです。

  • 初期値:各成分が一様乱数
    U(−0.1,0.1)U(-0.1,0.1)

     

    の3次元ベクトル。

  • 遷移:行動
    a∈{0,1}a\in\{0,1\}

     

    に対して

    st+1=clip⁡(st+(2a−1)×0.01⋅[1,1,1], −1, 1)s_{t+1}=\operatorname{clip}\bigl(s_t + (2a-1)\times 0.01 \cdot [1,1,1],\,-1,\,1\bigr)

    すなわち a=1 なら各成分に +0.01、a=0 なら各成分に −0.01 を一律加算(範囲は

    [−1,1][-1,1]

    にクリップ)。

例:

st=[0.03,−0.07,0.01]s_t=[0.03,-0.07,0.01]

 


  • a=1a=1

     

    [0.04,−0.06,0.02][0.04,-0.06,0.02]

     


  • a=0a=0

     

    [0.02,−0.08,0.00][0.02,-0.08,0.00]

     

プログラムの概要は理解しました。学習のプロセスや試走のプロセスを見たいのですが、どのようにコードを変更すれば良いですか

了解。**学習の進み具合と試走(推論)の中身を“見える化”**するために、以下の3点を足す。

  • 学習ログ:TensorBoard(loss, value loss, policy entropy など)
  • エピソード統計:Monitor で monitor_train.csv を出力(ep_reward/ep_len)
  • 試走ログ:各ステップの t, action, state, reward, ‖state‖ を標準出力に表示

追加インストール(WSL / Linux)

pip3 install stable-baselines3 gymnasium tensorboard

(前に入れていれば再インストール不要)


完成コード(train_my_env_logging.py

※ 前回の my_env.py はそのまま使う。学習はヘッドレス、試走はテキストで逐次表示。

# train_my_env_logging.py
import os
import numpy as np
from stable_baselines3 import PPO
from stable_baselines3.common.monitor import Monitor
from stable_baselines3.common.callbacks import EvalCallback, CheckpointCallback
from my_env import MyToyEnv  # 先に同ディレクトリに my_env.py を置く

# 出力先
os.makedirs("./logs", exist_ok=True)
os.makedirs("./models/best", exist_ok=True)
os.makedirs("./models/ckpt", exist_ok=True)
os.makedirs("./tb_logs", exist_ok=True)

# === 学習用環境(エピソード統計をCSVに出力) ===
train_env = Monitor(MyToyEnv(render_mode=None), filename="./logs/monitor_train.csv")

# === 評価用環境(学習中に定期評価) ===
eval_env = MyToyEnv(render_mode=None)

# === モデル(TensorBoard 有効化) ===
model = PPO(
    "MlpPolicy",
    train_env,
    verbose=1,
    tensorboard_log="./tb_logs",  # TensorBoard 出力
)

# === コールバック(定期評価とチェックポイント保存) ===
eval_cb = EvalCallback(
    eval_env,
    best_model_save_path="./models/best",
    log_path="./logs/eval",
    eval_freq=5_000,          # 5k ステップごとに評価
    deterministic=True,
    render=False,
)
ckpt_cb = CheckpointCallback(
    save_freq=20_000,         # 20k ステップごとにモデル保存
    save_path="./models/ckpt",
    name_prefix="ppo_mitoy",
)

# === 学習(進捗バー表示) ===
total_steps = 100_000
model.learn(
    total_timesteps=total_steps,
    callback=[eval_cb, ckpt_cb],
    tb_log_name="PPO_MyToy",
    progress_bar=True,
)

# === 試走(逐次ログ出力) ===
test_env = MyToyEnv(render_mode=None)  # GUI なし
obs, info = test_env.reset(seed=42)
ep = 0
ep_return = 0.0

print("\n[Rollout] deterministic=True")
for t in range(2_000):  # 適宜変更
    action, _ = model.predict(obs, deterministic=True)
    prev = obs.copy()
    obs, reward, terminated, truncated, info = test_env.step(action)
    ep_return += reward
    # 1行ログ:時刻, 行動, 状態, 報酬, 原点距離
    print(
        f"t={t:05d}  a={int(action)}  "
        f"state=[{obs[0]:+.4f},{obs[1]:+.4f},{obs[2]:+.4f}]  "
        f"reward={reward:+.4f}  |state|={np.linalg.norm(obs):.4f}"
    )
    if terminated or truncated:
        print(f"[EP END] ep={ep}  return={ep_return:.4f}  steps={t+1}")
        obs, info = test_env.reset()
        ep += 1
        ep_return = 0.0

test_env.close()

print("\nDone. See: ./logs/monitor_train.csv, ./tb_logs, ./models/")

実行

python3 train_my_env_logging.py

見方

  1. 逐次ログ(標準出力)
    t, a, state, reward, |state| が 1 行ずつ出る。
    エピソード終了時は [EP END] ep=... return=... steps=... を表示。
  2. エピソード統計(CSV)
    ./logs/monitor_train.csv
    先頭にヘッダ行とコメントが付き、各エピソードの l(長さ), r(総報酬), t(時刻)等が記録される。
    head -n 20 ./logs/monitor_train.csv
    
  3. TensorBoard(学習曲線)
    tensorboard --logdir ./tb_logs --bind_all
    

    ブラウザで http://localhost:6006 を開く(WSL なら Windows 側ブラウザで可)。
    charts で policy_loss / value_loss / entropy / explained_variance / fps などを確認。

  4. モデル
    • ベストモデル:./models/best/best_model.zip(評価スコア最大時)
    • 定期保存:./models/ckpt/ppo_mitoy_*.zip

必要なら「試走ログをCSVにも保存」「学習と同時に評価の統計を別CSVで書き出し」「CartPoleで動画記録」なども追記可能。

Using cpu device Wrapping the env in a DummyVecEnv. Logging to ./tb_logs/PPO_MyToy_1 --------------------------------- | rollout/ | | | ep_len_mean | 146 | | ep_rew_mean | -25.4 | | time/ | | | fps | 1070 | | iterations | 1 | | time_elapsed | 1 | | total_timesteps | 2048 | --------------------------------- ----------------------------------------- | rollout/ | | | ep_len_mean | 148 | | ep_rew_mean | -31.4 | | time/ | | | fps | 759 | | iterations | 2 | | time_elapsed | 5 | | total_timesteps | 4096 | | train/ | | | approx_kl | 0.012467397 | | clip_fraction | 0.0413 | | clip_range | 0.2 | | entropy_loss | -0.686 | | explained_variance | -0.0143 | | learning_rate | 0.0003 | | loss | 0.539 | | n_updates | 10 | | policy_gradient_loss | -0.00855 | | value_loss | 3.17 | ----------------------------------------- これらのパラメータを日本語で説明して下さい

以下は SB3/PPO の学習ログ各項目の意味と、表示値の読み方。

rollout(収集データの統計)

  • ep_len_mean:直近ロールアウト内の平均エピソード長(ステップ数)。長いほど「終端条件に達しにくい」=安定化傾向。
  • ep_rew_mean:直近ロールアウト内の平均エピソード総報酬。MyToyEnv では「原点に近いほど高報酬=値が0に近づくほど良い」。負の絶対値が小さくなる方向が改善。

time(速度・進捗)

  • fps:学習処理を含む1秒あたりの環境ステップ数。高いほど高速。
  • iterations:PPO の1ロールアウト+学習サイクル回数(おおむね「1回= n_stepsぶん収集→学習」)。
  • time_elapsed:学習開始からの経過秒。
  • total_timesteps:これまでに環境から収集した累積ステップ数。

train(方策更新の統計)

  • approx_kl:旧方策と新方策の近似KL乖離。大きすぎると学習が荒れる、極端に小さいと更新が弱い。PPOでは概ね 0.01 前後が無難な目安。
  • clip_fraction:方策比がクリップ範囲を超えて「クリップ適用」されたサンプル比率。多いほど更新が強すぎる兆候。
  • clip_range:PPO のクリップ幅 ε(既定 0.2)。方策更新の逸脱をこの幅で抑制。
  • entropy_loss:エントロピー項の損失(符号の都合で通常は負値表示)。値が大きく負→方策がランダム、高速に0へ接近→方策が決定的に。
  • explained_variance:価値関数がリターン(目標値)をどれだけ説明できているか(1に近いほど良い、0~負は未学習/不適合)。
  • learning_rate:現在の学習率。
  • loss:総合損失(方策損失+価値損失+エントロピー正則化の合算)。絶対値や単体比較よりも推移を見る。
  • n_updates:これまで実行した更新回数の累計(概ね iterations × n_epochs に相当)。
  • policy_gradient_loss:方策勾配損失(通常は負方向が改善、推移で強弱を把握)。
  • value_loss:価値関数の二乗誤差。小さく安定していけば価値推定が当たっている。

今回ログ値の解釈メモ

  • 学習序盤のため explained_variance < 0value_loss が大きめ は自然。進むにつれ EV は 0→正、value_loss は低下が望ましい。
  • approx_kl ≈ 0.012clip_fraction ≈ 0.04 は、更新が過剰ではない範囲。
  • ep_rew_mean が負なのは MyToyEnv の報酬設計(原点距離の負)による。改善時は「より 0 に近づく」方向を見る。
  • ep_len_mean ≈ 146→148 は、最大 200(既定)に対し「やや延びた」状態。方策の安定化でさらに伸びる余地あり。
モバイルバージョンを終了