☰
用GRPO强化微调Qwen3:数学推理与工具调用实战指南
2026/10/2 22:36:30 网站建设 项目流程

Qwen3 系列发布之后,社区里讨论最多的已经不是怎么做 SFT,而是怎么做强化微调。原因其实很现实:Qwen3 把 SFT 之后的模型直接拿去做了大规模 RLHF,但官方并没有针对数学推理、代码生成、工具调用这一类“有明确可验证奖励”的场景做专门的强化训练。所以你拿 Qwen3-4B 去跑数学题,或者像有些朋友把 qwen3:4b 接进 WorkBuddy 想让它直接操作电脑改代码,效果往往离预期差一截。不是模型底子不行,而是缺了一道专门针对你的任务场景做的 GRPO 强化微调。

这篇文章把我这段时间用 GRPO 微调 Qwen3-4B 和 14B 的真实流程、参数选择、踩过的坑全部整理出来。适合那些已经跑通 SFT、想再往上走一步做强化学习的朋友,也适合刚接触 GRPO、想搞清楚这套东西到底怎么落地的人。我会尽量讲清楚每一步“为什么这么干”,而不是只丢给你一个能跑的训练命令。

1. Qwen3 与 GRPO:先弄清楚这两件事

1.1 Qwen3 到底算什么模型

很多人在刚开始接触 Qwen3 时会有一个误解,以为 Qwen3 系列既然带了“思考模式”,官方也说了做过 RL,那我直接拿来不就行了?实际上 Qwen3 的“RL”指的是通用 RLHF,优化的是人类偏好的综合对话质量,而不是某个具体任务的得分。

注意 Qwen3 发布的时候,官方在技术报告里明确写过:Qwen3 的思考模型没有经过针对数学、代码等领域的专门 RLVR(可验证奖励的强化学习)。官方还特意提醒,如果你做的是数学题这类有标准答案的任务,建议自己再训一轮 GRPO。这基本就是给社区指了一条路:要追求 GSM8K 或 MATH 这类基准上的上限,你得自己动手做强化微调。

Qwen3 本身分成了 Base、Chat 和 Thinking 三种形态,也可以理解成“底座模型—指令模型—推理模型”。GRPO 强化微调一般从 Base 版本起步,因为 Chat 版本已经带了一层 SFT 和 RLHF,你再往上加强化学习,策略初始化分布已经偏离基础分布比较远,容易起跳困难。像 Qwen3-4B-Base、Qwen3-14B-Base,就是最常用来做 GRPO 的起点。

1.2 为什么是 GRPO,而不是 PPO

早期做大模型强化学习,大家默认用 PPO。PPO 的思路是让策略模型和环境交互,同时训练一个 Critic 价值网络去预估每个状态的价值。问题在于,Critic 模型和策略模型差不多大,等于你训练一个模型要背上两套模型权重加两套梯度,显存开销直接翻倍。对大模型团队来说,PPO 的显存成本和生产复杂度都太高了。

GRPO 是 DeepSeekMath 论文里提出来的,核心思路非常巧妙:同一道题让策略模型采样出 G 个回答,然后对这个 G 个回答的奖励做组内归一化,用归一化后的相对优势去指导策略更新。这样就不需要独立的 Critic 价值网络了。用一句话说,PPO 是“每个人配一个专属评分员”,GRPO 是“一个小组里互相比较打分”,后者省掉了评分员的岗位,自然省了大量显存。

实践里 GRPO 的显存占用通常比 PPO 能省 30% 到 40%。这个差距直接决定了单卡 24G 能不能跑起来,也是我选择 GRPO 做 Qwen3 微调的最直接原因。

2. 训练前你要准备的东西

2.1 硬件和软件栈

先说硬件门槛。如果你做的是 Qwen3-4B-Base 的 GRPO,单张 24G 显存的显卡就能跑,RTX 3090 或 4090 都行,前提是生成长度控制得合理。如果是 Qwen3-8B,一张 24G 卡非常吃力,建议两张 4090 或者直接上 A100 40G。到 Qwen3-14B 这个规模,24G 单卡只在极端保守的配置下勉强能跑 rollout,训练阶段基本需要 40G 以上的卡。

我这次用一个比较稳妥的组合:Qwen3-4B-Base 配单张 4090 跑通全流程,Qwen3-14B-Base 在 8 卡 A100 40G 上做正式训练。强烈建议第一次接触 GRPO 的朋友先从 4B 开始跑,把整个链路跑通之后再放大模型,否则调参排查问题的成本会很高。

软件栈方面,核心是这几个:PyTorch 2.1 以上、transformers 4.45 以上、verl 强化学习框架、vLLM 用于 rollout 阶段的高效采样、Liger-Kernel 用于显存优化。verl 是目前对 GRPO 支持最完善的开源框架,也是 Qwen 官方团队自己在用的训练栈。

2.2 数据集与奖励设计

GRPO 的数据集和 SFT 数据集有一个显著区别:GRPO 不需要你准备人工标注的回答,只需要准备“问题”和“标准答案”。训练时模型自己生成回答,奖励函数负责判断生成的回答对不对。这意味着两个要求:第一,任务必须有客观的判定标准;第二,这个判定标准要能写成代码规则。

最经典的入门任务是 GSM8K 数学应用题。每条数据包含问题文本和标准答案,我们只需要从标准答案中提取出最终的数字,然后判断模型输出的最终结果是否一致。这就是所谓的规则奖励(rule-based reward),比用奖励模型打分稳定得多,也便宜得多。

奖励设计可以直接决定训练成败。我强烈建议不要只用“答案对错”这一个信号,要加上格式奖励。比如要求模型按“最终答案: xxx”的格式输出,输出格式对了给 0.1 分,格式不对扣 0.5 分。这样的奖励 shaping 能引导模型先学会符合格式的生成,再逐步优化答案正确率,训练过程稳定非常多。

2.3 模型选择:Base 还是 Chat

这个问题值得单独讲清楚。很多第一次做 GRPO 的人直接拿 qwen3:4b(Ollama 下载的对话版本)来训,其实不太对。Ollama 上拉下来的 qwen3:4b 对应的是 Qwen3-4B-Chat,也就是已经 SFT 过的模型。在 Chat 版本上做强化学习不是不行,但你会面临两个问题:一是模型已经学会了大量对话宏观策略,改起来慢;二是奖励信号出现时,模型早就偏好某些回答模式,策略更新空间有限。

日常测试可以拿 Chat 版本快速验证奖励函数是否合理,但正式训练一定从 Base 版本开始。Qwen3 系列的 Base 权重在魔塔社区和 Hugging Face 都同步发布了。国内用户我更推荐从魔塔社区直接下载,速度稳定,下载完校验一下文件哈希再解压,避免权重损坏带来的各种诡异问题。数据集也一样,GSM8K 在魔塔上有现成的转好格式的版本,不需要自己从原始来源处理。

3. GRPO 训练机制拆解

3.1 GRPO 的核心公式在做一件什么事

GRPO 的训练目标可以拆成两层意思。对于每个问题,从旧策略模型里采样出 G 个回答,每个回答拿到一个奖励分数。然后对这 G 个分数做标准化——减去组内均值再除以组内标准差,得到每个回答的“相对优势”。如果某个回答比同组的其他回答好,优势就是正的,策略模型未来就要增加这类回答的概率;反之,优势是负的,就要降低。

用公式表示,TRPO/PPO 里的优势 A = r - V(s),GRPO 直接把它替换成组内标准化的分数 A_i = (r_i - mean(r)) / std(r)。这么做有两个直接好处:第一,不用训练价值网络,省下一大块显存;第二,组内标准化自动消掉奖励尺度的影响,比如奖励函数整体偏大偏小都不影响训练稳定性。

目标函数里还有一项容易被忽略的 KL 惩罚项。策略模型更新的时候,我们不想让它跟参考模型偏离太远,否则模型会快速过渡到某个局部最优,像背书一样重复那几个模板。所以目标函数里要在奖励之外减去一项 beta 乘以新旧策略的 KL 散度。这个 beta 就是整个训练里需要反复调的一个核心超参。

3.2 为什么 GRPO 能省近一半显存

PPO 需要四个模型同时驻留显存:策略模型、参考模型、奖励模型、Critic 价值模型。GRPO 把 Critic 直接砍掉了,剩下三个。而且 GRPO 在计算时是采样一批回答、统一打分、统一更新,没有 PPO 里那么复杂的时间差分计算,也不用存 GAE 需要的大量中间状态。

更直观地说,同样的 24G 显存,PPO 跑 4B 模型已经很紧张,GRPO 跑 7B 到 8B 都还有余量。对个人开发者和中小团队来说,这个差距是“能玩”和“玩不了”的分界线。

我在 4090 上跑 Qwen3-4B 的时候还配合了 Liger-Kernel。这是字节开源的一个算子库,融合了 attention 和 MLP 里的部分 kernel,显存占用再降 20% 左右,训练速度提升 15% 到 20%。安装非常简单,一条 pip 命令,然后配置里指到对应插件就行。

3.3 几个关键超参数的意义

GRPO 有四个超参数是每次训练都要认真过一遍的,直接决定训练成败。

第一个是生成数量 G。每个问题采样多少个回答,一般取 4 到 8。G 越大,组内相对优势越可靠,但采样耗时和显存占用也越高。我通常先用 4 验证整条流程,正式训练再用 8。第二个是 beta,也就是 KL 惩罚系数,Qwen3 官方在 GSMR8K 实验里用的是 0.04,这个值适合大多数生成任务。beta 太小,策略容易崩;beta 太大,模型学不到新技能,被绑死在参考模型附近。

第三个是学习率。GRPO 阶段的学习率要比 SFT 低一个数量级。SFT 一般用 1e-5 到 2e-5,GRPO 我建议 1e-6 到 2e-6。原因是在强化学习阶段,策略是在已有能力上做微小偏向调整,步子迈大了会把之前的 SFT 学到的语言能力全部破坏掉,表现就是 loss 在降、生成文本却开始乱码。第四个是生成温度,rollout 阶段通常用 0.7 到 1.0。GRPO 依赖采样多样性来探索更优策略,温度太低采出来的答案都差不多,组内奖励方差小,训练信号就弱了。

4. 实操:跑一个 Qwen3-4B 的数学推理强化微调

4.1 环境安装与数据准备

我以 verl 框架为例,先装依赖。创建一个干净的虚拟环境,然后安装核心库:

conda create -n qwen3-grpo python=3.10 -y conda activate qwen3-grpo pip install torch==2.4.0 --index-url https://download.pytorch.org/whl/cu124 pip install "transformers>=4.45" vllm ray verl pip install liger-kernel

verl 对 vLLM 的版本有要求,建议按 verl 仓库的 requirements 一一对齐,不要盲目装最新版。我踩过 vLLM 最新版导致 rollout 引擎起不来的坑,后来锁版本才解决。

数据准备方面,一条 GSM8K 训练数据最终应该是这样的格式:

{ "prompt": "<|im_start|>system\nYou are a helpful assistant.<|im_end|>\n<|im_start|>user\nAlice buys 3 apples for $2 each and 2 oranges for $3 each. How much does she spend in total?<|im_end|>\n<|im_start|>assistant\n", "reward_model": { "ground_truth": "12" } }

这里的核心是 ground_truth,只保留标准答案的最终数值。奖励函数做的事就是提取模型输出里的最终数字,和它做字符串匹配。如果你的奖励函数写得太复杂,比如试图解析完整解题步骤,很容易引入 bug,导致整个训练在学一个错误信号。宁可先用最笨的答案匹配,把训练跑通,再逐步加奖励条件。

4.2 训练配置

verl 的配置是 YAML 格式,最关键的部分如下:

algorithm: adv_estimator: grpo actor_rollout_ref: model: path: Qwen/Qwen3-4B-Base use_remove_padding: true actor: optim: lr: 1e-6 weight_decay: 0.01 ppo_mini_batch_size: 256 ppo_micro_batch_size_per_gpu: 2 use_kl_loss: true kl_loss_coef: 0.04 rollout: name: vllm temperature: 0.7 top_p: 0.95 max_prompt_length: 1024 max_response_length: 1024 data: train_files: data/gsm8k/train.parquet max_prompt_length: 1024 max_response_length: 1024 reward_model: type: custom path: reward_fn.py trainer: n_gpus_per_node: 1 num_nodes: 1 default_local_dir: output/qwen3_4b_grpo

逐项解释一下我为什么这么配。lr 用 1e-6,因为这是从 Base 模型开始做 RL,稍微保守一点更稳。kl_loss_coef 0.04 是 Qwen3 官方实验验证过的常用值。ppo_micro_batch_size_per_gpu 设成 2,是为了在 24G 显存下保证不会 OOM,你用 80G 卡可以调到 4 到 8。temperature 0.7 兼顾探索性和生成质量,如果发现训练后期奖励不涨,可以提高到 0.9 再把组大小 G 加一些。

reward_fn.py 里是奖励函数逻辑,我强烈建议在正式训练前先单独写个脚本批量测试奖励函数,把 GSM8K 验证集每个样本的奖励打分跑一遍,确认奖励值分布是合理的,再启动训练。

4.3 启动训练与观察指标

我通常用 Ray 启动分布式训练,单卡场景直接跑:

ray start --head --port=6379 bash scripts/run_grpo_qwen3_4b_gsm8k.sh

训练开始之后,重点观察三个指标。第一个是 mean reward,也就是每个 batch 的平均奖励值。它应该整体呈上升趋势,偶尔有波动是正常的,但如果连续几百步不涨,说明奖励函数或超参有问题,不要浪费时间硬跑。第二个是 response length,Qwen3 模型有过量生成“思维链”的倾向,如果生成长度持续飙升超过 max_response_length,要检查是不是思维模式没锁住。第三个是 KL 散度,如果 KL 涨得飞快,说明策略偏离参考模型太远,需要调高 beta 或降低学习率。

训练时长方面,Qwen3-4B + GSM8K,单张 4090,G=8,大概四到六个小时能跑完两三百步。14B 在 8 卡 A100 上,同样的数据量大约需要十五个小时左右。所以先花几块钱的卡时验证小模型全流程,再上大模型,性价比最高。

5. 常见问题与避坑清单

5.1 常见问题速查表

这段时间跑下来,遇到的典型问题基本都集中在下面这张表里:

现象原因解决办法
显存 OOMmicro batch 太大或 remove padding 没开ppo_micro_batch_size_per_gpu 调到 1 或 2,开启 use_remove_padding
reward 一直不变奖励函数有 bug 或 ground truth 格式不匹配单独跑奖励函数单元测试,打印每条样本的 score
生成内容越来越短KL 惩罚过大,策略被绑死在参考模型降低 kl_loss_coef,从 0.04 调到 0.02 试探
生成内容乱码学习率太高,破坏了 SFT 学到的语言能力lr 降到 5e-7,重新从上一个稳定 checkpoint 恢复
rollout 阶段连接失败vLLM 端口冲突或残留进程用 `ps aux
训练后期 reward 突然崩掉策略进入某个局部最优,生成重复文本提高温度到 0.9,增大 G,加强格式奖励的惩罚力度

5.2 两个 Qwen3 特有的坑

第一个坑是思维模式。Qwen3 最特殊的地方就是它有 thinking 和 no-thinking 两种模式,模型会自动在输出前补一段“Wait, let me think...”之类的内部推理。问题在于 GRPO 阶段你通常只想要一种固定行为。比如你做 GSM8K,希望模型直接给出解题过程和答案;做工具调用时,更希望模型不要输出大段思考过程,直接调用工具。

解决办法是在 system prompt 里写死模式。做数学题时可以用“Let's think step by step”引导正常输出,做 Agent 任务时系统提示“Don't think, just call the tool directly.”。同时,你要在奖励函数里针对模式做约束:如果要求 no-thinking 模式但模型输出了长段思维链,直接扣分。不锁死模式的话,模型会在训练过程中自由切换,奖励信号变得非常混乱。

第二个坑是 Chat 模板。Qwen3 的 tokenizer 要求消息按<|im_start|>和<|im_end|>包裹格式传入,GRPO 训练时如果忘记正确套用 Chat Template,模型生成的回答会缺少终结符,reward 函数提取不到答案,最终导致训练完全无效。我试过直接喂纯文本 prompt 给模型,结果生成内容末尾总缺im_end,奖励一直不跳,排查半天才发现是模板问题。解决办法是在数据预处理时用 tokenizer.apply_chat_template 统一转换。

5.3 训练效果不理想的时候怎么调

如果跑完一个完整流程,GSM8K 准确率只提升了三五个点,别急着加数据量。先看奖励曲线和生成样本。

诊断的第一步是看模型生成的错误案例。随机抽取一百条训练样本的生成结果,如果发现答案错了,但格式整齐、逻辑通顺,说明奖励信号已经正确传导,只是优化还不够,可以加训练步数或调大 G。如果发现答案对了一半但格式乱七八糟,那是格式奖励权重太高,模型在钻格式的漏洞,需要调低格式奖励分或者增加惩罚。

第二步看奖励噪声。GRPO 的组内标准化依赖组内奖励的方差。如果你的 reward 函数只返回 0 和 1,同组八条都是 0 分,方差为 0,优势全部为零,梯度直接消失。这种情况下即使训练 loss 在降,策略也不会往任何方向更新。解决办法是给奖励函数加入中间档位——步骤分、格式分、答案分拆开算,哪怕只分 0.1、0.5、1.0 三档,都能有效增加组内方差,让训练信号活起来。

我自己的经验是,很多“训练不生效”根本不是超参数问题,而是奖励函数太稀疏。GRPO 对奖励函数的设计要求比 PPO 更高,你需要提供足够的梯度信号供模型学习,否则再大再多的数据也白搭。

6. 训练完之后:合并、评估与部署

6.1 合并 LoRA 与评估

verl 支持 LoRA 微调,训练产物是一个 adapter 权重,正式使用前要把 LoRA 权重合并回 Base 模型。合并前先做一次基准评估,把 GSM8K 验证集分成 500 条子集,分别测试 Base、SFT、GRPO 三个版本的准确率。我通常还会顺带跑一下通用能力基准,比如 MMLU 抽取子集,确认强化学习没有大幅损伤模型的通用能力。以 Qwen3-4B 为例,GSM8K 准确率从 Base 的 52% 左右提升到 70% 以上是有可能的,但如果你从 55% 涨到 58% 且 MMLU 掉了很多,就要重新审视训练策略是不是过于激进。

合并命令根据不同训练框架而定。verl 的 checkpoint 里有 adapter 文件夹和原始模型配置,可以用以下方式合并:

python scripts/merge_lora.py \ --base_model Qwen/Qwen3-4B-Base \ --adapter_dir output/qwen3_4b_grpo/checkpoint-200/actor \ --output_dir output/qwen3_4b_grpo_merged

合并完成后用 transformers 加载一次,跑几条测试数据确认权重没问题,再转成部署格式。如果发现合并后输出异常,优先查 adapter 路径是否指向了正确 checkpoint,以及 Base 版本是否和训练时完全一致。版本不匹配是合并阶段最常见的翻车原因。

6.2 部署与工具链接入

合并后的权重可以直接用 vLLM 起服务,或者转成 Ollama 能加载的 GGUF 格式。如果你要把它接入 WorkBuddy 这类工具链,让模型操作电脑改代码,有两点必须重视。

第一,工具调用能力的强化训练和数学题不完全一样。数学 GRPO 的奖励是“最终答案是否正确”,工具调用的奖励是“是否选择了正确的工具动作序列”。我在训练数学推理后顺手做了一次工具调用微调,用的是可执行环境自动验证动作的效果作为奖励。也就是说,GRPO 奖励函数不止能判断输出文本,还能调用代码执行引擎试运行返回结果。这一点对 Agent 类任务特别关键,也让“接上 Ollama 后模型改不动代码”的问题有了解决方案。

第二,部署时不要贪快直接量化到 Q4,先用 FP16 或 BF16 跑。GRPO 训练强化出来的能力往往体现在特定格式和特定推理模式上,量化到 4bit 之后这些能力损失速度比通用能力快得多。我建议生产环境至少用 8bit 量化。如果你的服务器显存实在紧张,再考虑用 4bit 并做好完整评测对比。

很多人会把强化微调当作 SFT 之后的一步“自动化调优”,但从我的实际体验看,它更像是一门需要反复打磨的手艺。Qwen3 底子很强,GRPO 给了你在自己的数据上把它推向任务上限的钥匙,但这把钥匙要用好,奖励设计、超参选择、模式控制缺一不可。如果你也是第一次跑,我建议先拿 4B 模型把整个路径走通,照着我这份流程和参数表去复现,再逐步改成你自己的任务。最后说一句,训练日志和中间 checkpoint 一定都留好,GRPO 的训练不稳定是常态,回滚和对比才是提升效果最快的路径,别贪图省事直接跑完就删。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询