news 2026/10/8 11:39:09

从REINFORCE到PPO再到GRPO:策略梯度方差治理与算法选型实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从REINFORCE到PPO再到GRPO:策略梯度方差治理与算法选型实战

强化学习这条线我断断续续跟了几年,从最早手撸REINFORCE被方差折磨到怀疑人生,到后来用PPO把训练曲线压稳,再到最近折腾GRPO这类去掉Critic的变体,踩过的坑基本都集中在同一个地方——方差。很多人第一次跑策略梯度的时候都会遇到这种场景:代码逻辑明明没问题,reward也在涨,但loss曲线像心电图一样上下乱跳,同一个实验换个随机种子结果能差出一倍。这不是玄学,本质上是策略梯度估计的方差在作祟。这篇内容我打算把REINFORCE、PPO、GRPO这三代方法串起来讲,重点不是复述公式,而是说清楚每一代到底在解决什么方差问题、为什么这么设计、实际写代码时哪些细节会决定成败。适合已经跑过至少一个策略梯度demo、想搞明白背后逻辑的人,也适合正在选算法做项目、纠结该用PPO还是GRPO的从业者。

1. 策略梯度的方差到底从哪来

1.1 从REINFORCE的目标函数说起

REINFORCE的核心思想非常朴素:让带来高回报的动作概率变大,带来低回报的动作概率变小。它的梯度估计形式是回报乘以对数策略的梯度。问题就出在这个"回报"上。在一整条轨迹里,我们用一个标量回报去加权每一个时间步的动作,这意味着前面某个动作的好坏,被后面所有动作的结果一起"背锅"了。

举个具体的例子。假设一个episode有50步,第3步做了一个无关紧要的动作,但第40步因为运气好拿到了大奖励。REINFORCE会把这份功劳平摊到包括第3步在内的所有动作上,第3步的策略梯度就被这个和它几乎无关的大回报推了一把。单条轨迹这样估计,多条轨迹一平均,方差自然就上去了。

更麻烦的是回报的尺度。如果环境奖励是0到100的范围,那回报可能累积到几千,梯度更新的幅度就会非常大,学习率稍微大一点直接发散。我早期做的一个gridworld实验,奖励设成每步+10,结果训练十次有八次崩掉,后来把奖励归一化到0到1才稳下来。这就是方差在尺度上的体现。

1.2 蒙特卡洛估计的固有缺陷

REINFORCE用的是蒙特卡洛方法估计回报,也就是必须等一整条轨迹跑完才能更新一次。这带来两个直接后果。第一,单条轨迹的回报是一个高方差的无偏估计,样本量不够的时候噪声极大。第二,不同轨迹长度不同,回报的累积方式也不一样,长轨迹的方差天然比短轨迹大。

你可以把这件事类比成抽样调查。如果我想估计全国人的平均身高,只抽一个人问,那结果完全看运气;抽一万个人,结果就稳了。REINFORCE每次更新相当于只抽了很少的"样本"(一条或几条轨迹),估计自然不稳。要降方差,最直接的办法就是增加样本量,但采样在强化学习里是最贵的操作,很多时候根本采不起。

1.3 方差与偏差的权衡关系

这里必须点明一个贯穿全文的主线:降方差往往要引入偏差。最典型的就是后面要讲的Actor-Critic,用Critic估计的价值函数来代替真实回报,Critic估得准就降方差,估不准就引入偏差。PPO、GRPO的各种设计,本质上都是在"方差-偏差-样本效率"这个三角里找平衡点。

理解了这个权衡,你再看那些算法细节就不会觉得是拍脑袋想出来的。比如为什么PPO要限制策略更新幅度?因为策略变化太大会让旧数据估计的价值失效,偏差急剧上升。为什么GRPO敢去掉Critic?因为它用组内相对比较的方式,用一种更轻量的手段把方差压下去,代价是牺牲了一部分理论上的最优性。

2. REINFORCE的降方差改造:从基线到因果性

2.1 减去基线为什么有效

REINFORCE最经典的改进就是减去一个基线。公式上,把回报减去一个只和状态有关的基线函数,梯度期望不变,但方差会下降。为什么期望不变?因为基线不依赖动作,对动作求期望的时候它那一项会归零。为什么方差下降?因为减去基线相当于把回报"中心化"了,让正负回报更均衡,梯度更新的方向更集中。

实操里最常用的基线就是状态价值函数。你可以用一个单独的神经网络去拟合它,也可以用简单的滑动平均。我早期偷懒用过整条轨迹回报的均值当基线,效果居然还不错,尤其是在奖励分布比较均匀的任务里。这个技巧成本极低,但降方差效果立竿见影,强烈建议所有手写REINFORCE的人都加上。

2.2 因果性技巧:只让未来影响现在

比基线更狠的一招是因果性处理。既然第3步的动作不可能影响第40步之前发生的事,那第3步的梯度就不应该被第40步的奖励影响。具体做法是把回报改成"从当前时刻到结束的累积回报",也就是只累加未来的奖励。

这个改动看起来只是把求和范围变了一下,但对降方差的效果非常明显。因为它切断了大量无关的噪声来源。在长轨迹任务里,因果性技巧带来的方差下降往往比基线还大。我在一个路径规划的小项目里对比过,加上因果性之后,同样的训练轮数下策略的稳定性提升了一大截,收敛需要的episode数大概少了三成。

2.3 广义优势估计GAE的引入

把基线思想和因果性思想结合起来,就得到了优势函数的概念:某个动作相对于平均水平好多少。优势函数的估计方法里,GAE是最常用的一个。它用一个参数lambda在偏差和方差之间做连续调节。lambda等于0时只用一步的TD误差,方差最低但偏差最大;lambda等于1时退化成蒙特卡洛回报,无偏但方差最高。

实际调参时,lambda一般取0.95到0.99之间。这个区间是大量实验总结出来的经验值,兼顾了稳定性和准确性。我自己的习惯是先固定0.95,如果训练不稳再往上调一点。要注意GAE依赖一个价值网络来算TD误差,所以它天然属于Actor-Critic框架,纯REINFORCE用不了。

3. PPO凭什么成为默认选择

3.1 重要性采样与信任域思想

PPO要解决的核心问题是:能不能用一批旧策略采的数据,多更新几次策略?直接重复使用旧数据会出问题,因为旧数据是按旧策略分布采的,新策略变了之后这个分布就对不上了。重要性采样通过一个比值来修正这个分布差异,让旧数据还能用。

但重要性采样的比值如果偏离1太远,估计的方差会爆炸。所以PPO加了一个裁剪操作,把比值限制在一个区间里,比如0.8到1.2。这就是所谓的信任域思想:不让新策略离旧策略太远。这个裁剪是PPO的灵魂,也是它比原始策略梯度稳的根本原因。

3.2 裁剪机制背后的直觉

裁剪的直觉其实很好理解。假设某个动作在旧策略下概率是0.5,新策略想把它提到0.9,比值就是1.8,超出了1.2的上限,于是梯度被"截断",不再鼓励继续提高这个动作的概率。反过来如果新策略想把它压到0.1,比值0.2低于下限,同样被截断。

这样做的好处是防止某一次更新把策略带偏太远,导致后面用旧数据估计全都失效。代价是当策略确实需要大幅调整时,PPO会显得"保守",收敛变慢。我在做连续控制任务时深有体会,PPO前期往往比一些激进算法慢,但后期曲线明显更平滑,不容易崩。

3.3 实操中PPO最容易翻车的几个点

第一个坑是优势归一化。PPO对优势的尺度很敏感,如果不做归一化,不同batch之间的梯度幅度差异会很大。标准做法是在每个batch内对优势做零均值一方差的归一化。这个操作看起来不起眼,但不做的话训练稳定性会差很多。

第二个坑是裁剪系数的选择。默认0.2是个不错的起点,但任务不同要调。奖励稀疏的任务可以适当放宽到0.3,让策略敢动;奖励密集且容易过拟合的任务可以收紧到0.1。

第三个坑是价值函数的更新。很多人只关注策略网络,忽略了价值网络的拟合质量。价值网络如果跟不上,GAE算出来的优势就是错的,整个训练都会歪。我的经验是价值网络的更新频率可以比策略网络高一点,或者给价值损失一个稍大的权重。

参数常用取值调整方向影响
裁剪系数0.2稀疏奖励调大,密集奖励调小越大越激进,越小越保守
GAE lambda0.95不稳时调大越大偏差小方差大
学习率3e-4发散时减半直接决定更新幅度
优势归一化开启基本都开显著提升稳定性

4. GRPO的破局思路:去掉Critic行不行

4.1 组内相对比较的核心机制

GRPO最吸引人的地方就是它不需要Critic网络。传统Actor-Critic要额外维护一个价值网络,参数量大、训练不稳定、还容易和价值估计的偏差纠缠。GRPO换了个思路:对同一个问题采样一组回答,用组内的相对好坏来代替绝对的价值估计。

具体来说,对每个输入采样G个输出,算出每个输出的奖励,然后用组内奖励的均值和标准差做归一化,得到每个输出的相对优势。这个相对优势就替代了GAE里的优势函数。因为比较是在同一组内进行的,很多共享的噪声被抵消掉了,方差自然下降。

这个思路在语言模型的对齐任务里特别吃香,因为语言任务的奖励往往来自一个奖励模型,绝对尺度不好把握,但相对好坏很容易判断。GRPO在数学推理、代码生成这类有明确对错的任务上表现尤其好。

4.2 为什么去掉Critic反而更稳

Critic的问题在于它本身也是个需要学习的网络,它的估计误差会直接传导到策略更新里。在训练早期,Critic基本是瞎猜的,这时候用它算出来的优势去更新策略,等于在噪声上做优化。GRPO绕开了这个环节,用采样组内的统计量代替学习出来的价值,少了一个误差来源。

当然这不是没有代价。组内比较要求每个输入采样多个输出,采样成本上升。而且组内比较只在同一输入内部有意义,跨输入的绝对水平它管不了。所以GRPO更适合那种"每个问题独立、组内可比"的场景,不太适合需要跨状态精细价值估计的连续控制任务。

4.3 GRPO与PPO的适用边界

选PPO还是GRPO,我的判断标准是看任务形态。如果是连续控制、状态空间连续、需要精细的价值估计,PPO这类带Critic的方法更合适。如果是语言生成、每个样本独立、奖励可以组内比较,GRPO更省事也更稳。

还有一个现实因素是工程成本。PPO要维护两个网络,调参维度多;GRPO结构简单,但采样开销大。如果你的采样预算充足而算力紧张,GRPO是划算的;如果采样很贵,那还是老老实实用PPO。

5. 方差治理的通用工程手段

5.1 奖励设计与归一化

不管用哪个算法,奖励的尺度都会直接影响方差。我的习惯是在环境层面就把奖励控制在合理范围,比如统一归一化到0到1,或者做running mean标准化。这一步做在算法之前,收益比调任何超参都大。

奖励稀疏的任务要格外小心,因为大部分轨迹回报都是零,方差反而可能看起来很小,但一旦有非零回报就是大值,梯度会突然跳。这时候可以考虑奖励塑形,或者用课程学习逐步增加难度。

5.2 并行采样与批量大小

降方差最朴素的办法就是多采样。并行多个环境同时跑,把batch size做大,梯度估计的方差会按样本量的平方根下降。这是最可靠的手段,没有之一。代价是算力和内存。

实操里我会先确定一个能接受的训练时间,然后在这个约束下把batch size尽量做大。如果显存不够,可以用梯度累积模拟大batch。要注意的是batch size变大之后学习率通常也要相应调整,不然更新会显得太慢。

5.3 梯度裁剪与学习率调度

梯度裁剪是防发散的最后一道防线。当梯度范数超过阈值时按比例缩放,避免单次更新过猛。阈值一般设0.5到1.0之间。这个操作对PPO和GRPO都适用。

学习率调度也很关键。前期可以用大一点的学习率快速探索,后期衰减下来做精细调整。线性衰减或者余弦衰减都是常见选择。我个人的经验是,如果训练曲线在中后期开始震荡,八成是学习率没降下来。

6. 我踩过的几个真实坑

6.1 优势没归一化导致训练随机性极大

有一次做多智能体路径规划,用PPO训练,同样的代码换个种子结果天差地别。排查了半天以为是环境随机性,最后发现是优势没做归一化。加上归一化之后,不同种子的曲线立刻收敛到差不多的水平。这个坑让我记到现在,任何策略梯度方法我都会先检查优势的尺度。

6.2 价值网络学习率设错拖垮整个训练

还有一次价值网络的学习率设得和策略网络一样,结果价值估计一直不准,GAE算出来的优势全是噪声,策略怎么都学不好。后来把价值网络的学习率调大了一倍,训练立刻顺畅了。这件事说明Actor-Critic里两个网络的平衡很重要,不能想当然地设成一样。

6.3 GRPO组大小设置不当的后果

用GRPO的时候我一开始把组大小设成4,结果组内统计量噪声太大,相对优势估计不稳。后来加到16,效果明显改善。组大小太小,均值和标准差的估计就不靠谱;太大又浪费采样。经验值是8到16之间比较合适,具体看任务。

6.4 裁剪系数和KL惩罚的取舍

PPO里除了裁剪,有时还会加KL惩罚项来约束策略变化。这两个机制有重叠,同时用容易互相干扰。我的做法是优先用裁剪,只有在裁剪压不住的时候才加KL惩罚,而且惩罚系数要从小往大调,避免一上来就把策略锁死。

7. 从方差视角看算法选型

把REINFORCE、PPO、GRPO放在方差这条主线上看,脉络就很清楚了。REINFORCE是起点,方差最大但实现最简单;PPO通过裁剪和重要性采样,在样本效率和稳定性之间找到了很好的平衡,成了通用默认选择;GRPO则针对特定场景(尤其是语言模型对齐)用组内比较的方式绕开了Critic,进一步简化了结构。

选型的时候不要迷信哪个算法"更强",要看你的任务形态、采样预算、算力条件。连续控制优先PPO,语言生成且采样便宜优先GRPO,教学或者极简场景可以用REINFORCE加基线。理解了方差从哪来、每种方法怎么治它,你就能根据自己的约束做出合理判断,而不是盲目跟风。

最后分享一个我自己的习惯:不管用哪个算法,训练前先跑一个极小的任务,把reward曲线、优势分布、梯度范数都打印出来看一眼。很多方差问题在早期就能暴露,等到大规模训练崩了再回头查,成本高得多。这个习惯帮我省下的时间,比任何调参技巧都多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/8 11:38:20

AI工程化核心:skills能力体系实战落地指南

1. 这不是“技能列表”,而是一套可落地的AI工程化能力体系最近在多个技术社区和开发者群聊里,反复看到一个词被高频提起:skills。它既不是简历上泛泛而谈的“熟练掌握Python”“熟悉React”,也不是HR系统里打勾的软技能标签&#…

作者头像 李华
网站建设 2026/10/8 11:38:07

跨平台头文件设计:用vllm_platform.h守护全平台编译与链接契约

如果你写的是一个只在一台电脑上自娱自乐的小工具,平台差异基本不用太操心;但一旦项目要拿出去跨系统编译,你就得直面一个现实:同一份代码,在 Windows 上顺利链接,到 Linux 上连头文件都找不到,…

作者头像 李华
网站建设 2026/10/8 11:37:36

AI编程代理skills实战:从原理到落地的上下文工程化指南

1. 从"skills"这个词说起:它到底指什么 第一次看到"skills"这个标题,很多人会以为是某个泛泛的能力清单,或者一份简历上的技能罗列。但结合热搜词里高频出现的 Claude Code、Codex、agents、plugin 这些词,基…

作者头像 李华
网站建设 2026/10/8 11:36:52

权重方向与大小解耦:优化器的几何重构原理与实战

1. 为什么权重的“大小”和“方向”必须拆开管?这不是数学洁癖,是训练稳定性的生死线你有没有试过调 Adam 的 learning rate,调到 1e-3 感觉太猛,换成 1e-4 又像在爬行,中间那个 3e-4 像中了彩票——但换了个数据集&am…

作者头像 李华
网站建设 2026/10/8 11:36:52

华为云码道代码智能体深度体验:从IDE配置到MCP协议与多智能体协作

1. 从零上手华为云码道:一个后端老手的真实体验记录第一次听说华为云码道(CodeArts)代码智能体的时候,我正被一个祖传项目折磨得够呛——三万多行没有注释的Java代码,前任开发者留下的“天书”接口文档,还有…

作者头像 李华
网站建设 2026/10/8 11:36:16

VSCode调用本地大模型卡顿的根因与四步优化方案

1. 问题不是“卡”,而是VSCode插件层与本地模型服务的通信链路被悄悄拖垮了我第一次在Roo Code里调用本地Llama模型时,输入一个“写个Python函数计算斐波那契数列”,光标卡在末尾不动,等了12秒才吐出第一行代码。当时下意识以为是…

作者头像 李华