参考:
# 理论部分学习李宏毅笔记(github版)+叶强pdf、Morvan
# 实践部分学习叶强gym编写+Q-learning、Sarsa、DQN、DDQN的实战、Morvan
# 刘建平博客园
# DPG、DDPG论文
DDPG:Deep Deterministic Policy Gradient
- DDPG简介
- DDPG算法解析
- DDPG实战
- 总结与展望
1、DDPG简介
DQN算法解决了Q-learning算法无法在连续状态空间下有效处理RL问题,但其无法处理连续动作空间下的R问题,虽然可以将连续动作离散化处理,但是如果动作空间维数过高,比如1个7维的动作,每一个维度离散化为{-1,0,1},那么在使用贪心策略查找使得Q最大对应的动作时,你就需要在=2187个结果里面寻找,这无疑太消耗运算资源了,且离散化可能会丢失一些重要的动作信息。因此解决连续动作问题最好的方法就是policy-based方法,其基本思想就是直接去输出我的最优策略,不需要先通过求出最优值函数,然后经过贪心策略求出最优动作。
policy-based方法最初版本是REFORCEMENT算法,但是其更新是回合更新,且方差较大,收敛不稳定,因此引入Actor-Critic方法,比如A2C、QAC等,其不同在于Critic是优势函数或者是Q函数,AC采用步进更新,且引入TD算法对Q这种期望进行估计,这无疑是一个很大的进步。
AC框架固然是好,但是其未解决输入的连续性以及在估计值函数时,TD目标是和Q估计值同时变化导致难以收敛的问题,这是第一个问题。此外,由于我们采用的都是随机策略,比如离散动作空间采用softmax策略,连续动作空间采用高斯策略,但是Sutton在DPG这篇文章中证明,stochastic policy需要对状态空间和动作空间同时采样,对off-policy策略需要IS修正因子修正偏差,这是第二个问题。
针对第一个问题,我们需要引入DQN来解决,以off-policy策略的Q-learning来估计Q值。针对第二个问题,我们需要引入DPG,即确定性策略梯度。
两者结合就是DDPG=Deep + DPG,一种基于AC框架,off-policy,确定性策略,DQN来估计Q真实值的组合型算法。
DDPG论文:点这里
2、DDPG算法解析
如上图框架结构所示,将Nature DQN的思想与policy gradient结合在一起,构建四个网络:策略网络、策略目标网络、Q估计网络、Q目标网络。
具体网络结构如下:
Critic网络(Q网络):输出为1个神经元Q(s,a),是一个标量,离散动作常用另一种值函数近似器是输入为状态,输出为各个动作的Q值。
Actor网络:输出个数为动作的特征维数,每个维度下都是连续的值,比如拉力[-2,2]。是一个向量
当然也可以采用CNN、RNN等网络结构,这里只是最简单的入门结构。
DDPG算法伪代码如下:
Note:
①:DDPG仿照DQN,主网络参数到Target网络参数有2种赋值方式,一种是软更新,或者说微更新,即每次只更新一点点(相当于DQN中的过一阵子再更新),另一种是硬更新,即算法刚开始的时候,保持主网络和Target网络参数完全一致。
②:也是仿照DQN,DDPG设置了Experience Reply,勇于打破数据相关性,便于nn学到东西。
③:和DQN不用,DQN中我们的行为策略采用-greedy策略,而DDPG采用策略网络,因此是在确定性策略基础上增加了O-U噪声(或者李宏毅说的高斯噪声也不错)来增加探索能力。DQN的目标策略是贪心策略,而DDQN也是“贪心策略”,但换了一种思想,参照Silver DPG论文,他的方式是调整网络参数朝着Q值梯度上升的方向。那么当我们在计算TD目标值的时候,输入s',那么此时用策略目标网络选择输出的动作a'一定能弄出一个比较大的Q值来,他以这种方式来取代贪心策略的max用法。根本原因还是在于连续动作空间下,你用max策略是无法选出最大Q值对应的那个动作action的,即globally maximize。
④:在测试的时候,回忆下DQN或者Q-learning,我么是直接采用贪心策略的,去掉了-greedy中的探索性,这是我们的目标策略,而且必须是个确定性策略。那么在DDPG中,我们的目标策略就是我们网络直接输出的确定性策略,经过策略网络参数的训练,此时的策略网络能根据输出状态s,输出具有很大Q值得动作a,这其实就几乎等价于贪心策略的效果啦!具体措施就是拿掉噪声的加成,直接输出网络的结果。
3、DDPG算法实战
- gym环境分析
- 核心代码
- 结果分析
- 效果展示
3.1、gym环境分析
本次我将对gym环境中自带的Pendulum-v0以及叶强大佬编写的基于gym环境的连续动作空间版本的Puckworld进行实战。
3.1.1、Pendulum-v0
为了减小实施奖励r带来的方差,我将r进行了归一化处理。
这个环境输出的动作是个1维的向量,详情请参考我的另一篇关于Pendulum的简介:2.1节环境介绍
3.1.2、Puckworld_continue
详情请参考我的另一篇关于Puckworld的简介:四、任务结果分析,唯一不同的一点是,那个版本的puckworld采用离散的动作空间,即上、下、左、右,而我们的Puckworld_continue输出的动作是一个1维2特征的向量,第一个特征代表水平方向的推力大小,第二个特征代表垂直方向的推力大小,大小范围在[-1,1],如下图所示:
3.2、核心代码
def learning(self):
# 随机获取记忆里的Transmition
trans_pieces = self.sample(self.batch_size, per_off=True)
s0 = np.vstack([x.s0 for x in trans_pieces])
a0 = np.array([x.a0 for x in trans_pieces])
r1 = np.array([x.reward for x in trans_pieces])
# is_done = np.array([x.is_done for x in trans_pieces])
s1 = np.vstack([x.s1 for x in trans_pieces])
# 优化评论家网络参数
a1 = self.target_actor.forward(s1).detach()
next_val = torch.squeeze(self.target_critic.forward(s1, a1).detach())
# y_exp = r + gamma*Q'( s2, pi'(s2))
y_expected = torch.from_numpy(r1) + self.gamma * next_val
y_expected = y_expected.type(torch.FloatTensor)
# y_pred = Q( s1, a1)
a0 = torch.from_numpy(a0) # 转换成Tensor
y_predicted = torch.squeeze(self.critic.forward(s0, a0))
# 使用smooth loss
loss = nn.SmoothL1Loss()
# loss_critic = F.smooth_l1_loss(y_predicted, y_expected)
loss_critic = loss(y_predicted, y_expected)
self.critic_optimizer.zero_grad()
loss_critic.backward()
self.critic_optimizer.step()
# 优化演员网络参数,优化的目标是使得Q增大
pred_a0 = self.actor.forward(s0) # 直接使用a0会不收敛
# 反向梯度下降(梯度上升),以某状态的价值估计为策略目标函数
loss_actor = -1 * torch.mean(self.critic.forward(s0, pred_a0))
self.actor_optimizer.zero_grad()
loss_actor.backward()
self.actor_optimizer.step()
# 软更新参数
soft_update(self.target_actor, self.actor, self.tau)
soft_update(self.target_critic, self.critic, self.tau)
return (loss_critic.item(), loss_actor.item())
这里需要注意一点是,根据Silver在DPG一文中对于Actor更新的公式,动作pred_a0应该来自于经验池中的s0经过Actor网络的输出,而不是经验池中的a0。
3.3、结果分析
3.3.1、Pendulum-v0
上图是DDPG算法在Pendulum-v0的表现,从reward的学习曲线看,由于立杆时候奖励在0附近,曲线在200个episodes之后,开始将累计奖励稳定在-20附近而每个epsiode都是满200步,故每一步的奖励都在-0.1,也就是说,抛去初始状态的大负奖励不谈,杆子是能直接树立起来的,DDPG还是学到了将杆子树立起来的参数。
训练结束后,我将1000个epsiode训练之后的Agent进行测试,下图是测试结果:
为了更好展现DDPG的表现,下图是在50个epsiode上的测试结果:可见每一次都能从随机的初始位置直接竖立!
3.3.2、Puckworld_continue
上图是DDPG在Puckworld上的表现效果,从reward_steps来看,因为puckworld中,奖励是根据小球与目标的距离决定的,如果小球一直未找到目标,那么累计的奖励就会负的很厉害,反之,奖励会大很多,注意,小球在400个epsiode之前,步数很大,但是奖励很小,并不代表着收敛了,很有可能是小球一直在目标很近的地方打转,并没有追上目标。收敛的地方差不多在400个epsiode之后,那时候步伐稳定在400步左右,而奖励也很小。
在训练了1000个epsiode之后,在50个epsiode上的测试效果:
从上图可以看出,小球追逐目标的效果还是很明显的。
3.4、效果展示
为了更直观体现DDPG在Puckworld上的表现,动图如下:
4、总结与展望
从上述2个实验可以看出,DDPG对于连续动作空间的RL问题处理的效果还是不错的,但是并没有达到完美,因为研究发现,DDPG会导致Q值被显著高估,而Q值的准确性直接影响了Actor网络的训练,Q值高估问题如下所示:
另外,DDPG在超参数和其他类型的调整方面经常很敏感。
针对以上2个问题,TD3算法可以进行有效处理,即双延迟DDPG(Twin Delayed DDPG,简称TD3)
因此,下一步的提升工作可以朝着TD3。
另外和DDPG并驾齐驱的还有A3C算法,他尝试从另一个角度去解决问题。