OpenAI Gymの倒立振子をKerasで解いてみる.
概要
- シンプルな方法でOpenAI Gymの倒立振子(CartPole-v0)を解いてみた.
CartPole-v0のルール
- 台車に立てられた棒を台車に左右から力を加えることでバランスを取る問題.
- "CartPole-v0"と"CartPole-v1"の違いは最大ターン数と成功条件の閾値のみ
- 各クリア条件と成功条件の閾値がここにまとまっている.
- すごい重要な情報な気がしますが,皆さん最初どうやって見つけているんでしょう...
register(
id='CartPole-v0',
entry_point='gym.envs.classic_control:CartPoleEnv',
max_episode_steps=200,
reward_threshold=195.0,
)
register(
id='CartPole-v1',
entry_point='gym.envs.classic_control:CartPoleEnv',
max_episode_steps=500,
reward_threshold=475.0,
)
行動空間
- 右か左のどちらかへ棒に力を加えられる.
状態空間
OpenAI Gymのコードによると,状態空間は下記の連続する4次元の値で構成されています.
- 各次元の定義
- 0: 位置($x$: position of the cart on the track)
- 1: 速度($\dot{x}$: cart velocity)
- 2: 角度($\theta$: angle of the pole with the vertical)
- 3: 角速度($\dot{\theta}$: rate of change of the angle)
報酬入手条件
- 倒立振子の角度が垂直から15度以内
- 振り子の位置が中心から台車2.4台分以内
ゲーム失敗条件
- 報酬入手条件を満たさない状態になる
ゲーム成功条件
- 200ターンでゲームは終了(これが明示されてないので,とっかかりづらい気がする...)
- 連続100回のゲームで平均スコアで195以上獲得
報酬設計
- なるだけ失敗条件を満たさないようにすれば良い.
- 最大ターン数$T$は200なので,最大収益は200.
- 0〜1となるようTで割った値を収益に設定
G = \frac{1}{T}\sum^T_{t=0} R(x_t)
ここで$R(x_t)$は状態$x_t$時に得られた報酬.
解法
行動価値関数$Q(x_t, a_t)$を下記で更新.
Q(x_t, a_t) \leftarrow (1 - \alpha)Q(x_t, a_t) + \alpha G
import numpy as np
import gym
from gym import wrappers
import keras
from keras.models import Sequential
from keras.layers.core import Dense, Activation
from keras.utils import np_utils
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
def build_model(input_dim, output_dim):
model = Sequential()
model.add(Dense(200, kernel_initializer="he_normal", activation="relu", input_dim=input_dim))
model.add(Dense(200, kernel_initializer="he_normal", activation="relu"))
model.add(Dense(output_dim, kernel_initializer="he_normal", activation="sigmoid"))
return model
def run():
max_score = 200.0
num_episodes = 3000
env = gym.make("CartPole-v0")
env = wrappers.Monitor(env, directory="/tmp/cartpole-v0", force=True)
logger.info("Action Space: %s" % str(env.action_space))
logger.info("Observation Space: %s" % str(env.observation_space))
model = build_model(input_dim=env.observation_space.shape[0], output_dim=env.action_space.n)
model.compile(loss="mse", optimizer="adam", metrics=["mae", "mse"])
Gs = []
for episode in range(num_episodes):
x = env.reset()
X, Q, A, R = [], [], [], []
done = False
while not done:
q = model.predict(np.asarray([x]))[0]
a = np.argmax(q)
X.append(x)
A.append(a)
Q.append(q)
x, r, done, info = env.step(a)
R.append(r)
# print episode, len(X), a, q, x, r, done, info
alpha = 0.1
T = len(X)
G = np.sum(R)
for t in range(T):
a = A[t]
Q[t][a] = (1-alpha) * Q[t][a] + alpha * (G / max_score)
model.fit(np.asarray(X), np.asarray(Q), verbose=0, batch_size=T)
logger.debug("Episode: %d, Reward: %.2f" % (episode, G))
Gs.append(G)
logger.info("Average Reward: %.3f" % np.mean(Gs))
env.close()
if __name__ == "__main__":
run()
References
[1]. OpenAI Gym, Brockman et al., 2016
[2]. Neuronlike Adaptive Elements That Can Solve Difficult Learning Control Problem, Barto et al., 1983
[3]. Simple reinforcement learning methods to learn CartPole, Frans, 2016
[4]. Actor-Criticの疑問のまとめ, yasaki6023, 2017
[5]. 倒立振子で学ぶ DQN (Deep Q Network), ashitani, 2016
[6]. 倒立振子でDQNにおけるモデルの複雑さと学習内容の関係をちらっと確かめてみた系の話, enakai00, 2016
[7]. 各クリア条件と成功条件の閾値, Brockman et al.,2016
Author And Source
この問題について(OpenAI Gymの倒立振子をKerasで解いてみる.), 我々は、より多くの情報をここで見つけました https://qiita.com/namakemono/items/9b75d1c0c98916b396ba著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .