見出し画像

Stable Baselines チュートリアル(1) / Getting Started

以下のColabが面白かったので、ざっくり訳してみました。

Stable Baselines Tutorial - Getting Started

1. はじめに

このノートブックでは、「Stable Baselines」を使用するための基本事項、つまりRLモデルの作成、訓練、評価の方法を学習します。すべてのアルゴリズムが同じインターフェースを共有しているため、あるアルゴリズムから別のアルゴリズムに切り替えることがいかに簡単かがわかります。

2. pipを使用して依存関係とStable Baselinesをインストール

Colabでのインストールコマンドは次の通りです。

!apt-get install ffmpeg freeglut3-dev xvfb  # For visualization
!pip install stable-baselines[mpi]==2.8.0

完全な依存関係のリストはREADMEにあります。

3. インポート

「Stable Baselines」は、Gymインタフェースに従う環境で動作します。
利用可能な環境のリストは、こちらで確認できます。

また、Gymには適切なドキュメントがないため、ソースコードを確認して各envの状態空間および行動空間の詳細を確認することをお勧めします。

すべてのアルゴリズムがすべての行動空間で機能するわけではありません。
この要約表で詳細を確認できます。

import gym
import numpy as np

最初にインポートする必要があるのはRLモデルです。ドキュメントを確認して、どの問題で何を使用できるかを確認してください。

from stable_baselines import PPO2

次にインポートする必要があるのは、ネットワークの作成に使用されるポリシークラスです(ポリシー/値関数用)。コンストラクタで文字列を直接使用できるため、この手順はオプションです。

PPO2('MlpPolicy', env) : 文字列で指定
PPO2(MlpPolicy, env) : クラスで指定

「SAC」などの一部のアルゴリズムには独自のMlpPolicy(stable_baselines.common.policies.MlPolicyとは異なる)があることに注意してください。そのため、ポリシーに文字列を使用することを推奨します。

from stable_baselines.common.policies import MlpPolicy

最後に、「PPO2」に必要なVecEnvをインポートします。これは、後でマルチプロセッシングを行うときに役立ちます。

from stable_baselines.common.vec_env import DummyVecEnv

4. Gym環境を作成し、エージェントをインスタンス化

この例では、古典的な制御問題であるCartPole環境を使用します。

画像2

ポールは、無作動のジョイントによってカートに取り付けられ、摩擦のない軌道に沿って移動します。システムは、カートに+1または-1の力を加えることで制御されます。振り子は直立し、目標は ポールが直立したままのタイムステップごとに+1の報酬が提供されます。

CartPole環境: https://gym.openai.com/envs/CartPole-v1/

注:ベクトル化環境では、簡単にマルチプロセストレーニングを行うことができます。この例では、DummyVecEnvという1つのプロセスのみを使用しています。

CartPoleの入力は画像ではなく特徴ベクトルであるため、MlpPolicyを選択しました。使用する行動種別(離散/連続)は、環境行動空間から自動的に推測されます。

ここでは、「Actor-Critic方式」である、「PPO」アルゴリズム(「PPO2」はGPU用に最適化されたバージョンです)を使用しています。価値関数を使用して、ポリシーの勾配降下を(分散を減らすことにより)改善します。「A2C」と「TRPO」のアイデアを組み合わせています。「PPO」はオンポリシーなアルゴリズムです。つまり、ネットワークの更新に使用される軌道は、最新のポリシーを使用して収集する必要があります。通常、「DQN」「SAC」「TD3」などのオフポリシーのアルゴリズムよりもサンプルの効率は低くなりますが、実時間に関してははるかに高速です。

env = gym.make('CartPole-v1')
# ベクトル化環境により、簡単にマルチプロセストレーニングが可能
# 次の例でその有用性を示します
env = DummyVecEnv([lambda: env])  # The algorithms require a vectorized environment to run

model = PPO2(MlpPolicy, env, verbose=0)

エージェントを評価するヘルパー関数を作成します。

def evaluate(model, num_episodes=100):
    """
    RLエージェントを評価
    :param model: (BaseRLModel object) RLエージェント
    :param num_episodes: (int) エピソード数
    :return: (float) 平均報酬
    """
    # この関数は単一の環境でのみ機能します
    env = model.get_env()
    all_episode_rewards = []
    for i in range(num_episodes):
        episode_rewards = []
        done = False
        obs = env.reset()
        while not done:
            # _statesは、LSTMポリシーを使用する場合にのみ有用です
            action, _states = model.predict(obs)

            # ベクトル化環境を使用しているため、行動、報酬、エピソード完了は配列です
            obs, reward, done, info = env.step(action)
            episode_rewards.append(reward)

        all_episode_rewards.append(sum(episode_rewards))

    mean_episode_reward = np.mean(all_episode_rewards)
    print("Mean reward:", mean_episode_reward, "Num episodes:", num_episodes)

    return mean_episode_reward

訓練されていないエージェントを評価してみましょう。これはランダムなエージェントでなければなりません。

# 訓練前のランダムエージェント
mean_reward_before_train = evaluate(model, num_episodes=100)
Mean reward: 22.25 Num episodes: 100

5. エージェントを訓練して評価

# 10000ステップのエージェントの訓練
model.learn(total_timesteps=10000)
# 訓練されたエージェントの評価
mean_reward = evaluate(model, num_episodes=100)
Mean reward: 156.24 Num episodes: 100

訓練はうまくいったようで、平均報酬は大幅に増加しました。

6. ビデオ録画の準備

# 偽のディスプレイを設定
# これがないとレンダリングは失敗する
import os
os.system("Xvfb :1 -screen 0 1024x768x24 &")
os.environ['DISPLAY'] = ':1'
!pip install pyglet==1.3.1  # pyglet v1.4.1 ではエラーになります
import base64
from pathlib import Path

from IPython import display as ipythondisplay

def show_videos(video_path='', prefix=''):
  """
  https://github.com/eleurent/highway-envから取得

  :param video_path: (str) ビデオを含むフォルダへのパス
  :param prefix: (str) ビデオをフィルタリングし、このプレフィックスで始まるもののみを表示
  """
  html = []
  for mp4 in Path(video_path).glob("{}*.mp4".format(prefix)):
      video_b64 = base64.b64encode(mp4.read_bytes())
      html.append('''<video alt="{}" autoplay
                    loop controls style="height: 400px;">
                    <source src="data:video/mp4;base64,{}" type="video/mp4" />
                </video>'''.format(mp4, video_b64.decode('ascii')))
  ipythondisplay.display(ipythondisplay.HTML(data="<br>".join(html)))

VecVideoRecorderラッパーを使用してビデオを録画します。これらのラッパーについては、次のノートブックで学習します。

from stable_baselines.common.vec_env import VecVideoRecorder

def record_video(env_id, model, video_length=500, prefix='', video_folder='videos/'):
  """
  :param env_id: (str)
  :param model: (RL model)
  :param video_length: (int)
  :param prefix: (str)
  :param video_folder: (str)
  """
  eval_env = DummyVecEnv([lambda: gym.make('CartPole-v1')])
  # step = 0でビデオを開始し、500ステップを記録
  eval_env = VecVideoRecorder(env, video_folder=video_folder,
                              record_video_trigger=lambda step: step == 0, video_length=video_length,
                              name_prefix=prefix)

  obs = eval_env.reset()
  for _ in range(video_length):
    action, _ = model.predict(obs)
    obs, _, _, _ = eval_env.step(action)

  # ビデオレコーダーを閉じる
  eval_env.close()

7. 訓練されたエージェントの視覚化

record_video('CartPole-v1', model, video_length=500, prefix='ppo2-cartpole')
show_videos('videos', prefix='ppo2')

画像1

8. 【ボーナス】 RLモデルを1行で訓練

使用するポリシークラスが推測され、環境が自動的に作成されます。
両方が登録されているため、これは機能します。

model = PPO2('MlpPolicy', "CartPole-v1", verbose=1).learn(1000)

9. DQNエージェントの訓練

前の例では、「Stable Baselines」によって提供される多くのアルゴリズムの1つであるPPOを使用しました。次の例では、「Deep Q-Network」エージェント(DQN)を訓練し、その拡張機能(Double-DQN、Dueling-DQN、Priorized Experience Replay)によって提供される改善の可能性を確認します。このセクションの重要なポイントは、ハイパーパラメータを微調整することがいかに簡単かを示すことです。

「Stable Baselines」の主な利点は、アルゴリズムを使用するための共通インターフェースを提供するため、コードは非常に似ていることです。

・DQN paper: https://arxiv.org/abs/1312.5602
・Dueling DQN: https://arxiv.org/abs/1511.06581
・Double-Q Learning: https://arxiv.org/abs/1509.06461
・Prioritized Experience Replay: https://arxiv.org/abs/1511.05952

10. Vanilla DQN:拡張なしのDQN

from stable_baselines import DQN

# すべてのDQN拡張機能を無効にして、元のバージョンを使用
# 実際には、それらをアクティブにすることをお勧めする
kwargs = {'double_q': False, 'prioritized_replay': False, 'policy_kwargs': dict(dueling=False)}

# DQNのMlpPolicyはPPOのMlpPolicyとは異なることに注意
# Stable Baselinesは文字列を渡すと自動的に処理
dqn_model = DQN('MlpPolicy', 'CartPole-v1', verbose=1, **kwargs)
# 訓練前のランダムエージェント
mean_reward_before_train = evaluate(dqn_model, num_episodes=100)
Mean reward: 9.29 Num episodes: 100


# 10000ステップのエージェントの訓練
dqn_model.learn(total_timesteps=10000, log_interval=10)
# 訓練されたエージェントの評価
mean_reward = evaluate(dqn_model, num_episodes=100)
Mean reward: 130.02 Num episodes: 100

11. DQN + Prioritized Replay

# Prioritized Replayのみをアクティブ化
kwargs = {'double_q': False, 'prioritized_replay': True, 'policy_kwargs': dict(dueling=False)}

dqn_per_model = DQN('MlpPolicy', 'CartPole-v1', verbose=1, **kwargs)
dqn_per_model.learn(total_timesteps=10000, log_interval=10)
# 訓練されたエージェントの評価
mean_reward = evaluate(dqn_per_model, num_episodes=100)
Mean reward: 110.18 Num episodes: 100

12. DQN + Prioritized Experience Replay + Double Q-Learning + Dueling

# すべての拡張機能を有効化
kwargs = {'double_q': True, 'prioritized_replay': True, 'policy_kwargs': dict(dueling=True)}

dqn_full_model = DQN('MlpPolicy', 'CartPole-v1', verbose=1, **kwargs)
dqn_full_model.learn(total_timesteps=10000, log_interval=10)
mean_reward = evaluate(dqn_per_model, num_episodes=100)
Mean reward: 110.02 Num episodes: 100

この特定の例では、拡張機能は単純なDQNバージョンと比べて改善されないようです。それにはいくつかの理由があります。

(1) CartPole-v1は非常にシンプルな環境です。
(2) DQNの訓練はごく少数のタイムステップで行いましたが、違いを確認するには十分ではありませんでした。
(3) DQNのデフォルトのハイパーパラメータは、訓練タイムステップの数がはるかに大きく(10 ^ 6)、入力観測値がイメージであるAtariゲーム用に調整されています。
(4) 実験ごとにランダムシードを1つだけ比較しました。

13. 参照

・Github repo: https://github.com/araffin/rl-tutorial-jnrr19
・Stable-Baselines: https://github.com/hill-a/stable-baselines
・Documentation: https://stable-baselines.readthedocs.io/en/master/
・RL Baselines zoo: https://github.com/araffin/rl-baselines-zoo
・Medium article: https://medium.com/@araffin/stable-baselines-a-fork-of-openai-baselines-df87c4b2fc82


この記事が気に入ったらサポートをしてみませんか?