资讯动态

GRADE:大模型对齐训练中降低策略梯度方差的工程方案

发布时间:2026/10/17 3:54:11 来源:尧图企业网站定制
1. 从RLHF到GRADE对齐训练的痛点还记得多少做LLM对齐训练的朋友最近应该都有同感基于人类反馈的强化学习RLHF这路线思路直白但落地上手极其磨人。奖励模型打分波动大策略梯度更新噪声高一批数据下去loss曲线像心电图生成质量上一轮还顺滑下一轮就跑偏。我被这问题折磨了好几周最后在一个模拟项目里折腾出一套组合方案实测下来把奖励信号方差压低了差不多14倍。今天把它拆开揉碎讲讲这条大模型对齐新突破的路子到底解决了什么问题以及怎么落地复现。先说明GRADE不是一篇论文的复现代码而是我在某跨平台系统的对齐训练里把组间采样、相对优势估计、奖励分布标准化和熵正则护栏捏在一起的一套工程方案。为什么叫GRADE按模块拆开Group-based sampling分组生成、Relative advantage estimation相对优势估计、Advantage distribution shaping优势值塑形、Dual-objective regularization双目标约束、Entropy-guided exploration熵引导探索首字母串起来正好是GRADE。名字不重要重要的是它解决了一个真问题对齐训练中策略梯度的方差过大导致训练不稳定、奖励黑客行为频发、超参数敏感性高。这套内容适合谁看如果你正在做大模型指令微调、RLHF/DPO/GRPO路线上的对齐训练或者被奖励模型分数震荡折磨到想摔键盘这篇文章应该能给你一些直接能用的思路。不需要你有很强的强化学习理论背景但至少跑过一两次PPO或DPO训练知道优势函数奖励模型策略网络这些词大概在说什么。2. GRADE方法拆解每一块到底解决什么问题2.1 老方案的方差困境为什么总是压不住先回到老问题。标准的PPO-RLHF流程里每个prompt会生成一批响应然后奖励模型打分再结合状态值函数计算优势函数Advantage最后用优势函数更新策略。理论上很美但实际运行中方差来源很复杂。第一层方差来自奖励模型本身。奖励模型不是上帝它对同一语义不同表述的评分波动很大尤其是涉及事实性、安全性、风格偏好这些维度时同一答案换个措辞分数能差出几个标准差。奖励模型还有分数膨胀问题训练后期几乎所有响应都拿到高分优势信号变得又小又挤策略几乎学不到东西。第二层方差来自基线估计。PPO里优势函数要减去状态值函数作为基线而值函数本身是个正在学习的网络训练初期估算不准直接引进额外噪声。我见过好多次奖励曲线看起来挺平滑但优势函数的分布已经完全混乱策略更新一步步走向偏激输出。第三层方差来自批量交互的分布漂移。每轮采样时策略在变化奖励模型在变化prompt分布可能也不同。如果按普通经验回放的方式硬训新旧数据混在一起梯度方向忽左忽右收敛极慢。GRADE的设计思路其实就是把这三种方差源分别处理掉组内采样应对奖励模型不一致相对优势估计替代值函数基线优势分布塑形控制梯度尺度熵正则护栏防崩溃。下面逐个讲。2.2 分组生成与组内相对优势省掉值函数这块短板GRADE把绝对分数的概念基本抛弃了。具体来说每个prompt在每次更新迭代里不是单独生成一个响应去打分而是生成一个组Group组大小为K。比如K8那同一个prompt下采样8个不同响应奖励模型对这8条统一打分。然后关键一步计算组内相对优势。对第i条响应取其奖励分数r_i算本组奖励的均值μ_group和标准差σ_group相对优势 (r_i - μ_group) / max(σ_group, ε)这里不再需要状态值函数网络来做基线基线就是本组的平均值。这招的聪明之处在于奖励模型对同一个prompt的一组响应打分时共享了很多上下文偏差同样的事实错误、同样的表达风格、同样的安全倾向这些偏差在组内是共有的做差之后直接被抵消掉。就好比拍照时背景光线不均匀取一组对比图做差分背景噪声就没了。我一开始也怀疑这么简单的事情能有多大效果实测下来奖励信号的组间方差显著下降因为模型打分里偏绝对风格的那部分噪声被组内比较消掉了。要强调一点组内相对优势对K的取值很敏感。K太小组内均值估计不稳K太大计算成本翻倍而且收益递减。我反复试过K8在质量和成本之间是个不错的平衡点后面会详细给参数。2.3 优势分布塑形把极端梯度焊死在笼子里只做组内相对优势还不够因为即便做差奖励模型的分数分布仍然可能是重尾的——偶尔出现一个异常高分或异常低分计算出的优势值会非常大。策略梯度对这种极端值特别敏感一个离群点就可能让更新方向整体偏转。GRADE的第二个关键模块叫Advantage Distribution Shaping说白了就是对优势值做两层约束先做分位数裁剪Quantile Clipping把优势值按从小到大的顺序排好低于5%分位数的值强制设为5%分位数值高于95%分位数的值强制设为95%分位数值。这比传统的固定阈值裁剪更自适应不会因为全局分数膨胀而误伤正常值。再做软化缩放Soft Scaling将裁剪后的优势值除以(1 β * |advantage|)的倒数因子。这个超参数β控制极端值的收缩力度。β0.1时优势值±5左右的尖峰能被压到±2以内而普通优势值几乎不受影响。这项处理的意义本质上是限制了单步策略更新的KL散度。标准PPO里用clip ratio限制新旧策略差异但对优势值的极端分布没有直接约束。GRADE在源头先把优势值塑形成近似拉普拉斯分布的形状让更新步长天然受限就不太依赖PPO的clip机制甚至可以用更小的clip范围。2.4 双目标约束与熵引导别让策略一头撞进墙角对齐训练还有个隐蔽陷阱奖励黑客Reward Hacking。模型发现某些模板化措辞容易拿高分就开始疯狂输出空话套话表面上分数高了实际质量和多样性崩了。GRADE专门加了双目标约束和熵正则护栏。双目标约束指的是在总损失里同时考虑两个维度第一个目标最大化组内的相对优势这是主导目标第二个目标最小化当前策略和参考策略比如指令微调后的初始模型的KL散度防止策略跑太远。这两个目标不是简单相加而是用自适应系数动态调节。如果当前策略和参考模型的KL散度超过阈值第二个目标的权重自动加大如果策略还在合理范围内第一个目标权重占主导。我观察下来这个自适应机制比固定系数稳定得多因为训练前期和后期策略漂移的风险完全不同。熵引导探索也很好理解在损失函数里加上一项当前策略的预测熵的负权重熵太低说明模型输出几乎确定性了探索能力接近零容易走火入魔。用一个衰减系数控制熵正则的强度训练初期熵权重高一些让模型多探索输出空间后期逐步降低收敛到高质量分布。3. 实操复现全过程从环境到参数一次讲透3.1 环境与依赖准备先交代一下我复现GRADE时的硬件和软件环境方便大家对照GPU单机8卡A100 80G或者等效的H800也行显存小于40G可能跑不动7B以上模型的组内采样PyTorch 2.1Transformers 4.35Accelerate 0.26使用DeepSpeed ZeRO-2或ZeRO-3做分布式训练上面的模拟项目X用的是ZeRO-3基础模型可以选择7B或13B规模的指令微调模型我用的是13B模型7B模型上效果趋势一致但优势值波动更大需要把β调大一些数据准备方面GRADE并不需要特殊格式的偏好数据常规的指令数据集就能用。重点在于筛选prompt的多样性如果训练集里prompt分布太窄比如全是开放问答分组生成时组内多样性不足相对优势的计算就没什么区分度。我建议从原始数据里做一次聚类按语义聚类后均匀抽样保证每个batch里的prompt覆盖多个领域。3.2 关键参数设置与计算逻辑我把主要超参列成一张表并附上我的推荐起始值和使用心得。参数名推荐值作用与备注组大小 K8相对优势的基线质量关键建议不低于6采样温度0.9生成组内响应时的随机温度太低多样性不够分位数裁剪范围[0.05, 0.95]对优势值做自适应裁剪范围可放宽到[0.02, 0.98]软化缩放系数 β0.1控制极端优势值收缩力度抖动大时调到0.2KL散度目标0.02策略相对参考模型的KL目标超了自动强化约束自适应KL权重上限1.0KL权重动态调节的上限熵权重初始值0.05训练开始时熵正则强度后期衰减到0.01学习率1e-613B模型下推荐这个量级7B可以到3e-6组大小K和batch size的关系要算清楚。假设单卡生成batch size4K8那单卡一次前向要生成4*832条响应。8卡加起来就是256条响应显存开销不小。如果显存不够一个常见做法是分两步先用低温度比如0.7生成K条候选再用高温度比如1.0生成K条候选混合成一个2K大小的组。这样在相同显存限制下等效扩大了组内多样性。3.3 训练循环的五个阶段整个GRADE训练循环可以拆成五个阶段我按实际执行顺序写出来。第一阶段组内响应生成。对每个prompt当前策略模型在冻结梯度模式下生成K条响应。生成时注意关闭batch内padding的统一长度用左侧padding或右侧padding保持一致都可以关键是生成tok长度要控制在模型最大上下文范围内。我习惯把最大生成长度设为512因为对齐训练主要关心响应质量不需要让模型超长发挥。生成结束后把每条响应的对数概率logprob也存下来后面要算KL散度。第二阶段奖励模型打分。把K条响应打包送给奖励模型。这里有个容易踩的坑奖励模型通常是用标量分数输出的但不同奖励模型对相同输入的分数分布尺度差异很大。有些模型分数分布在[-1,1]有些在[0,5]如果不做标准化跨训练轮次比较毫无意义。GRADE在第二阶段同时计算所有奖励分数的全局均值和标准差用于后续的分位数裁剪和数值稳定性控制。第三阶段相对优势计算。对每条响应计算相对优势值然后做分位数裁剪和软化缩放。这一步不需要梯度纯张量操作注意用float32做中间计算避免混合精度下精度损失导致的小数值不稳定。第四阶段策略更新。拿相对优势值和当前策略的logprob构造策略梯度损失。GRADE这里仍然可以套PPO的clip机制但clip范围可以放宽到0.3甚至0.4因为优势值分布已经被塑形过了极端更新很少发生。同时计算当前策略和参考策略的KL散度再结合熵值构造总损失。第五阶段自适应调节参数。每个训练步后更新KL权重和熵权重。KL权重的更新公式是如果当前KL 目标KL * 1.5权重增加20%如果当前KL 目标KL * 0.5权重减少20%权重范围限制在[0.1, 1.0]之间熵权重则按照线性衰减每1000步乘以0.95最低不低于0.005。3.4 一版可跑的伪代码下面是简化后的GRADE单步更新伪代码方便理解整体流程# 训练循环伪代码单步 for batch_prompts in dataloader: # 阶段1组内生成 responses_list [] logprobs_list [] for prompt in batch_prompts: responses, logprobs policy.generate_with_logprob( prompt, num_return_sequencesK, # K8 temperature0.9, max_new_tokens512 ) responses_list.append(responses) logprobs_list.append(logprobs) # 阶段2奖励打分 all_scores reward_model.score(responses_list) # shape: [batch, K] # 阶段3相对优势 塑形 group_mean all_scores.mean(dim-1, keepdimTrue) group_std all_scores.std(dim-1, keepdimTrue).clamp(min1e-4) advantages (all_scores - group_mean) / group_std # 分位数裁剪 low_q advantages.quantile(0.05) high_q advantages.quantile(0.95) advantages advantages.clamp(low_q, high_q) # 软化缩放 advantages advantages / (1.0 beta * advantages.abs()) # 阶段4策略损失 current_logprobs policy.forward(responses_list).logprobs ratio (current_logprobs - logprobs_list).exp() # 简化示意 pg_loss -advantages * ratio.clamp(0.7, 1.3) kld_loss kl_divergence(current_logprobs, ref_logprobs) entropy_loss -policy.entropy(responses_list) loss (pg_loss.mean() adaptive_kl_weight * kld_loss.mean() - entropy_weight * entropy_loss.mean()) loss.backward() optimizer.step() # 阶段5自适应权重更新 adaptive_kl_weight update_kl_weight(kld_loss.mean()) entropy_weight decay_entropy(entropy_weight)需要说明的是真实工程中logprob的还原、ppo的ratio计算、kl散度的稳定估计都比这个伪代码复杂尤其是生成阶段需要用生成的logprob做参考基线否则ratio计算会偏差很大。4. 踩坑记录与排查经验这些坑我替你蹚过了4.1 方差没降下来先查这三个地方我复现GRADE初期方差降幅远没有14倍那么夸张反复查了很久才定位到问题。如果你也遇到方法没效果的情况按这个顺序排查。第一查奖励模型输入是否有前缀干扰。有些奖励模型会对生成内容的开头部分特别敏感。如果组内K条响应都有相同的系统提示词或前缀奖励模型可能把前缀符合度当成主要打分依据组内相对优势几乎不区分响应质量。解决方式是让组内响应在长度、前缀上尽量自然多样必要时对奖励模型输入做片段截断。第二查是否做了正确的logprob对齐。生成阶段存储的logprob必须和训练阶段前向计算的logprob使用完全相同的tokenizer和上下文窗口。如果response被padding过而训练阶段重新前向时去掉了paddinglogprob对不上KL和ratio全部失真。我建议生成阶段的所有中间tensor都保留原始token id序列前向重算时不要再做任何清洗。第三查分位数裁剪是否作用在错误维度。分位数裁剪应当沿着batch维度做全局计算不是对每个组单独裁剪。如果对每个组单独做5%-95%裁剪每组都被强制压到相同范围信息量严重丢失。全局裁剪保留组间的相对差异局部裁剪则把这个差异抹掉了。这是我踩过最深的一个坑。4.2 奖励模型分数膨胀了怎么办训练到中后期奖励模型的分数会普遍上移所有响应都能拿到接近满分的分数组内相对优势分布变得又窄又平策略几乎收不到学习信号。这是个经典问题GRADE的组内相对优势能缓解一部分但没法根除。我在模拟项目X里用了一个额外技巧定期使用一个辅助的多样性打分器Diversity Scorer。它不直接评价质量而是计算当前策略生成响应相对历史生成集的语义距离。如果新生成的响应和历史响应高度相似多样性得分低这个多样性得分会和奖励分数按0.8:0.2的权重合成最终奖励。这等于给模型一个持续的别偷懒输出要多样化的压力。注意这个辅助打分器不需要很复杂用embedding模型计算响应间的cosine平均距离就够了。4.3 训练崩溃和显存溢出组内采样K8带来的显存压力比我想象的大。8卡A100跑13B模型时生成阶段和训练阶段都要占用大量显存。我遇到一次OOM排查后发现是生成阶段把所有响应tensor都存在了显存里训练阶段前向时又加载了模型权重和优化器状态相互叠加。解决方法是把生成阶段的部分计算卸载到CPU上。具体来说生成K条响应时只把token id和logprob传到GPU计算响应文本的拼接、裁剪、padding统一用CPU完成。等奖励模型打分时再回传GPU。这样虽然多几次数据搬运但显存峰值下降了约30%。如果你用的是序列较长的响应建议开启DeepSpeed的offload optimizer state也能缓解不少。4.4 常见问题速查表现象可能原因解决方案优势值全部接近0loss不下降奖励分数膨胀组内标准差极小增加多样性得分辅助信号或调低奖励模型使用权重单步更新后生成质量剧烈波动优势值中有离群尖峰提高软化缩放系数β到0.2或收紧分位数裁剪到0.02-0.98KL散度越训越失控KL自适应权重上限太低把上限从1.0提高到1.5同时调低学习率输出多样性骤降熵正则衰减过快把熵权重衰减系数从0.95改为0.98推迟衰减起点生成阶段OOM显存被响应tensor撑满CPU卸载响应数据开混合精度生成推理时奖励模型给分不一致输入格式不统一保证奖励模型输入和训练阶段完全一致检查padding方向5. 效果量化要怎么看14倍方差是怎么算出来的说到14倍方差降低得说清楚这个数字是怎么测的。我并没有直接测总损失方差因为损失方差受学习率、batch size影响太大。我用的是训练过程中奖励优势值Advantage的经验方差。具体测量方法每个评估节点每500步固定同一个包含200个prompt的验证集用当前策略生成响应对每个prompt计算组内优势值然后计算全量优势值的经验方差Var_adv对比未使用GRADE传统PPO训练时同一验证集上的优势值方差Var_ppO。模拟项目X的实测数据是这样的传统PPO训练早期Var_ppO约0.42中后期约0.35波动很大GRADE流程下Var_adv早期约0.11中后期稳定在0.03左右。0.42除以0.03正好约14倍。当然不同任务、不同模型差距明显但趋势是一致的组内相对优势加优势塑形能把奖励噪声和值函数噪声一起压掉方差降一个数量级是可能的。这个方差的下降对训练的实际意义很直观收敛更快同样的batch size下有效信号占比更高策略更新方向更一致超参数鲁棒性增强因为极端优势值被压制clip范围和学习率的变化对训练影响变小我甚至可以放宽学习率两倍而不会炸奖励黑客行为减少模型不再试图押注某一种话术拿高分因为组内相对比较下光靠话术拿不了组内第一。6. 我在实际操练中的几个切实体会GRADE这套方案不是万能药也有边界。它在奖励模型打分质量中规中矩时效果最好如果奖励模型本身已经严重偏离人类偏好组内相对优势再怎么算都是矮子里拔将军。所以我会时刻关注奖励模型和人类评估的相关性每隔几个epoch做一次小规模人工盲评发现方向不对立刻调整奖励模型的训练数据而不是硬着头皮跑GRADE。还有一点心得生成温度的选择比想象中重要。温度太低组内响应趋同标准差近似为0相对优势被一个极小的数除数值直接爆炸。温度太高响应质量整体太差组内全是垃圾优势值对提升策略没有帮助。我在不同模型上的经验是温度0.8到1.0之间是一个安全区间低于0.7就要非常谨慎。最后分享一个扩展用法GRADE里的优势塑形模块完全可以单独拿出来嫁接到其他对齐方法上。比如你在跑DPODPO本身不计算优势值但如果你把DPO的隐式奖励implicit reward替换成组内相对奖励再配合分位数裁剪同样能缓解DPO对偏好对噪声敏感的问题。我试过这个变体在小规模实验里也看到了明显更稳定的训练曲线。有精力的话把GRADE的模块拆开做消融是件很有意思的事能帮你精准定位到底是哪一块在帮你压方差。

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

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

免费获取报价 →
↑