DRL---------DQN详解

总结一下DQN.

在传统的强化学习中,例如Q_learning以及Sarsa都需要一张由状态S以及行为A组成的Q表,行为的种类一般较少,比如常见的前进后退两种或上下左右四种等,也就是Q表的列一般还好,可是状态的话就不一定了,有些场景的状态多到可怕,就比如围棋等等,也就是Q表的行数过多,导致的结果就是难以维护如此大的一张Q表。

现在假设有一个函数 f(x)

如果输入状态S就可以得到每个行为的Q值即 Q(S)= f(S)

这不就解决了吗?只要知道这个函数,就不必再去维护那张很大的Q表。

那么怎么找到这一函数模型呢?那就是神经网络了,由于这是深度学习(DL)和强化学习(RL)的结合,所以也叫作DRL,而DQN就是DRL的一种,其是神经网络和Q_learning的一种结合,当然DQN已经有了很多改进版本,先从最基本的DQN说起。

其有两个关键技术:

冻结targetNet

experience replay(经验池)

冻结targetNet就是说每隔一段时间将训练好的神经网络参数保存下来,这里实际就是定义两个完全相同的神经网络Net1和Net2,然后Net1作为实时训练的网络,里面包括loss以及optimizer,而Net2有着与Net1相同的模型结果,但没有loss以及optimizer,没隔一段时间,就将Net1中训练到目前为止的权值和偏置值保存到Net2。

experience replay它存储了带标签的一个个数据样本,然后神经网络通过随机抽样解决了相关性及非静态分布问题。训练神经网络是需要带标签的样本的,experience replay是通过将( S , A , R , S')(当前状态,基于当前状态采取的下一行动,采取A后的奖励值,采取A后到达的下一步状态)作为一个带标签的样本,先看一下Q_learning的更新Q表公式:

DRL---------DQN详解

这里就是将DRL---------DQN详解作为每个样本的label,将DRL---------DQN详解作为S输入后的得到的预测值。

然后loss=DRL---------DQN详解,只不过代码在这里实现的时候,要注意的就是常常不是真真取出行动最大的Q单独值做相加,而是矩阵相减,神经网络的输入是状态S,输出是该状态对应下的所有行为的Q值(当然也可以是这样:输入是状态和采取某一行为,输出是在该状态下采取这一某行为的Q值,这里我们仅按第一种情况说明。)

下面通过一个简单的例子说明:

假设该场景的每个状态有三种动作(a0,a1,a2对应0,1,2)可选

假设我们随机从experience replay抽取出一个batch(大小为4)为:

batch_1 s_1 a_1 r_1 s'_1
batch_2 s_2 a_2 r_2 s'_2
batch_3 s_3 a_3 r_3 s'_3
batch_4 s_4 a_4 r_4 s'_4

 

这里的a_1,a_2,a_3,a_4假设分别为0,1,1,2

r_1,r_2,r_3,r_4假设分别为2,2,2,2

即s_1是通过执行a0到达s'_1的,并且该步得到的奖励值为2,s_2是通过执行a1到达s'_2的并且该步得到的奖励值也为2,依次类推.................

 

那么将该batch的s作为输入到Net1得到输出为prediction:

  a0 a1 a2
prediction_batch_1 4 3 0
prediction_batch_2 5 6 4
prediction_batch_3 1 3 0
prediction_batch_4 0 8 9

 

将batch的 S' 输入到Net2得到输出为target:

  a0 a1 a2
target_batch_1 2 6 0
target_batch_2 4 2 0
target_batch_3 2 4 9
target_batch_4 3 2 5

那么先让label矩阵=prediction,然后根据a_1,a_2,a_3,a_4改变要改变的值即红色的

  a0 a1 a2
label_batch_1 4 3 0
label_batch_2 5 6 4
label_batch_3 1 3 0
label_batch_4 0 8 9

 

接下来(假设DRL---------DQN详解

DRL---------DQN详解

DRL---------DQN详解

DRL---------DQN详解

DRL---------DQN详解

即操作后label为:

  a0 a1 a2
label_batch_1 7.4 3 0
label_batch_2 5 5.6 4
label_batch_3 1 10.1 0
label_batch_4 0 8 6.5

然后label-prediction即为:

  a0 a1 a2
label_batch_1 3.4 0 0
label_batch_2 0 -0.4 0
label_batch_3 0 7.1 0
label_batch_4 0 0 -2.5

 

loss就是要优化这个矩阵,例如tensorflow框架下可以通过tf.reduce_mean(tf.squared_difference(label-prediction))进行优化,以及选什么optimizer都可以属于优化问题了,这里不做讨论。

注意:

(1)通过随机抽取experience replay中几个样本作为一个batch就解决了相关性,因为状态之间原先都是有相关性的,通过随机抽取就打乱了

(2)可以规定experience replay的大小,比如100,那么这个经验池就最多存100条记录,如果再从101时,可以采取将101替换掉现在存储的第一条,依次来不断刷新经验池

(3)每隔多长时间将Net1训练好的参数保存到Net2以及每隔多长时间训练一次神经网络都是可以设定的,这些也属于优化问题了

(4)其实一开始最容易想到的不是DQN这种框架而是只有一个Net1,那么通过将S和S'都输入到Net1来得到相应的输出进行loss计算并反向传播,但是这样就容易导致数据间存在关联性,从而使训练不稳定,所以就再用一个神经网络Net2,即由原来的DRL---------DQN详解改为DRL---------DQN详解

(5)Loss以及Net1更新到Net2的部分是分时间段进行一次,experience replay是实时进行的。

(6)关于为什么能用S'作为标签让S去不断逼近,这个还是要回到Q_learning 算法,可以参考https://blog.csdn.net/weixin_42001089/article/details/81412506,注意里面max下脚表可能是a不是a',但无本质区别意思都是取最大的奖励对应的动作值。

最后一个问题就是怎么根据当前状态S选取下一步的行为,以前是有Q表,现在不需要了,因为已经通过神经网络训练了Net1(这个网络就是开头说的 f(x)),所以只需要将状态S输入到Net1中就可得到所有下一步行动的Q值,再从中挑取做大的就好了。

例如将S输入到Net1后得到:

  a0 a1 a3
S 1 2 3

那么就选a3作为下一步的行动,然后到环境中根据当前状态S和采取的下一步行动就可以得到当前奖励值r和一下步的状态S'啦,是不是很方便,当然记得要用这四个值去更新经验池,以便为训练神经网络提供样本!!!!!!!

流程图大概就是:

DRL---------DQN详解

 

 其中草绿色就是两个关键技术

##############################################################################################

改进DQN版本:Double DQN

改进的地方是在如下地方:

DRL---------DQN详解

它不在选择最大的Q值,即DRL---------DQN详解作为行动值,而是将s'_1所谓Net1的输入得到输出比如输出为:

  a0 a1 a2
s' 6 2 5

 

那么我们就选定a0即DRL---------DQN详解

其他的类似,总结一下就是:

DRL---------DQN详解改为:DRL---------DQN详解

框架为:

DRL---------DQN详解

所以总结一下要改变的主要就是loss部分

###################################################################################################

改进DQN版本:Dueling DQN

这里是在神经网络的输出层做了文章,原来输出层是维数是:

[batch,n_actions]

下载是这样,先预算出两个:

[batch,1]和[batch,n_actions]

然后再合并两者,这里为了避免[batch,n_actions]学习最后结果为0,所以在合并的时候将[batch,n_actions]-E([batch,n_actions]),

它的主要思想就是拆分为2个,一个看作是当前状态的价值[batch,1],另一个是采取行动所得的奖励[batch,n_actions],最后将两者相加即可。对比原先的DQN的[batch,n_actions]这里就是多了一个[batch,1]

所以总结一下要改变的主要就是神经网络模型(输出部分)

######################################################################################################

改进DQN版本:Prioritised Replay DQN

这个是在神经网络抽取样本的时候做文章,原先是使用Sample的随机抽取方法,现在呢?是要将experience replay中的样本按重要性排一下顺序然后按重要性进行抽取,而不是随机,这里的重要性是用'Loss'来体现的,Loss越大,说明越需要学习,那么其重要性就对应的越高。

核心的东西就是在experience replay构建中加了一个TD-error其实就是loss

每个样本除了以前的参数还加上了这一个loss

构建的数据结构是Tree

这里应用:莫凡(https://www.bilibili.com/video/av16921335/?p=20

DRL---------DQN详解

假设我们设定experience replay就是8(就是叶子结点数),其中的数值就是重要等级数。

当进来一个样本的刷新的时候,就从叶子结点左到右依次更新,比如这次更新了上图中红色的这个,下次再有新的样本进来,那么就该替换绿色的啦。当然更新后因为绿色地方的重要等级变了,所以相应的紫色都得改变。

抽取的时候,这里就直接看一下莫凡给的类子吧,很好理解:

DRL---------DQN详解

注意:这里的走法实际就是拿当前的值(比如这里一开始是24)每次在两个孩子结点中选取最大的那条路走,如果最大值对应的路是走左面那就顺着走就可以,如果是右面那么就要减去当前的左孩子节点的值,(如这里的24-13),如此以往直到直到叶子结点。

所以总结一下就是:主要要改一下experience replay中存储方式即memory,可以参考:

https://github.com/jaara/AI-blog/blob/master/Seaquest-DDQN-PER.py当中的Memory Class

其中用到的Tree结构可以参考:

https://github.com/jaara/AI-blog/blob/master/SumTree.py

还有就是learn(就是训练)中记得算abs_errors(errors的绝对值),然后和样本一起更新到memory中。