
如果你看过 PPO 论文大概率对下面这个式子有印象[ L^{CLIP}(\theta) \mathbb{E}_t \left[ \min \left( r_t(\theta) A_t, ; \operatorname{clip}(r_t(\theta), 1-\epsilon, 1\epsilon) A_t \right) \right] ]其中 (r_t(\theta)) 就是标题里说的 Probability Ratio也就是概率比率。很多初学者卡在这里这个比率是两个概率相除这谁都知道可它俩到底在比什么为什么比一下就能限制策略更新又为什么这个比值直接决定了 PPO 的收敛稳定性这篇文章我就盯着这一个公式讲清楚争取让你三分钟内建立直觉。我会先拆解 ratio 的定义和它背后的 importance sampling 逻辑再结合 clip 机制说明它为什么能控制更新步长最后从代码层面聊几个实际计算时容易踩的坑。无论你是刚入门的强化学习新手还是已经跑过几个环境但一直没把公式和实现对应上的实践者这篇内容都适合你。1. 先搞清楚 PPO 在优化什么一个容易被跳过的前提1.1 策略梯度为什么需要“新旧策略”两个演员在理解 Probability Ratio 之前必须先把 PPO 的优化目标说清楚。PPO 属于策略梯度方法它的核心思想很直白如果某个动作在某个状态下带来了较高的回报正的优势就提高策略在这个状态下选择该动作的概率反之就降低概率。问题在于策略梯度定理给出的梯度形式是[ \nabla J(\theta) \mathbb{E}{s, a \sim \pi\theta} \left[ \nabla_\theta \log \pi_\theta(a|s) \cdot A(s, a) \right] ]这里的期望是对“当前策略 (\pi_\theta) 采样得到的轨迹”求的。这意味着传统策略梯度是一种 on-policy 方法你用当前策略跑环境采集一批数据然后用这批数据更新策略更新完之后这批数据就作废了下一轮更新必须重新跑环境采样。这种做法的成本非常高。尤其是用真实机器人或复杂仿真环境做实验时每更新一次策略都要重新采一批数据训练速度会被采样瓶颈卡死。PPO 想解决的核心问题就是能不能让一批旧数据多被利用几次同时又不让策略更新太猛导致训练崩溃于是它引入了 importance sampling把原本对新策略的期望改写成对旧策略的期望。1.2 Surrogate Objective 里的那个比值是怎么冒出来的做一次简单的数学变换。假设我们有一批由旧策略 (\pi_{\theta_{\text{old}}}) 采样得到的数据想用这批数据来估计新策略 (\pi_\theta) 的梯度。根据 importance sampling 公式[ \mathbb{E}{x \sim p(x)}[f(x)] \mathbb{E}{x \sim q(x)} \left[ \frac{p(x)}{q(x)} f(x) \right] ]把策略梯度里的期望从新策略分布换到旧策略分布就得到[ \mathbb{E}{s, a \sim \pi{\theta_{\text{old}}}} \left[ \frac{\pi_\theta(a|s)}{\pi_{\theta_{\text{old}}}(a|s)} \nabla_\theta \log \pi_\theta(a|s) A(s, a) \right] ]新策略概率除以旧策略概率——这不就是 Probability Ratio 吗所以这个比值本质上是 importance weight它修正的是“数据来自旧策略”这个事实让旧数据能够被用来估计新策略的期望。这也是理解 PPO 的第一层关键PPO 之所以是 off-policy 风格的算法靠的并不是经验回放缓冲区而是这个比值把所有采样分布偏差都吸收掉了。只要 ratio 计算正确理论上旧数据就能被反复用于多次梯度更新。2. Probability Ratio 到底在比较什么不只是两个概率相除2.1 从数学式看比较的对象[ r_t(\theta) \frac{\pi_\theta(a_t | s_t)}{\pi_{\theta_{\text{old}}}(a_t | s_t)} ]分子和分母都是“在状态 (s_t) 下采取动作 (a_t)”的概率区别只在于策略参数不同。(\pi_{\theta_{\text{old}}}(a_t | s_t))采集轨迹时使用的那版策略。它在一轮优化中固定不变是你跑环境时保存下来的“快照”。(\pi_\theta(a_t | s_t))当前正在被梯度更新的策略。它在每一轮 minibatch 更新后都会变化。需要注意这里“比较”的不是两个不同动作的概率而是同一个动作在不同策略版本下的概率变化。很多初学者容易搞混以为 ratio 是在比较当前动作和另一个动作谁更优。不是的它是同一个 (s, a) 对在参数更新前后的概率之比。举个例子。假设某个状态下旧策略 (\pi_{\text{old}}) 选择“向左走”的概率是 0.4经过一轮参数更新后新策略 (\pi_\theta) 选择“向左走”的概率变成了 0.6。那么 ratio 0.6 / 0.4 1.5。这说明新策略在这个状态下对这个动作的偏好程度提高了 50%。2.2 比值的三种取值对应什么含义ratio 的取值范围直接反映了策略变化的幅度和方向ratio 取值含义策略更新方向(r \approx 1)新旧策略在该动作上的概率几乎没变化参数几乎没动(r 1)新策略更倾向于选择该动作该动作的概率在上升(r 1)新策略更不倾向于选择该动作该动作的概率在下降由此可以引出一个非常关键的直觉ratio 就是策略更新步长的度量。一个状态-动作对对应的 ratio 偏离 1 越远说明策略在那个状态下对这个动作的改变越剧烈。你可能会想那直接用新旧策略的差值 (\pi_\theta - \pi_{\text{old}}) 不也能衡量变化吗为什么非要用比值这个问题问得好答案有两层。第一层是 importance sampling 本身需要比值形式这是数学推导的结果不是人为设计的选择。第二层是比值比差值更能刻画“相对变化”。举个简单的例子旧概率从 0.01 变成 0.02差值是 0.01但相对变化是翻倍旧概率从 0.4 变成 0.41差值也是 0.01但相对变化只有 2.5%。对策略的采样分布来说前者对行为的影响要大得多。比值能自然捕捉这种相对变化差值则不能。2.3 为什么不能直接比较新旧策略的输出分布还有一个常见误区既然 PPO 想控制新旧策略不要差太多为什么不直接比较两个策略输出的概率分布比如用 KL 散度TRPO 确实就是那么做的。TRPO 的约束条件是新旧策略的 KL 散度不超过某个阈值这是一个硬约束求解时需要计算二阶近似复杂度高实现起来麻烦。PPO 的一个设计目标就是去掉这个二阶约束用一阶的方法达到类似效果。PPO 的思路是既然策略更新过猛会导致 KL 散度急剧增大那我直接在单步上限制每个动作的概率变化幅度不就行了对每个 (s, a) 对把 ratio 限制在 ([1-\epsilon, 1\epsilon]) 区间内相当于限制了每个动作概率的相对变化幅度。这就是 clip 机制的朴素来源。所以可以这样理解TRPO 是全局限制约束整体分布差异PPO 是局部限制约束每个动作的概率变化。PPO 之所以在实践中更常用是因为它不需要计算 KL 散度的二阶近似实现简单而且单点限制的累积效果在经验上也足够好。3. 无约束的 Ratio 为什么危险一段让你直观理解的数值演示3.1 一个极简的假想场景假设现在有一个状态 (s)旧策略 (\pi_{\text{old}}) 选择动作 (a) 的概率是 0.5这个动作的优势 (A 1)明显是好动作。我们用旧策略采了一批数据其中包含这个 (s, a) 对。现在开始更新策略。由于梯度会推动“好动作概率上升”新策略 (\pi_\theta) 下这个动作的概率从 0.5 慢慢涨到 0.6、0.7、0.8……在不同概率下ratio 的变化如下| (\pi_\theta(a|s)) | (\pi_{\text{old}}(a|s)) | ratio | 对梯度的贡献(r \times A) | |---|---|---|---| | 0.5 | 0.5 | 1.0 | 1.0 | | 0.6 | 0.5 | 1.2 | 1.2 | | 0.75 | 0.5 | 1.5 | 1.5 | | 0.9 | 0.5 | 1.8 | 1.8 | | 0.99 | 0.5 | 1.98 | 1.98 |看起来似乎没什么问题ratio 越大梯度贡献越大新策略越会把动作概率往上推。但这里隐藏着一个危险。3.2 为什么说“步子太大容易扯着”上一节的表格看起来人畜无害但实际上 ratio 一直增大意味着策略正在快速偏离旧策略。在单纯 policy gradient 方法里策略更新受学习率控制不会一步迈太远。而 PPO 要在同一批旧数据上做多轮梯度更新如果没有限制几轮迭代后新策略就可能完全偏离旧策略的采样分布。此时问题出现了我们的数据是旧策略采的如果新策略已经把某个动作的概率推得很高但旧策略采到的该动作样本其实很少那么梯度估计的方差会急剧增大。ratio 越大这个方差放大越严重。从数学上看importance sampling 估计的方差与 weight 的平方成正比weight 越大估计越不稳定。这也是实际训练中常见的崩溃现象奖励突然掉到谷底策略瞬间退化。原因往往就是某一步 ratio 过大导致梯度更新过于激进策略直接冲进一个性能很差的区域。PPO 的 clip 机制就是为了防范这一点。它不追求精确地控制每个 ratio而是设定一个容忍区间 ([1-\epsilon, 1\epsilon])超出区间的部分就做截断让对应样本不再提供进一步推动策略更新的梯度。4. Clip 机制当 Ratio 越界时PPO 到底在做什么4.1 Clip 的数学形式和直觉PPO 的最终损失函数是[ L^{CLIP}(\theta) \mathbb{E}_t \left[ \min \left( r_t(\theta) A_t, ; \operatorname{clip}(r_t(\theta), 1-\epsilon, 1\epsilon) A_t \right) \right] ]其中 (\epsilon) 通常取 0.2。结合优势 (A_t) 的正负可以拆成两种情况来看。情况一(A_t 0)这是个好动作我们希望新策略更倾向于选择该动作。此时如果 ratio 在 ([1-\epsilon, 1\epsilon]) 内梯度正常推动概率上升如果 ratio 已经超过 (1\epsilon)说明这个动作的概率已经被提高太多了clip 操作把梯度贡献截断在 (1\epsilon)不再继续推动。换成人话动作好鼓励提升但别一次性提太猛。概率已经涨到一定幅度之后再多就不给你梯度鼓励了。情况二(A_t 0)这是个坏动作我们希望新策略降低选择该动作的概率。此时如果 ratio 在区间内梯度正常推动概率下降如果 ratio 已经低于 (1-\epsilon)说明该动作概率已经降得够低了clip 把梯度贡献停在 (1-\epsilon)不再继续压制。也换成人话动作差鼓励降低但同样别一棒子打死。概率已经降到一定程度再多也不给你梯度惩罚了。注意一个细节这里的 min 操作对于 (A_t 0) 时取的是 clip 之后的值作为上限对于 (A_t 0) 时取的是 clip 之后的值作为下限。换句话说min 和 clip 组合起来的效果是用一个有界的目标替代无界的原始目标让梯度不会因为个别极端样本而失控。4.2 一个具体数字推演沿用前面的例子。旧策略 (\pi_{\text{old}}(a|s) 0.5)假设当前新策略已经把该动作概率推到了 0.8ratio 1.6。设置 (\epsilon 0.2)则 clip 上限是 1.2。如果 (A 1)那么原始项 (r \times A 1.6)clip 项 (\text{clip}(r, 0.8, 1.2) \times A 1.2)min 取小1.2这说明虽然 ratio 已经到 1.6 了但损失函数只按 1.2 算梯度。梯度仍然存在不是零但被削弱了策略依然会缓慢推高这个动作的概率只是不会像无约束时那样猛烈。反过来如果 (A -1)ratio 已经跌到 0.4clip 下限是 0.8原始项 (0.4 \times (-1) -0.4)clip 项 (0.8 \times (-1) -0.8)min 取小-0.8注意这里 min 取的是 -0.8绝对值更大梯度方向是提高该动作的概率因为 (A0)loss 减小意味着概率应该上升。这不是矛盾而是当 ratio 远低于下界时说明策略已经过度惩罚了这个动作clip 后的目标会更温和地把它拉回来。4.3 Ratio 与 KL 散度的关系一句经验法则虽然 PPO 在实现上没有显式计算 KL 散度但 ratio 和 KL 散度有直接联系。当策略变化很小时KL 散度约等于 ratio 相对 1 的偏差的平方和。[ D_{KL}(\pi_{\text{old}} | \pi_\theta) \approx \mathbb{E} \left[ \frac{1}{2} (r_t(\theta) - 1)^2 \right] ]所以当 ratio 被限制在 ±0.2 范围内时实际是在隐式地控制 KL 散度在一个比较小的范围。你不需要显式计算 KL 散度clip 本身就起着软约束的作用。这里我补充一点个人经验(\epsilon) 取 0.2 是论文给出的默认值但实际任务里不一定是最优的。如果你发现训练初期策略就剧烈波动可以把 (\epsilon) 调小到 0.1如果训练稳定但收敛偏慢可以试试 0.3。调这个参数比调学习率的直觉更直接因为它直接控制了每一步允许的策略变化量。5. 从代码层面看 Ratio 计算的三个常见坑5.1 用 log 相减再 exp别直接相除实际实现时几乎所有强化学习框架都不会真的去计算 (\pi_\theta(a|s)) 和 (\pi_{\text{old}}(a|s)) 再相除而是用对数概率相减再取指数[ r_t(\theta) \exp \left( \log \pi_\theta(a_t|s_t) - \log \pi_{\theta_{\text{old}}}(a_t|s_t) \right) ]原因很朴素策略网络输出的是 logits经过 softmax 后才是概率。如果先算概率再相除中间会多一次指数运算不仅计算量大而且概率值可能非常小尤其是动作空间很大时直接相除容易触发数值下溢。用 log 相减则安全得多。下面是 PyTorch 风格的伪代码# 假设 dist_new 和 dist_old 都是某个分布对象 log_prob_new dist_new.log_prob(action) log_prob_old dist_old.log_prob(action).detach() # 旧策略不计算梯度 ratio torch.exp(log_prob_new - log_prob_old)注意这里dist_old.log_prob(action).detach()不能漏。旧策略的参数在收集数据时就固定了它对当前损失函数的梯度必须为零。如果忘了 detach梯度会顺着旧策略的参数传播回去导致更新逻辑完全错误。5.2 连续动作空间里ratio 算的是概率密度如果你在连续动作空间用 PPO比如机械臂控制、自动驾驶等场景动作是从高斯分布里采样得到的那么 (\pi_\theta(a|s)) 就不是概率质量而是概率密度函数PDF。概率密度的值可以大于 1这一点许多初学者会困惑。比如一个方差很小的高斯分布中心点的概率密度可能有好几这是完全正常的。ratio 依然按照密度值相除来计算重要性权重依然有效。只要新旧策略都使用同一动作的密度值作比数学上就没有问题因为重要性权重关心的是密度比值而不是密度的绝对值。不过这里有一个实操要点连续动作下如果一个动作落入了旧策略分布的尾部区域密度极小ratio 可能变得非常不稳定因为旧密度趋近于零。此时即使新策略对它的密度是合理的比值也会被放大。这正是训练中经常遇到 spike 的原因之一。一般通过 clip 就能兜住这个问题但如果 spike 频繁出现建议检查一下是否某个维度的动作方差过小导致采样密度过于集中。5.3 时序数据里要注意 mask如果 PPO 用在序列决策任务中比如对话生成、游戏中的长序决策每个 batch 里可能有不同长度的轨迹。计算 log_prob 时需要对 padding 部分做 mask否则填充帧的概率会被错误计入 ratio。举个真实场景。我在做游戏 AI 时一个 episode 最多 512 步但很多轨迹只有 30 步就结束了。如果不 maskpadding 部分的 action 是无效的但模型依然会输出一个概率计算出来的 ratio 会被当成有效样本参与梯度更新。这会让策略被一堆根本没发生的动作干扰训练出来的策略往往会出现诡异的偏好。正确做法是# batch_ratio: [batch_size, seq_len] # mask: [batch_size, seq_len]有效位置为 1padding 为 0 loss -(torch.min(ratio * advantage, clipped_ratio * advantage) * mask).sum() / mask.sum()按 mask 的有效位置求和再除以有效数量而不是对整个 batch 求平均这是细节但直接影响训练质量。6. Dual-Clip PPO 和“比率”在算法家族中的位置6.1 Dual-Clip 为什么要再 clip 一次如果顺着 ratio 的思路往下走你会发现一个边界情况当 (A 0) 且 ratio 远大于 (1\epsilon) 时原始 PPO 的 min 操作已经把目标值限制在 ((1\epsilon)A)看起来没问题。但实际训练中如果某条轨迹的 advantage 存在较大误差比如 reward 归一化没做好个别样本的 ratio 可能极端大即使被 clip 过损失函数中仍可能存在较大的异常梯度。Dual-Clip PPO 的思路是对 (A 0) 的情况再加一道防线当 ratio 超过一个更大的阈值比如 10时把该样本的目标直接设为 0让它完全不参与梯度更新。相当于告诉优化器“这个样本已经不可信了放弃它。”这种做法在稀疏奖励任务中尤其有用。稀疏奖励环境下偶尔出现的正样本可能携带巨大的 advantage 估计值一次性把策略推出很远。Dual-Clip 的额外截断能显著降低方差。6.2 理解 ratio 对读懂整个策略优化算法家族的意义如果你理解了 ratio再回头看各类策略优化算法的区别就会清晰很多算法对策略更新幅度的控制方式是否依赖 ratioREINFORCE仅靠学习率无显式限制不使用TRPOKL 散度硬约束隐式使用PPO局部 ratio clip核心机制Dual-Clip PPOclip 大比例截断核心机制IQL / 离线 RL价值约束策略不使用这里特别提一下离线强化学习。IQLImplicit Q-Learning这类方法不使用 ratio而是通过价值函数直接约束策略。原因是在离线设定下数据来自一个固定的行为策略你无法通过在线采样来校正分布偏移ratio 的估计方差会爆炸所以需要换一种思路。理解 ratio 和 importance sampling 的局限有助于你判断什么时候 PPO 适用、什么时候应该转向离线 RL 方法。6.3 连续控制任务的 ratio 调试经验最后分享一个我实际调模型的经验。在连续控制任务比如 MuJoCo 的 HalfCheetah上训练 PPO 时我会在训练日志里同时记录 ratio 的均值、最大值和超过 1.2 的比例。如果你发现超过 1.2 的样本占比长期高于 5%说明策略更新频率太高或者学习率偏大训练已经处于一种“每天都在暴走”的状态。一个实用的调参策略是先把 (\epsilon) 固定为 0.2调整学习率直到 ratio 的异常比例稳定在 2% 以下然后再反过来微调 (\epsilon)。这个顺序比盲目同时调两个参数更有效因为你能够分清是学习率导致的走过头还是 clip 边界设得太宽。如果 ratio 经常出现几十上百的异常值别急着调 clip先检查 reward 归一化和 advantage 估计是否出了问题。我在实际项目里遇到过几次这种情况最后定位到的原因都是 advantage 没有做标准化导致正负样本的梯度量级差异悬殊。从我个人的经验来看理解 Probability Ratio 比背 PPO 的损失函数公式要有用得多。公式只是最终产物ratio 背后连接的是 importance sampling 的数学基础、策略更新步长的控制哲学以及算法稳定性和数据效率之间的权衡。把这一层想明白了以后不管是调参、看变体论文、还是自己实现新算法都会有更踏实的底气。