1. 为什么 GRPO 训练总卡在采样这一步
如果你最近在本地跑过 GRPO,大概率会有一种很割裂的体验:模型明明不大,7B 级别,单卡也能塞得下,但训练速度就是上不去。我拿 Qwen2.5-7B-Instruct 在 8 卡上跑过一轮,单 iter 里采样时间占比能到 70% 左右,训练卡大部分时间在等采样卡出结果。这不是配置写错了,而是 GRPO 算法本身的结构决定的。
GRPO 是 PPO 的一类改进,核心思路是用采样代替 value model,省掉了价值网络的训练开销,但代价是把压力全压到了采样环节。DeepSeekMath 论文里单 query 的 group size 给到 64,意味着一条 prompt 要生成 64 条候选回答,再算组内相对优势。这个采样量对推理引擎的吞吐是硬考验。你如果只拿一张卡既做训练又做采样,那基本就是训练等采样、采样等训练,来回空转。
魔搭社区围绕 MS-SWIFT 训练框架和 EvalScope 评估框架,给了一套相对完整的 GRPO 全链路方案,重点解决三件事:采样资源怎么倾斜、采样和训练怎么重叠、多模态怎么接进来。这篇就按本地落地的路径,把配置骨架、加速开关、评测脚本和一次端到端验证动作拆开讲,目标是让你能照着复现出接近官方给出的提速效果。
适合谁看:手里有 8 卡左右中小集群、想跑 GRPO 但被采样拖慢的人;想从 TRL 或 veRL 迁到 SWIFT 的人;以及要做多模态 VQA 强化训练、但不确定数据字段怎么组织的人。下面所有命令和配置都以 SWIFT 仓库的 BestPractices 文档为准,路径和参数名保持一致,方便你直接对照。
先说清楚一个前提:GRPO 的提速不是靠某一个开关,而是几个机制叠加。多实例数据并行采样解决资源分配,异步采样解决训练和采样的串行等待,多轮更新减少采样频率,LMDeploy 替换 vLLM 提升单次采样吞吐。这四个叠起来,才是官方在 8 卡上把单步耗时从 280 秒级压到 120 秒级的原因。单独开一个,收益有限。
2. 环境准备与 TaoToken 接入前置
在正式跑训练之前,有一件事容易被忽略:GRPO 训练过程中经常需要调用外部模型做数据构造、奖励校验或者对比评测,尤其是你想复现 DeepSeek 同款流程时,会涉及用 API 做推理验证。这时候一个稳定的 API 入口能省不少事。TaoToken 提供统一的模型调用入口,Base URL 是https://taotoken.net/api,你可以在控制台生成 Key,然后在脚本里按 OpenAI 兼容格式调用。
具体操作路径:先到官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 注册,进控制台 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite 创建 API Key,然后在 API Keys 页面 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 复制你的 Key。如果你只是想先验证模型能不能通,可以直接用模型对话页面 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite 发一条消息试试。
环境侧,SWIFT 的安装建议用源码方式,因为 GRPO 相关的最佳实践更新比较快:
git clone https://github.com/modelscope/ms-swift.git cd ms-swift pip install -e .[llm] pip install lmdeploy pip install evalscopeLMDeploy 一定要装,后面采样引擎要切到它。vLLM 也保留,方便你做对照实验。显存方面,7B 模型全参数 GRPO 训练,8 卡 A100 80G 是比较舒服的配置;如果只有 4 卡,建议把 group size 降到 16 以内,或者改用 LoRA。
关于 API 调用,如果你要在训练脚本里做奖励校验,可以这样写一个最小验证:
from openai import OpenAI client = OpenAI( base_url="https://taotoken.net/api", api_key="你的Key" ) resp = client.chat.completions.create( model="deepseek-chat", messages=[{"role": "user", "content": "1+1等于几"}] ) print(resp.choices[0].message.content)跑通这一步,说明你的 API 链路是通的。后面训练里如果需要用外部模型做 reward 打分,就可以复用这个 client。注意 Key 不要硬编码进仓库,用环境变量TAOTOKEN_API_KEY传进去。
3. 可复制的 GRPO 训练配置骨架
这一节是核心。SWIFT 的 GRPO 训练用命令行参数驱动,我把关键参数拆成几组,你按自己的卡数改。
第一组是模型和数据:
--model Qwen/Qwen2.5-7B-Instruct \ --dataset AI-MO/NuminaMath-TIR \ --split_dataset_ratio 0.01 \第二组是 GRPO 算法参数:
--rlhf_type grpo \ --reward_funcs external_countdown format \ --num_generations 24 \ --num_iterations 4 \ --beta 0.001 \ --learning_rate 7e-5 \num_generations就是 group size,官方实验里用 24,DeepSeekMath 论文用 64,你按显存调。num_iterations是多轮更新轮次,对应论文里的 mu 值,设成 4 时整体训练耗时约为单轮更新的一半,且官方说小于等于 4 基本不影响效果。beta是 KL 散度权重,GRPO 训练不稳定,beta 给 0.001 这种小值是官方在 Countdown 任务上试出来的。
第三组是加速开关,这是提速的关键:
--use_vllm true \ --vllm_mode server \ --num_infer_workers 2 \ --async_generate true \ --sleep_level 1 \num_infer_workers 2表示拿 2 张卡专门做采样,剩下 6 张做训练。async_generate true打开异步采样,训练时同时采样,采样结果用于下一 iter。sleep_level 1是模型 placement 的显存控制,actor 训练时让推理引擎进 sleep 模式省显存。
如果你想切 LMDeploy 做采样引擎,把use_vllm换成:
--use_lmdeploy true \ --lmdeploy_engine turbomind \官方实测 LMDeploy 相比 vLLM,在 Qwen2.5-7B-Instruct 上整体训练速度从 44 分/50steps 加速到 37 分/50steps,加速比约 16%,采样耗时只有基础实现的 70%。
多模态训练的话,数据集里加images、videos或audios字段即可,SWIFT 会自动把多模态内容喂进模型。参考 R1-V 的计数任务:
--model Qwen/Qwen2.5-VL-3B-Instruct \ --dataset okwinds/clevr_cogen_a_train \ --reward_funcs external_r1v_acc format \ --num_infer_workers 2 \ --max_completion_length 1024 \ --learning_rate 1e-6 \这里num_infer_workers 2加进程数 6,就是 2 卡 vLLM 采样、6 卡训练。external_r1v_acc是自定义准确性奖励,format是格式奖励,两个都已经内置在 SWIFT 里。
如果你用 Cline MCP 或者 Codex 这类工具做辅助开发,配置里要写全三件套:Base URL 填https://taotoken.net/api,Key 填你生成的,Model ID 填你要用的模型名。缺一个都会报 401。
4. 启动训练与端到端验证
配置写好后,完整启动命令长这样:
swift rlhf \ --rlhf_type grpo \ --model Qwen/Qwen2.5-7B-Instruct \ --dataset AI-MO/NuminaMath-TIR \ --reward_funcs external_countdown format \ --num_generations 24 \ --num_iterations 4 \ --beta 0.001 \ --learning_rate 7e-5 \ --use_lmdeploy true \ --lmdeploy_engine turbomind \ --num_infer_workers 2 \ --async_generate true \ --sleep_level 1 \ --max_completion_length 1024 \ --per_device_train_batch_size 6 \ --gradient_accumulation_steps 8 \ --output_dir ./grpo_output启动后你会看到日志里分两块:rollout 和 train。异步采样打开后,rollout 和 train 的日志会交错出现,这是正常的。如果看到local proxy failed或者连接超时,先检查num_infer_workers是不是超过了实际卡数,以及 LMDeploy 的 server 有没有正常拉起。
验证训练是否真的在提速,看两个指标:单步耗时和 reward 走势。官方在 8 卡、batch_size 48、group size 24 的设置下,SWIFT 单步约 120 秒,veRL 约 280 秒,TRL 多步更新约 144 秒、单步更新约 320 秒。你跑起来后对比自己的单步耗时,如果明显高于 120 秒,检查异步采样有没有真正生效。
reward 走势方面,Countdown 任务训练 2000 步,准确性奖励和格式奖励应该稳步上升,reward_std最终落在 0.2 到 0.3 左右,说明模型还有上升空间。completion_length会从 500 左右降到 200 再涨到 300-400,这个变化对应模型思考方式的转变:先反推、再精简、最后变成列举组合。
多模态计数任务训练 500 个 epoch 基本收敛,任务成功率从 0.4 升到 1 左右,reward_std在 300 步左右降到 0.1,completion_length稳定在 60-80。训练后的输出会带<think>和<answer>标签,逐个列举图中物体。
训练完做评测,用 EvalScope:
evalscope eval \ --model Qwen/Qwen2.5-7B-Instruct \ --datasets modelscope/R1-Distill-Math-Test \ --work-dir ./eval_output这个数据集整合了 MATH-500、GPQA-Diamond 和 AIME-2024,直接传 ID 就能用。评测结果支持可视化,能看推理性能。如果你要评思考效率,EvalScope 还提供 token 效率、思考长度、子思维链数量和准确率四个维度的指标,针对 Underthinking 和 Overthinking 问题。
5. 常见报错与排查对照
跑 GRPO 最容易撞的几个坑,我按报错原文列一下。
401 Unauthorized:如果你在训练脚本里调了外部 API 做奖励校验,Key 没传对或者 Base URL 写错都会报这个。检查base_url是不是https://taotoken.net/api,Key 是不是从 API Keys 页面复制的完整串。用环境变量传,别硬编码。
local proxy failed:这个通常出现在 LMDeploy 或 vLLM 的 server 模式启动时,端口被占或者num_infer_workers配得比实际卡数大。先nvidia-smi看卡数,再确认num_infer_workers不超过空闲卡数。如果是端口冲突,换一个--vllm_server_port。
Error reading choices:这个报错一般出现在解析模型输出时,模型返回的格式不符合预期,比如没有<answer>标签。检查你的reward_funcs里格式奖励函数是不是和模型输出格式匹配。Countdown 任务要求<think>和<answer>标签,如果你换了任务但没换奖励函数,就会解析失败。
OAuth token expired:如果你用 Codex 或类似工具做辅助,token 过期会报这个。重新生成 Key 即可。注意这类工具配置里 Base URL、Key、Model ID 三件套要写全,缺一个都会认证失败。
CUDA out of memory:GRPO 显存占用比 SFT 高不少,因为要同时放训练模型和采样引擎。降num_generations、开sleep_level、或者改用 LoRA。如果还不行,把per_device_train_batch_size降到 1,靠gradient_accumulation_steps补。
reward_std一直是 0:说明组内所有采样结果奖励一样,优势算出来全是 0,梯度就没了。检查奖励函数是不是写错了,或者 group size 太小导致采样多样性不够。把num_generations调大试试。
训练崩溃、loss 突然飙高:GRPO 本身不稳定,学习率和 beta 给大了容易崩。官方在 Countdown 上最终用 7e-5 和 0.001,你可以从这个组合起步,再微调。
6. 长期训练与 Agent 场景的接入建议
如果你打算把 GRPO 训练做成长期任务,或者要接 Agent 类场景,有几个点值得提前规划。
第一是采样资源的动态分配。SWIFT 支持在任意比例的训练卡上拉起采样实例,8 卡里可以 4 训练 4 采样,也可以 6 训练 2 采样。模型越大、batch_size 越大,采样耗时占比越高,越应该往采样倾斜。你可以先跑一个短实验,看日志里 rollout 和 train 的耗时比,再决定卡数分配。
第二是异步采样的稳定性。异步采样用的是 old policy model,和当前 policy 只差一个 iter,所以训练稳定性几乎不降。但权重加载那一步是 stop the world 的,如果权重同步慢,会拖累整体速度。用 LMDeploy 的 Turbomind 引擎,权重加载速度比 vLLM 快,这也是它整体提速的一个原因。
第三是多模态扩展。SWIFT 目前支持近两百个多模态模型的微调,这些模型天然支持 GRPO 训练。你只要在数据集里给images、videos、audios字段,GRPO 就会把多模态内容喂进去。做 VQA 类任务时,奖励函数可以拆成格式奖励和准确性奖励两个,格式奖励保证输出结构,准确性奖励算答案对不对。
第四是评测链路。EvalScope 除了常规评测,还提供思考效率评测,针对推理模型 Underthinking 和 Overthinking 的问题。这个对 Agent 场景特别有用,因为 Agent 的推理链太长会浪费 token,太短又容易跳步。你可以用 token 效率、思考长度、子思维链数量这几个指标来调优。
如果你需要长期跑编码类或 Agent 类任务,可以考虑用 Coding Plan 做资源规划,入口在 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite 。接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,里面有完整的 API 说明和示例。Claude Code 相关的接入可以参考 https://taotoken.net/claude-code-anthropic?utm_source=taotoken_aicg_blog_end&utm_content=claudecode&utm_campaign=rewrite 。
最后说一个实操细节:GRPO 训练日志里,completion_length的变化比 reward 更能反映模型在学什么。Countdown 任务里它从 500 降到 200 再涨到 300-400,对应模型从反推、到精简、到列举组合的思考方式转变。你如果看到 completion_length 一直不动,说明模型没在学新范式,检查奖励函数或者数据难度。