前言:为什么是 PPO?
在深度强化学习(Deep RL)的浩瀚星空中,算法多如牛毛:DQN、DDPG、A3C、SAC......但如果你问任何一位资深的算法工程师:“如果我只想快速把一个新环境跑通,或者要做 RLHF(人类反馈强化学习)来训练大语言模型,我该选哪个算法?”
答案几乎永远是同一个:PPO (Proximal Policy Optimization)。
它是 OpenAI 的“默认首选”算法,它支撑了 ChatGPT 的诞生,它在性能和复杂度之间找到了近乎完美的平衡。
但这并不意味着 PPO 很简单。很多同学看论文觉得懂了,一写代码就发散;或者代码跑通了,却不知道为什么要加那一行 clip。
先把结论放前面一句:PPO 的核心就是一句话——“每次只改一点点策略,别把旧策略推得太远”。
今天,我们就剥开公式的外衣,从直觉到数学,深入剖析 PPO 的灵魂。
一、 痛苦的根源:步长(Step Size)之殇
要理解 PPO,我们必须先回到它的前身——策略梯度(Policy Gradient, PG)。
PG 的核心思想非常直观:让智能体去玩游戏,如果某一步操作带来了高回报,我们就调整神经网络的参数,增加在这个状态下做出这个动作的概率;反之则降低概率。
更新公式通常长这样:
这里有一个致命的超参数:学习率 (也就是步长)。
在监督学习(如分类猫狗)中,步长选大了,大不了 Loss 震荡一下。但在强化学习中,步长选大了是非常严重的。
朴素策略梯度有个大问题:更新步子太大时,策略可能一下子变形严重,性能直接掉崖。

你可以想象:
-
采样数据时,用的是「旧策略」。
-
更新参数时,好几步梯度迭代后,变成「新策略。
-
如果改动太大,新策略看到相同状态时,选动作的分布已经完全不一样了。
-
但我们用来更新的那批数据,其实是旧策略下采的,已经不再「代表」当前策略的行为了。
于是会出现这样的现象:
一开始训练得很好,reward 往上冲;然后某次更新特别激进,策略突然变差,reward 掉到很低,甚至学到奇怪行为。
1. 掉下悬崖(Cliff Collapse)
强化学习的数据是由策略(Policy)产生的。
-
如果你步子迈太大,参数
更新过猛,策略
就会发生剧变。
-
剧变的策略可能会导致智能体在接下来的互动中表现极差(比如一直原地转圈)。
-
最可怕的是:因为策略变傻了,它采集回来的下一批数据全是垃圾。
-
神经网络拿着垃圾数据训练,只会变得更傻。
这是一个不可逆的恶性循环,我们称之为“策略坍塌”。
2. 样本效率极低(Sample Efficiency)
传统的 PG 是 On-Policy(同策略) 的。意思是:我必须用当前的策略去玩游戏,产生的数据只能用一次,更新完参数就得扔掉。因为参数一变,刚才的数据分布就不对了。这导致训练非常慢。
于是,PPO 的两大核心使命诞生了:
-
稳: 无论你怎么调参,我要限制你的更新幅度,确保新策略不偏离旧策略太远(Trust Region,信任区域)。
-
快: 我想让旧策略采集的数据,能被新策略重复利用(这就引入了 Importance Sampling)。
二、 从 TRPO 到 PPO:奥卡姆剃刀的胜利
在 PPO 之前,大神 Schulman 先提出了 TRPO (Trust Region Policy Optimization)。
TRPO 的数学极度优美。它直接告诉求解器:“请帮我找到提升最大的新参数,但前提是:新旧策略的 KL 散度(衡量两个分布差异的指标)不能超过 。”
然而,TRPO 有一个巨大的工程缺陷:它太慢了。计算 KL 散度的二阶导数(Hessian Matrix)和共轭梯度法,对于大规模神经网络来说简直是噩梦。
PPO 的出现,就是为了用“一阶的方法”(类似普通的 SGD/Adam),去模拟 TRPO 的“二阶约束”。
PPO 说:“别算什么 Hessian 矩阵了,我用一个最简单的数学技巧——剪裁(Clipping),只要发现新策略跑偏了,我就把梯度切断,不再奖励它。”
这就好比给赛车手装了一个电子限速器:你想踩油门尽管踩,但只要仪表盘显示偏离赛道超过 20%,油门自动失效。
这就是 PPO 的核心直觉:由简至繁的智慧。
三、 PPO 的数学灵魂:裁剪代理目标 (Clipped Surrogate Objective)
在上一部分我们提到,为了让旧数据能被重复利用(Off-Policy),我们需要引入重要性采样 (Importance Sampling)。这就要讲到 PPO 的核心变量:概率比率 (The Probability Ratio)。
1. 衡量变化的尺子:
我们要更新策略,实际上就是要调整参数 。在时间步
,面对状态
,动作
的概率从旧策略的
变成了新策略的
。
我们定义这个比率为:
这个比率非常直观:
-
如果
,说明新策略比旧策略更倾向于做这个动作。
-
如果
,说明新策略比旧策略更排斥这个动作。
-
如果
,说明策略没变。
2. 原始的(危险的)目标函数
如果我们直接用这个比率来做优化,我们的目标大概长这样:
其中 是优势函数 (Advantage),代表这个动作比平均水平好了多少。
仔细看这个公式,危机四伏:
如果 是正的(好动作),网络会拼命增大
(即提高该动作概率)。如果没有约束,
可能瞬间飙升到 100、1000... 这意味着新旧策略差异巨大,直接破坏了“信任区域”,导致我们在第一部分说的“掉下悬崖”。
3. PPO 的杀手锏:Clip 机制
为了防止 跑偏,PPO 修改了目标函数。这也是整个算法最精华的公式:
这个公式看着很吓人,其实逻辑只有两层:
-
Clip(截断): 强制把
限制在
的范围内。
通常取 0.2,也就是说,只允许概率变化幅度在 0.8 到 1.2 倍之间。
-
Min(取极小值): 在“原始目标”和“截断目标”之间取一个更小的(更悲观的)。
为什么要这么做?我们分两种情况通过图解逻辑来剖析:
情况 A:动作是好的 (
)
比如在《王者荣耀》里,你残血反杀了一波,Advantage 是正的大数。
我们希望增加这个动作的概率(即增大 )。
-
如果不截断: 梯度会一直推着
往无穷大跑,容易过拟合。
-
PPO 的逻辑:
-
如果
还没超过
(比如 1.1):这在安全区域内,正常奖励,让你多增加一点概率。
-
如果
超过了
(比如 1.3):停! 此时
clip生效,目标函数被锁死在。这意味着函数变平了,梯度变为 0。
-
-
潜台词: “我知道这个动作很棒,但你提升的概率已经够多了(超过 1.2 倍了),不要再贪婪了,保持现状就好。”
情况 B:动作是坏的 (
)
比如你从悬崖上跳下去了,Advantage 是负数。
我们希望减小这个动作的概率(即减小 )。
-
如果不截断: 网络可能会把概率直接降到 0,这毁坏了策略的分布。
-
PPO 的逻辑:
-
如果
还没低于
(比如 0.9):安全,允许你继续降低概率。
-
如果
低于了
(比如 0.7):停!
clip生效,目标函数被锁死在。
-
-
潜台词: “我知道这个动作很烂,但你降幅已经触碰底线(0.8 倍)了,别把这个动作彻底杀绝,留一线生机。”
4. 总结:悲观主义者的胜利
PPO 的这个 本质上是一种“悲观下界” 的思想。
它只拿“最保守”的那个估计来更新梯度。这种保守,恰恰换来了强化学习最稀缺的品质——稳定性。它就像给狂奔的野马套上了缰绳,允许你跑,但不允许你失控。
四、 隐形的功臣:GAE (广义优势估计)
在 PPO 的公式里,有一个项叫 (优势函数)。我们在理论推导时假设它是已知的,但在实际训练中,它是未知的。
我们要如何计算“这一步动作到底有多好”?
1. 这一步的“惊喜”:TD Error (
)
一切的基石是一个叫做 (Delta) 的东西。它是“现实”与“预期”的差值。
我们有一个 Critic 网络 。
在 时刻,我们得到了真实奖励
,并到达了新状态
。
单步 TD 误差定义为:
-
:这是TD Target,代表我们要去的方向(一步真实奖励 + 之后全靠 Critic 预测)。
-
:这是 Critic 原本的预测。
-
含义: 如果
,说明这一步的表现比 Critic 预期的要好(惊喜);反之则是失望。
2. 只有
是不够的:N步回报的展开
我们要估计优势函数 。理论上
。
由于 Q 未知,我们可以用不同长度的“真实轨迹”来近似 Q。
让我们看看不同“视野”下的 估计值长什么样:
-
看 1 步 (1-step Advantage):
我们只信一步真实的
,后面全信 Critic。
-
特点: 偏差大(全赖 Critic),方差小。
-
-
看 2 步 (2-step Advantage):
我们信两步真实的
,后面信 Critic。
数学魔法来了: 这个公式可以完美拆解成两个
的和!
(你可以试着推导一下:把
的定义代进去,中间项
会正负抵消)
-
看 3 步 (3-step Advantage):
-
看无穷步 (MC Advantage):
一直加到游戏结束。
-
特点: 无偏差(全是真实数据),方差极大。
-
3. GAE 的本质:指数加权平均
现在我们有了一堆估计值:
到底选哪个?
-
选
?太短视,Critic 不准就完了。
-
选
?太动荡,很难训练。
GAE 的大神 John Schulman 说:“小孩子才做选择,我全都要。”
GAE 定义为这些 N 步估计值的指数加权平均:
这里的 就是那个权重参数。
如果你把上面的 展开式代入这个加权平均公式,经过一番数学化简(利用几何级数求和),你会得到一个极其优雅简洁的结果:
这就是 GAE 的真面目:它是未来所有 TD Error () 的折扣累加和。
-
当前的优势
,不仅仅取决于这一步的惊喜
。
-
还取决于下一步的惊喜
(打个折
)。
-
还取决于下下步的惊喜
(打个折
)。
4. 代码实现的推导:递归形式
虽然求和公式很美,但写代码时如果要算无穷级数太累了。
我们可以把它写成递归 (Recursive) 形式,这正是我们在代码里用 reversed 循环的原因。
观察公式:
你会发现:
所以得到最终的代码实现公式:
# delta = r + gamma * V_next - V_now
delta = rewards[t] + gamma * next_value - vals[t]
# gae = delta + gamma * lambda * next_gae
gae = delta + gamma * gae_lambda * gae
5. 深度理解
的物理意义
现在再看(Lambda),你就透彻了:
-
时:
。
这就是 TD(0)。优势只看这一步的 $\delta$。
含义: 极其信任 Critic 的预测,完全不看长远。偏差大,方差小。
-
时:
。
这就是 Monte Carlo。
含义: 这一步的
会一直传递下去不衰减(除了
)。完全依赖真实的回报。偏差小,方差大。
-
(PPO 标配):
我们在中间取了一个平衡。
物理图景: 如果 Critic 在
步时预测错了,产生了一个巨大的误差
。由于有
的存在,这个远处的错误传导回
时已经被大大削弱了。这样就保证了当前的
估计既利用了长远信息,又不会被远处的噪声过度干扰。
五、 PPO 的工程“黑魔法” (Implementation Tricks)
如果你直接照着公式写代码,模型大概率是不收敛的。以下这 4 个 Tricks,是 DeepRL 社区用无数次失败换来的“血泪经验”,它们是 PPO 能否 work 的关键。
1. 状态标准化 (Observation Normalization)
神经网络对输入数据的尺度非常敏感。
-
在 Atari 游戏中,输入是像素 (0-255);
-
在 MuJoCo 机器人中,输入可能是关节角度 (-3.14 到 3.14) 和速度 (-100 到 100)。
如果直接把这些原始数据喂给网络,梯度会乱跳。
解法: 维护一个动态的均值和方差 (Running Mean & Std)。每进来一个状态,都先减去均值、除以标准差,把它变成标准的正态分布,再喂给网络。这是一个对性能提升巨大的操作。
2. 优势归一化 (Advantage Normalization)
这是 PPO 代码中最容易被忽视的一行代码。
在一个 Batch(比如 2048 步)的数据中,有些片段的 Advantage 可能是 100,有些是 0.1。这会导致 Update 时梯度的尺度不一致。
解法: 在计算 Loss 之前,强制将这一个 Batch 内的所有 Advantage 进行归一化:
这就像给梯度装了一个“稳压器”,保证 Actor 每一步更新的力度是均匀的。
3. 正交初始化 (Orthogonal Initialization)
如果你用 PyTorch 默认的初始化(Xavier 或 Kaiming),在 RL 中往往表现不佳。
解法:
-
全连接层使用正交初始化。
-
关键点: Actor 网络输出层(决定动作概率的那一层)的初始化权重,要缩小到 0.01。
-
为什么? 这能保证在训练刚开始时,所有动作的概率几乎是相等的(Logits 接近 0)。这意味着智能体会进行最大化探索,而不是一开始就“瞎蒙”一个动作一直做。
4. 梯度剪裁 (Global Gradient Clipping)
即使有了 PPO 的 Clip Objective,神经网络内部的梯度依然可能在某些极端数据下发生爆炸。
解法: 像电路保险丝一样,设置一个阈值(通常为 0.5)。如果梯度范数超过这个值,就强行缩放回来。
结语:中庸之道的胜利
PPO 并不是最先进的算法(它没有 SAC 的样本效率高),也不是最简单的算法(比 DQN 复杂)。
但它之所以能成为 OpenAI、DeepMind 以及几乎所有 AI 实验室的首选基线,是因为它体现了一种“中庸的智慧”:
-
它在 On-Policy 的低效和 Off-Policy 的不稳定之间,找到了重要性采样这个平衡点。
-
它在激进更新和保守不变之间,找到了Clipping 这个平衡点。
-
它在数学理论和工程 Trick 之间,建立了一套标准化的流程。
当你掌握了 PPO,你掌握的不仅仅是一个算法,而是深度强化学习中处理“稳定性”与“探索性”这对核心矛盾的通用方法论。
PPO 的优点与局限
优点
-
实现简单
无需二阶优化、无约束优化器,普通的 SGD/Adam 就能跑起来。 -
稳定性好
clip + 多 epoch 更新 + GAE 的组合,让它在很多环境里表现得比传统策略梯度、A2C 之类更稳定。 -
适配连续动作
对高维连续动作空间特别友好,这一点上比 DQN 类方法优势明显。 -
实践经验丰富
由于用了很多年,社区里有大量经验、可参考的超参数和实践技巧。
局限
-
仍然是 on-policy
采到的数据基本只能用几轮,很难像 DQN 或 SAC 那样高效复用大量旧数据,样本效率不高。 -
对超参数仍然敏感
尽管比 TRPO 等稳定,但在复杂环境中,学习率、clip 范围、batch 大小等依然会影响很大,需要调参。 -
探索能力有限
虽然有熵正则,但在特别稀疏奖励的环境中,PPO 可能仍然探索不足,需要配合其他技巧(如奖励设计、curiosity 等)。 -
理论上是 TRPO 的近似,但不完全等价
它的 clip surrogate 是启发式的,并不是严格解决某个约束优化问题,不过实践证明「好用就够了」。
什么时候该考虑用 PPO?
可以粗略给你一个「使用指南」:
-
如果你的任务是:
-
连续动作控制(机器人、自动驾驶中的控制模块、工业控制)
-
经典 RL benchmark(如 MuJoCo、PyBullet 等)
-
中小规模的离散动作任务(比如棋盘类、小型游戏)
-
-
并且:
-
你希望算法实现不要太复杂;
-
能接受 on-policy 带来的样本开销;
-
那 PPO 基本可以当成「首选算法」来尝试。
如果你的任务:
-
数据采集成本极高(比如现实世界机器人),必须极致提高样本效率;
-
或者环境奖励非常稀疏,探索难度大;
你可能会考虑:
-
Off-policy 的方法:SAC、TD3、DQN 变体;
-
再结合 PPO 等做一些混合或分层。
3113

被折叠的 条评论
为什么被折叠?



