【深度学习】对强化学习的理解(在CartPole-v1游戏下的强化学习)

在上篇文章中【PaddlePaddle】 强化学习(CartPole-v1),我们介绍了如何使用PaddlePaddle在CartPole-v1游戏上实现强化学习,但是对实现思想讲解的不是很多,也不是很清晰。于是,这篇文章主要记录实现上述强化学习的细节以及具体实现思路。

Q-Learning

在传统的图搜索中,我们一般用一个Q-table矩阵来记录每一步学到的经验(我们一般称“经验”为“最大收益”,也就是走这一步的可以获得的最大收益是多少),每走一步就更新一次Q-table,也就是将这一步学到的知识加入Q-table中。在Q-table迭代到一定程度时,Q-table趋于稳定状态,随后,我们使用Q-table来进行决策,因为我们可以通过Q-table了解到每一步怎么走可以获得最大收益。
更新的方法是Bellman Equation,这个算法在上篇文章中已经有所提及,这里就不多讲了,Q-Learning的具体理解可以参考这篇文章:理解Q-learning,一篇文章就够了,这篇文章中有例子,能更好理解一些。

DQN

DQN全称是Deep Q-Learning Network,这个思想是将Q-Learning和深度学习相结合,提倡不使用Q-table记录最大收益Q值,而是使用神经网络预测执行某个action(action=动作)对应的收益值Q。
我们使用神经网络预测在当前状态下,执行所有action得到的Q值。取出最大Q值对应的那个action,作为下一步要执行的动作。也就是取出可以达到最大收益的action作为下一步的动作。

实现思路

第一步:创造记忆库

我们先让系统随机玩几次游戏,通过定义的epsilon-greedy搜索策略,根据训练的进度,选择自动执行动作或者是使用模型预测的动作作为动作输入。通过搜索策略,让训练前期多一些自动动作,训练后期多一些神经网络预测的动作。
然后把在当前状态下执行这个动作的信息(比如:当前状态、动作、执行后的下一个状态、动作的奖励、游戏是否结束等信息)记录到记忆库中,以供后续训练使用。训练的数据是从记忆库中随机提取的。我们在python中使用deque,当数据存满的时候下一数据就会覆盖掉记忆库中的第一个数据。
在填充记忆库的过程中,如果当前状态下执行当前动作导致游戏结束,那我们就将done_data(用来标记游戏是否结束)置为1,reward置为-10,这样的奖励相当于一种惩罚措施。如果当前状态下执行当前动作没有导致游戏结束,那么done_data置为0,reward根据游戏规则自动计算(肯定是一个大于0的奖励)。
当记忆库填充的差不多了,就可以开始训练了,在训练的过程中,记忆库还在被一直填充,只不过在循环中多一个反向传播优化参数的过程。

第二步:搭建神经网络的思路

我们将网络分为两个,一个是反向传播更新参数,我们称之为state_model,一个只进行前向传播我们称之为target_model。但是根据状态值预测Q值的神经网络,他们二者使用的是同一个。

根据状态预测Q值的神经网络DQNetWork

我们定义了一个简单的神经网络,输入的是状态,输出的是在这个状态下,所有动作对应的Q值。对于CartPole-v1游戏来说,有两个动作(向左或者向右移动),所以最终生成的Q值的维度是2,对应于当前状态下分别执行两个动作得到的收益。代码片段如下:

def DQNetWork(ipt, variable_field):
    fc1 = fluid.layers.fc(input=ipt, size=24, act='relu', param_attr=ParamAttr(name='{}_fc1'.format(variable_field)),
                          bias_attr=ParamAttr(name='{}_fc1_b'.format(variable_field)))
    fc2 = fluid.layers.fc(input=fc1, size=24, act='relu', param_attr=ParamAttr(name='{}_fc2'.format(variable_field)),
                          bias_attr=ParamAttr(name='{}_fc2_b'.format(variable_field)))
    # size=2,即输出维度为2,对应两个动作的Q值(收益值)
    fc3 = fluid.layers.fc(input=fc2, size=2, param_attr=ParamAttr(name='{}_fc3'.format(variable_field)),
                          bias_attr=ParamAttr(name='{}_fc3_b'.format(variable_field)))
    return fc3

这样我们就可以得到在一个状态下,分别执行两个action,对应的收益值Q1和Q2。

target_model的作用

target_model只进行前向传播。
再讲state_model之前,我们先来看看target_model,因为state_model的标签是由target_model生成的,具体的方式如下:
1、向DQNetWork中输入执行动作后的下一个状态,获取两个收益值Q1和Q2,这个收益值是next_state的收益。
2、通过Bellman Equation公式计算出当前状态可达的最大收益。具体公式如下:

q_target = reward_data + gamma * best_v * (1 - done_data)

其中reward_data,是执行当前动作的奖励,best_v是Q1和Q2中较大的那个收益值,gamma是best_v(下一状态对应的最大收益值)所占的比重,done_data是这个动作下游戏是否结束。通过Bellman Equation公式的定义我们可知,q_target是执行当前动作获得的reward加上后续状态的收益gamma×best_v,其实就是 当前状态执行当前行动的最大收益(q_target)=显式奖励(reward)+ 潜在收益(gamma×best_v),当前动作的执行不但参考当前动作能获得的奖励,也参考了下一状态的潜在最大收益,使得模型有了前瞻性。q_target即为在当前状态下,执行当前动作可以获得的理论上的最大收益。

如果输入数据的done_data为1,那么q_target就为-10,因为对于done_data=1的数据,我们设置了惩罚reward=-10,可以看到在这个情况下,q_target是一个很小的值,也就是理论上的收益很小,属于惩罚收益。

如果输入数据的done_data为0,那么q_target就会结合显式奖励reward和潜在收益gamma*best_v,计算出在当前状态下,理论上能获得的最大收益。

state_model的作用

state_model用来反向传播优化参数。state_model计算出当前状态下,输入当前动作能得出的预测收益值。我们向DQNetWork输入的是当前状态,预测在当前状态下,分别执行两个操作的收益值Q1和Q2。然后将[Q1,Q2]和输入action的one_hot矩阵进行逐元素相乘,获得在特定输入action下的收益值q_eval。

state_model预测出的结果q_eval要向target_model预测出的q_target靠近。也就是说state_model计算出的q_eval是向理论上的最大收益或者惩罚收益靠近。

我们向DQNetWork输入一个状态,分别执行两个操作,得到两个收益值,我们取两个收益值中较大的那个收益对应的action作为当前状态应该执行的动作。因为在这个动作下,获得的收益最高。

第三步:训练神经网络

前面有提到过,q_eval要向target_model预测出的q_target靠近,所以我们用一个简单的均方误差计算q_eval和q_target之间的差距,并将其作为损失函数进行反向传播,从而优化参数。
在这期间,target_model的DQNetWork网络参数定期根据state_model的DQNetWork参数进行复制,修剪。因为target_model是不进行反向传播来优化参数的。

发布了61 篇原创文章 · 获赞 16 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_41427568/article/details/103552660