更新1:は、εを非常に少ない量にする前に取ったエピソードの数が非常に少ないという貪欲イプシロンポリシーを改訂しました。私はコードを更新しました。なぜ、q学習機能がopenai山岳車に収束しないのですか?
新しい問題は完全にそれがはるかに逸脱してはならない訓練の後であるが、それは間違った値をピックアップし、すぐに発散するイプシロンは小さな
になっている私は私の目標として今かなりいつかのためにopenai gymプラットフォームに取り組んできました強化学習の詳細については、スタックオーバフローユーザー@sajadの助けを借りて、経験豊富なリプレイ(PER)でダブルディープq学習(DQN)を実装しました。カートポールの問題で、注意深いハイパーパラメータチューニングで非常に良い成功率を得ました。これはこれまでのところ、私が学んだ最善のアルゴリズムですが、私が何をするにしても、報酬が常にエピソードの-200に続く山車の問題でこの仕事を得るようには見えません。私は自分のコードを見て、various tutorialsから私は私のメモリの実装が正しいと思います。
基本的なDQNからPERを持つDQNまでのアルゴリズムのどちらも機能していないようです。
私はコードやここ
を収束していない、それを引き起こしている可能性があり、他の実装の変更をデバッグするには、いくつかの助けを得るならば、それは役に立つだろうが、私の実装です:すべてのパラメータは、通常の名前
# implemented using sum_tree
import os
import random
import gym
import numpy as np
import tensorflow as tf
from memory import Memory
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
env = gym.make("MountainCar-v0")
env.reset()
model_save_path = "C:/Users/sanka/codes/mountain car openai/mc_save"
class dqn(object):
def __init__(self):
self.flag = 0
self.batch_size = 64
self.episodes = 20000
self.input_size = env.observation_space.sample().size
self.output_size = env.action_space.n
self.gamma = 0.99
self.epsilon = 1.0
self.step = 0
self.learning_rate = 0.0001
self.lambda1 = 0.001
self.initial_epsilon = self.epsilon
self.final_epsilon = 0.01
self.weights = {}
self.biases = {}
self.target_weights = {}
self.target_biases = {}
self.create_nn()
self.create_training_network()
self.max_size = 10000
self.memory = Memory(size=self.max_size)
self.sess = tf.InteractiveSession()
self.sess.run(tf.global_variables_initializer())
self.saver = tf.train.Saver()
def create_nn(self):
s1 = {1: [self.input_size, 30], 2: [30, 100], 3: [100, 30], 4: [30, self.output_size]}
s2 = {1: [30], 2: [100], 3: [30], 4: [self.output_size]}
for i in s1:
self.weights[i] = tf.Variable(tf.truncated_normal(s1[i]), name='w{0}'.format(i))
self.biases[i] = tf.Variable(tf.truncated_normal(s2[i]), name='b{0}'.format(i))
self.target_weights[i] = tf.Variable(tf.truncated_normal(s1[i]), name='tw{0}'.format(i))
self.target_biases[i] = tf.Variable(tf.truncated_normal(s2[i]), name='tb{0}'.format(i))
def feed_forward(self, z):
q = tf.nn.relu(tf.matmul(z, self.weights[1]) + self.biases[1])
for i in range(2, len(self.weights), 1):
q = tf.nn.relu(tf.matmul(q, self.weights[i]) + self.biases[i])
q = tf.matmul(q, self.weights[len(self.weights)]) + self.biases[len(self.biases)]
return q
def feed_forward_target(self, z):
q = tf.nn.relu(tf.matmul(z, self.target_weights[1]) + self.target_biases[1])
for i in range(2, len(self.weights), 1):
q = tf.nn.relu(tf.matmul(q, self.target_weights[i]) + self.target_biases[i])
q = tf.matmul(q, self.target_weights[len(self.weights)]) + self.target_biases[len(self.weights)]
return q
def create_training_network(self):
self.x = tf.placeholder(tf.float32, [None, self.input_size])
self.y = tf.placeholder(tf.float32, [None])
self.a = tf.placeholder(tf.float32, [None, self.output_size])
self.q_value = self.feed_forward(self.x)
self.q_value_target = self.feed_forward_target(self.x)
self.output = tf.reduce_sum(tf.multiply(self.q_value, self.a), reduction_indices=1)
self.action = tf.argmax(self.q_value, 1)
self.loss = tf.reduce_mean(tf.square(self.output - self.y))
self.optimizer = tf.train.AdamOptimizer(learning_rate=self.learning_rate).minimize(self.loss)
def append_to_memory(self, state, action, reward, next_state, done):
one_hot_action = np.zeros(self.output_size)
one_hot_action[action] = 1.0
prob = (abs(reward) + .01) ** 0.6
self.memory.append(prob, (state, one_hot_action, reward, next_state, done))
if self.memory.current_size >= self.memory.size:
self.step += 1
# self.epsilon = self.final_epsilon + (self.initial_epsilon - self.final_epsilon) * np.exp(
# -self.lambda1 * (self.step/200))
self.epsilon = max(self.initial_epsilon - (self.step/200) * self.lambda1, self.final_epsilon)
if (self.flag == 0):
print("started training")
self.flag = 1
self.train()
def get_reward(self, q1, q2, reward, done):
if done:
return reward
else:
return reward + self.gamma * q2[np.argmax(q1)]
def train(self):
index, sample = self.memory.sample(self.batch_size)
train_x = [i[0] for i in sample]
action = [i[1] for i in sample]
reward = [i[2] for i in sample]
next_state = [i[3] for i in sample]
train_y = []
q = self.sess.run(self.q_value, feed_dict={self.x: np.array(train_x)})
q_1 = self.sess.run(self.q_value, feed_dict={self.x: np.array(next_state)})
q_next = self.sess.run(self.q_value_target, feed_dict={self.x: np.array(next_state)})
for i in range(len(reward)):
train_y.append(self.get_reward(q_1[i], q_next[i], reward[i], sample[i][4]))
train_y = np.array(train_y)
train_x = np.array(train_x)
action = np.array(action)
self.sess.run(self.optimizer, feed_dict={self.x: train_x, self.y: train_y, self.a: action})
for i in range(self.batch_size):
error = abs(np.max(q[i]) - train_y[i])
self.memory.update(index[i], (error + 0.01) ** 0.6)
# return loss
def copy_variables(self):
for i in range(1, len(self.weights) + 1, 1):
self.sess.run(self.target_weights[i].assign(self.weights[i]))
self.sess.run(self.target_biases[i].assign(self.biases[i]))
def save(self):
self.saver.save(self.sess, model_save_path)
print("model saved")
def main():
obj = dqn()
for e in range(obj.episodes):
p = env.reset()
for i in range(500):
# obj.step += 1
ac = obj.sess.run(obj.action, feed_dict={obj.x: np.array([p])})[0]
if np.random.rand() < obj.epsilon:
ac = random.randint(0, obj.output_size - 1)
obs, rew, done, _ = env.step(ac)
obj.append_to_memory(p, ac, rew, obs, done)
p = obs
if done:
break
if obj.step % 1000 == 0 and obj.flag == 1:
obj.copy_variables()
# print("episode {0} completed with loss: {1}".format(e, total_loss))
if e % 100 == 0:
print("episodes {0} completed".format(e),)
av = []
for f in range(10):
p = env.reset()
r = 0
for i in range(200):
ac = obj.sess.run(obj.action, feed_dict={obj.x: np.array([p])})[0]
p, rew, done, _ = env.step(ac)
r += rew
if done:
break
av.append(r)
print("average score is {0}".format(np.average(np.array(av))))
obj.save()
if __name__ == '__main__':
main()
を持っていますここで参考のため
は別個のモジュールとして実装メモリの実装である:予め
import numpy as np
import random
class Memory(object):
def __init__(self, size):
self.size = size
self.data = np.zeros(size, dtype=object)
self.tree = np.zeros(2 * size - 1, dtype=np.float32)
self.current_size = 0
self.last = 0
def append(self, p, data):
self.current_size = min(self.current_size + 1, self.size)
cur = self.last + self.size - 1
self.update_at_index(cur, p - self.tree[cur])
self.data[self.last] = data
self.last += 1
if self.last >= self.size:
self.last = 0
def update(self, index, p):
self.update_at_index(index, p - self.tree[index])
def update_at_index(self, index, change):
while (index >= 0):
self.tree[index] += change
index = (index - 1) // 2
def get(self, index, s):
left = index * 2 + 1
if (left >= self.size):
return (index, self.data[index + 1 - self.size])
if (self.tree[left] >= s):
return self.get(left, s)
else:
right = left + 1
return self.get(right, s - self.tree[left])
def sample(self, n):
av_sum = self.tree[0]/n
l = []
m = []
for i in range(n):
min_sum = av_sum * i
max_sum = av_sum * (i + 1)
s = random.uniform(min_sum, max_sum)
x = self.get(0, s)
l.append(x[0])
m.append(x[1])
return l, m
おかげ
はい私は最初の50回のエピソード(私の記憶が10000であるため)を完全に探索し、その後は指数関数的な速度でイプシロンを減少させ始め、学習を開始しました。無作為抽出の私の最初の試みの間に少し収束しましたが、再びトラップに落ちます。 PERとは4000エピソードでさえ収束しません。私はまた、イプシロンが減少する減少率を試しました。しかし、私はそれが動作するかどうかを見てあなたの報酬の方法を試します –
あなたは正しい、それは探査の問題だった。私はランダムな値を使用していた回数を更新しました。だから収束し始めますが、私のイプシロンが非常に少なくなった後、再び発散するようになります。これに対する解決策を見つけることができませんでした –