SageMaker Studio Labで強化学習を行ってみた
目標
SageMaker Studio Labが公開されたので使ってみる
- Google Colabと違い、現時点ではroot権が必要なインストールをサポートしていないので、仮想ディスプレイ(xvfb)は利用できないのがつらいです stackoverflow.com
Keras-RLを用いてMountainCar-v0を強化学習する
- まずは、動いて強化学習できれば目標達成とする
MountainCar-v0 について
谷底にあるAgentの車が、200ステップ以内に画面右上の旗のところにつけばクリア!
でも、車のエンジンは一気に山を登り切るパワーはありません (ホンダのPUにすれば一気に・・・)。 と言うわけで成功するには左側の山に登って、勢いよく下ってから右の山を登る必要があります。
Reward, Observation, Actions などは以下の公式ページに記載があります。 github.com
学習開始!
必要なモジュールのインストールとimportを実行します。
インストール
%pip install gym %pip install keras-rl2
import
import gym from gym import wrappers from numpy.lib.function_base import average from tensorflow.keras.models import Sequential,load_model from tensorflow.keras.layers import Dense, Activation, Flatten from tensorflow.keras.optimizers import Adam from rl.agents.dqn import DQNAgent from rl.policy import BoltzmannQPolicy, EpsGreedyQPolicy from rl.memory import SequentialMemory
TensorFlowのバージョンを確認します。
2021/12/03 に試した時は、以下のバージョンが導入されていました。現時点での最新版ですね。
import tensorflow as tf tf.__version__
'2.7.0'
学習時のコールバック関数
学習結果をグラフ化するために、各ステップの情報を記憶するCallbackを実装します。今回はエピソードごとの報酬をグラフにしています。
import rl.callbacks class EpisodeLogger(rl.callbacks.Callback): def __init__(self): self.rewards = {} def on_episode_begin(self, episode, logs): self.rewards[episode] = 0.0 def on_step_end(self, step, logs): episode = logs['episode'] self.rewards[episode] = self.rewards[episode] + logs['reward'] cb_ep = EpisodeLogger()
パラメーターを指定
学習回数や環境(MountainCar-v0)、モデルの保存場所指定します。
limit_steps = 50000 nb_episodes = 5 env_name = 'MountainCar-v0' notebook_root = "/home/studio-lab-user" #ファイルやモデルの保存場所 title_name = f"{notebook_root}/{env_name}_{str(limit_steps)}" model_path = f"{notebook_root}/{env_name}/model/"
モデルの保存ディレクトリを作成
import os os.makedirs(model_path,exist_ok=True)
環境の作成
env = gym.make(env_name)
nb_actions = env.action_space.n #有効なaction数
モデルの定義
- OpenAI Gymのサンプルにある簡単なニューラルネットワークを作りました。
IN
車の速度、車の場所
OUT
車のアクション 左、何もしない、右
# モデルの定義 model = Sequential() model.add(Flatten(input_shape=(1,) + env.observation_space.shape)) model.add(Dense(16)) model.add(Activation('relu')) model.add(Dense(16)) model.add(Activation('relu')) model.add(Dense(16)) model.add(Activation('relu')) model.add(Dense(nb_actions)) model.add(Activation('linear'))
学習環境の作成
- ポリシーの指定
- epsilon-greedy を指定。
- Keras-RLには他にもポリシーがあります。
- LinearAnnealedPolicy, SoftmaxPolicy, EpsGreedyQPolicy, GreedyQPolicy, BoltzmannQPolicy, MaxBoltzmannQPolicy, BoltzmannGumbelQPolicy
- 学習の設定
- DQN(Deep Q-Network)を採用、オプションでDDQNなども利用可能。 Experience Replay用のメモリ
- DNNの学習を安定させるために用いられる仕組み。
- DNNは時系列に相関があるデータをその順番のまま使うとうまく学習できないらしく、後でランダムにデータを読み込んで学習を行う方法。
# Experience Replay用のメモリ設定 memory = SequentialMemory(limit=limit_steps, window_length=1) # ポリシーの作成 policy = EpsGreedyQPolicy() # DQN Agentの作成 dqn = DQNAgent(model=model, nb_actions=nb_actions, memory=memory, nb_steps_warmup=10, target_model_update=1e-2, policy=policy) # コンパイル dqn.compile(Adam(learning_rate=1e-3), metrics=['mae'])
学習開始!
ちなみに、visualize=False にしないとエラーになります。描画対象の画面がないからです。 (Google Clabだと、仮想ディスプレイ使えるからmp4で保存できるんですが。)
dqn.fit(env, nb_steps=limit_steps, visualize=False, verbose=2, callbacks=[cb_ep])
学習成果を確認する
matplotlibをインストールします。
%pip install matplotlib
Callbackで保持していたエピソードごとのReward(報酬)をグラフにする
import matplotlib.pyplot as plt plt.figure(figsize=[16,9]) plt.plot(list(cb_ep.rewards.keys()), list(cb_ep.rewards.values())) plt.xlabel("Episode") plt.ylabel("Reword") plt.title(title_name) plt.show()
150エピソードあたりから少しずつクリアする回数が多くなり、300エピソードくらいから安定してクリアしてくる様子が見て取れます。
学習済みモデルを用いてテスト
うまく旗までたどり着くかな・・・
# モデルをテスト dqn.test(env, nb_episodes=nb_episodes, visualize=False, callbacks=[cb_ep])
5エピソード分テストしましたが、すべて-200以上なので、2000step以内に山を登って旗に到達しています!
Testing for 5 episodes ... Episode 1: reward: -147.000, steps: 147 Episode 2: reward: -143.000, steps: 143 Episode 3: reward: -155.000, steps: 155 Episode 4: reward: -146.000, steps: 146 Episode 5: reward: -150.000, steps: 150
とりあえず、SageMaker Studio Labで強化学習を実施することができました。 ローカルの環境やGoogle Colabでは、以下のように実際車が山を登るところを確認できます。Google Colab版のコードは別途アップ予定です。
番外編
モデルの保存
うまく行ったらモデルを保存します。overwrite=False
をつけることで、意図しない上書きを防止しています。
save_model_name = "save_test" dqn.model.save(model_path + save_model_name,overwrite=False)
モデルの読み込み
学習済みのモデルをロードもできます。
load_model_name = "model100000" print("モデル取得場所: {0}{1}".format(model_path,load_model_name)) # モデルの読み込み model=load_model(model_path + load_model_name)
あとは、以下のように読み込んだmodel
をDQNAgentに渡せばよいです。
# テスト動画保存先 env_test = gym.make(env_name) # エージェントの設定 memory = SequentialMemory(limit=limit_steps, window_length=1) dqn = DQNAgent(model=model, nb_actions=nb_actions, memory=memory) dqn.compile(Adam(lr=1e-3), metrics=['mae']) # モデルをテスト dqn.test(env_test, nb_episodes=nb_episodes, visualize=False, callbacks=[cb_ep])