LoginSignup
1
0

More than 5 years have passed since last update.

KerasでOpenAI GymのFrozenLake8x8-v0を解きたかった...

Last updated at Posted at 2017-08-07

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
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0