深度强化学习(四):PPO(Proximal Policy Optimization ...
PPO是OpenAI spinning up下的第三个算法,翻译为“近端策略优化”。TRPO是同轨策略(on-policy)算法,且可以在离散的和连续的环境中使用。它是又一个基于策略梯度方法的算法,同样由John Schulman提出。PPO与TRPO旨在解决相同的问题:在策略梯度定理的步长\alpha的选取中,如何选取合适的步长,使得更新的参数尽可能对应最好的策略,但也不至于走得太远,以至于导致性能崩溃。PPO也继承了TRPO的核心思想:引入重要性采样,提高样本效率;同时,通过某种方式来约束新旧策略间的差异不要太大。不同的是,TRPO 试图用复杂的二阶方法解决这个问题(对目标函数采取一阶近似,约束条件采取二阶近似),然而PPO采用了一系列的一阶方法(Clip),它们使用一些其他技巧来使新策略接近旧策略。PPO在算法上更加简单,且效果不输于TRPO算法的效果。
在2017年OpenAI的《Proximal Policy Optimization Algorithms》中,介绍了PPO的两种变体:PPO-惩罚(PPO-penalty, PPO1)和PPO-截断(PPO-Clip, PPO2)。下面将逐一对其进行介绍。
PPO-惩罚(PPO1)
回顾一下,TRPO算法对以下目标函数进行优化问题的求解: \underset{\theta}{\operatorname{maximize}} \hat {\mathbb{E}}_{t}\left[\frac{\pi_\theta(a_t \mid s_t)}{\pi_{\theta_{old}}(a_t \mid s_t)} A_{t}\right] \\\text { subject to } \hat {\mathbb{E}}_{t}\left[{\mathrm{KL}}\left(\pi_{\theta_{\text {old }}}(\cdot \mid s) \| \pi_\theta(\cdot \mid s)\right)\right] \leq \delta\tag{1}这里,\theta_{old}是更新之前的策略参数向量,A_t是在时刻t的优势函数估计,期望\hat {\mathbb E}_t是在采样和优化之间交替的算法中,有限批次样本的经验平均值。求解的过程采用到了共轭梯度和线性搜索的方式。
TRPO在目标函数中,另外增加了一个约束条件。在推导该式的过程中, 涉及到了一个将KL散度作为惩罚项的极值问题,转化为KL散度作为约束条件的优化问题的过程。将KL散度作为惩罚项的问题,公式如下:\underset{\theta}{\operatorname{maximize}} \hat{\mathbb{E}}_t\left[\frac{\pi_\theta\left(a_t \mid s_t\right)}{\pi_{\theta_{\text {old }}}\left(a_t \mid s_t\right)} \hat{A}_t-\beta \mathrm{KL}\left[\pi_{\theta_{\text {old }}}\left(\cdot \mid s_t\right), \pi_\theta\left(\cdot \mid s_t\right)\right]\right]\tag{2}然而,因为权重\beta难以选择和调整的问题,因此TRPO并没有采取这样的方式进行目标函数的设定。
但PPO-惩罚(PPO1)用拉格朗日乘数法直接将KL散度的限制放入了目标函数,因此变成了一个无约束的优化问题,在迭代的过程中不断更新KL散度前的系数。这里,使用几个阶段的小批量SGD,优化KL惩罚目标,其更新方式即为公式(2)。
为了对\beta进行动态调整,作者提出了自适应KL散度(adaptive KL divergence)的思想。具体做法是,在每个epoch对KL惩罚目标进行优化后,计算d=\hat{\mathbb{E}}_t\left[\mathrm{KL}\left[\pi_{\theta_{\text {old }}}\left(\cdot \mid s_t\right), \pi_\theta\left(\cdot \mid s_t\right)\right]\right]:
[*]如果d<\frac{\delta}{1.5},则\beta \leftarrow \frac{\beta}{2}。
[*]如果d>1.5 \delta,则\beta \leftarrow 2{\beta}。
[*]否则,\beta保持不变。
在这里,更新的\beta用于下一次迭代时的参数更新。
PPO1的伪代码如下:
说明:
Line2-4:采样数据、计算优势函数(GAE的方式)和策略初始化。
Line5-8:Actor网络(策略网络)更新,采用公式(2)。参数M的含义为策略网络的参数个数。
Line9-12:Critic网络(价值函数网络)更新。通过Critic网络的预测值为V_\phi(s_t),Label为\sum_{t^{\prime}>t} \gamma^{t^{\prime}-t} r_{t^{\prime}}。
Line13-17:对权重\beta进行调整。
PPO-截断(PPO2)
PPO2在限制新的策略参数与旧的策略参数的距离上,相比于PPO1更加直接。区别于PPO1使用KL散度的方式进行限制,PPO2直接在目标函数上进行限制:L^{C L I P}(\theta)=\hat{\mathbb{E}}_t\left[\min \left(r_t(\theta) \hat{A}_t, \operatorname{clip}\left(r_t(\theta), 1-\epsilon, 1+\epsilon\right) \hat{A}_t\right)\right]\tag{3}其中, r_t(\theta)=\frac{\pi_\theta\left(a_t \mid s_t\right)}{\pi_{\theta_{\text {old }}}\left(a_t \mid s_t\right)} 称为概率比,易得r_t(\theta_{old})=1。\operatorname{clip}\left(r_t(\theta), 1-\epsilon, 1+\epsilon\right)指的是将r_t(\theta)限制在的范围内。\epsilon为超参数,表示进行截断操作的范围,一般取\epsilon=0.2。这样,就始终保证了新旧策略的比值在的范围内,保证了两个策略的差距不会太大。
PPO2中,较为精妙的一点是在\text{clip}操作后乘了\hat A_t(以下用A表示),而优势函数A是有正负的。如下面两张图所示, \frac{\pi_\theta\left(a_t \mid s_t\right)}{\pi_{\theta_{old}}\left(a_t \mid s_t\right)} 是绿色的线;\operatorname{clip}\left(\frac{\pi_\theta\left(a_t \mid s_t\right)}{\pi_{\theta_{old}}\left(a_t \mid s_t\right)}, 1-\varepsilon, 1+\varepsilon\right) 是蓝色的线;在绿色的线与蓝色的线中间,我们要取一个最小的结果。如左图所示,假设前面乘上的项 A 大于0,取最小的结果,就是红色的这条线。如右图所示,如果 A 小于0,取最小结果的以后,就得到红色的这条线。下面来做一个详细的讨论。
[*]如果 A>0,也就是某一个状态-动作二元组相比于状态价值函数V更好,我们就希望增大这个状态-动作二元组的概率。也就是,我们想让 \pi_\theta\left(a_t \mid s_t\right) 越大越好,但它与 \pi_{\theta_{\text {old }}}\left(a_t \mid s_t\right) 的比值不可以超过 1+\epsilon 。如果超过 1+\epsilon,新策略与旧策略之间的差距就会过大而产生问题。所以在训练的时候,当 \pi_\theta\left(a_t \mid s_t\right) 被训练到\frac{\pi_\theta\left(a_t \mid s_t\right)}{\pi_{\theta_{old}}\left(a_t \mid s_t\right)}>1+\epsilon时,训练就会停止。
[*]如果 A<0,也就是某一个状态-动作二元组相比于状态价值函数V更差,那么我们希望把 \pi_\theta\left(a_t \mid s_t\right) 减小。如果 \pi_\theta\left(a_t \mid s_t\right) 比 \pi_{\theta_{old}}\left(a_t \mid s_t\right) 还大,那我们就尽量把它减小,减到 \frac{\pi_\theta\left(a_t \mid s_t\right)}{\pi_{\theta_{old}}\left(a_t \mid s_t\right)} 是 1-\epsilon 的时候停止, 此时不用再减得更小,即新旧策略之间的差距不会过大。
在spinning up的源码中,目标函数被改写成了以下形式:L\left(s, a, \theta_k, \theta\right)=\min \left(\frac{\pi_\theta(a \mid s)}{\pi_{\theta_k}(a \mid s)} A^{\pi_{\theta_k}}(s, a), \quad g\left(\epsilon, A^{\pi_{\theta_k}}(s, a)\right)\right)\tag{4}其中,g(\epsilon, A)= \begin{cases}(1+\epsilon) A & A \geq 0 \\ (1-\epsilon) A & A<0\end{cases}\tag{5}不难看出,两者在数学上是等价的。
虽然Clip操作已经很大程度上限制了新策略与旧策略之间的差距,但最终新旧策略依然有可能相差太远。不同的PPO算法采用了不同的技巧来避免这种情况。在spinning up的代码框架中,采用了提前停止的策略。具体来说,如果新策略和旧策略的平均KL散度超过了某个阈值,则停止采取更新参数的步骤。
PPO2的伪代码如下:
代码框架看上去就非常简洁。Line3-5是每个epoch的初始化操作,Line6采用Adam优化器的方式对Actor网络的参数进行更新,Line7对Critic网络的参数进行更新。
说明:本文是作者在学习算法过程中的笔记与总结,参考了一些博客和答主的文章,在此表示大大的感谢!如有侵权,请联系删除。
页:
[1]