KerasとCartPoleでDQN (Deep Q-Network)
つりながら学ぶ!深層強化学習 PyTorchによる実践プログラミング 良い
マイナビ出版からPyTorchを使って深層強化学習を作りながら学ぶという本が出てて、発売日にすぐ買って、今日もまだ読んでる途中なんだけれど、いかんせんディープラーニング関係はKerasと時々生TensorFlowぐらいしか弄ってないから、PyTorchが今ひとつ分からない。
そこで勉強ついでに、ネットの記事を調べつつ、本のソースコードを元にDQNをKerasを使って実装するってのが今日のお話。
使うライブラリ
- OpenAi Gym
- TensorFlow 1.9.0
- Keras (tf.keras)
まず前提として、DQNの実装で重要なのは以下の通り。
DQN で重要な4つのポイント
- Experience Replay
- Fixed Target Q-Network
- Reward Clipping
- Huber Loss
Huber Loss
は TensorFlowの損失関数の中に実装されているのでそれを使うことにします。
10回連続して棒を立たせられたら終了するコード。
# coding: utf-8 import random import gym import numpy as np from collections import deque from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, InputLayer from tensorflow.keras.optimizers import Adam from tensorflow.losses import huber_loss EPISODES = 500 ENV = "CartPole-v0" GAMMA = 0.99 MAX_STEPS = 200 NUM_EPISODES = 500 CAPACITY = 10000 BATCH_SIZE = 32 class ExperienceMemory: def __init__(self, capacity): self.capacity = capacity self.memory = deque(maxlen=capacity) def push(self, state, action, next_state, reward): # if len(self.memory) < self.capacity: # self.memory.append(None) self.memory.append((state, action, next_state, reward)) def sample(self, batch_size): return random.sample(self.memory, batch_size) def __len__(self): return len(self.memory) class Q_network: def __init__(self, num_state, num_action): self.memory = ExperienceMemory(CAPACITY) self.num_state, self.num_action = num_state, num_action self.model = Sequential() self.model.add(InputLayer(input_shape=(num_state, ))) self.model.add(Dense(32, activation="relu")) self.model.add(Dense(32, activation="relu")) self.model.add(Dense(num_action, activation="linear")) self.optimizer = Adam(lr=0.00001) self.model.compile(loss=huber_loss, optimizer=self.optimizer) def replay(self, target_q_n): if len(self.memory) < BATCH_SIZE: return inputs = np.zeros((BATCH_SIZE, self.num_state)) targets = np.zeros((BATCH_SIZE, self.num_action)) transitions = self.memory.sample(BATCH_SIZE) for i, (state_batch, action_batch, next_state_batch, reward_batch) in enumerate(transitions): inputs[i:i+1] = state_batch target = reward_batch if not (next_state_batch == np.zeros(state_batch.shape)).all(axis=1): mainQ = self.model.predict(state_batch)[0] next_action = np.argmax(mainQ) target = reward_batch + GAMMA * target_q_n.model.predict(next_state_batch)[0][next_action] targets[i] = self.model.predict(state_batch) targets[i][action_batch] = target self.model.fit(inputs, targets, epochs=1, verbose=0) def decide_action(self, state, episode, target_q_n): epsilon = 0.5 * (1 / (episode + 1)) if epsilon <= np.random.uniform(0, 1): action = np.argmax(target_q_n.model.predict(state)[0]) else: action = np.random.choice(self.num_action) return action class Agent: def __init__(self, num_states, num_actions): self.brain = Q_network(num_states, num_actions) self.target_q_n = Q_network(num_states, num_actions) def update_q_function(self): self.brain.replay(self.target_q_n) def get_action(self, state, episode): return self.brain.decide_action(state, episode, self.target_q_n) def memorize(self, state, action, state_next, reward): self.brain.memory.push(state, action, state_next, reward) class Environment: def __init__(self): self.env = gym.make(ENV) self.num_states = self.env.observation_space.shape[0] self.num_actions = self.env.action_space.n self.agent = Agent(self.num_states, self.num_actions) def run(self): complete_episodes = 0 episode_final = False for episode in range(NUM_EPISODES): observation = self.env.reset() state = observation state = np.reshape(state, [1, self.num_states]) self.agent.target_q_n = self.agent.brain for step in range(MAX_STEPS): action = self.agent.get_action(state, episode) next_state, _, done, _ = self.env.step(action) next_state = np.reshape(next_state, [1, self.num_states]) if done: next_state = np.zeros(state.shape) if step < 195: reward = -1 complete_episodes = 0 else: reward = 1 complete_episodes += 1 else: reward = 0 self.agent.memorize(state, action, next_state, reward) self.agent.update_q_function() state = next_state if done: print("{} Episode: Finished after {} steps: complete_episodes: {}".format( episode, step+1, complete_episodes)) break if episode_final: self.env.render() break if complete_episodes >= 10: print("10回成功") episode_final = True cartpole_env = Environment() cartpole_env.run()
実行結果
上手くいけば100 ~ 150ステップぐらい回せば終わるんだけれど、途中で成功回数が9回ぐらいまでガクッと落ちて、なかなか学習がうまくいかないことが多々あるので、学習が上手くいってないな と思ったら再度実行。 これがなぜなのかが分からない。乱数お祈りゲーなのかな??原因を探しつつDueling DQN書く。
おまけ
自分で集めたデータを使ってKeras用のデータセットを簡単に作れるライブラリ作ったので、使って見てね github.com
インストール方法は、
pip install tartare
からかい上手の高木さん 2期はよ来い。
参考にした本
「つりながら学ぶ!深層強化学習 PyTorchによる実践プログラミング」は強化学習関係の本で一番簡単で分かりやすいと思うけど、O'Reillyの「実践Deep Learning」の強化学習のページと「速習 強化学習」を片手に調べるとさらに良いと思う。
あと、「つくりながら(ry」はJupyter Notebookを使って進んでいくけど、個人的には .py
形式で話を進めてくれたほうが、PyCharmみたいなIDEで調べながら学べて値の動きとかが分かれただろうからちょっと残念。あと、PyTorch慣れないから分かりにくい()。
つくりながら学ぶ! 深層強化学習 ~PyTorchによる実践プログラミング~
- 作者: 株式会社電通国際情報サービス小川雄太郎
- 出版社/メーカー: マイナビ出版
- 発売日: 2018/06/28
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
実践 Deep Learning ―PythonとTensorFlowで学ぶ次世代の機械学習アルゴリズム (オライリー・ジャパン)
- 作者: Nikhil Buduma,太田満久,藤原秀平,牧野聡
- 出版社/メーカー: オライリージャパン
- 発売日: 2018/04/26
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (2件) を見る
- 作者: Csaba Szepesvari,小山田創哲,前田新一,小山雅典,池田春之介,大渡勝己,芝慎太朗,関根嵩之,高山晃一,田中一樹,西村直樹,藤田康博,望月駿一
- 出版社/メーカー: 共立出版
- 発売日: 2017/09/21
- メディア: 単行本
- この商品を含むブログを見る