强化学习之policy-based方法DDPG实现(PyTorch)

参考:

# 理论部分学习李宏毅笔记(github版)+叶强pdf、Morvan
# 实践部分学习叶强gym编写+Q-learning、Sarsa、DQN、DDQN的实战、Morvan
# 刘建平博客园
# DPG、DDPG论文

 

DDPG:Deep Deterministic Policy Gradient

  1. DDPG简介
  2. DDPG算法解析
  3. DDPG实战
  4. 总结与展望

 

1、DDPG简介

DQN算法解决了Q-learning算法无法在连续状态空间下有效处理RL问题,但其无法处理连续动作空间下的R问题,虽然可以将连续动作离散化处理,但是如果动作空间维数过高,比如1个7维的动作,每一个维度离散化为{-1,0,1},那么在使用贪心策略查找使得Q最大对应的动作时,你就需要在3^7=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中我们的行为策略采用\epsilon-greedy策略,而DDPG采用策略网络,因此是在确定性策略基础上增加了O-U噪声(或者李宏毅说的高斯噪声也不错)来增加探索能力。DQN的目标策略是贪心策略,而DDQN也是“贪心策略”,但换了一种思想,参照Silver DPG论文,他的方式是调整网络参数\theta朝着Q值梯度上升的方向。那么当我们在计算TD目标值的时候,输入s',那么此时用策略目标网络选择输出的动作a'一定能弄出一个比较大的Q值来,他以这种方式来取代贪心策略的max用法。根本原因还是在于连续动作空间下,你用max策略是无法选出最大Q值对应的那个动作action的,即globally maximize。

④:在测试的时候,回忆下DQN或者Q-learning,我么是直接采用贪心策略的,去掉了\epsilon-greedy中的探索性,这是我们的目标策略,而且必须是个确定性策略。那么在DDPG中,我们的目标策略就是我们网络直接输出的确定性策略,经过策略网络参数的训练,此时的策略网络能根据输出状态s,输出具有很大Q值得动作a,这其实就几乎等价于贪心策略的效果啦!具体措施就是拿掉噪声的加成,直接输出网络的结果。

 

3、DDPG算法实战

  1. gym环境分析
  2. 核心代码
  3. 结果分析
  4. 效果展示

 

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算法,他尝试从另一个角度去解决问题。

  • 4
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值