FrozenLake-v0は盤面サイズが4x4でしたが,こちらは8x8.
https://gym.openai.com/envs/FrozenLake8x8-v0
4x4での解法はこちらに記載しています.
http://qiita.com/namakemono/items/989f94fe788532a335f2
盤面が大きくなるので,テーブルで持つことは難しく関数近似が必要になります.
クリア条件
- 直近100回の試行の報酬の平均値が0.99以上.
- 報酬はクリアできたら+1,落とし穴に落ちたら0とする.
考察
今回のマップは
S.......
........
...H....
.....H..
...H....
.HH...H.
.H..H.H.
...H...G
-
S: ゲーム開始地点
-
G: クリア地点(移動できれば成功)
-
H: 落とし穴(落ちると失敗)
-
F: 移動できる場所(Fだと見づらいので, "."で表示しています.)
-
開始地点(S)から右に行って,下に行くのが正解となる.
-
2/3の確率で意図した方向とは異なる方向(直角)に進む(下記リンク参照)ので,最初0.99は無理でしょと思ったが,最後の2マスは右押して移動することで,100%クリアは可能ということに気づく.
https://github.com/openai/gym/blob/master/gym/envs/toy_text/frozen_lake.py#L99 -
左下からの1/3の確率で意図した方向と違う方向に進むために,安定してゴールすることはできない.(つまり,こちらのコースは引っ掛けであることをコンピュータは学習する必要がある)
コード
# -*- coding: utf-8 -*-
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
import numpy as np
import gym
from gym import wrappers
from keras.models import Sequential
from keras.layers import Dense
def build_model(input_dim, output_dim):
model = Sequential()
model.add(Dense(input_dim, kernel_initializer="he_normal", activation="relu", input_shape=(input_dim, )))
model.add(Dense(output_dim, kernel_initializer="he_normal", activation="softmax"))
return model
def run():
env = gym.make("FrozenLake8x8-v0")
env = wrappers.Monitor(env, directory="/tmp/frozenlake8x8-v0", force=True)
logger.info("Observation Space: %d, Action Space: %d" % (env.observation_space.n, env.action_space.n))
max_episode = 100000
Gs = [] # Revenues
best = -1
model = build_model(env.observation_space.n, env.action_space.n)
model.compile(loss="categorical_crossentropy", optimizer="nadam", metrics=["mae", "mse"])
for episode in range(max_episode):
x = env.reset()
X = [] # States
A = [] # Actions
Q = [] # Action Values
done = False
alpha, gamma = 0.03, 0.9
while not done:
v = np.zeros(env.observation_space.n)
v[x] = 1
q = model.predict(np.asarray([v]))[0]
a = np.argmax(q)
X.append(v)
A.append(a)
Q.append(q)
x, r, done, info = env.step(a)
if done:
r = +1 if r > 0 else -1
break
T = len(X)
for t in range(T-1):
a = A[t]
Q[t][a] = (1-alpha) * Q[t][a] + alpha * r
model.fit(np.asarray(X), np.asarray(Q), verbose=0, batch_size=T)
Gs.append(int(r > 0))
avg = np.mean(Gs[-100:])
best = max(best, avg)
logger.info("Episode: %d, End of turn: %d, Revenue: %.2f, Average: %.2f, Best: %.2f" % (episode, len(X), r, avg, best))
if __name__ == "__main__":
run()
スコア
- 0.96±0.02