ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

verl 强化学习奖励函数实战指南:从 RewardManager 机制到自定义打分函数实现

verl 强化学习奖励函数实战指南:从 RewardManager 机制到自定义打分函数实现 verl 强化学习奖励函数实战指南从 RewardManager 机制到自定义打分函数实现【免费下载链接】verlverl/HybridFlow: A Flexible and Efficient RL Post-Training Framework项目地址: https://gitcode.com/GitHub_Trending/ve/verl本文聚焦 verlHybridFlow框架中数据集奖励函数Reward Function的设计与实现从RewardManager的执行机制、DataProto输入约定到 GSM8k/MATH 等预实现打分函数的内部原理再到通过custom_reward_function配置自定义奖励函数的完整实操。读完本文你将能够为任意数据集编写、注册并接入自己的奖励函数让 PPO/GRPO 等后训练流程正确计算每条响应的 reward。一、奖励函数在 verl 后训练流程中的定位verl 是一个面向大模型强化学习后训练RL Post-Training的框架。在 PPO 等在线策略训练中模型生成响应后训练循环必须为每条响应计算一个数值奖励reward用于优势估计与策略更新。verl 的做法是每个数据集要么配套实现一个奖励函数要么接入一个奖励模型Reward Model来打分。仓库中的奖励函数实现集中在verl/utils/reward_score目录官方当前已预实现GSM8k基于字符串匹配的规则打分见 verl/utils/reward_score/gsm8k.pyMATH解析\boxed{}答案并做数学表达式规范化等价比较见 verl/utils/reward_score/math_reward.py此外还内置了math_dapo、prime_mathNumina 系列、geo3k、search_r1_like_qa_em、prime_code代码类与sandbox_fusion沙箱执行等更多打分实现统一由default_compute_score按data_source分发见 verl/utils/reward_score/init.py。而对于 RLHF 类数据集如full_hh_rlhfverl 采用Reward Model打分代码生成类数据集如 APPS则通过SandBox 沙箱执行验证正确性。二、RewardManager奖励计算的统一入口在 PPO 后训练脚本入口 verl/trainer/main_ppo.py 中verl 实现了RewardManager来调用预实现的奖励函数为每条响应计算分数。其核心工作流为接收一个DataProto作为输入取出其中的响应 token 与 ground truth对响应 token 做 detokenize得到响应字符串将响应字符串与 ground truth 字符串交给compute_score_fn计算每条响应的分数。2.1 DataProto 输入约定RewardManager的__call__接收的DataProto中需要包含以下字段字段说明input_ids、attention_mask经过 chat_template 处理后的输入包含 prompt 与 response 两部分responses模型生成的响应 tokenground_truth当前 prompt 的标准答案字符串存放在DataProto的non_tensor_batch中需在数据预处理阶段写入 parquet 文件data_source当前 prompt 所属数据集名称同样存放在non_tensor_batch中用于分发到对应的打分函数以仓库内置的NaiveRewardManager见 verl/experimental/reward_loop/reward_manager/naive.py为例其run_single方法展示了完整的数据读取逻辑data_source data_item.non_tensor_batch[data_source] ground_truth data_item.non_tensor_batch[reward_model][ground_truth] extra_info data_item.non_tensor_batch.get(extra_info, {}) response_str await self.loop.run_in_executor( None, lambda: self.tokenizer.decode(valid_response_ids, skip_special_tokensTrue) ) result await self.loop.run_in_executor( None, lambda: self.compute_score( data_sourcedata_source, solution_strresponse_str, ground_truthground_truth, extra_infoextra_info, ), )几点实现细节值得注意对多序列输出NaiveRewardManager只取最后一个序列计算奖励data data[-1:]并通过attention_mask截取有效响应长度后再解码ground_truth存放在non_tensor_batch[reward_model][ground_truth]中extra_info还可携带num_turns、rollout_reward_scores、工具调用附加字段等信息传入奖励函数打分函数返回值既可以是纯数字也可以是包含score键的字典此时其余键会作为reward_extra_info透传用于记录acc等额外指标。三、预实现奖励函数解析3.1 GSM8k字符串匹配 格式约束GSM8k 的打分逻辑见 verl/utils/reward_score/gsm8k.py采用强格式约束设计强制模型在四个####之后输出最终答案再通过字符串匹配与 ground truth 比对。评分规则答案完全正确得 1 分格式正确能提取出答案但与 ground truth 不符得 0.1 分format_score0.0的默认值在不同调用场景下可配置格式不正确无法提取答案得 0 分。核心的答案提取函数extract_solutiongsm8k.pyL20-L49支持两种模式strict默认用正则#### (\-?[0-9\.\,])匹配####后的数字取最后一个作为最终答案同时剔除了,与$符号——这种模式同时检验了模型的输出格式flexible直接取字符串中最后一个合法的数字不要求####格式。源码中还包含一个实用优化当solution_str超过 300 个字符时只对末尾 300 字符做正则匹配_SOLUTION_CLIP_CHARS 300因为数学题的最终答案通常位于末尾可以显著加速长字符串的正则扫描。3.2 MATHboxed 答案解析 数学表达式规范化MATH 的打分实现见 verl/utils/reward_score/math_reward.py沿用了 lm-evaluation-harness 中hendrycks_math的做法核心流程为last_boxed_only_string定位响应中最后一个\boxed{...}兼容\fbox与\boxed写法提取括号内内容remove_boxed剥掉\boxed外壳拿到答案字符串is_equiv通过strip_string对两侧字符串做大量规范化后比较是否等价。strip_string的处理极其细致包括但不限于去除换行、\left/\right、美元符号、百分号与单位把\tfrac/\dfrac统一为\frac把\sqrt3修正为\sqrt{3}把a/b改写为\frac{a}{b}把0.5归一为\frac{1}{2}等等。正是这一套规范化使得\frac{1}{2}与1/2、0.5等不同写法都能被正确判定为等价答案。3.3 更多内置打分器与按数据集分发所有内置打分器统一由 verl/utils/reward_score/init.py 中的default_compute_score按data_source字符串分发L44-L107。当前支持的主要数据集别名包括openai/gsm8k→gsm8k.compute_scorelighteval/MATH、DigitalLearningGmbH/MATH-lighteval、HuggingFaceH4/MATH-500→math_reward.compute_score源码注释提示可手动pip install math-verify后切换为math_verify.compute_score以提升精度math_dapo、math、math_dapo_reasoning及aime前缀 →math_dapo.compute_scorenumina_*系列 →prime_math.compute_scorecodecontests、apps、codeforces、taco→ 优先走sandbox_fusion.compute_score需要配置沙箱 URL否则回退prime_code.compute_scorehiyouga/geometry3k→geo3k.compute_score其实现将格式奖励与答案正确性奖励加权组合见 verl/utils/reward_score/geo3k.pysearchR1_*系列 →search_r1_like_qa_em.compute_score。对于未覆盖的data_source会直接抛出NotImplementedError——这也提示我们遇到新数据集时正确姿势是编写自定义奖励函数见下一节。四、自定义奖励函数完整实操4.1 通过配置指定自定义函数verl 支持在独立的 Python 文件中实现自定义奖励函数并通过配置项指定无需修改框架源码。相关配置位于 verl/trainer/config/reward/reward.yaml# configs for the reward computation _target_: verl.workers.config.RewardConfig # 启动的 reward manager 数量用于并行化奖励计算 num_workers: 8 # 自定义奖励函数定义 custom_reward_function: # 存放自定义奖励函数的文件路径 path: null # 文件中奖励函数的名称默认是 compute_score name: compute_score其中RewardConfig的数据结构定义可参考 verl/workers/config/reward.pynum_workers默认 8另有reward_manager、reward_model、sandbox_fusion三个子配置块。完整配置项的逐条说明可进一步查阅配置文档原文档指引参见config-explain-page仓库内对应示例说明见 docs/examples/config.rst。4.2 函数签名约定自定义奖励函数的参数签名固定为def my_reward_fn(data_source, solution_str, ground_truth, extra_infoNone): return len(solution_str) / 100参数含义参数说明data_source数据集名称可用于在同一个函数内区分不同数据集的打分逻辑solution_str模型生成的响应文本detokenize 之后ground_truth标准答案字符串extra_info附加信息可选可包含num_turns、工具调用字段等返回值应为数值奖励如果返回字典则需包含score键作为奖励值其余键会作为reward_extra_info记录。4.3 场景一单函数测试如果只测试一个自定义奖励函数最简单的做法是把函数命名为compute_score配置中只填写custom_reward_function.pathname留空默认值即为compute_score。4.4 场景二多函数对比测试当需要对比多个奖励函数时可在同一个文件中实现多个函数通过修改custom_reward_function.name切换而无需改动path# my_reward.py def compute_score(data_source, solution_str, ground_truth, extra_infoNone): return 1.0 if solution_str ground_truth else 0.0 def length_based_score(data_source, solution_str, ground_truth, extra_infoNone): return len(solution_str) / 100 def keyword_score(data_source, solution_str, ground_truth, extra_infoNone): return 0.5 if answer: in solution_str.lower() else 0.0然后分别为每次试验设置custom_reward_function: path: /path/to/my_reward.py name: length_based_score # 每次试验只改这里这种方式特别适合在脚本中批量跑多组奖励函数对比试验。4.5 源码层面的加载机制自定义函数并非简单地import而是通过动态加载机制完成见 verl/trainer/ppo/reward.py 中的get_custom_reward_fnL50-L86从config.reward.custom_reward_function读取path与name若未配置path则返回None此时回退到预实现函数通过verl.utils.import_utils.load_extern_object(module_path, object_name)动态导入配置中若提供了reward_kwargs会与调用时的 kwargs 合并以配置为准后partial包装若自定义函数是async协程函数会被自动识别并走异步调用路径便于接入远程/异步奖励源。在load_reward_manager同文件 L111-L157中若未配置自定义函数且配置了sandbox_fusion.url则会自动用default_compute_score结合沙箱 URL、并发信号量默认max_concurrent64与内存上限默认1024MB构造打分函数用于代码类数据集的沙箱执行验证。五、数据预处理与端到端接入要确保奖励函数正常工作数据预处理阶段必须把data_source与ground_truth写入non_tensor_batch。仓库提供了现成的数据预处理脚本作为参考例如examples/data_preprocess/gsm8k.py构造 GSM8k 训练/测试 parquet写入 prompt 与标准答案examples/data_preprocess/math_dataset.pyMATH 数据集同理examples/data_preprocess/full_hh_rlhf.pyRLHF 数据集示例可配合 Reward Model 打分。接入流程可归纳为数据预处理写入ground_truth/data_source→ 训练配置指定custom_reward_function.path或使用预实现函数→ PPO 入口的RewardManager自动完成 detokenize 与打分。跑通后可参考 examples/grpo_trainer/run_qwen3_8b_fsdp.sh 等启动脚本结合实际数据集验证奖励是否符合预期。六、小结verl 的奖励函数体系设计清晰、扩展成本低预实现函数覆盖 GSM8k、MATH、代码、几何等多类数据集RewardManager统一调度custom_reward_function提供零侵入的自定义入口。对开发者而言接入一个新数据集只需三步预处理出ground_truth与data_source、按(data_source, solution_str, ground_truth, extra_info)签名编写打分函数、在配置中指定path与name。若需多函数对比试验仅需在脚本中切换name即可无需改动任何框架代码。【免费下载链接】verlverl/HybridFlow: A Flexible and Efficient RL Post-Training Framework项目地址: https://gitcode.com/GitHub_Trending/ve/verl创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表