如果你也在用PPO做RLHF,大概率遇到过这种局面:训练时reward一路飙升,离线指标却纹丝不动甚至掉头向下,等真正换上推理用的采样参数去跑,生成质量更是崩得让人怀疑人生。这就是"训练和推理不一致"的典型表现,也是强化学习场景里最磨人的工程问题之一。最近我仔细跟进了Score Centering这个手法,它没有改模型结构,也不动损失函数,只是把奖励/打分信号的统计分布做了居中处理,却在训推一致性上带来了实打实的改善。这篇文章我把原理、推导、实现和踩坑记录都摊开讲,希望让同样被这个问题卡住的人少走弯路。
1. 先搞清楚"训推一致性"到底卡在哪:训练时全能、推理时翻车
1.1 训练和推理之间到底差了什么
很多做RLHF的人会把训推不一致简单归结为"训练用采样、推理用贪心",但实际上问题远不止采样参数这一层。
模型训练时,策略不断在动作空间里做探索。对文本生成来说,这个动作空间就是我们熟悉的token概率分布。PPO训练过程中,我们一般用温度比较高(比如1.0甚至更高)的采样来生成rollout数据,让模型充分探索不同表达方式。而到了推理阶段,为了追求稳定输出,我们通常把温度调低到0.7、0.6,或者直接用top-p截断、甚至greedy decoding。训练时那个"什么都敢说"的分布和推理时那个"只捡确信度高的话说"的分布,天然就存在差异。
但这还算不上最致命的。真正麻烦的是奖励信号在训练过程中发生了隐形的漂移。偏好模型或奖励模型是提前训练好的,它给出的分数分布并不是一成不变的——随着策略模型被更新,它产出的文本在奖励模型眼里可能整体变得"偏高"或"偏低"。一开始平均分数是0.2,过几个epoch之后平均分数可能涨到0.8,这种均值的变化会直接污染PPO对优势函数(advantage)的估计。
你想象一个场景:策略本轮生成的样本平均质量确实比上一轮好,奖励均值从0.3涨到了0.6。但如果不做任何处理,PPO会把"分数绝对值提高了0.3"解读为"这个方向是对的,继续加大更新步长",于是策略一头往那个方向上猛冲。等冲到奖励分布整体抬高但生成文本变得单一、模式化时,推理侧的多样性早就没了,而reward本身看着依然在涨。这就是典型的"训练指标自嗨"。
1.2 分布外采样带来的二次打击
还有一个容易忽略的点是分布外采样。训练时策略在温度=1.0下的输出分布,和推理时温度=0.7下的输出分布并不完全重叠。策略在训练阶段没有充分见过"低温度下会生成的token序列",那么在推理时它面对的就是一个偏分布外的输入状态。
这时候如果奖励模型给出的分数还整体偏移,模型就完全没有能力去辨别"我该不该在当前状态下做这个选择"。于是训练时看起来每一步都在改进,实际更新的却是只适合高温采样区域的策略,低温推理时自然就崩了。
Score Centering之所以能切入这个问题,就是它先把奖励信号中的常数偏移去掉,让PPO只关注"相对提升量"而不是"绝对分数",从源头上缓解策略被均值带偏的问题。下面我们把原理拆开看。
2. Score Centering到底在"居中"什么:一个被很多人忽略的统计细节
2.1 这里说的Score到底是哪个Score
大模型RL训练语境里,Score被混用过很多次。有人拿它指奖励模型的输出精确分数,有人拿它指logits,还有人拿它指生成样本的打分。在Score Centering这个技术里,它指的其实是RLHF训练过程中模型收到的标量奖励信号——不管是奖励模型的reward,还是经过KL惩罚之后的综合回报,都是被居中的对象。
为什么需要对它做居中?因为PPO这类算法对奖励的绝对尺度是敏感的。PPO的自变量是策略比值(概率比),但更新的方向和幅度由advantage决定。而advantage是回报减去baseline的差值。如果我们使用的baseline是价值网络的估计,那么价值网络本身也在不断被更新,它拟合的是当前奖励信号的绝对水平。一旦奖励信号的绝对水平整体变动,价值网络就需要费额外多的优化步数去追这个飘移的均值,这就给策略更新引入了一个"追赶影子"的滞后效应。
2.2 Centering的数学本质:减去一个可估计的baseline
从数学上看,Score Centering做的事情非常朴素,就是让奖励信号变成中心化的形式:
$$r_{centered}^{(t)} = r^{(t)} - b^{(t)}$$
这里的b(t)是一个随时间变化的统计量。最简单的情况下,它可以是截至当前批次的历史奖励均值,也就是running mean:
$$b^{(t)} = \alpha \cdot mean(rewards_{batch}) + (1 - \alpha) \cdot b^{(t-1)}$$
alpha是移动平均的系数,通常取0.9~0.99。更激进的做法是直接用当前batch的均值做per-batch centering:
$$r_{centered} = r - mean(r_{batch})$$
这两种做法背后的逻辑是:策略优化真正需要的不是一个绝对分数,而是"这个样本比平均水平好多少"。如果一个分数普遍高于均值,那它并没有提供有效梯度信息,反而会让策略过度自信地往某个方向收缩。
生活化类比一下:你去评估一位学生这学期的成绩变化,比起盯着每次考试卷面分看,更好的做法是看每次考试相对全班平均分的偏离程度。卷面分会因为试卷难度整体波动,但"相对位置"才是学生真实水平的体现。奖励模型打出的分也一样,由于策略分布漂移,它整体偏高偏低是常态,居中之后才显露出每一条样本的"真实增量"。
2.3 它和奖励标准化、优势标准化的区别
很多人会把Score Centering和reward normalization、advantage normalization混在一起,它们确实有关系,但作用层次不同。
奖励标准化(reward normalization)通常指对奖励做scale调整,比如除以标准差,让奖励的绝对尺度变得可控。Advantage normalization则是在GAE算出优势之后做一次标准化,让优势分布大致落在单位方差附近。
Score Centering只做"减法",不做"除法"。它把整体偏移去掉,让奖励分布的均值贴近0。这样做有一个额外好处:经过center后的reward和KL惩罚项(通常期望也是0附近)在数值尺度上更容易兼容,不会出现奖励均值是5、KL惩罚均值是0.01这种完全不对称的情况。而这种对称性,恰恰是很多训练崩坏的隐藏根源。
3. 为什么居中能同时稳住训练和推理:从PPO的优势估计链路说起
3.1 优势函数如何被均值漂移误导
PPO的策略梯度可以写成期望形式,里面最核心的量就是优势函数A(s,a)。它衡量的是"在状态s下选择动作a比平均策略好多少"。
如果奖励基准整体偏移了C,也就是说每个时间步的奖励都多了C,那么长期回报会累积成更大的偏移。假设一个回合有T个时间步,回报的偏移就是T乘以C。即便价值网络也在同步调整,但只要偏移速度和价值网络收敛速度不完全一致,优势函数的估计就会带上一个不受控制的方向性偏差。
后果很具体:假设某批次里所有样本的奖励均值都偏高,那么即便某条样本的表现只是中规中矩,它的绝对回报也会看起来像是正收益,优势被高估。策略会以为"这个方向的输出很好",于是朝着这个方向持续加大概率。等过几个epoch,推理模型因为分布收缩出现退化,你在benchmark上一测,答案变短了、句式变重复了、内容同质化严重。
3.2 Centering如何避免"策略被常数项推着走"
加入Score Centering后,奖励偏移项C在进入回报累积之前就被扣掉了。数值上,我们用的奖励序列变成了围绕0上下波动的中心化信号。此时一个中规中矩的样本,其累计回报天然接近0,优势值也自然被压回到0附近。策略只能从那些"显著优于当前平均水平"的样本里获得正向梯度。
这个机制对推理阶段的好处是深层的。训练时策略没有在一个被高估的激励信号下过度收敛,那它学到的概率分布就不会被压缩成窄尖峰。高温度采样下它仍然保有一定的探索空间,而这种探索空间保留到低温度推理时,就成了应对未见输入状态的缓冲垫。换句话说,训练时少走偏一步,推理时就少崩一点。
我在自己的实验里观察到一个非常典型的信号变化:加centering之前,训练日志里KL散度经常突然拔高,说明策略在某个方向上剧烈跳变;加centering之后,KL走势平稳,reward曲线也不那么虚高。这其实就是策略更新的"步子"被约束回了合理范围。
3.3 与KL约束的协同效应
再往深一层看,Score Centering还改变了KL惩罚在整体loss里的相对权重。基础RLHF公式里,PPO的总回报往往是:r_total = r_reward - beta * KL。当奖励模型打分整体偏高时,r_reward动不动就是2.0、3.0,KL项即便被惩罚,也显得无关痛痒,模型在"奖励走高"的诱导下可以无视KL约束,快速偏离原始模型。
一旦把r_reward居中到0附近,KL项不再被淹没在噪声级奖励里,它真实地参与到了更新权衡中。KL的合理作用范围是"微调,但别跑太远",而centering让这个说法真正在数值上成立。我在调参时就有体会:beta值的敏感度在centering之后大幅降低,之前2倍beta差异能导致完全不同的结果,现在没那么剧烈了。
4. 工程落地:在RLHF训练流程里正确加Score Centering
4.1 最简实现:给reward序列套一个滑动中心化
如果你用的是类TRL或自研的PPO训练器,Score Centering的实现成本不高。我一般把它放在rollout数据准备好、GAE计算之前,对每一个训练样本的reward序列做处理。
伪代码如下:
class ScoreCentering: def __init__(self, momentum=0.99): self.running_mean = 0.0 self.momentum = momentum self.step = 0 def update(self, batch_rewards): # batch_rewards: shape [batch_size, seq_len] or [batch_size] batch_mean = batch_rewards.mean().item() if self.step == 0: self.running_mean = batch_mean else: self.running_mean = self.momentum * self.running_mean + \ (1 - self.momentum) * batch_mean self.step += 1 def center(self, batch_rewards): mean = self.running_mean if self.step > 1 else batch_rewards.mean().item() return batch_rewards - mean我建议的接入位置在"奖励合成之后、价值目标计算之前"。如果是sequence-level的reward(文本生成任务大多如此),直接在每条样本的reward标量上减均值。如果是token-level MDP(比如带过程奖励的数学推理任务),就得小心一点,通常只对非填充位置的token做中心化,避免padding token的0值干扰统计。
4.2 两种窗口策略:running-mean还是per-batch center
选择running-mean还是per-batch center,取决于你的训练数据构成。
如果rollout batch足够大(例如大于512条样本),per-batch center表现已经很稳。每个batch内部算均值并减去,实现最简单,也不会引入跨batch的历史信息滞后。缺点是如果某个batch里恰好多是高质量样本,centering会把它们全都扣成负分,降低这个batch整体的学习效率。这种情况在训练后期策略已经很强时会更明显。
running-mean则更平滑,它用历史信息估计"当前策略下奖励的期望水平",理论上更接近baseline的定义。它的风险在于非平稳性——如果训练进程经历了剧烈的reward分布变化,running_mean的更新速度可能跟不上。我通常把momentum设在0.95到0.99之间,并让前几十个batch快速蹭到真实水平(momentum临时调低到0.9),之后再恢复稳定的滑动平均。
4.3 一个容易忽略的细节:with replacement的旧数据怎么办
PPO训练里,一个batch的rollout数据往往会被循环利用好几次(replay / minibatch iteration)。这个时候要小心:Score Centering应该在rollout生成完毕之后、进入训练循环之前,一次性完成中心化,而不是在每次minibatch迭代时反复扣除新的均值。否则同一条样本在不同minibatch轮次里会有不同的中心化结果,等于给奖励信号注入了额外噪声。
我的习惯是保存一份原始reward,一份centered reward。训练时用centered版本计算advantage,但日志里打印原始reward的均值/分布,这样既能做监控,又能排查问题。
4.4 和价值网络、reward model的scale搭配
还有一种实践中常见的做法是:不仅center奖励,还同时center价值网络的target。价值网络学的是回报的期望,而回报经centering后均值在0附近,价值网络的输出自然也更小、更容易回归。我在实验里发现,价值损失(value loss)的收敛速度在centering后有可见提升,这反过来让advantage估计更准。
不过要记住一个关键点:如果reward model的输出本身是有意义的绝对度量(比如某些场景下3分才能通过),盲目的center可能模糊掉"优秀"和"及格"的门槛信息。解决办法是在centering之外保留一个偏移量用于部署阈值判断,训练和评估用两套口径,互不干扰。
5. 实测效果与容易踩的坑:我用两个模型跑出来的真实差异
5.1 一组肉眼可见的对比数字
我先后在7B和13B两个规模的开源模型上做了对比实验,任务是对话场景的RLHF微调。batch大小128,PPO epoch数3,KL系数beta为0.05,训练总rollout约10万条。
不加Score Centering的那组,训练到第5个epoch时reward均值从0.31爬到了1.87,看起来异常漂亮。但拿同一策略去做人工评估集上的生成,对比原始SFT模型的win-rate只有51.3%,几乎没提升。同一份日志里,KL散度在训练后半段出现三次尖峰,每次尖峰之后模型输出长度都明显缩短。
加上running-mean Score Centering(momentum=0.99)重跑同一份流程,reward均值稳定在-0.05到0.1之间,KL散度曲线平滑很多,win-rate提升到了56.8%。最明显的变化出现在推理侧:用温度0.7、top-p 0.9做生成,输出长度和句式的多样性都保持得更好,不再出现"一句话重复三遍"的退化现象。
5.2 坑一:冷启动时running mean把自己带偏了
第一个让我头疼的问题是训练刚开始时的冷启动。前几个batch的rollout样本极其不稳定,奖励分布可能在一个极端值附近跳动。如果running_mean用一个很高的初始值启动,后续中心化会把绝大多数正常样本都变成负分,模型一上来就被负梯度压制,整体收敛变慢。
解决办法上文提过:前若干个batch强制使用per-batch center,等统计量稳定后再切换成running-mean模式。也可以给running_mean加一个warmup步数,在warmup期间用更大的momentum让它快速追数据。
5.3 坑二:把"绝对质量门槛"也一起扣掉了
第二个坑是语义层面的。Reward model打出的分数如果本身就承担着"回答是否安全、是否有毒"的硬性门槛,那么center之后,一条绝对质量很高但相对当前batch略低的样本,它的centered得分会变成负数。策略会收到"不要学这条高质量样本"的错误信号。
这种问题在混合奖励来源(比如安全性分加有用性分合成最终reward)时尤其突出。我的做法是在做center之前,先对不同类型的奖励做加权组合,然后只对组合后的最终reward做center;安全类硬性惩罚则放在组合之前单独拉闸。如果你用的reward model输出本身就带校准含义,建议先跑一版不做center的基线,再看center引入后"掉到负分的样本"里有没有大量高质量答案,如果有,就该给center加一个下限保护或改用分位数center(减去中位数而不是均值)。
5.4 坑三:centering和advantage normalization叠用导致信号失真
还有一个容易被忽视的叠加效应。如果不做centering,直接对advantage做标准化,模型还能从"相对名次"里学到东西。但如果先center再normalize,相当于对advantage做了两轮位置变换,放大了离群样本的梯度。我曾经在8卡并行训练里因为同时开启这两个操作,遇到持续的loss震荡。
最终我的选择是:如果使用Score Centering,advantage标准化只做方差缩放,不再做均值平移;或者干脆去掉标准化,只靠centering和GAE的lambda折现来控制尺度。建议新人刚开始只用Score Centering,等跑通了再逐步叠加其他trick,不要一上来全上。
6. 使用Score Centering的几条私人经验
做了这么多轮实验后,我对Score Centering的定位变得更清楚了。它不是那种"加了就能起飞"的魔法组件,而是一个"把地基夯实"的基础操作。它解决的是一个很具体的问题——奖励信号均值漂移带来的优势估计污染,顺带改善了推理侧的分布偏移。它的价值不在于让reward跑得更高,恰恰相反,它让reward这个指标变得不再虚假。
给正在RLHF训练泥潭里挣扎的人几个实际建议。如果你的训练日志里reward曲线一路高歌猛进、但人工评估和推理侧评测怎么测都不涨,优先检查一下你的reward均值是不是正在大幅漂移——给它画个时间序列图,如果斜率很陡,score centering大概率就是你现在缺的那味药。如果你已经在用centering,但模型效果没起色,回头看一眼centering窗口是不是太短、冷启动是不是没处理好,这两个细节我实测影响很大。
另外提一个很多人没意识到的用法:Score Centering也可以在奖励模型本身的迭代训练中提前做。奖励模型打分的绝对一致性是出了名的难以保证,如果你在偏好数据集上就对label做center,训练出来的奖励模型天然会对均质漂移更鲁棒,下游RLHF也就更稳。这个我没有做大规模验证,但小规模实验里确实看到reward model的校准误差有改善。
最后多说一句,训推一致性是整个RLHF生产链路里的系统性难题,Score Centering解决的是其中一环。它把"训练信号"和"推理评估"的口径拉近了一步,但采样策略、温度退火、prompt分布这些环节依然需要同步关注。至少在我目前见过的诸多方案里,Score Centering是用最小改动换最大稳定性的那个选择,值得放进你的默认工具箱。下次线上推理崩了的时候,可以先别急着调温度,回去看看你的reward是不是早就飘到天上去了。