ms-swift GRPO 奖励模型实战:ORM 加载、GenRM 插件与外部部署全解析 ms-swift GRPO 奖励模型实战ORM 加载、GenRM 插件与外部部署全解析【免费下载链接】swiftUse PEFT or Full-parameter to CPT/SFT/DPO/GRPO 600 LLMs (Qwen3.6, DeepSeek-V4, GLM-5.1, InternLM3, Llama4, ...) and 300 MLLMs (Qwen3-VL, Qwen3-Omni, InternVL3.5, Ovis2.5, GLM4.5v, Gemma4, Llava, Phi4, ...) (AAAI 2025).项目地址: https://gitcode.com/GitHub_Trending/swift1/swift本篇指南聚焦 ms-swift 中 GRPO 训练的奖励模型Reward Model机制如何通过reward_model参数加载带分类头的输出奖励模型ORM如何用reward_model_plugin实现生成式奖励模型GenRM以及如何将大参数奖励模型通过swift deploy外部部署以提升推理速度。读完本文你将能够独立完成三种形态奖励模型的接入并理解它们在 GRPOTrainer 内部被装配、调用与加权融合的完整链路。什么是奖励模型ORM在 ms-swift 的 GRPO 训练中默认情况下的奖励模型是指具有分类头数值输出的模型通常称为输出奖励模型Outcome Reward ModelORM。这类模型会对策略模型生成的响应进行评分输出一个标量值表示响应的质量。与之相对的是奖励函数reward_funcs纯规则或程序化打分逻辑如答案正确性校验、格式校验不占用模型显存。ms-swift 允许两者混用并按权重融合这由 GRPOArguments 中的reward_funcs与reward_weights参数控制。通过 reward_model 参数加载 ORM最直接的用法是通过--reward_model参数加载奖励模型既可以加载一个原生的带回归头value head的奖励模型也可以加载经过奖励建模RM训练得到的模型随后训练时直接以模型的 logits 作为奖励值。与model参数类似的配置项在 RewardModelArguments 中定义支持列表形式可同时挂多个奖励模型参数说明默认值--reward_model奖励模型 ID 或本地路径用法与--model相同None--reward_model_type奖励模型类型用法与--model_type相同可省略通常自动推断None--reward_model_revision奖励模型的具体版本用法与--model_revision相同None--reward_template奖励模型使用的对话模板None--reward_adapters奖励模型加载的 LoRA 适配器路径列表如把 SFT 的 LoRA 权重当作奖励模型用[]--reward_model_plugin奖励模型的处理插件逻辑每个reward_model对应一个插件名[default] * len(reward_model)一个典型的组合示例来自仓库示例 run_external_reward_model.sh其中同时挂载了两个奖励模型并指定了不同的插件CUDA_VISIBLE_DEVICES0,1,2,3,4,5,6,7 \ NPROC_PER_NODE8 \ swift rlhf \ --rlhf_type grpo \ --model Qwen/Qwen2.5-7B \ --dataset AI-MO/NuminaMath-TIR#5000 \ --load_from_cache_file true \ --use_vllm true \ --vllm_mode colocate \ --vllm_gpu_memory_utilization 0.5 \ --external_plugins examples/train/grpo/plugin/plugin.py \ --reward_funcs format \ --reward_model Qwen/Qwen2.5-3B-Instruct Shanghai_AI_Laboratory/internlm2-7b-reward \ --reward_model_plugin genrm my_rmplugin \ --reward_weights 0.1 1 1 \ --sleep_level 1 \ --offload_model true \ --offload_optimizer true \ --log_completions true \ --deepspeed zero2这里--reward_funcs format提供 1 个奖励函数--reward_model提供了 2 个奖励模型--reward_model_plugin genrm my_rmplugin分别指定了两个奖励模型的处理逻辑--reward_weights 0.1 1 1的长度3必须等于奖励来源总数。源码解析奖励模型如何进入训练循环在 GRPOTrainer._prepare_rewards 中可以看到关键的装配逻辑先解析reward_funcs字符串名从内置注册表orms中查类或接受 callable若配置了reward_model则按reward_model_plugin未指定时默认为[default] * len(reward_model)逐个实例化插件要求插件数量必须与奖励模型数量一致否则抛出断言错误每个奖励模型PreTrainedModel实例会被append到self.reward_funcs末尾即reward_model 依次追加在 reward_funcs 之后reward_weights的顺序因此对应[reward_funcs, reward_model]奖励模型随后按 DeepSpeed / FSDP / 普通 DDP 三种方式执行prepare进入评估模式并放置到训练设备上。打分阶段发生在 compute_rewards_per_func对每个reward_func如果它是nn.Module实例即奖励模型就不走普通 callable 通道而是调用与之配对的reward_model_plugin(inputsreward_rows, **reward_kwargs)插件返回的每个奖励值若为None会被替换为torch.nan且当某一样本的所有奖励函数都返回 None 时Trainer 会打印该样本的 kwargs 以便排查。异步奖励函数AsyncORM子类则被自动检测并通过asyncio.runasyncio.gather并发执行这一点对后面外部部署场景的并发调用很重要。Megatron-SWIFT 的 GRPO 同样支持reward_model_plugin见 megatron_args.pyWebUI 的 GRPO 高级选项页也暴露了该字段grpo_advanced.py因此上述插件机制对命令行、WebUI 与 Megatron 后端均适用。自定义生成式奖励模型的两种调用方式对于生成式奖励模型用 LLM 打分即 LLM-as-judgems-swift 提供两种调用方式Trainer 内部插件用reward_model_plugin在 Trainer 内部直接定义奖励模型逻辑借助TransformersEngine对奖励模型做推理。模型被内嵌在 Trainer 内部无需额外占用独立计算资源集成方便但生成速度相对较慢更适合参数量较小的奖励模型外部部署服务通过swift deploy或vllm serve等命令把模型服务部署到独立设备在奖励函数中通过 HTTP 调用可大幅提升推理速度适合参数量较大的模型但需要预留额外硬件资源。方式一内部插件 reward_model_pluginreward_model_plugin允许开发者自定义奖励模型的完整处理逻辑包括自定义模型的系统提示定义特定的指令和上下文以指导评估过程处理模型交互历史管理对话上下文提供有意义且上下文感知的评估定义自定义评估标准设置独特的标准和度量超越默认的准确性与相关性衡量。插件通过__call__方法被调用接受inputs参数其中包含模型输入输出的 messages 以及数据集中的其他列如solutiondef __call__(self, inputs): print(inputs) [ { messages: [ {role: system, content: system prompt}, {role: query, content: query}, {role: user, content: completions1}, ], solution: abc, }, { messages: [ {role: system, content: system prompt}, {role: query, content: query}, {role: user, content: completions2}, ], solution: abc, } ] 内置实现DefaultRMPlugin 与 GenRMPluginms-swift 在 rm_plugin.py 中提供了两个内置插件并注册在模块末尾的rm_plugins字典中rm_plugins { default: DefaultRMPlugin, genrm: GenRMPlugin, }DefaultRMPluginrm_plugin.py对应上面讲的 ORM 场景它假设模型是带 value head输出维度 1的分类模型用template.encode逐条编码输入、data_collator组 batch然后在torch.inference_mode()下前向一次取logits[:, 0]作为奖励分数class DefaultRMPlugin: def __init__(self, model, template): self.model model self.template template def __call__(self, inputs, **kwargs): batched_inputs [self.template.encode(deepcopy(infer_request)) for infer_request in inputs] reward_inputs to_device(self.template.data_collator(batched_inputs), self.model.device) with torch.inference_mode(): return self.model(**reward_inputs).logits[:, 0]注意_prepare_rewards中对模板的两处特殊处理rm_template.set_mode(train)编码走训练模式以及rm_template.max_length None禁用截断因为输入长度在前面已被截断过这保证了奖励模型看到与策略模型一致的完整输入。GenRMPluginrm_plugin.py是生成式奖励模型的完整参考实现其流程为__init__中用TransformersEngine(self.model, templateself.template, max_batch_size0)初始化推理引擎0表示不限 batch并创建RequestConfig同时内置一个系统提示要求模型基于对话历史判断响应是否准确、完整、相关并以Reward: {score}0~1的格式输出分数prepare_rm_inputs深拷贝每条inputs用messages_to_query把多轮 messages 压缩成User: ...\nAssistant: ...形式的单一 query再构造{role: system, ...}, {role: user, content: query}发给奖励模型self.engine.infer(rm_inputs, self.request_config, use_tqdmFalse)批量推理compute_rewards对每个 choice 用正则Reward:\s*(0-1?)抽取分数取均值抽取失败记 0 并告警全部失败或抛异常时兜底为0.0。这就是文档中的骨架代码在仓库中的完整形态class RMPlugin(DefaultRMPlugin): def __init__(self, model, template): super().__init__(model, template) # initialize TransformersEngine to infer self.engine TransformersEngine(self.model, templateself.template, max_batch_size0) self.request_config RequestConfig() def __call__(self, inputs): system_prompt ... query ... messages [{role: system, content: system_prompt}, {role: query, content: query}] result self.engine.infer([messages], self.request_config, use_tqdmFalse) rewards ... return rewards注册自定义插件在 plugin.py 中可以看到官方推荐的三步注册模式文件头注释# Step 1: 定义 Reward 类在 __call__ 中实现自定义逻辑 class MyRMPlugin(DefaultRMPlugin): ... # Step 2: 加入 rm_plugins 注册表 from swift.rewards.rm_plugin import rm_plugins rm_plugins[my_rmplugin] MyRMPlugin # Step 3: 命令行配置 # swift rlhf \ # --external_plugins /path/to/plugin.py \ # --reward_model_plugin my_rmplugin同一个示例文件里还有 QwenLongPlugin展示了一个更复杂的用法它同时用 LLM 判断模型答案与参考答案是否等价输出[[YES]]/[[NO]]并可选地与规则化accuracy_orm的分数取max融合说明插件可以组合生成式裁判 规则校验两种信号。使用内部插件的注意事项在 GRPOTrainer 中reward_model会依次 append 到reward_funcs末尾因此reward_weights的顺序对应[reward_funcs, reward_model]reward_model_plugin默认为default即使用 ORM 处理逻辑取分类头 logits对于参数量较大的模型TransformersEngine生成速度较慢请使用下文的外部部署方式。另外对于 BERT 这类无法通过reward_model参数正常加载无对应模板/架构支持的模型社区给出的做法是内置在 reward_function 中自行加载参见仓库 issue 讨论即绕过插件通道、直接写一个继承ORM的奖励函数在__call__里持有并调用该 BERT 模型打分。方式二外部部署外部部署方式不需要使用reward_model_plugin而是直接在奖励函数--reward_funcs中发起远程调用。第一步用 swift deploy 启动模型服务。注意部署设备不要与训练设备重叠CUDA_VISIBLE_DEVICES0,1,2,3 \ swift deploy \ --model Qwen/Qwen2.5-72B-Instruct \ --vllm_tensor_parallel_size 4 # [INFO:swift] model_list: [Qwen2.5-72B-Instruct] # INFO: Started server process [xxxxxx] # INFO: Waiting for application startup. # INFO: Application startup complete. # INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRLC to quit)第二步在奖励函数中通过 OpenAI 库初始化客户端指定服务地址与端口from openai import OpenAI class RMReward(ORM): def __init__(self): super().__init__() try: self.client OpenAI( api_keyEMPTY, base_urlhttp://127.0.0.1:8000/v1, # 若在本地部署则为 127.0.0.1 ) self.verify_model_name self.client.models.list().data[0].id except Exception as e: raise RuntimeError(Failed to connect to the model service. Please deploy the model using swift deploy or vllm serve.) from e def __call__(self, completions, messages, **kwargs) - List[float]: rewards [] for completion, message in zip(completions, messages): rm_prompt ... # 构建 reward model 的 prompt chat_response self.client.chat.completions.create( modelself.verify_model_name, messages[ { role: system, content: You are a helpful assistant. }, { role: user, content: rm_prompt }, ], ) response chat_response.choices[0].message.content.strip() reward ... # 根据奖励模型生成结果提取奖励值 rewards.append(reward) return rewards注意__init__中client.models.list()的失败会直接抛出带提示信息的RuntimeError——这是一个很好的服务未就绪即快速失败的写法避免训练中途才发现服务没起。进阶异步并发调用 AsyncORM上面的同步写法逐条串行请求网络往返会成为瓶颈。ms-swift 的奖励基类提供了 AsyncORM其子类实现async def __call__会被训练器自动识别并用asyncio.gather并发执行见 grpo_algorithm.py。仓库示例 AsyncGenRMReward 给出了完整范式用aiohttp对已swift deploy的 GenRM 服务并发发起/chat/completions请求要求模型以[[score]]格式输出 0~10 分并归一化到 [0, 1]超时或异常均回退为 0.0。其用法为export GENRM_API_BASEhttp://localhost:8000/v1 swift rlhf \ --rlhf_type grpo \ --external_plugins plugin.py \ --reward_funcs async_genrm ...三种方案的选型与要点小结维度ORMdefault 插件GenRM内部插件外部部署 奖励函数模型形态带分类头/回归头的判别式模型任意生成式 LLM任意可部署服务本地/远程接入参数--reward_model插件默认default--reward_model--reward_model_plugin genrm或自定义插件名--reward_funcs--external_plugins打分方式logits[:, 0]Reward: x正则抽取、多 choice 取均值自定义解析如[[score]]资源开销内嵌 Trainer与训练共享设备内嵌 Trainer生成速度慢适合小模型需独立设备/显存但推理快、可扩展适用场景标准 RM 头模型小参数量生成式裁判大参数量裁判、已有推理服务几个容易踩坑的点权重数量必须对齐reward_weights长度 len(reward_funcs) len(reward_model)gym 环境场景还会额外追加一列gym_reward源码中该断言位于 grpo_trainer.py插件数量必须与模型数量一致reward_model_plugin与reward_model一一对应缺省统一为default奖励值兜底插件/奖励函数返回None会被转成 NaN全部为 None 时训练器会打印该行样本的完整 kwargs 告警因此自定义插件应像GenRMPlugin一样提供 0 分兜底保证至少有一个奖励函数返回有效奖励模板注意默认插件依赖reward_template/模型自带模板对输入做encode多模态或长上下文场景请确认模板与max_length行为符合预期。相关文档可进一步阅读奖励建模RM训练、GRPO 奖励函数自定义、GRPO 快速上手示例代码参考 examples/train/grpo/plugin/ 与 run_external_reward_model.sh核心实现位于 swift/rewards/rm_plugin.py、swift/rewards/orm.py 与 swift/rlhf_trainers/grpo_trainer.py。【免费下载链接】swiftUse PEFT or Full-parameter to CPT/SFT/DPO/GRPO 600 LLMs (Qwen3.6, DeepSeek-V4, GLM-5.1, InternLM3, Llama4, ...) and 300 MLLMs (Qwen3-VL, Qwen3-Omni, InternVL3.5, Ovis2.5, GLM4.5v, Gemma4, Llava, Phi4, ...) (AAAI 2025).项目地址: https://gitcode.com/GitHub_Trending/swift1/swift创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考