强化学习10-Deep Q Learning-fix target

时间:2023-03-10 01:52:21
强化学习10-Deep Q Learning-fix target

针对 Deep Q Learning 可能无法收敛的问题,这里提出了一种  fix target 的方法,就是冻结现实神经网络,延时更新参数。

这个方法的初衷是这样的:

1. 之前我们每个(批)记忆都会更新参数,这是一种实时更新神经网络参数的方法,这个方法有个问题,就是每次都更新,由于样本都是随机的,可能存在各种不正常现象,比如你考试得了90分,妈妈奖励了你,但是也有可能是考了90分,被臭骂一顿,因为别人都考了95分以上,当然这只是个例子,正是各种异常现象,可能导致损失忽小忽大,参数来回震荡,无法收敛。

2. fix target 方法搭了2个神经网络,一个是估计,一个是现实,估计神经网络实时更新,而现实神经网络暂时冻结,q估计用估计神经网络,q现实用现实神经网络,冻结现实神经网络,就是我先不动,然后派很多人去做尝试,回来给我汇报,我根据汇报总结经验,然后再行动,这是我们正常的处事逻辑,这样显得神经网络更稳重,容易收敛。

核心代码如下

def _build_net(self):
# ------------------ build evaluate_net ------------------
self.s = tf.placeholder(tf.float32, [None, self.n_features], name='s') # input
self.q_target = tf.placeholder(tf.float32, [None, self.n_actions], name='Q_target') # for calculating loss
with tf.variable_scope('eval_net'):
# n_l1 第一隐层的神经元个数 w b 初始化
c_names, n_l1, w_initializer, b_initializer = \
['eval_net_params', tf.GraphKeys.GLOBAL_VARIABLES], 10, \
tf.random_normal_initializer(0., 0.3), tf.constant_initializer(0.1) # config of layers # first layer. collections is used later when assign to target net
with tf.variable_scope('l1'):
w1 = tf.get_variable('w1', [self.n_features, n_l1], initializer=w_initializer, collections=c_names)
b1 = tf.get_variable('b1', [1, n_l1], initializer=b_initializer, collections=c_names)
l1 = tf.nn.relu(tf.matmul(self.s, w1) + b1) # second layer. collections is used later when assign to target net
with tf.variable_scope('l2'):
w2 = tf.get_variable('w2', [n_l1, self.n_actions], initializer=w_initializer, collections=c_names)
b2 = tf.get_variable('b2', [1, self.n_actions], initializer=b_initializer, collections=c_names)
self.q_eval = tf.matmul(l1, w2) + b2 with tf.variable_scope('loss'):
self.loss = tf.reduce_mean(tf.squared_difference(self.q_target, self.q_eval))
with tf.variable_scope('train'):
self._train_op = tf.train.RMSPropOptimizer(self.lr).minimize(self.loss) # ------------------ build target_net ------------------
self.s_ = tf.placeholder(tf.float32, [None, self.n_features], name='s_') # input
with tf.variable_scope('target_net'):
# c_names(collections_names) are the collections to store variables
c_names = ['target_net_params', tf.GraphKeys.GLOBAL_VARIABLES] # first layer. collections is used later when assign to target net
with tf.variable_scope('l1'):
w1 = tf.get_variable('w1', [self.n_features, n_l1], initializer=w_initializer, collections=c_names)
b1 = tf.get_variable('b1', [1, n_l1], initializer=b_initializer, collections=c_names)
l1 = tf.nn.relu(tf.matmul(self.s_, w1) + b1) # second layer. collections is used later when assign to target net
with tf.variable_scope('l2'):
w2 = tf.get_variable('w2', [n_l1, self.n_actions], initializer=w_initializer, collections=c_names)
b2 = tf.get_variable('b2', [1, self.n_actions], initializer=b_initializer, collections=c_names)
self.q_next = tf.matmul(l1, w2) + b2 def store_transition(self, s, a, r, s_):
# 存储记忆,固定大小的记忆库
if not hasattr(self, 'memory_counter'):
self.memory_counter = 0 transition = np.hstack((s, [a, r], s_)) # replace the old memory with new memory
index = self.memory_counter % self.memory_size
self.memory[index, :] = transition self.memory_counter += 1 def choose_action(self, observation):
# q learning 选择动作 e贪心
observation = observation[np.newaxis, :] if np.random.uniform() < self.epsilon:
actions_value = self.sess.run(self.q_eval, feed_dict={self.s: observation})
action = np.argmax(actions_value)
else:
action = np.random.randint(0, self.n_actions)
return action def learn(self):
# 每隔一定步数更新,代表积累了一定的经验才进行总结,这样显得不那么武断,对应到神经网络,就是更新效率高,容易收敛
if self.learn_step_counter % self.replace_target_iter == 0: # 更新神经网络参数
self.sess.run(self.replace_target_op)
print('\ntarget_params_replaced\n') ##### 取样本
## memory 是 初始化一个 memory_size 的数据表,当记忆大于这个表时,表已被填满,随机从表中选择记忆即可,
## 当记忆小于这个表时,表未被填满,只能从记忆里随机选样本
if self.memory_counter > self.memory_size:
sample_index = np.random.choice(self.memory_size, size=self.batch_size)
else:
sample_index = np.random.choice(self.memory_counter, size=self.batch_size)
batch_memory = self.memory[sample_index, :] ##### 训练神经网络
# 利用神经网络 计算 q_next 下个状态的q值,q_eval 当前状态的q值
q_next, q_eval = self.sess.run([self.q_next, self.q_eval], feed_dict={
self.s_: batch_memory[:, -self.n_features:], # 下一个状态
self.s: batch_memory[:, :self.n_features], # 当前状态
}) q_target = q_eval.copy() # q_eval 是q 估计 ### 更新 q learning 的 q表
## 每个真实实验有个动作和奖励
batch_index = np.arange(self.batch_size, dtype=np.int32)
eval_act_index = batch_memory[:, self.n_features].astype(int) # 动作
reward = batch_memory[:, self.n_features + 1] # 奖励 ## 更新q表
q_target[batch_index, eval_act_index] = reward + self.gamma * np.max(q_next, axis=1) # q 现实
# 注意这里的动作当前状态选择的动作,而不是下个状态基于贪心的动作 # train eval network
_, self.cost = self.sess.run([self._train_op, self.loss],
feed_dict={self.s: batch_memory[:, :self.n_features],
self.q_target: q_target})
self.cost_his.append(self.cost) # increasing epsilon
self.epsilon = self.epsilon + self.epsilon_increment if self.epsilon < self.epsilon_max else self.epsilon_max
self.learn_step_counter += 1

图示如下

强化学习10-Deep Q Learning-fix target