PPO
Proximal Policy Optimization
PPO 是什么
想办法让策略变好,但又不能一下子改太猛。
在强化学习里,我们想学一个策略
所以你可以把 PPO 理解成:
一个“带刹车”的策略梯度方法。
TIP
PPO 是一种 on-policy 的 actor-critic 强化学习算法,可以看成是对传统策略梯度方法的一种“保守更新”改造。
它从旧策略采样轨迹,使用 value function 和 GAE 估计 advantage,再通过 importance ratio 构造 surrogate objective。
为了防止同一批数据被反复优化时造成过大的策略漂移,PPO 不直接最大化
其中 clip 的作用不是完全禁止大更新,而是在更新过大时移除额外收益,从而让训练更稳定。
实践中,PPO 还会同时训练 value function,并加入 entropy bonus 鼓励探索,因此完整目标通常由 policy loss、value loss 和 entropy 三部分构成。
和 TRPO 相比,PPO 放弃了更复杂的 trust-region 约束求解,换来了更简单、更易实现、但通常仍然很稳的训练方式。
PPO 的核心不是“直接让奖励变大”,而是:用旧策略采到的数据,谨慎地调整新策略,让好动作概率上升、坏动作概率下降,但不要一次改太猛。
从策略梯度讲起
PPO 不是凭空出现的,它是从最基础的 policy gradient 一路长出来的。
强化学习里最根本的目标是最大化策略的期望回报:
这里:
是策略参数; 是一整条轨迹; 是这条轨迹的总回报。 表示“轨迹是由当前策略采样出来的”,所以策略一变,采到的数据分布也会变。这就是后面 PPO 为什么要小心更新的根源。
也就是说,我们真正想做的是:
调整参数
,让策略平均拿到更高的回报。
策略梯度方法告诉我们,可以直接对这个目标做梯度上升。最基本的 policy gradient 形式是:
这里的
这个式子表达的意思其实很朴素:
- 如果一个动作比平均水平更好,也就是
,那就增加它的概率; - 如果一个动作比平均水平更差,也就是
,那就降低它的概率。
所以 policy gradient 的精神就是:
好动作多做,坏动作少做。
TIP
“概率本身的梯度” 可以写成 “概率 × log 概率的梯度”。
在 RL 中,这么写可以把求和变成期望:
利用恒等式变成:
也就是:
这就很方便了:我们不用枚举所有动作,只要从策略里采样动作,就能估计这个梯度。
为什么不能直接一直优化这个目标
看起来很自然,但这里有一个大坑。
如果我们直接把 policy gradient 写成一个“损失函数”,比如
然后拿着同一批轨迹反复做很多步梯度上升,往往会出事。
原因是:
这批数据是旧策略采出来的,不是新策略采出来的。
一旦你更新了参数,当前策略就不是生成这批数据的那个策略了。此时你再继续拿同一批旧数据狠狠干,就会越来越偏离真实目标,最后可能把策略推崩。
PPO 原论文在背景部分就明确指出:对同一批轨迹做多步优化,经验上经常会导致破坏性的超大策略更新。PPO 想解决的正是这个问题。
Advantage 到底是什么
advantage function 的定义是:
它表示:
这个动作到底比“当前策略在这个状态下的平均表现”好多少。
其中
所以:
,说明这个动作比平均水平好; ,说明这个动作比平均水平差; ,说明它大概就是平均水平。
这也是为什么 advantage 特别适合拿来做 policy update:它直接告诉你“该鼓励还是该打压”。
TIP
比如某个状态下平均能得 10 分,而你选的动作最后预计能得 14 分,那么 advantage 是 4,说明这个动作值得鼓励。
如果预计只能得 7 分,那么 advantage 是 -3,说明这个动作要被压低概率。
Value function 和 baseline 为什么会出现
如果你直接用整条轨迹的总回报做权重,方差通常很大,学习会很抖。
一个经典技巧是加 baseline。最常见的 baseline 就是 value function:
于是我们不再问“这次回报有多大”,而是问:
这次结果比我原本预期的好还是差?
这就把 return 变成了 advantage,也就是
这样做的好处是:
不改变期望梯度,但通常能显著降低方差。
直觉上也很好理解:
- 如果结果和预期差不多,那就别太激动;
- 真正值得大改策略的,是那些“明显比预期好”或“明显比预期差”的动作。
GAE 是怎么来的
PPO 实际应用里最常用的 advantage 估计方法之一就是 GAE,也就是 Generalized Advantage Estimation。
先定义 TD residual:
这个量可以理解成:
一步现实结果 - 一步价值预测。
更通俗的讲:
真实看到的一步结果 − 原本对当前状态的预测
其中
所以
如果 value function 很准,那么
但只看一步会偏;看很长的回报又会方差大。所以 GAE 采取折中:把很多步的 TD 误差按指数衰减加起来。
GAE 的定义是:
就是把很多步的 TD residual 加起来。
GAE 公式推导
先定义
把前几项展开看一下:
GAE 的想法是,把这些不同步长的估计做指数加权平均:
把上面的展开式代进去,然后把同类项收集,就会得到:
这就是 GAE 论文给出的简洁形式。
到底在控制什么
如果
它方差小,但偏差可能大。
如果
它偏差更小,但方差更大。
所以
这也是为什么 PPO 实现里常看到像
从旧策略到新策略:为什么会出现 ratio
PPO 真正的关键转折点在这里。
我们想更新策略,但手里拿到的数据是旧策略
对同一个动作,新策略比旧策略更想做,还是更不想做?
这时会用到一个非常经典的东西:importance sampling ratio。
定义:
这个比值很好理解:
- 如果
,说明新策略更想做这个动作; - 如果
,说明新策略更不想做这个动作; - 如果
,说明新旧策略在这个动作上的态度一样。
于是,旧策略数据上的 surrogate objective 可以写成:
这通常叫 surrogate objective。
这个目标的直觉
如果
如果
听起来完全合理。
但问题是:
如果你只顾着把这个目标做大,很容易把策略改得太远。
因为这个 surrogate objective 本质上只是“在旧策略附近”的一个局部近似。离得太远,它就不可靠了。
TRPO 为什么会出现
在 PPO 之前,一个很有代表性的思路是 TRPO,也就是 Trust Region Policy Optimization。
TRPO 的想法是:
既然 surrogate objective 只在旧策略附近可靠,那我就强行限制每次更新不能离旧策略太远。
它写成约束优化就是:
也就是说,一边想让 surrogate objective 变大,一边要求新旧策略之间的平均 KL divergence 不超过阈值
这个想法很漂亮,但工程上比较重,因为它涉及约束优化、二阶近似、共轭梯度等技巧,实现复杂。
PPO 的核心想法:别搞那么重,直接 clip
PPO 的核心思想就是:
我也想让新策略别离旧策略太远,但我不想像 TRPO 那样搞一个重型约束优化。
于是 PPO 提出一个更简单的做法:直接在 objective 里把 ratio 卡住。
PPO-Clip 的核心目标是:
这里的
这个式子看起来吓人,但其实只是在做一件事:
如果 ratio 改得太多,就不给你继续赚这部分收益。
clip 到底在干什么
这是 PPO 最容易看懵、但其实最该弄懂的一步。
先看
这说明这个动作是好动作。我们当然希望新策略提高它的概率,所以想让
如果没有限制,最自然就是一直把
但 PPO 说:
可以往上推,但推到
以后,再继续推,objective 不再继续奖励你。
因为这时候:
于是目标就最多只会按
再看
这说明这个动作是坏动作,我们希望新策略降低它的概率,也就是让
PPO 同样说:
可以往下压,但压到
以后,再继续压,objective 也不再继续奖励你。
所以不管是奖励好动作还是惩罚坏动作,PPO 都在做同一件事:
限制单次更新不要太激进。
用一个小数字例子理解
假设旧策略下某动作概率是
那么
如果
这时如果该动作的 advantage 为正,本来
来算。
也就是说,PPO 会告诉你:
这动作是好,但你别一次把它的概率抬太多。
反过来,如果它是坏动作,旧概率
如果
所以 clip 真正干的事不是“完全禁止大更新”,而是:
取消大更新带来的额外激励。
为什么公式里要取
对于:
为什么是取最小值?
答案是:
因为 PPO 想要一个偏保守、偏悲观的目标。
原论文就明确说,这个 clipped objective 是 unclipped objective 的一个 lower bound,也就是一种 pessimistic bound。
它的思路是:
- 如果修改方向对我们有利,但改得太多,那就按 clip 后的更保守版本算;
- 如果修改方向对我们不利,那就老老实实把不利后果算进去。
宁可保守一点,也不要把策略一步推飞。
PPO-Penalty 和 PPO-Clip 的关系
PPO 其实有两个主要变体。
一个是 PPO-Penalty,写法更接近 TRPO 的软约束版本:
也就是直接把 KL penalty 加到目标里。
另一个就是最常见的 PPO-Clip。OpenAI Spinning Up 也明确说,实际大家最常讨论和使用的是 PPO-Clip。
直觉上可以这样区分:
PPO-Penalty:用 KL 项“罚”你走太远;PPO-Clip:直接把 ratio 的可盈利区间截住。
工程上大家更爱 PPO-Clip,因为更简单、也通常更稳。
PPO 里的 actor 和 critic 到底各干什么
PPO 通常是一个 actor-critic 方法。
其中:
actor就是策略网络; critic就是价值网络。
两者分工很明确。
策略网络负责“怎么选动作”。
价值网络负责“现在这个状态大概值多少钱”,也就是帮助估计 advantage。
所以 critic 不是直接输出动作,它更像一个老师,负责告诉 actor:
你刚才那个动作,和平均水平相比,到底是赚了还是亏了。
这也是为什么 PPO 和 GRPO 最大的区别之一,就是 GRPO 删掉了 PPO 里的 critic/value model,改成组内相对奖励来构造 advantage。
13. PPO 的完整训练目标
在真实实现里,PPO 通常不只有 policy loss。
原论文给出的组合目标是:
其中:
是策略更新项; 是 value function 的回归误差; 是 entropy bonus,用来鼓励探索。
value loss 通常是平方误差:
entropy bonus 为什么有用
如果策略太快变得特别确定,探索就会变差。
entropy 大表示策略还比较随机,说明它还在探索;entropy 太小表示策略已经很“死板”了。于是加一项 entropy bonus,就是在告诉模型:
先别那么快把所有概率压成 0 和 1,保留一点探索。
PPO 的完整训练流程
如果把 PPO 忘掉一切细节,只记训练循环,可以记成下面这几步。
先用当前旧策略
然后用这批轨迹计算:
- reward-to-go;
- value targets;
- advantage,通常用 GAE。
接着固定这批旧数据,计算旧策略下的 log-prob,形成 importance ratio:
然后对 clip objective 做多轮小步 SGD 或 Adam 更新。
与此同时,再训练 value network 去拟合 return 或 value target。
最后,把更新后的策略当成新的 old policy,再去环境里采下一批数据。
为什么 PPO 是 on-policy
因为它主要使用的是“当前旧策略刚采出来的数据”,而不是像 DQN、SAC 那样长时间反复使用一个大的 replay buffer。
所以 PPO 属于典型的 on-policy 方法。
这类方法一般优点是训练更稳定、理论更顺;缺点是样本利用率通常不如很多 off-policy 方法。
你可以把 PPO 理解成什么
如果非要找一个特别通俗的比喻,PPO 很像:
你每次根据最近一次考试结果调整学习策略,但调整幅度不能太大。
如果某种做题方法最近明显有效,那下次更倾向于继续用;
如果某种方法最近明显无效,那下次就少用。
但你不会因为一次考试表现好,就把整套学习方法完全推翻重来。PPO 的 clip 就是在干这个事:
允许改,但别一次改过头。
总结
PPO = 用 clipped objective 限制策略每次不要改太猛的 actor-critic 策略梯度方法。
importance ratio:
PPO-Clip 核心目标:
GAE: