Skip to main content

R1-Zero (GRPO) 在小模型上的复现踩坑全记录

原文:R1-Zero(GRPO)的复现实验记录,踩坑问题(小模型) | 知乎:zhuanlan.zhihu.com/p/1888591707769135444 | 作者:刘聪NLP

这篇文章是基于刘聪 NLP 公众号原文的深度扩写。我以第一视角重新梳理了在 1.5B/3B 小模型上复现 R1-Zero(GRPO 训练推理能力)时踩的坑——format reward 设计问题、Instruct vs Base 模型的 trick、小模型训练的三个阶段退化和 KL 散度爆炸。这篇文章不是告诉你 GRPO 的成功经验,而是把踩的坑全部摊开。


这篇文章说了什么

作者在用 OpenRLHF 框架 + Qwen2.5-1.5B/3B 模型 + MATH 数据集复现 R1-Zero(DeepSeek-R1 的纯 RL 版本)时,遇到了大量"小模型专属"的奇奇怪怪问题。

核心踩坑:

  1. Format reward 正则太严格导致梯度为零pattern = r"^.*?<think>.*?</think>.*?<answer>.*?</answer>$" 要求 response 必须从开头就是 <think>、结尾是 </answer>——在 RL 探索阶段,模型几乎永远满足不了,format_reward 长期为 0
  2. Instruct 模型和 Base 模型表现相反:3B Instruct 喜欢在 <think> 后加 \n,导致 format pattern 匹配失败;Base 模型不加 \n,反而是正常的 pattern 才能匹配。同一个超参,两个模型效果完全不同
  3. 小模型训练存在三阶段退化:model 先学会格式 → 正常发展 → 然后突然开始重复/退化
  4. KL 散度经常爆炸:token-level loss 在不同输出长度下梯度计算不稳定

核心结论:小模型 + GRPO 的组合,超参敏感度远超预期。Format reward 的设计要从"严格"逐步改为"宽松",否则模型根本拿不到训练信号。


有效的实验就这几招

方法做了什么效果
Format pattern 逐步宽松从严格正则 ^<think>... 改为 .*<think>.*,允许 response 不以 <think> 开头和结尾format_reward 从接近 0 变到正常值
Tag count 逐步奖励正确放置前 x 个 tag 得 0.25*x 的奖励,多个 tag 顺序正确且每个只出现一次比一刀切更平滑,模型有渐进学习路径
Instruct 模型特殊适配发现 3B-Instruct 喜欢在 think 和 answer 之间加 \n,修改正则为 ^.*?<think>.*?\n.*?</answer>$格式匹配率恢复正常
Base 模型不加 \n正常的 pattern 即可,加了 \n 反而匹配不到Base 和 Instruct 在这个细节上完全相反
强制 format 奖励反而是负担去掉强制的 format 奖励后,模型推理能力反而更好格式奖励可能跟推理能力优化方向冲突

试了但翻车的情况

  • 3B-Instruct 直接沿用 1.5B-Base 的 format pattern → format reward 崩掉
  • 以为 3B 的 Instruc 和 Base 表现一致 → 完全相反

一、实验配置

参数
框架OpenRLHF
模型Qwen2.5-1.5B/3B-Base/Instruct
训练数据MATH(7.5k)
指令格式orz style: think + answer 标签
奖励函数accuracy_reward + format_reward

指令格式(参考 orz 的 think/answer 格式):

"A conversation between User and Assistant. The user asks a question, 
and the Assistant solves it. The assistant first thinks about the
reasoning process in the mind and then provides the user with the
answer. The reasoning process and answer are enclosed within
<think> and </think>, <answer> and </answer> tags respectively,
i.e., <think> reasoning process here </think> <answer> answer here </answer>"

"Please put your final answer within \boxed{}."

奖励函数

  • accuracy_reward:使用 math_verify 做答案抽取和匹配
  • format_reward:借鉴 Open-R1 的正则 pattern = r"^.*?<think>.*?</think>.*?<answer>.*?</answer>$"

二、核心踩坑:Format Reward 设计

2.1 第一个坑:Format reward 去哪了?

跑 Qwen2.5-1.5B-Base 时,基础超参:

train_batch_size = 16, 32, 64
rollout_size = 16
n_generate = 6
lr = 1e-6
kl_coef = 1e-3

accuracy_reward 和 response 长度都在正常增长,训练曲线看起来不错。

但是 format_reward 几乎为 0,而且还在下降。

检查模型实际输出才发现问题:模型确实能生成 <think></think><answer></answer>,但——

不是从 response 开头就是 <think>,也不是以 </answer> 结尾。

比如模型生成了:

To find the number of zeros in the expansion of $999,999,999,998^2$, 
we first need to understand the structure...

<think>
... reasoning ...
</think>

<answer>
... answer ...
</answer>

<think> 前面有一大段"裸"推理文本!正则 ^<think> 要求 response 第一个字符就是 <,所以匹配失败。

而原来严格的 pattern r"^.*?<think>.*?</think>.*?<answer>.*?</answer>$" 要求 response 必须以 <think> 开头,以 </answer> 结尾,中间不能有其他内容——在 RL 探索阶段,这几乎不可能满足。

2.2 Gradation 逐步宽松

尝试两种改进:

方案 A:Tag count 逐步奖励

正确放置前 x 个 tag 得到 0.25*x 的奖励。正确放置的定义:

  • 多个 tag 顺序正确(<think><answer> 之前)
  • 每个 tag 只出现一次
  • 成对的 open/close tag 都存在

例如:

  • 只有 <think></think>:0.5 分
  • <think></think><answer>:0.75 分
  • 四个 tag 全有且顺序正确:1.0 分

方案 B:宽松 pattern

pattern = r".*?<think>.*?</think>.*?<answer>.*?</answer>"

去掉 ^$,允许 response 在 tag 前后有任意内容。

结论:两种方案都能改善 format_reward,但各有侧重。逐步奖励方式给模型提供了更平滑的学习路径。

2.3 第二个坑:Instruct 模型和 Base 模型表现相反

在用 Qwen2.5-1.5B-Base 调好 format 后,自然想:换成 Instruct 模型应该更简单吧?Instruct 已经做过对齐,格式遵循能力更强。

1.5B-Instruct:确实没问题。 Format reward 直接就好,不需要适配。

3B-Instruct:崩了。

检查输出发现:3B-Instruct 在对齐训练中养成了一个习惯——喜欢在 <think> 后加一个 \n(换行)。

<think>\n... reasoning ...\n</think>\n\n<answer>\n... answer ...\n</answer>

原来的 pattern 不期待这个换行,所以匹配失败。

修复:给 3B-Instruct 专门加 \n 的正则:

pattern = r"^.*?<think>.*?\n.*?</answer>$"

但 3B-Base 呢? Base 模型没有经过对齐,不会自动加 \n。正常的 pattern 就可以,加了 \n 反而匹配不到。

同一个超参,Base 和 Instruct 在两个尺寸上的行为矩阵

模型1.5B3B
Base正常 pattern ✓正常 pattern ✓
Instruct正常 pattern ✓需要加 \n pattern

教训:不要假设"同一系列的模型行为一样"。对齐训练可能在任何地方引入细微的格式差异,而这种差异在小模型上会被 GRPO 的 reward normalization 放大。


三、小模型训练的三阶段退化

3.1 观察到的三阶段模式

在小模型 GRPO 训练中,作者观察到一个反复出现的三阶段模式:

阶段一:学习格式

  • 模型把主要精力花在学会输出 <think> + <answer> 标签
  • 思考长度下降(为了满足格式而压缩输出)
  • 在长度最低点,format reward 达到极值
  • KL 散度出现波动——格式学习阶段是 KL 变化最剧烈的时候

阶段二:正常发展

  • 格式稳定后,模型开始在格式约束下提高回答质量
  • 思考长度回升到正常水平
  • 回答准确率逐步提升

阶段三:退化

  • 模型开始产生重复内容
  • 或者一味追求更长输出(不是"更有逻辑",就是简单地重复/啰嗦)
  • Format reward 和 accuracy reward 都受阻

3.2 为什么会退化

可能的原因:

  • 小模型容量有限:3B 的参数对于"学习推理 + 保持格式 + 不退化"可能处于临界点
  • GRPO 的 KL 散度约束不完美:token-level loss 在不同输出长度下的梯度计算不稳定,可能在某些步长导致策略偏离太远
  • KL 散度爆炸:这是一个反复出现的问题,一旦 KL 失控,模型就会退化

四、实验结果

在 Qwen2.5-3B-Base 上跑完训练后的测试结果:

测试集基准GRPO 后
MATH500基准值小幅提升
GAOKAO23基准值小幅提升
AIME基准值小幅提升
AMC基准值小幅提升

作者坦言效果"不是很明显"——可能跟训练步数太少有关。

但有一个重要发现:去掉强制的 format 奖励后,模型推理能力表现反而更好。

这说明 format reward 和 accuracy reward 之间可能存在冲突——模型在"追求格式正确"和"追求推理正确"之间分配了有限的精力,而 format 奖励可能挤占了推理优化的空间。


五、未解决的问题

5.1 KL 散度爆炸

训练过程中 KL 散度经常爆炸。直觉上 KL 系数(kl_coef)应该控制住它,但在 token-level loss + 不同长度的输出序列下,实际的 KL 约束效果不稳定。

5.2 Token-level loss 的梯度不稳定

GRPO 用的是 token-level loss(每个 token 位置单独计算 loss 再平均),这意味着:

  • 长序列贡献更多梯度(更多 token)
  • 短序列的梯度被稀释
  • 不同 rollout 之间的长度差异可能引入系统性偏差

可能的解决方案(文章未实现,但值得关注):

  • Sequence-level loss:整个序列算一个 loss,不按 token 平均
  • 长度归一化:按序列长度归一化梯度
  • DAPO 的 token-level + length normalization 混合

六、工程启示

6.1 Format reward 要逐步放宽,不要一步到位

RL 训练早期,模型还在探索,严格的正则几乎不可能满足。先用宽松条件让模型拿到训练信号,再逐步收紧——或者干脆用 tag count 这种平滑的奖励递增方式。

6.2 Base 和 Instruct 是两个完全不同的训练起点

不要假设 Instruct 总是"更容易"。对齐训练可能引入你意想不到的格式习惯,而 GRPO 对这些细节非常敏感。

6.3 小模型的 GRPO 训练可能需要更保守的超参

1.5B 和 3B 模型的容量本身就卡在"能学推理"的边缘,超参调优的余地更小。大模型可以靠参数冗余消化训练噪声,小模型不行。

6.4 不一定要有 format reward

你可能会觉得 format reward 是标配,但实际上:如果模型本身就倾向于输出合理的格式(比如 Instruct 模型),硬加一个 format reward 可能是在跟 accuracy reward 抢梯度。


七、跟其他 GRPO 项目的对比

维度本文 (R1-Zero 复现)基金助手Copilot Planning
场景数学推理 (MATH)基金 API AgentMulti-Agent 调度
模型大小1.5B/3B7B32B
Format 设计严格 → 逐步宽松ReAct 三层结构think + JSON plan
是否有 SFT 前置
核心贡献Format reward 设计教训NGRPO 治零梯度思考长度 S 形约束

独特性:这是所有 GRPO 笔记里唯一一篇专门讲 format reward 设计踩坑的——而且来自小模型的独特视角。如果你在小于 7B 的小模型上用 GRPO,这篇应该作为必读。