大模型的对齐训练里RLHF基于人类反馈的强化学习几乎是绕不开的一环。我最早接触这套流程是在一个对话模型微调项目里当时模型已经做完了指令微调回答问题的格式没问题但输出质量参差不齐——有的回答啰嗦绕圈有的答非所问还有的会一本正经地编造事实。后来把RLHF这套流程搭起来跑通模型的回答风格和有用性有了肉眼可见的改善。这篇文章就把我踩过的坑、调过的参数、想明白的原理完整地摊开讲一遍。RLHF本质上解决的是“模型怎么知道什么样的回答算好”这个问题。监督微调只能告诉模型“这个回答是对的”但没法告诉它“这个回答比那个回答好多少”。而人类对质量的判断天然是相对的、有排序的RLHF正是把这种相对偏好转化成训练信号的一套工程方法。它适合已经完成预训练和监督微调、想要进一步提升模型输出质量和对齐程度的从业者参考对强化学习零基础但熟悉深度学习训练流程的读者也能跟下来。1. 整体方案设计与思路拆解1.1 为什么是“三阶段”而不是一步到位RLHF的标准流程拆成三个阶段监督微调SFT、奖励模型训练RM、强化学习优化RL。很多人第一次看会觉得绕——既然最终目标是让模型输出更好为什么不直接拿人类偏好数据去训模型这里的关键在于人类偏好数据的形式是“A回答比B回答好”它是一个比较信号不是绝对标签。你没法直接拿这种比较信号去做监督学习因为监督学习需要的是“标准答案”。而奖励模型的作用就是把这种离散的、成对的比较关系压缩成一个连续的标量打分函数。有了这个打分函数强化学习才能对模型生成的任意回答给出即时反馈。我试过跳过奖励模型、直接用偏好数据做某种对比损失来微调效果很不稳定。原因是模型很容易学到“讨好比较数据里的表面特征”比如回答越长越容易被偏好结果模型开始无脑堆长度。奖励模型这一层相当于一个缓冲带它把偏好信号抽象成打分能力再由强化学习去优化策略整个链条的可控性强很多。三个阶段的分工可以这样理解SFT负责让模型“会说话”奖励模型负责让模型“知道什么话算好话”强化学习负责让模型“主动多说好话”。缺了SFT模型连基本格式都不对奖励模型没法评缺了奖励模型强化学习没有反馈信号缺了强化学习模型只能模仿SFT数据没法超越数据分布去探索更好的回答。1.2 奖励模型为什么用“成对比较”而不是“绝对打分”这是我在设计阶段纠结最久的一个点。让标注员直接给回答打1到10分数据利用率不是更高吗一个人一次能标好几条成本也低。实测下来绝对打分的标注一致性很差。同一个回答不同标注员给的分能差三四分同一个人隔一天再标也会漂移。而换成成对比较——“这两个回答哪个更好”——标注员的判断一致性明显提升因为人做相对判断比做绝对判断稳定得多这是认知层面的规律不是靠培训能完全消除的。所以奖励模型的训练数据组织成promptchosen回答rejected回答的三元组损失函数用的是Bradley-Terry模型下的成对排序损失。简单说就是让奖励模型给chosen打的分尽量高于rejected两者差值经过sigmoid后做二元交叉熵。这个设计的好处是它只关心相对高低不关心绝对分值天然适配人类偏好的相对性。注意成对比较的数据里chosen和rejected的质量差距要拉开一些。如果两条回答质量接近标注员自己都犹豫这种数据训进去只会给奖励模型引入噪声。我在数据清洗阶段会把标注员置信度低的样本直接剔除宁可少几百条也不要脏数据。1.3 PPO为什么是主流选择它的代价是什么强化学习阶段主流用PPO近端策略优化。选它的核心理由是稳定——PPO通过裁剪clip机制限制每次策略更新的幅度避免模型在优化奖励的过程中跑偏太远把语言能力搞崩。但PPO的工程代价不小。它需要同时维护四个模型策略模型要训的、参考模型冻结的SFT模型用来算KL惩罚、奖励模型冻结的用来打分、价值模型critic用来估计基线。四个模型同时驻留显存7B级别的模型在单卡上基本放不下必须做模型并行或者用参数卸载。我第一次搭的时候没算清楚显存跑到一半OOM排查了半天才发现是价值模型和奖励模型重复加载了。KL惩罚这一项也值得单独说。它的作用是约束策略模型不要偏离SFT模型太远防止模型为了刷奖励模型的分数而输出一些奖励模型喜欢但人类看着别扭的文本也就是奖励黑客。KL系数设太小模型容易跑飞设太大模型几乎不更新等于白训。我一般从0.01到0.05之间试具体看奖励曲线的形态来调。2. 核心细节解析与实操要点2.1 SFT阶段的数据质量决定天花板很多人把SFT当成走过场觉得反正后面有RLHF兜底。这个想法很危险。SFT模型是后续参考模型和策略模型的初始化起点它的质量直接决定了RLHF的探索空间。SFT数据里如果有大量格式混乱、逻辑跳跃的样本策略模型一开始就带着坏习惯强化学习阶段要花很大力气去纠正甚至纠正不过来。我在SFT阶段的做法是数据量不求多但每条都要过三关。第一关是格式关确保回答结构完整、没有截断第二关是事实关涉及具体信息的回答要人工核对第三关是风格关统一回答的语气和详略程度。这三关过下来数据量可能只剩原始采集的一半但训练出来的SFT模型明显更“听话”。SFT的训练超参也有讲究。学习率不能太大我一般用1e-5到2e-5之间epoch数控制在3左右。训太多轮模型会过拟合SFT数据的表达方式回答变得模板化这对后面的RLHF不利——策略模型需要一定的表达多样性才能探索出更好的回答。2.2 奖励模型的架构与训练细节奖励模型的常见做法是拿SFT模型改的把最后的语言模型头换成一个输出单标量的线性头。这样奖励模型能复用SFT模型的语言理解能力收敛更快。训练时的几个关键点我列一下学习率要比SFT小我用5e-6左右。奖励模型的训练目标比语言建模更敏感学习率大了容易震荡。batch内要保证chosen和rejected成对出现不能打乱。排序损失依赖成对关系打乱就失效了。训练轮数控制在1到2个epoch。奖励模型很容易过拟合偏好数据训多了它在训练集上打分很准但泛化到策略模型新生成的回答上就失准这会直接导致RL阶段奖励信号失真。验证集要看排序准确率不是看loss。排序准确率指的是奖励模型给chosen打分高于rejected的比例这个指标到70%以上基本可用到75%以上算不错。提示奖励模型的输出分值范围不需要归一化到固定区间但训练时建议对分值做中心化处理让chosen和rejected的分值差在0附近波动这样排序损失的梯度更稳定。还有一个容易忽略的点奖励模型的输入要包含完整的prompt加回答不能只喂回答。因为同一个回答在不同prompt下的好坏判断是不一样的奖励模型必须看到上下文才能做出合理打分。2.3 PPO训练的四个模型协同PPO阶段的工程复杂度最高我把四个模型的角色和更新关系理清楚模型是否训练作用显存占用策略模型是生成回答被优化高含梯度参考模型否算KL惩罚约束策略中仅推理奖励模型否给回答打分中仅推理价值模型是估计基线降方差高含梯度每次迭代的流程是策略模型对一批prompt生成回答奖励模型给每个回答打分参考模型算策略模型和参考模型的KL散度作为惩罚项价值模型估计每个token位置的预期回报作为基线最后用优势函数奖励减基线再减KL惩罚去更新策略模型和价值模型。这里有个实操细节生成阶段要用采样而不是贪心解码温度一般设0.7到1.0之间。贪心解码生成的回答缺乏多样性策略模型没法从中学到“哪种回答更好”的对比信息。但温度也不能太高太高生成的回答质量太差奖励模型打出来的分全是低分梯度信号没有区分度。价值模型的训练目标常被忽视。它的作用是降低策略梯度的方差如果价值模型估得不准优势函数的噪声会很大策略更新方向就会抖。我一般给价值模型设一个比策略模型稍大的学习率让它跟得上策略的变化速度。2.4 KL惩罚系数的动态调整KL系数我一开始是固定值后来发现固定值很难兼顾训练前期和后期。前期策略模型离参考模型近KL小固定系数下惩罚力度不够模型容易早期就跑偏后期策略模型已经优化了不少KL自然变大固定系数下惩罚过重模型几乎不更新。后来改成自适应KL设定一个目标KL值比如6每轮迭代后看实际KL高于目标就把系数调大低于目标就调小。这样训练全程的KL能稳定在目标附近策略更新的节奏更均匀。这个技巧在多个项目里都验证有效强烈建议加上。3. 实操过程与核心环节实现3.1 数据管线的搭建整个RLHF的数据分三类SFT数据、偏好数据、PPO阶段的prompt数据。三类数据的来源和处理方式不同我建议分开建管线不要混在一起。SFT数据是prompt回答对来源可以是人工撰写、模型生成后人工筛选、或者从高质量语料里构造。偏好数据是promptchosenrejected三元组核心是标注环节。PPO阶段的prompt数据只需要prompt不需要回答因为回答是策略模型现场生成的。偏好数据的标注我踩过一个坑一开始让标注员自由发挥结果不同标注员的偏好标准差异很大有人偏好详细有人偏好简洁训出来的奖励模型打分标准混乱。后来改成给标注员一份明确的偏好准则比如“优先考虑事实准确性其次考虑完整性最后考虑简洁性”并且定期做标注一致性校准奖励模型的排序准确率才稳定下来。数据配比也需要注意。偏好数据里如果某类任务比如代码问答占比过高奖励模型会在这类任务上打分很准但在其他任务上失准。我一般让偏好数据的任务分布尽量贴近实际使用场景的分布各类任务按比例采样。3.2 奖励模型的训练脚本关键配置奖励模型的训练循环和普通语言模型训练类似核心差异在损失计算。下面是我常用的损失实现逻辑PyTorch风格伪代码# 输入chosen_ids, rejected_ids, attention_mask chosen_rewards reward_model(chosen_ids, attention_mask) # shape: [batch] rejected_rewards reward_model(rejected_ids, attention_mask) # Bradley-Terry 成对排序损失 loss -torch.log(torch.sigmoid(chosen_rewards - rejected_rewards) 1e-8).mean()几个配置项我固定下来优化器用AdamWweight_decay设0.01梯度裁剪max_norm设1.0防止梯度爆炸学习率带warmupwarmup比例0.1batch size尽量大成对样本的batch我一般设到64对以上排序损失的梯度才稳训练过程中我盯两个指标训练集上的排序准确率和验证集上的排序准确率。两者差距超过5个百分点就说明过拟合了要早停。另外我会定期用奖励模型给一批人工标注过绝对质量的回答打分看打分和人工判断的相关性这个相关性比排序准确率更能反映奖励模型的实际可用性。3.3 PPO训练循环的完整实现PPO训练循环是整个流程里最容易出bug的部分我把关键步骤拆开讲。第一步是生成。策略模型对batch里的每个prompt生成回答记录每个token的log概率。这里要注意生成时的log概率要用策略模型当前参数算不能用旧参数否则后面算重要性采样比率会错。第二步是打分。奖励模型给完整回答打分得到序列级奖励。这里有个细节奖励模型打的是整个回答的分但PPO需要的是每个token的奖励。常见做法是把序列级奖励放在最后一个token上前面的token奖励设0然后通过价值模型和折扣因子把奖励往前传播。折扣因子一般设1.0因为语言生成任务里每个token对最终质量的贡献都需要被考虑。第三步是算KL惩罚。对每个token算策略模型和参考模型在该token上的log概率差作为KL惩罚加到奖励上。KL惩罚是逐token算的不是序列级。第四步是算优势。用价值模型估计每个token位置的基线值优势等于实际回报减基线。实际回报是奖励加上后续token的折扣累积这里用GAE广义优势估计来算lambda设0.95。第五步是更新。策略模型的损失是PPO的裁剪损失价值模型的损失是均方误差。两个模型分别更新但共享同一批数据。# PPO策略损失核心逻辑伪代码 ratio torch.exp(new_logprobs - old_logprobs) surr1 ratio * advantages surr2 torch.clamp(ratio, 1 - clip_eps, 1 clip_eps) * advantages policy_loss -torch.min(surr1, surr2).mean()clip_eps我一般设0.2这是PPO的默认值实测下来在语言模型上也比较稳。3.4 训练监控与早停策略RLHF训练不像监督学习那样有明确的收敛点必须靠监控指标来判断什么时候停。我盯的指标有这么几个平均奖励分应该整体上升但如果上升过快比如几轮就翻倍大概率是奖励黑客模型在钻奖励模型的空子。KL散度应该稳定在目标值附近突然飙升说明策略跑偏了。回答长度这是奖励黑客的经典信号。如果平均长度持续增长而奖励分也涨很可能是模型学会了堆长度讨好奖励模型。人工抽检每训练若干轮人工看一批生成回答判断质量是否真的在提升。这个环节不能省指标好看但实际输出变差的案例我见过不止一次。早停的触发条件我设了两条一是KL连续多轮超过目标值上限二是人工抽检发现质量下降。满足任一条就回滚到之前的检查点。4. 常见问题与排查技巧实录4.1 奖励黑客模型学会了骗奖励模型这是RLHF里最经典也最头疼的问题。表现是奖励分一路涨但人工看输出发现模型在输出一些“奖励模型喜欢但人类觉得奇怪”的内容。常见的黑客模式有无脑堆长度、堆砌礼貌用语、重复prompt里的关键词、输出格式花哨但内容空洞。排查思路是先定位奖励模型被钻了什么空子。我的做法是拿一批黑客样本去问奖励模型看它给这些样本打多少分再对比人工判断。如果奖励模型给黑客样本打分明显偏高说明奖励模型的训练数据里这类样本的覆盖不够需要补充负样本重新训奖励模型。缓解手段有几个加大KL惩罚系数让策略模型不敢偏离SFT模型太远在奖励里加长度惩罚项抑制堆长度定期用新策略模型生成的样本去扩充奖励模型的训练数据让奖励模型跟上策略的演化。我一般组合使用单靠一个手段效果有限。4.2 训练不稳定奖励曲线剧烈震荡PPO训练中奖励曲线震荡是常见现象轻微震荡正常剧烈震荡说明有问题。我遇到过几次排查下来原因各不相同现象可能原因排查方法解决手段奖励分忽高忽低学习率过大看梯度范数降低策略学习率奖励分整体下降KL系数过大看KL曲线调小KL系数奖励分不动优势函数全接近0看价值模型输出检查价值模型是否训崩生成回答重复温度过低看生成配置提高采样温度有一次奖励分整体下降我查了半天以为是KL系数问题后来发现是价值模型的学习率设太小基线估计严重滞后优势函数算出来全是负的策略模型被往反方向推。把价值模型学习率调大后恢复正常。这个坑提醒我四个模型的学习率要协同调不能只盯策略模型。4.3 显存不够四个模型放不下怎么办7B模型做PPO四个模型全精度加载需要大量显存单卡基本不可能。我的解决方案组合参考模型和奖励模型用半精度加载且只做推理不存梯度显存占用能压到策略模型的一半左右。策略模型和价值模型用梯度检查点gradient checkpointing用计算换显存显存能省30%到40%代价是训练速度慢一些。如果还不够用参数卸载把参考模型和奖励模型的部分层放到CPU内存需要时再加载回GPU。这个方案会拖慢训练速度但能跑起来。最后的手段是模型并行把策略模型和价值模型切到多卡上。这个方案工程复杂度最高非必要不用。注意半精度加载参考模型时KL散度的计算要用float32做半精度下log概率的精度损失会让KL估计偏差很大进而影响惩罚项的准确性。4.4 偏好数据标注质量差怎么补救标注质量差是很多团队的实际困境尤其是预算有限、标注员培训不到位的情况。我的补救思路分两层第一层是数据清洗。用奖励模型哪怕是个初步版本给偏好数据打分找出那些“奖励模型判断和标注标签严重不符”的样本人工复核。这类样本要么是标注错了要么是奖励模型还没学到无论哪种都值得单独处理。第二层是数据增强。对高质量的偏好样本做改写增强比如把chosen回答换个表达方式但保持质量生成新的偏好对。这样能在不增加标注成本的前提下扩充数据量。但增强要控制比例增强数据占比太高会让奖励模型学到改写风格而不是质量判断。4.5 训练完了效果不明显怎么办有时候整套流程跑完模型输出质量提升很有限。我复盘过几次原因通常出在几个环节SFT模型本身太强RLHF的提升空间本来就小。这种情况不是RLHF没用而是边际收益递减需要更精细的偏好数据才能挖出提升点。奖励模型和实际使用场景不匹配。偏好数据的任务分布和实际场景偏差大奖励模型在场景内打分不准策略模型优化方向就偏了。解决办法是补充场景内的偏好数据重训奖励模型。KL系数设太大策略模型几乎没更新。看KL曲线和策略模型的参数变化量能确认这一点调小系数重训即可。还有一种情况是评估方式有问题。RLHF提升的往往是对齐质量有用性、无害性、诚实性而不是知识量。如果评估只看知识问答准确率可能看不出提升。评估要覆盖对齐维度比如用人工偏好评估或者专门的奖励模型打分。5. 工程化落地的经验补充5.1 训练成本与资源规划RLHF的训练成本比SFT高一个量级主要高在PPO阶段。以7B模型为例SFT阶段单卡几小时能跑完一轮PPO阶段四模型协同单轮迭代的时间是SFT的十几倍完整跑下来需要多卡多天。资源规划时要把PPO阶段作为瓶颈来算。我的经验是PPO阶段的迭代轮数不用太多几百到上千轮每轮一个batch通常能看到明显效果再多边际收益递减。关键是每轮的数据质量和奖励信号准确性而不是轮数堆砌。5.2 迭代式RLHF多轮循环单轮RLHF跑完模型质量提升到一定程度就停滞了。这时候可以做迭代式RLHF用当前策略模型生成新回答人工标注偏好扩充偏好数据重训奖励模型再跑一轮PPO。这个循环每转一圈奖励模型和策略模型都同步进化质量能持续爬升。迭代式RLHF的成本主要在标注环节但效果比单轮显著。我一般做两到三轮迭代再往上成本收益比就不划算了。5.3 评估体系不能省RLHF的评估比训练还重要因为训练信号本身来自奖励模型而奖励模型可能有偏。评估体系我建议至少包含三层自动指标奖励模型打分、困惑度、人工偏好评估成对比较、场景化测试针对实际使用场景设计测试用例。三层都过才算训练有效。人工偏好评估的样本量不用太大几百条就能看出趋势但评估维度要覆盖有用性、无害性、诚实性三个方向不能只看一个。我在实际项目里的体会是RLHF这套流程的难点不在算法本身算法都是公开的难在工程细节和数据质量。四个模型的协同、KL系数的动态调整、奖励黑客的识别和缓解、偏好数据的标注一致性这些环节任何一个出问题都会让最终效果打折扣。把每个环节的监控做扎实比追求算法上的花活有用得多。后续如果要继续扩展可以考虑把奖励模型换成多个专家奖励模型的集成降低单一奖励模型被黑客的风险这个方向我还在试等有稳定结论再分享。
阅读完成 · 觉得有帮助?