爱吧机器人网 » 技术 > 神经网络 > 正文

实战深度强化学习DQN-理论和实践

作者:石晓文   中国人民大学信息学院在读研究生
个人公众号:小小挖掘机(ID:wAIsjwj)


1、Q-learning回顾

Q-learning 的 算法过程如下图所示:

在Q-learning中,我们维护一张Q值表,表的维数为:状态数S * 动作数A,表中每个数代表在当前状态S下可以采用动作A可以获得的未来收益的折现和。我们不断的迭代我们的Q值表使其最终收敛,然后根据Q值表我们就可以在每个状态下选取一个最优策略。

Q值表的更新公式为:


公式中,Q(S,A) 我们可以称做Q估计值,即我们当前估计的Q值,而:



称为Q-target,即我们使用贝尔曼方程加贪心策略认为实际应该得到的奖励,我们的目标就是使我们的Q值不断的接近Q-target值。

2、深度Q网络(Deep - Q - Network)

2.1 DQN简介

为什么会出现DQN呢

在普通的Q-learning中,当状态和动作空间是离散且维数不高时可使用Q-Table储存每个状态动作对的Q值,而当状态和动作空间是高维连续时,使用Q-Table不现实。

两篇DQN奠基之作

[1]Playing Atari with Deep Reinforcement Learning
[2]Human-level control through deep reinforcement learning

如何将原始的Q-learning转换成深度学习问题

将Q-Table的更新问题变成一个函数拟合问题,相近的状态得到相近的输出动作。如下式,通过更新参数 θ 使Q函数逼近最优Q值 。因此,DQN就是要设计一个神经网络结构,通过函数来拟合Q值,即:

2.2 DL和RL结合带来的问题

1、DL需要大量带标签的样本进行监督学习;RL只有reward返回值,而且伴随着噪声,延迟(过了几十毫秒才返回),稀疏(很多State的reward是0)等问题;
2、DL的样本独立;RL前后state状态相关;
3、DL目标分布固定;RL的分布一直变化,比如你玩一个游戏,一个关卡和下一个关卡的状态分布是不同的,所以训练好了前一个关卡,下一个关卡又要重新训练;
4、过往的研究表明,使用非线性网络表示值函数时出现不稳定等问题。

2.3 DQN解决问题方法

那么DQN是如何解决上述问题的呢?

1、通过Q-Learning使用reward来构造标签(对应问题1)
2、通过experience replay(经验池)的方法来解决相关性及非静态分布问题(对应问题2、3)
3、使用一个神经网络产生当前Q值,使用另外一个神经网络产生Target Q值(对应问题4)

构造标签

对于函数优化问题,监督学习的一般方法是先确定Loss Function,然后求梯度,使用随机梯度下降等方法更新参数。DQN则基于Q-Learning来确定Loss Function。我们想要使q-target值和q-eval值相差越小越好。DQN中的损失函数是:

这里yi是根据上一个迭代周期或者说target-net网络的参数计算出的q-target值,跟当前网络结构中的参数无关,yi的计算如下:


这样,整个目标函数就可以通过随机梯度下降方法来进行优化:


经验回放

经验池的功能主要是解决相关性及非静态分布问题。具体做法是把每个时间步agent与环境交互得到的转移样本 (st,at,rt,st+1) 储存到回放记忆单元,要训练时就随机拿出一些(minibatch)来训练。(其实就是将游戏的过程打成碎片存储,训练时随机抽取就避免了相关性问题)

双网络结构

在Nature 2015版本的DQN中提出了这个改进,使用另一个网络(这里称为target_net)产生Target Q值。具体地,Q(s,a;θi) 表示当前网络eval_net的输出,用来评估当前状态动作对的值函数;Q(s,a;θ−i) 表示target_net的输出,代入上面求 TargetQ 值的公式中得到目标Q值。根据上面的Loss Function更新eval_net的参数,每经过N轮迭代,将MainNet的参数复制给target_net。

引入target_net后,再一段时间里目标Q值使保持不变的,一定程度降低了当前Q值和目标Q值的相关性,提高了算法稳定性。

2.4 DQN算法流程

NIPS 2013版


Nature 2015版


可以看到,两版的DQN都使用了经验池,而2015版的DQN增加了target-net,提高了算法稳定性。

3、DQN实现DEMO

找了很多DQN的例子,有原版的实现Atari的,也有Flappy Bird的,但是最简单的还是莫烦大神的Demo,github地址是:https://github.com/MorvanZhou/Reinforcement-learning-with-tensorflow。

在介绍整个Demo前,我们介绍两种DQN的实现方式,一种是将s和a输入到网络,得到q值,另一种是只将s输入到网络,输出为s和每个a结合的q值。这里莫烦大神的代码采取了后一种方式。

如果你对DQN的原理有比较深刻的认识,那么读莫烦大神的代码也并不是十分困难。这里我们想要实现的效果类似于寻宝。


其中,红色的方块代表寻宝人,黑色的方块代表陷阱,黄色的方块代表宝藏,我们的目标就是让寻宝人找到最终的宝藏。

这里,我们的状态可以用横纵坐标表示,而动作有上下左右四个动作。使用tkinter来做这样一个动画效果。宝藏的奖励是1,陷阱的奖励是-1,而其他时候的奖励都为0。

接下来,我们重点看一下我们DQN相关的代码。

定义相关输入

这了,我们用s代表当前状态,用a代表当前状态下采取的动作,r代表获得的奖励,s_代表转移后的状态。
self.s = tf.placeholder(tf.float32,[None,self.n_features],name='s')
self.s_ = tf.placeholder(tf.float32,[None,self.n_features],name='s_')
self.r = tf.placeholder(tf.float32,[None,],name='r')
self.a = tf.placeholder(tf.int32,[None,],name='a')

经验池

   def store_transition(self,s,a,r,s_):
       if not hasattr(self, 'memory_counter'):
           self.memory_counter = 0
       # hstack:Stack arrays in sequence horizontally
       transition = np.hstack((s,[a,r],s_))
       index = self.memory_counter % self.memory_size
       self.memory[index,:] = transition
       self.memory_counter += 1

双网络结构

target_net和eval_net的网络结构必须保持一致,这里我们使用的是两层全链接的神经网络,值得注意的一点是对于eval_net来说,网络的输入是当前的状态s,而对target_net网络来说,网络的输入是下一个状态s_,因为target_net的输出要根据贝尔曼公式计算q-target值,即


代码如下:

w_initializer, b_initializer = tf.random_normal_initializer(0., 0.3), tf.constant_initializer(0.1)

# ------------------ build evaluate_net ------------------
with tf.variable_scope('eval_net'):
   e1 = tf.layers.dense(self.s,20,tf.nn.relu,kernel_initializer=w_initializer,
                        bias_initializer=b_initializer,name='e1'
                        )

   self.q_eval = tf.layers.dense(e1,self.n_actions,kernel_initializer=w_initializer,
                                 bias_initializer=b_initializer,name='q')

# ------------------ build target_net ------------------

with tf.variable_scope('target_net'):
   t1 = tf.layers.dense(self.s_, 20, tf.nn.relu, kernel_initializer=w_initializer,
                        bias_initializer=b_initializer, name='t1')
   self.q_next = tf.layers.dense(t1, self.n_actions, kernel_initializer=w_initializer,
                                 bias_initializer=b_initializer, name='t2')

每隔一定的步数,我们就要将target_net中的参数复制到eval_net中:

t_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES,scope='target_net')
e_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES,scope='eval_net')

with tf.variable_scope('soft_replacement'):
     self.target_replace_op = [tf.assign(t,e) for t,e in zip(t_params,e_params)]

计算损失并优化

首先,对于eval_net来说,我们只要得到当前的网络输出即可,但是我们定义的网络输出是四个动作对应的q-eval值,我们要根据实际的a来选择对应的q-eval值,这一部分的代码如下:

with tf.variable_scope('q_eval'):
   # tf.stack
   #a = tf.constant([1,2,3])
   # b = tf.constant([4,5,6])
   # c = tf.stack([a,b],axis=1)
   # [[1 4]
   #  [2 5]
   # [3 6]]
   a_indices = tf.stack([tf.range(tf.shape(self.a)[0], dtype=tf.int32), self.a], axis=1)
   # 用indices从张量params得到新张量
   # indices = [[0, 0], [1, 1]]
   # params = [['a', 'b'], ['c', 'd']]
   # output = ['a', 'd']
   # 这里self.q_eval是batch * action_number,a_indices是batch * 1,也就是说选择当前估计每个动作的Q值
   self.q_eval_wrt_a = tf.gather_nd(params=self.q_eval, indices=a_indices)

中间有几个函数不太了解的,上面都有详细的注释,如果还不是很理解的话,大家可以百度或者阅读相应函数的源码。
对于target_net网络来说,我们要根据下面的式子来计算q-target值:


第一部分的R我们是已经得到了的,剩下的就是根据贪心策略选择四个输出中最大的一个即可:

with tf.variable_scope('q_target'):
   q_target = self.r + self.gamma * tf.reduce_max(self.q_next,axis=1,name='Qmax_s_')
   # 一个节点被 stop之后,这个节点上的梯度,就无法再向前BP了
   self.q_target = tf.stop_gradient(q_target)

接下来,我们就可以定义我们的损失函数并选择优化器进行优化:

with tf.variable_scope('loss'):
   self.loss = tf.reduce_mean(tf.squared_difference(self.q_target,self.q_eval_wrt_a,name='TD_error'))

with tf.variable_scope('train'):
   self._train_op = tf.train.RMSPropOptimizer(self.lr).minimize(self.loss)

网络的训练

每隔一定的步数,我们就要将eval_net中的参数复制到target_net中,同时我们要从经验池中选择batch大小的数据输入到网络中进行训练。

def learn(self):
   if self.learn_step_counter % self.replace_target_iter == 0:
       self.sess.run(self.target_replace_op)
       print('\ntarget_params_replaced\n')

   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,:]

   _,cost = self.sess.run(
       [self._train_op,self.loss],
       feed_dict={
           self.s:batch_memory[:,:self.n_features],
           self.a:batch_memory[:,self.n_features],
           self.r:batch_memory[:,self.n_features+1],
           self.s_:batch_memory[:,-self.n_features:]
       }
   )

剩下的代码就不介绍啦,大家不妨去github上fork大神的代码,跟着进行练习,相信会对DQN的原理有一个更进一步的认识。

4、参考文献

1、深度强化学习——DQN:https://blog.csdn.net/u013236946/article/details/72871858
2、莫烦的github:https://github.com/MorvanZhou/Reinforcement-learning-with-tensorflow


上一篇:CNN经典论文研读之VGG网络及其tensorflow实现
下一篇:计算机视觉领域前沿一览
精选推荐
助力卷积神经网络时空特征学习 史上最大行人重识别视频数据集被提出
助力卷积神经网络时空特征学习 史上最大行人重识别视频数据集被提出

[2017-12-25]  本文提出了一个大型的、长序列的、用于行人重识别的视频数据集,简称LVreID。与现有的同类数据集相比,该数据集具有以下特点:1)长序列:平均每段视频序列长为200帧,包含丰......

集群机器人领域最新研究:一种用于探测未知环境的微型无人机群
集群机器人领域最新研究:一种用于探测未知环境的微型无人机群

[2019-10-26]  (图:无人机扩散至不同方向来探索环境。当一个无人机注意到另一个无人机在它的首选方向,它将试图飞到另一个方向。若首选方向冲突,低优先 ...

CES 2018:英特尔推出49量子位芯片争夺量子霸权
CES 2018:英特尔推出49量子位芯片争夺量子霸权

[2018-01-10]  在与Google、IBM的一场关于建立量子计算系统的马拉松比赛中,英特尔通过了一个关键的里程碑。近日,这个科技巨头已经推出了一个49个量子位 ...

新型轻便机器人套装重5kg,辅助跑步和步行
新型轻便机器人套装重5kg,辅助跑步和步行

[2019-10-23]  虽然步行对大多数人来说似乎不是负担,但对有些人来说,这项简单的运动往往会让人感到筋疲力尽。比如手术或中风后恢复的患者、帕金森氏症患 ...

瑞士研发出微型机器人集群 可像蚂蚁一样互相交流并协同工作
瑞士研发出微型机器人集群 可像蚂蚁一样互相交流并协同工作

[2019-07-12]  EPFL(瑞士联邦理工学院)的研究人员受到了蚂蚁的启发,开发了一款仅有10克重的小型机器人:他们可以相互交流,分配角色并完成复杂的任务。 ...

2023年服务机器人市场将超过250亿美元
2023年服务机器人市场将超过250亿美元

[2017-09-04]  全球服务机器人市场预计到2023年将达到250亿美元, 并在预测期内登记15% 的复合年增长率。短期中期回收期和投资回报率高 (ROI), 以及在教育和研究、临场感、防御、救援和安......

受大脑控制的机器人
受大脑控制的机器人

[2017-03-21]   想让机器人做我们想做的,首先,他得全面地了解我们。通常,这就意味着人类需要要付出更多。比如,教机器人复杂的人类语言或者把一项任务 ...

从AI中窥探人性
从AI中窥探人性

[2018-01-03]  人们对人造智能的恐惧早已成为科幻书籍和电影的极好题材。但现在,一些同样的担忧开始影响关于现实世界AI技术的政策讨论。如果这样的担忧演变成为一种技术恐慌...

本周栏目热点

神经网络:人工智能以及我们的未来

[2016-11-20]   作者:James Crowder翻译:王益军审校:心原文链接:techcrunch把自己想象成在一辆未来的自动驾驶汽车的乘客。这辆汽车与你以一种 ...

[2016-11-20]   include "stdio h" include "stdlib h" include "time h" include "math h" *********************************************i ...

OpenAI开辟全新AI音乐领域,发布Jukebox神经网络生产歌曲

[2020-05-19]  日前,外媒报道,人工智能(AI)技术生成的音乐会给人们带来非常奇妙体验。其中有两大原因,第一,这是一个非常吸引人的全新领域;第二,这 ...

50行代码玩转生成对抗网络GAN模型!(附源码)

[2018-07-30]  本文为大家介绍了生成对抗网络(Generate Adversarial Network,GAN),以最直白的语言来讲解它,最后实现一个简单的 GAN 程序来帮助大家加深理解。...

深度神经网络揭示了大脑喜欢看什么

[2019-11-06]  爱吧机器人网编者按:近日,《自然-神经科学》发表了一篇论文,研究人员创建了一种深度人工神经网络,能够准确预测生物大脑对视觉刺激所产 ...