尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

RLVR与GRPO:用可验证奖励重塑大模型后训练

RLVR与GRPO:用可验证奖励重塑大模型后训练 在实际的大模型开发和落地过程中预训练并不是终点。预训练让模型学会语言规律和世界知识但模型要真正进入产品、承担“回答问题、写代码、做数学题、操作工具”这类任务还需要后训练post-training阶段的改造。近两年后训练的权重越来越高其中一条主线把 SFT、RLHF 和强化学习串了起来监督微调让模型学会响应格式RLHF 让模型对齐人类偏好而可验证奖励强化学习RLVRReinforcement Learning with Verifiable Rewards则把一批可以用程序客观验证的任务交给了更稳定、更可解释的奖励信号。这篇解析从概念、机制、最小实现、参数、排错和工程化几个层面展开核心目标是让读者掌握 RLVR 为什么适合数学、代码这类任务明白 GRPO 与 PPO 的取舍关系并能在小规模模型上搭出一个可运行的后训练回路。适合正在学习大模型开发课程、做模型微调实验或者准备把规则奖励接入生产流水线的算法工程师和开发者阅读。1. 后训练的本质从预训练接力到可验证强化学习很多初学者会把后训练理解成“上完预训练课之后再补一次微调”。这种理解不算错但容易忽略后训练内部的层次差异。预训练、指令微调、偏好对齐和可验证奖励强化学习每一层解决的问题不同消耗的资源也不同。1.1 预训练和后训练的分工预训练阶段的目标是让模型在超大规模语料上学习语言规律和知识。模型的参数在这一阶段获得较强的“知识容量”但它并不知道怎么用这些知识回答用户问题。后训练阶段则是面向使用场景做再加工让模型学会“用户希望我怎样说话、怎样完成任务、怎样避免无意义输出”。后训练通常可以分为几类继续预训练用领域语料让模型补学某个垂直领域的知识。SFTSupervised Fine-Tuning监督微调用“问题-标准回答”样本教会模型指令跟随和输出结构。RLHF / DPO从人类偏好数据中学习对齐目标让模型判断什么是更被接受的回答。RLVR用可验证奖励信号做强化学习让模型在数学、代码、结构化抽取等任务上迭代策略。四类方法不是互斥的实际流水线里经常按“继续预训练 - SFT - RLHF/RLVR”的顺序组合使用。下表可以帮助快速区分它们的定位。训练阶段主要信号目标典型成本适用场景继续预训练语料里的下一个词补充领域知识高需要大算力垂直领域知识增强SFT人工或模型构造的标准回答指令跟随、回答格式中通用指令调优、冷启动RLHF人类偏好 奖励模型对齐主观偏好高需要高质量偏好数据对话质量、有害性控制、主观评价RLVR程序验证器或规则计算出的奖励提升客观可验证任务能力中不需要训练奖励模型数学、代码、SQL、结构化抽取RLVR 在表格中的定位非常清晰它不属于“知识注入”类方法也不负责解决主观偏好问题它只负责把那些拥有客观评价标准的任务做成可迭代的策略优化。1.2 RLHF 的局限让可验证奖励成为一个独立问题RLHF 的核心是先训练一个奖励模型来近似人类偏好再用强化学习让策略模型追求该奖励模型。这个思路对主观任务有效但存在两个明显问题。第一奖励模型的训练成本高。每一条偏好数据都需要人工标注样本质量不稳定时奖励模型的打分也会漂移。第二奖励模型本身是“代理信号”它并不是任务真正的评价标准。模型很容易找到奖励模型没有覆盖的角落生成内容看起来正确但实际没有意义这也是常说的 reward hacking。数学题和代码任务提供了另一种可能。一个数学题的标准答案是确定性的一组代码是否能通过单元测试也是确定性的。既然任务的完成标准不依赖人类主观判断就不必先训练奖励模型可以直接用一个验证器计算奖励。这正是 RLVR 的核心思想奖励不是训练出来的而是被“计算”出来的。RLVR 并不是一种全新的强化学习算法。它强调的是奖励来源的变化。模型仍然在做策略优化但优化目标变成了程序化、规则化、可复现的奖励这一变化让训练过程更稳定也让实验结果更容易解释。2. RLVR 的机制拆解验证器、GRPO 与训练循环理解了 RLVR 的价值下一步要看它是怎么跑起来的。一套 RLVR 训练系统至少包含三部分一个能输出奖励分数的验证器、一个策略优化算法、以及一组负责稳定训练的辅助机制。2.1 验证器的四个设计层级验证器是 RLVR 的灵魂。它决定“什么样的输出算对”因此它的设计质量直接决定训练效果。验证器的复杂度可以从低到高分为四个层级。第一层是字符串匹配。比如要求模型最终输出A或B直接用字符串比较。实现最简单但对格式极其敏感模型稍加改写就会误判。第二层是结构化解析。先要求模型按指定格式输出比如把最终答案放在\boxed{...}里或 JSON 字段里再解析出答案进行比较。该方式可以匹配大多数带格式约束的任务。第三层是数学规范化比较。把表达式转成等价形式再比较比如1/2和0.5在数学上是同一个值但字符串不同。此时可以借助符号计算库归一化后判断。第四层是执行验证。让模型生成代码或 SQL把代码放到沙箱环境里执行用单元测试用例判断对错。这是目前代码任务 RLVR 最常用的方式。可以用下表总结不同层级的取舍。验证方式示例优点局限字符串匹配目标值 模型输出实现最快格式敏感容易被绕过结构化解析从 json /\boxed{}提取答案结果稳定适合数学解析失败会漏掉正确回答规范化比较SymPy 化简、数值比较能处理等价表达式依赖解析和化简准确性执行验证单元测试、SQL 执行更接近真实任务需要沙箱执行成本高设计验证器的原则是“宁可漏判不要误判”。误判的惩罚是给错误输出高分模型会朝着错误方向强化破坏力远大于不奖励正确答案。2.2 为什么 GRPO 适合可验证奖励RLVR 的难点不在验证器而在让模型高效利用奖励信号更新策略。经典的 PPO 需要同时训练一个价值模型critic来估计优势函数计算量大显存占用高。PPO 最初是为了在通用奖励函数下稳定更新策略而设计的价值模型在这里承担了“预测未来回报”的角色。GRPOGroup Relative Policy Optimization这一类方法做了更符合规则奖励任务的设计。每次对一个 prompt 采样一组回答把这组回答的奖励做归一化得到每个回答的相对优势再用这个相对优势更新策略。它不再单独训练价值模型因此训练内存更小、流程也更简单。相对优势的计算可以用一个简化公式表示advantage_i (reward_i - mean(reward_group)) / (std(reward_group) eps)这个式子的含义是如果某个回答的奖励高于这一组回答的平均水平那么它的权重为正策略被鼓励生成类似回答如果低于平均权重为负策略被抑制。归一化还让不同 prompt 的奖励尺度被拉齐避免某个高分 prompt 对整个梯度造成过大影响。GRPO 能高效工作的前提是奖励本身可比较。可验证奖励恰好满足这个前提因为同一组回答面对同一个验证标准奖励尺度天然一致。这也是为什么在后训练和 RLVR 的实践中GRPO 风格的方法高频出现。2.3 一次迭代内的训练数据流一次标准的 RLVR 训练迭代可以拆成六步。从训练集中取一个 prompt batch。对每个 prompt 采样多个完整回答数量记为num_generations。用验证器给所有回答打分。在每个 prompt 内部做奖励归一化得到每个回答的优势。根据优势计算策略损失同时引入参考模型的 KL 约束防止策略漂移。反向传播更新策略模型参数进入下一轮采样。下面是一段概念性伪代码用来展示核心逻辑并不对应某个具体框架。for prompt in train_dataset: responses [policy.sample(prompt) for _ in range(G)] rewards [verifier(resp, expectedprompt.answer) for resp in responses] mean_r sum(rewards) / len(rewards) std_r (sum((r - mean_r) ** 2 for r in rewards) / len(rewards)) ** 0.5 advantages [(r - mean_r) / (std_r 1e-4) for r in rewards] for resp, adv in zip(responses, advantages): logp_new policy.log_prob(prompt, resp) logp_old old_policy.log_prob(prompt, resp) ratio exp(logp_new - logp_old) clipped_ratio min(max(ratio, 1 - eps), 1 eps) policy_loss -min(ratio * adv, clipped_ratio * adv) kl_loss kl_coef * kl_divergence(reference_model, policy, prompt, resp) policy.update(policy_loss kl_loss)伪代码中省略了大量工程细节但读者可以清楚看到 RLVR 训练回路的基本形状采样、验证、归一化、更新。真实框架里还会加入日志、断点、梯度裁剪、reward 缓存等机制但主线不会变。3. 最小可运行案例数学任务上的 RLVR/GRPO 训练回路下面用一个数学问答任务演示如何把 RLVR 落地。这里以 Qwen2.5-1.5B-Instruct 这类小规模模型为例目标是让读者理解完整流程而不是追求最终评测分数。实际项目里可以根据算力替换成更大的基座模型。3.1 环境准备与依赖建议使用 Linux 环境、Python 3.10 或 3.11并准备一块 24GB 显存以上的 GPU。下面的依赖以 Hugging Face TRL、Transformers、Datasets 和 SymPy 为主。pip install torch transformers trl datasets sympy peft不同版本对 API 的影响很大尤其是 TRL 的GRPOTrainer参数命名和 RewardFunc 签名。落地前建议先执行pip show trl查看版本再对照官方文档微调下方代码。如果用旧版接口直接套用最常见的问题是构造函数报参数不存在。3.2 准备训练数据和验证器先准备一个很小的训练数据文件math_train.jsonl每条数据包含一个问题和一个标准答案。{problem: 计算 17 25最终答案请用 \\boxed{...} 包裹。, answer: 42} {problem: 计算 3 * 7最终答案请用 \\boxed{...} 包裹。, answer: 21} {problem: 计算 100 - 37最终答案请用 \\boxed{...} 包裹。, answer: 63}验证器负责从模型输出中解析答案并和标准答案做数学等价比较。使用 SymPy 的好处是1/2与0.5会被识别为同一个值避免字符串比较的误判。import re import sympy as sp def parse_boxed(text: str): pattern r\\boxed\{([^}]*)\} match re.search(pattern, text) if not match: return None return match.group(1).strip() def math_reward(completions, answer, **kwargs): rewards [] for completion, answer_item in zip(completions, answer): raw parse_boxed(completion) if raw is None: rewards.append(0.0) continue try: left sp.sympify(raw) right sp.sympify(answer_item) rewards.append(1.0 if left.equals(right) else 0.0) except Exception: rewards.append(0.0) return rewards注意parse_boxed的正则只处理单层花括号。实际工程里公式经常包含嵌套花括号例如\boxed{\frac{1}{2}}此时需要编写更完整的括号匹配解析器或者要求模型输出不含复杂嵌套结构的最终值。3.3 用 GRPOTrainer 拉起训练准备好数据集和验证器后可以用 TRL 的GRPOTrainer启动训练。from datasets import load_dataset from trl import GRPOConfig, GRPOTrainer dataset load_dataset(json, data_filesmath_train.jsonl, splittrain) config GRPOConfig( output_dir./rlvr_math_output, per_device_train_batch_size2, num_generations4, max_prompt_length256, max_completion_length512, learning_rate3e-6, beta0.04, logging_steps5, save_steps50, seed42, ) trainer GRPOTrainer( modelQwen/Qwen2.5-1.5B-Instruct, reward_funcs[math_reward], argsconfig, train_datasetdataset, ) trainer.train()代码里需要特别关注num_generations。它表示一个 prompt 会生成多少个候选回答直接影响组内奖励归一化的稳定性。数值太小优势估计噪声大数值太大显存和采样时间成倍增加。3.4 手工检查验证器是否生效训练开始前不要直接跑完整数据而是先用几段手工样本检查验证器逻辑。这能避免辛苦训练几小时后才发现奖励全部为 0。samples [ 先算出结果是42所以 \\boxed{42}, 172542, 结果是 \\boxed{43}, 我不知道, ] answers [42, 42, 42, 42] print(math_reward(samples, answers))正常输出应该是[1.0, 0.0, 0.0, 0.0]。如果第二项得到 1.0说明验证器没有真正检查结构要求如果第四项得到非 0说明异常处理有问题。4. 训练前必须对齐的参数与冷启动条件RLVR 训练对参数组合比较敏感。项目里“照着代码跑起来”并不难难的是训练能稳定收敛。下面几个配置点是训练前必须先想清楚的。4.1 关键参数速查表不同框架的参数名会有细节差异但语义保持一致。下表以 TRL 的常用参数为例给出建议起始值。参数含义建议起始值调大影响调小影响per_device_train_batch_size每个 GPU 的 prompt 数量1 到 4吞吐更高显存占用更大训练更稳定速度更慢num_generations每个 prompt 采样多少个回答4 到 8奖励估计更稳定耗时增加奖励波动大训练不稳定max_completion_length最大生成长度512 或 1024能支持更长推理链显存成本上升长推理被截断奖励偏低betaKL 约束权重0.01 到 0.1策略更保守行为不易漂移策略探索更多容易失控learning_rate策略模型学习率1e-6 到 1e-5更新更快震荡风险更高更稳定收敛更慢max_prompt_lengthprompt 最大长度256 或 512能处理更复杂任务过长 prompt 会被截断RLVR 中num_generations与per_device_train_batch_size是显存联动关系。实际显存占用约等于“batch size x num_generations x 最大生成长度”。如果一个 batch 有 2 个 prompt每个 prompt 生成 8 个回答等于同时维护 16 条推理序列显存压力会比普通 SFT 大很多。4.2 冷启动先让模型学会格式再让它学策略RLVR 的第一个隐藏门槛是“模型是否已经学会按要求输出”。如果模型基本不会在回答里放\boxed{...}那么所有奖励都为 0训练没有有效梯度信号。模型只能靠随机探索碰运气效率极低。推荐做法是先跑一小段 SFT 冷启动用几十到几百条含标准格式的样本让模型稳定输出“先思考、再给出最终答案”的形式。冷启动之后再做 RLVR奖励才能有区分度。如果基座模型本身已经是指令微调版本冷启动时间可以缩短但依然建议在训练集上抽样验证格式覆盖率。可以在训练前用小批量 prompt 生成结果统计parse_boxed的解析成功率。如果成功率低于 80%先补 SFT 数据。4.3 LoRA、显存和本地部署边界小规模模型全参数 RLVR 在 24GB 显存下可以尝试但如果有预算限制用 LoRA 是更稳妥的选择。LoRA 只训练低秩适配器冻结主干参数显存占用显著降低。from peft import LoraConfig from trl import GRPOConfig, GRPOTrainer lora_config LoraConfig( r16, lora_alpha32, target_modulesall-linear, ) config GRPOConfig( output_dir./rlvr_math_lora, per_device_train_batch_size2, num_generations4, max_prompt_length256, max_completion_length512, learning_rate3e-6, beta0.04, )不同 TRL 版本对peft_config的传递方式不同有的版本要求把peft_config直接传给GRPOTrainer有的版本要求放在GRPOConfig里。这里不写死某个版本就是为了避免误导。落地前务必对照本地库的文档和inspect.signature检查。模型训练完之后要落盘后续部署仍然可以按标准推理服务来做。如果使用 LoRA 适配器需要把适配器权重合并回主模型或者推理时动态加载适配器。无论是 vLLM 部署还是普通 Transformers 推理都要保证合并后的模型在测试集上能复现训练时的输出格式。5. 训练结果怎么验证出了问题怎么排查RLVR 训练日志比普通 SFT 复杂指标波动也更明显。只盯着“平均奖励有没有上涨”是不够的还要看 KL 曲线、生成长度和样本质量。5.1 训练时应该监控哪些指标建议至少关注六个指标指标含义健康状态reward_mean本日志区间平均奖励缓慢上升或震荡向上reward_std同组奖励标准差不应该持续为 0kl策略与参考模型的 KL 散度平稳上升禁止爆炸grad_norm梯度范数不应出现 NaN 或剧增completion_length生成长度不应无限变长成功率验证器通过的样本占比逐步上升平均奖励上涨是好的信号但不能只看它。如果模型通过“输出超长内容”绕过了验证器或通过复读训练集中的答案来拿分平均奖励也会上涨但这不代表真实能力提升。5.2 常见事故排查表RLVR 的常见问题往往集中在验证器设计、奖励稀疏和超参数漂移上。下表列了最常见的几种情况。现象可能原因检查方式处理建议reward 恒为 0验证器解析失败或数据格式不匹配手工构造拟合样本测试 reward 函数先用少量样本单测验证器模型输出重复无意义 token奖励过稀疏模型找不到有效奖励查看 KL 和生成长度曲线增加num_generations降低beta补 SFT 冷启动训练时 OOMbatch x generation 过大nvidia-smi查看显存调小 batch 或max_completion_length启用 LoRA高 reward 输出仍然明显错误验证器被绕过量化逻辑有漏洞人工抽查高 reward 样本强化验证器增加规范化处理KL 快速上升策略偏离参考模型太远查看 kl 曲线增大beta降低学习率训练集上分数高但评测集差数据泄漏或过拟合检查训练与评测集重复度增加数据难度和多样性排查顺序建议从验证器开始。RLVR 里最常遇到的问题是验证器“看似正确但实际不工作”。先跑最小样本再跑一个 batch最后再完整训练每一步都确认信号是合理的。5.3 离线评估不要只看 reward 指标训练结束后必须在独立评测集上做离线评估。数学任务建议使用 pass1即每个问题只采样一次计算模型回答正确的比例。python eval_math.py \ --checkpoint ./rlvr_math_output \ --dataset math_eval.jsonl \ --num_samples 1如果算力允许还可以额外采样多次计算 passk用来观察模型是否存在“第一次不对、多试几次能对”的情况。对 RLVR 来说pass1 更接近真实产品体验因为线上通常只让模型回答一次。离线评估时还要统计“格式覆盖率”。即使答案正确如果模型没有按要求输出在产品侧依然可能被判失败。RLVR 训练后格式覆盖率下降通常说明奖励函数没有约束输出结构需要把格式规则作为硬约束加入验证器。6. 把 RLVR 从实验变成可复用流水线实验阶段可以用 Jupyter Notebook 跑通但生产环境的后训练流水线要稳定、可回滚、可审计。下面几个建议可以帮助 RLVR 从一次性脚本变成可复用的工程模块。6.1 学习环境与生产环境的差异学习环境里只需要关注模型能不能跑起来、奖励有没有变化。生产环境要额外补齐这些内容数据版本管理训练集、评测集、验证器版本都要有记录。日志可追踪每次训练对应的模型版本、奖励函数代码版本、数据版本要能对齐。沙箱隔离代码任务执行验证器时必须在隔离的沙箱中运行避免恶意代码破坏训练环境。自动回滚如果评测指标下降能快速回滚到上一个稳定模型。监控告警KL 爆炸、奖励长期为 0、生成长度异常时触发告警。人工抽检固定抽取训练产出样本由人工判断质量防止验证器过拟合。实验环境可以随意改参数生产环境必须把“验证器回归测试”作为发布前置条件。6.2 验证器的接口设计与回归测试验证器不是一次性函数建议把它独立成包并定义统一接口。# validator.py class RewardValidator: def __init__(self, config): self.config config def validate(self, response: str, expected: str) - float: raise NotImplementedError def validate_batch(self, responses: list[str], expected: list[str]) - list[float]: return [self.validate(r, e) for r, e in zip(responses, expected)]有了统一接口后可以给验证器维护一组正负样例。正样例包括“答案正确且格式正确”的输出负样例包括“格式正确但答案错误”“答案正确但格式错误”等。每次修改验证器逻辑时都跑一遍回归测试确保不会因为修正一个正则而放走另一种 hack 写法。6.3 扩展方向与落地建议RLVR 最适合从自动化验证成本低的场景开始落地。数学推理、代码生成、SQL 生成、JSON 结构化抽取、基于检索的引用验证都是不错的切入点。主观性较强的对话质量、摘要合适度、安全性评估仍然建议保留 RLHF 或偏好模型。实际项目中可以直接把多个验证器组合成一个复合奖励函数。比如代码任务可以用“编译通过 单测通过 运行时长度”三部分组成奖励。但组合时要保证每部分权重可解释不要为了拟合指标写出连作者都看不懂的奖励逻辑。如果读者想继续深入建议按以下顺序补强阅读 GRPO 原始论文和 DeepSeekMath 技术报告理解组内奖励归一化的数学动机。阅读 TRL 文档中关于 GRPOTrainer 和奖励函数签名的部分手写一个数学任务 demo。阅读 OpenRLHF、veRL 等项目的训练实现了解大规模 RLVR 在分布式场景下的工程难点。在代码生成任务上做一次“执行验证”体验沙箱、资源限制和超时处理带来的额外复杂度。后训练不是“最后加一层指令对齐”而是决定模型从“知识量大”到“生产可用”的质变过程。RLVR 的价值在于把强化学习的目标从主观奖励部分替换为客观可验证的奖励让策略优化更稳定、更可解释也更接近任务本身。建议从数学或代码这类可自动化验证的任务入手按照“验证器先行、SFT 冷启动、GRPO 训练、回归评测”的顺序落地。先把最小闭环跑通再逐步扩大数据规模和任务复杂度。这样即便后续换更大模型、更复杂任务训练和排查的思路仍然可以复用。
返回列表