Dueling DQN—一种简单有效提高DQN效果的方法
2019-07-24 本文已影响0人
CristianoC
1.前言
关于DQN我们还会讲最后一种升级办法,我们只需要稍微改动DQN中的神经网络的结构,就能大幅提升学习效果,加速收敛,这种新方法叫做Dueling DQN。用一句话概括Dueling DQN就是:它将每一个动作的Q拆分成了state的Value加上每个动作的Advantage。
2.算法
2.1Dueling 算法
我们看一下Dueling DQN的神经网络架构和普通DQN有什么不同:
image
我们可以很明显地看出,上面普通的DQN只有一个输出,就是每一个动作的Q值;而Dueling DQN则拆成了state的Value和每个动作的Advantage。
我们再来看一下公式:
image
它分成了这个state的值,加上每个动作在这个state上的advantage。因为有时候在某种state,无论做什么动作,对下一个state都没有多大的影响,比如论文当中的上面这个图:
image
这是开车的游戏,左边是state value,发红的部分证明了state value和前面的路线有关,右边是advantage,发红的部分说明了advantage很在乎旁边要靠近的车子,这时的动作会受advantage的影响。发红的地方左右了自己车子的移动原则。
2.2 更新方法
imageclass DuelingDQN:
def __init__(..., dueling=True, sess=None)
...
self.dueling = dueling # 会建立两个 DQN, 其中一个是 Dueling DQN
...
if sess is None: # 针对建立两个 DQN 的模式修改了 tf.Session() 的建立方式
self.sess = tf.Session()
self.sess.run(tf.global_variables_initializer())
else:
self.sess = sess
...
def _build_net(self):
def build_layers(s, c_names, n_l1, w_initializer, b_initializer):
with tf.variable_scope('l1'): # 第一层, 两种 DQN 都一样
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(s, w1) + b1)
if self.dueling:
# Dueling DQN
with tf.variable_scope('Value'): # 专门分析 state 的 Value
w2 = tf.get_variable('w2', [n_l1, 1], initializer=w_initializer, collections=c_names)
b2 = tf.get_variable('b2', [1, 1], initializer=b_initializer, collections=c_names)
self.V = tf.matmul(l1, w2) + b2
with tf.variable_scope('Advantage'): # 专门分析每种动作的 Advantage
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.A = tf.matmul(l1, w2) + b2
with tf.variable_scope('Q'): # 合并 V 和 A, 为了不让 A 直接学成了 Q, 我们减掉了 A 的均值
out = self.V + (self.A - tf.reduce_mean(self.A, axis=1, keep_dims=True)) # Q = V(s) + A(s,a)
else:
with tf.variable_scope('Q'): # 普通的 DQN 第二层
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)
out = tf.matmul(l1, w2) + b2
return out
...
3.对比结果
这次我们看看累计奖励reward,杆子立起来的时候奖励=0,其他时候都是负值,所以当累积奖励没有在降低的时候,说明杆子已经被成功立起来很久了。
我们可以发现当可用工作越高,学习难度就越大,不过Dueling DQN还是会比Natural DQN学习得更快,收敛效果更好。
完整代码:https://github.com/cristianoc20/RL_learning/tree/master/Dueling_DQN
参考:https://github.com/MorvanZhou