资讯动态

RLHF与PPO实战解析:从人类偏好到策略优化的完整链路

发布时间:2026/10/27 22:33:48 来源:尧图企业网站定制
RLHF和PPO这两个词如果你最近翻过几篇大模型相关的论文或者技术博客大概率会反复撞见。但真正让人头疼的地方在于很多资料一上来就甩公式把奖励模型优势函数裁剪目标堆在一起看完只觉得每个字都认识连起来不知道在说什么。我自己最开始接触这块的时候也是这样SFT能理解到RLHF就卡住了再到PPO那堆符号直接劝退。后来是逼着自己把整条链路从头到尾手推了一遍又对着代码逐行跑通才算真正把这件事想明白。这篇内容就是把我踩过的那些坑、绕过的那些弯重新整理成一条能走通的路。核心讲清楚三件事RLHF到底在解决什么问题、PPO为什么会被选来做这件事、以及这套东西落到代码里长什么样。适合已经了解Transformer和SFT、想往对齐方向深入的人也适合做LLM应用、需要判断什么时候该上RLHF的工程同学。不堆砌论文原话尽量用能复现的逻辑把每一步的动机讲透。1. 从SFT的局限说起为什么还需要RLHF1.1 SFT本质上是在做模仿而模仿有天花板SFTSupervised Fine-Tuning的逻辑很直白准备一批问题-标准答案对让模型去拟合这些答案。你给它十万条高质量对话它就学着在这些场景下输出类似风格的回答。这件事在让模型学会听话、学会格式、学会基本对话这个层面非常有效也是所有对齐流程的第一步。但问题在于SFT的监督信号是逐token的交叉熵。也就是说模型在每个位置被要求去逼近那个标准答案的token分布。这里有个隐含假设标准答案就是唯一正确的。可现实是同一个问题往往有多个都挺好的回答只是风格、详略、侧重点不同。SFT会把这些都还行的答案强行压成一个分布模型学到的是平均意义上的像而不是人类真正偏好的那个。更麻烦的是很多能力是难以示范但容易判断的。比如让模型写一段有分寸的拒绝、让它在多轮对话里保持一致性、让它避免那种看似正确实则有害的建议——你很难写出一个完美的标准答案去教它但你一眼就能看出它写得好不好。这种评价比生成容易的场景正是SFT的盲区。1.2 RLHF的核心思路把人类偏好变成可优化的信号RLHFReinforcement Learning from Human Feedback要解决的就是上面这个盲区。它的核心洞察是既然人类擅长比较而不擅长示范那就别让人类写答案让人类做比较。具体做法是给模型同一个问题的多个回答让人来排序——哪个更好、哪个更差。这些排序数据本身不能直接拿来训练因为它是相对偏好而不是绝对分数。于是引入一个奖励模型Reward ModelRM让它去学习人类的排序习惯把哪个更好学成一个能给任意回答打分的函数。有了这个打分函数就可以把它当作环境给的奖励用强化学习去优化策略模型让它生成得分更高的回答。这条链路的价值在于它把人类模糊的偏好转化成了可微、可优化的标量信号。模型不再被要求模仿某个特定答案而是被鼓励去探索什么样的输出能拿到更高的人类评分。这就打开了SFT打不开的那扇门。1.3 一个容易被忽略的前提奖励模型本身也会犯错这里必须提前说一个坑因为它直接决定了后面PPO为什么要加那么多约束。奖励模型是从有限的人类标注里学出来的它只是一个人类偏好的近似。当策略模型足够强时它会找到奖励模型的漏洞——生成一些在RM眼里分很高、但人类看了直摇头的输出。这在文献里叫reward hacking奖励劫持。我见过最典型的例子是RM对长回答有轻微偏好因为标注时人容易觉得详细认真结果策略模型迅速学会把所有回答都写得又臭又长堆砌一堆正确但无用的废话分数确实上去了可用性反而下降。这个现象不是bug是这套机制的固有风险。理解了这一点你才能理解PPO里那个KL惩罚项为什么不是可有可无的装饰而是整套系统能work的关键保险。2. PPO登场它到底在优化什么2.1 先搞清楚强化学习的基本框架要理解PPO得先把强化学习那套语言对齐一下。在这个场景里智能体Agent就是我们要训练的语言模型也就是策略Policy记作π。状态State当前已经生成的上下文也就是prompt加上已经吐出来的token。动作Action下一个要生成的token。注意这里动作空间是整个词表动辄几万维。奖励Reward整段回答生成完后由奖励模型给出的那个分数。策略Policy给定状态输出下一个token的概率分布。和打游戏不同这里的一局就是生成一整段回答。奖励只在整段结束后给一次中间每一步没有即时反馈。这种稀疏奖励超大动作空间的组合让朴素的强化学习算法很难直接work这也是为什么最后是PPO这类算法胜出。2.2 策略梯度直接往高奖励方向推概率最基础的思路是策略梯度。直觉很简单如果某个动作带来了高回报就提高它被选中的概率如果带来低回报就降低。数学上就是让参数沿着回报对策略对数概率的梯度方向更新。但原始策略梯度有个致命问题方差极大。因为一整段回答的奖励是一个数它要分摊到几十上百个token上每个token到底贡献了多少其实说不清。而且每次更新后策略就变了旧数据立刻失效样本利用率极低。语言模型训练本来就贵这样搞根本烧不起。2.3 重要性采样与旧策略数据复用PPO的第一个关键设计是重要性采样。它允许我们用旧策略π_old采出来的数据去估计新策略π的梯度。做法是给每个样本乘一个比值ratio π(a|s) / π_old(a|s)这个比值衡量的是新策略选这个动作的概率是旧策略的多少倍。如果新策略更倾向于这个动作ratio大于1梯度就被放大反之缩小。这样一来一批数据可以反复用好几次样本效率大幅提升。但重要性采样有个前提两个分布不能差太远否则比值会爆炸估计就失真了。这就引出了PPO的第二个关键设计。2.4 裁剪目标PPO最核心的那把安全锁PPO全称Proximal Policy Optimization关键词是Proximal——近端。它的核心思想是每次更新别让新策略跑太远就在旧策略附近小步走。实现方式就是那个著名的裁剪clip目标L min( ratio * A, clip(ratio, 1-ε, 1ε) * A )其中A是优势函数后面讲ε通常取0.1或0.2。这个式子的意思是当ratio落在[1-ε, 1ε]区间内时正常用ratio乘优势一旦超出这个区间梯度就被截断不再鼓励策略继续往那个方向猛冲。为什么这么设计因为一旦ratio偏离太远说明新策略和旧策略差异过大重要性采样的估计就不可靠了这时候再按这个不可靠的梯度更新很容易把策略带崩。裁剪相当于给每次更新装了个限速器宁可慢一点也要稳。提示ε的取值是个经验活。太小如0.05会导致更新过于保守训练慢得像蜗牛太大如0.3则失去约束意义容易震荡。实践中0.1到0.2是常见起点具体要看任务和batch大小。2.5 优势函数判断这个动作比平均好多少光有奖励还不够因为奖励是整段的我们想知道的是在某个状态下选这个token比平均水平好多少。这就是优势函数A(s,a)的作用它等于这个动作的实际回报减去这个状态的平均回报基线。减去基线的意义在于降方差。举个例子如果所有回答的奖励都是100分左右那奖励本身没有区分度但减去基线后高于平均的为正、低于平均的为负信号就清晰了。常用的估计方法是GAEGeneralized Advantage Estimation它通过一个衰减因子λ在偏差和方差之间做权衡。λ接近1方差大偏差小λ接近0则相反通常取0.95。3. RLHF的完整训练管线四个模型同台3.1 四个模型的角色分工真正跑起来的时候内存里同时存在四个模型这是很多人第一次看代码时最懵的地方模型作用是否更新参数Actor策略模型生成回答就是要训练的主角是Critic价值模型估计状态价值算优势用是Reward Model给完整回答打分否Reference Model提供KL约束的基准否Actor和Critic要训练所以需要优化器和梯度Reward和Reference是冻结的只做前向。这也是为什么RLHF对显存的要求远高于SFT——四个模型同时驻留哪怕用LoRA、梯度检查点这些省显存的手段开销依然可观。3.2 为什么需要一个Reference ModelReference Model通常是SFT之后的那个模型副本参数冻结。它的唯一作用是计算KL散度KL(π || π_ref) 每个token上当前策略与参考策略分布的差异这个KL项会被加进奖励里作为惩罚。也就是说最终奖励不是单纯的RM分数而是total_reward RM_score - β * KLβ是KL惩罚系数。这个设计的动机前面提过防止策略为了刷RM分数而跑偏跑得离原始SFT模型越远惩罚越大。它相当于一根橡皮筋把策略拴在说人话的范围内。我个人的经验是β这个参数比想象中敏感。β太小模型很快学会输出一堆讨好RM但没营养的内容β太大模型几乎不敢偏离SFTRLHF等于白做。常见起点在0.01到0.1之间需要盯着KL的实际数值动态调。3.3 训练循环的每一步在干什么把整个循环拆开大概是这么个流程从数据集采样一批prompt。Actor对每个prompt生成回答rollout记录每个token的log概率。Reward Model给每个完整回答打分。Reference Model对同样的回答算log概率用于计算KL。Critic对每个状态估计价值结合奖励算出优势。用PPO的裁剪目标更新Actor用均方误差更新Critic。每隔若干步把Actor的参数同步给Reference有些实现是固定不动的看具体方案。这里有个实操细节rollout阶段是纯推理不建计算图非常耗显存和时间。所以通常会控制每次生成的batch大小并且把生成和训练分成两个阶段中间把log概率、reward这些中间量存下来。我第一次跑的时候没注意把生成和反向传播混在一起显存直接爆掉。3.4 一个常被问的问题能不能跳过RM直接用人类打分理论上可以但完全不现实。人类标注速度是每秒几个字符级别而PPO需要成千上万次rollout来更新。让人类实时给每次生成打分训练一轮要等到天荒地老。RM的价值就在于把人类偏好蒸馏成一个能毫秒级打分的函数让强化学习的高速迭代成为可能。这也是为什么RM的质量直接决定RLHF的上限——RM学歪了后面全白搭。4. 落到代码PPO的关键实现细节4.1 优势计算的代码逻辑GAE的计算是逐token反向递推的核心就几行但很容易写错。逻辑大致是# 从后往前遍历每个token for t in reversed(range(T)): # TD误差即时奖励 折扣*下一状态价值 - 当前状态价值 delta reward[t] gamma * value[t1] - value[t] # GAE递推 gae delta gamma * lam * gae advantage[t] gae # 优势归一化这一步对稳定性很关键 advantage (advantage - advantage.mean()) / (advantage.std() 1e-8)这里有两个坑。第一value[T]最后一个状态之后的价值要设成0因为episode结束了。第二优势归一化几乎必做不做的话不同batch之间尺度差异大训练会抖得厉害。我一开始省了归一化loss曲线跟心电图似的。4.2 裁剪损失的具体写法PPO的actor loss实现要注意符号和维度# 新旧策略的概率比 ratio torch.exp(new_logprobs - old_logprobs) # 未裁剪的目标 surr1 ratio * advantages # 裁剪后的目标 surr2 torch.clamp(ratio, 1 - clip_eps, 1 clip_eps) * advantages # 取较小值注意是最大化目标所以loss取负 actor_loss -torch.min(surr1, surr2).mean()torch.exp(new_logprobs - old_logprobs)这个写法比直接算概率再相除更数值稳定因为log概率通常是很小的负数直接相除容易出精度问题。另外old_logprobs必须是生成时记录下来的、detach过的不能带梯度否则整个重要性采样的逻辑就错了。4.3 KL惩罚的两种实现方式KL惩罚有两种常见做法效果和稳定性不一样加在奖励里reward rm_score - beta * kl每个token都算KL累加进奖励。这是最经典的做法。加在loss里把KL作为一个独立的正则项加到总loss上。第一种更符合理论推导第二种实现更简单。实践中第一种更常见但要注意KL是按token算的一段长回答的KL累积起来可能很大所以β要相应调小。有些实现会用自适应KL——设定一个目标KL值如果实际KL超过目标就增大β低于目标就减小β让KL维持在一个合理区间。这个技巧在调参困难时特别有用。4.4 Critic的训练目标Critic的任务是预测每个状态的价值也就是从这个状态往后能拿多少回报。它的loss就是预测值和实际回报的均方误差critic_loss F.mse_loss(values, returns)returns通常用优势加价值算出来returns advantages values。Critic的更新和Actor是分开的但共享同一批数据。有个细节是Critic的loss有时会乘个系数如0.5再和actor loss相加避免critic的梯度主导整个更新。5. 实操中最容易翻车的几个点5.1 奖励尺度不统一导致训练发散RM输出的分数范围是不固定的可能这一批都是0.5左右下一批突然出现个3.0。如果直接拿来做优势计算尺度差异会让梯度忽大忽小。解决办法是对奖励做归一化或者用running mean/std做标准化。我吃过这个亏训练到一半loss突然爆炸排查半天才发现是某批数据的奖励异常高。5.2 rollout和训练的策略不一致这是个隐蔽的bug。如果你在rollout时用了某种采样策略比如temperature、top-p但在计算log概率时用了默认的greedy那新旧策略的概率就对不上ratio从一开始就是错的。必须保证生成时用的采样参数和计算logprob时的参数完全一致。5.3 显存不够时的取舍四个模型同时在线显存压力巨大。常见的省显存手段有用LoRA只训练低秩适配器、开启梯度检查点、把Reference和Reward量化到8bit、减小rollout的batch。这些手段可以叠加但要注意量化会带来精度损失可能影响KL计算的准确性。我的建议是优先减batch和用LoRA量化作为最后手段。5.4 训练不稳定的信号识别PPO训练过程中有几个指标要盯着KL散度、clip比例被裁剪的样本占比、reward均值、entropy。如果clip比例长期很高比如超过0.3说明策略每次跑得太远要减小学习率或增大ε如果entropy快速下降说明策略过早收敛到确定性输出探索不足可能要加entropy bonus。这些指标比单纯的loss更能反映训练健康度。6. 关于这套方法的一些个人判断RLHF加PPO这套组合在ChatGPT之后几乎成了对齐的标配但它绝不是终点。PPO本身是为连续控制任务设计的搬到语言模型上其实有点水土不服——四个模型的开销、超参数的敏感、训练的不稳定都是实打实的工程负担。后来出现的DPODirect Preference Optimization就是冲着这些痛点去的它绕开了显式的奖励模型和强化学习循环直接用偏好数据优化策略实现简单得多。但DPO也不是万能。它在某些需要复杂推理、需要在线探索的任务上效果未必比得上PPO。所以现在很多团队的做法是先用DPO快速迭代遇到瓶颈再上PPO精调。理解PPO的每一个设计动机哪怕最后你不用它也能帮你看懂后来那些简化方案到底简化了什么、牺牲了什么。我自己跑通这套流程最大的收获不是记住了那几个公式而是理解了对齐这件事的本质它是在一个近似的人类偏好信号下小心翼翼地引导一个强大的生成模型既要让它变好又不能让它跑偏。那个KL惩罚项、那个裁剪区间本质上都是这种小心的工程化表达。想清楚这一层再看那些公式就不会觉得它们是无意义的符号堆砌了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑