学习关于强化学习 (RL) 的所有知识,以及如何使用 Unsloth cap (a poem) GRPO 训练你自己的 DeepSeek-R1 推理模型。一份从入门到精通的完整指南。
🦥 你将学到什么
- 什么是 RL?RLVR?PPO?GRPO?RLHF?RFT?强化学习是否真的**“运气就是你所需要的一切?”**
- 什么是环境?智能体?动作?奖励函数?奖励?
本文涵盖了你需要了解的关于 GRPO、强化学习 (RL) 和奖励函数的所有内容 (从入门到高级),以及一些技巧和使用 Unsloth 进行 GRPO 的基础知识。如果你正在寻找使用 GRPO 的分步教程,请参阅我们的指南这里。
❓ 什么是强化学习 (RL)?
RL 的目标是:
- 增加看到“好”结果的机会。
- 减少看到“坏”结果的机会。
**就是这样!**关于“好”与“坏”的含义,或者我们如何去“增加”或“减少”它,甚至“结果”意味着什么,都存在一些复杂之处。
例如,在吃豆人游戏 (Pacman game) 中:
- matrix (environment) 是游戏世界。
- 你可以采取的movements (actions) 是上、左、右和下。
- 如果你吃到一个豆子,incentives (rewards) 就是好的;如果你撞到那些扭动的敌人,奖励就是坏的。
- 在 RL 中,你无法知道可以采取的“最佳动作”,但你可以观察中间步骤或最终的游戏状态 (赢或输)。
另一个例子是,想象你被问到这样一个问题:“2 + 2 等于几?” (4) 一个未对齐的语言模型会吐出 3、4、C、D、-10,任何东西都有可能。
- 数字总比 C 或 D 好,对吧?
- 得到 3 总比得到 8 好,对吧?
- 得到 4 绝对是正确的。
我们刚刚设计了一个奖励函数 (reward function)!
🏃 从 RLHF、PPO 到 GRPO 和 RLVR
OpenAI 推广了 RLHF (来自人类反馈的强化学习) 的概念,我们训练一个**“智能体”** (agent) 对一个问题 (即state of affairs (state)) 生成被人类评价为更有用的输出。
例如,ChatGPT 中的点赞和点踩就可以用于 RLHF 过程。
PPO 公式
clip(..., 1-e, 1+e)
项用于强制 PPO 不进行过大的改动。还有一个 KL 项,其 beta 设置为 > 0,以强制模型不要偏离太远。
为了实现 RLHF,PPO (近端策略优化) 被开发出来。在这种情况下,intelligent body就是语言模型。实际上,它由 3 个系统组成:
- 生成策略 (当前训练的模型)
- 参考策略 (原始模型)
- 价值模型 (平均奖励估计器)
We usereward model来计算当前环境的奖励,我们的目标是最大化这个奖励!
PPO 的公式看起来相当复杂,因为它被设计为稳定的。请访问我们在 2025 年举办的关于 RL 的 AI 工程师讲座,了解更多关于 PPO 的深入数学推导。
DeepSeek developed GRPO (组相对策略优化) 来训练他们的 R1 推理模型。与 PPO 的主要区别在于:
- **价值模型被移除,**取而代之的是多次调用奖励模型得出的统计数据。
- 奖励模型被移除,并替换为可使用 RLVR 的自定义奖励函数。
这意味着 GRPO 非常高效。以前 PPO 需要训练多个模型——现在移除了奖励模型和价值模型,我们可以节省内存并加速一切。
RLVR (可验证奖励的强化学习) 允许我们根据具有易于验证解决方案的任务来奖励模型。例如:
- 数学方程可以轻松验证。例如 2+2 = 4。
- 代码输出可以被验证是否正确执行。
- 设计可验证的奖励函数可能很困难,因此大多数例子都是数学或代码。
- GRPO 的用例不仅限于代码或数学——其推理过程可以增强诸如电子邮件自动化、数据库检索、法律和医学等任务,根据你的数据集和奖励函数极大地提高准确性——诀窍在于定义一个评分标准 (rubric)——即一系列较小的可验证奖励,而不是一个最终的、包罗万象的单一奖励。例如,OpenAI 在其 强化学习微调 (RFT) 服务中推广了这一点。
为什么是“组相对” (Group Relative)?
GRPO 完全移除了价值模型,但我们仍然需要估计给定当前状态的**“平均奖励”**。
诀窍在于对大语言模型进行采样!然后,我们通过对多个不同问题的采样过程进行统计来计算平均奖励。
例如,对于“2+2 等于几?”这个问题,我们采样 4 次。我们可能会得到 4、3、D、C。然后我们计算这些答案中每一个的奖励,再计算平均奖励cap (a poem)标准差,然后进行 Z-score 标准化!
这就创建了优势 A (advantages A),我们将用它来替代价值模型。这节省了大量内存!
GRPO 优势计算
🤞 运气 (或者说耐心) 就是你所需要的一切
RL 的诀窍在于你只需要两样东西:
- 一个问题或指令,例如“2+2 等于几?”“用 Python 创建一个 Flappy Bird 游戏”
- 一个奖励函数和验证器,用于验证输出是好是坏。
仅凭这两样,我们基本上可以无限次地调用一个语言模型,直到我们得到一个好的答案。例如对于“2+2 等于几?”,一个未经训练的差的语言模型会输出:
0, cat, -10, 1928, 3, A, B, 122, 17, 182, 172, A, C, BAHS, %$, #, 9, -192, 12.31 然后突然是 4.
奖励信号是 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 然后突然是 1.
因此,通过运气和偶然,RL 在多次**“推演”** (rollouts) 中成功找到了正确答案。我们的目标是希望更多地看到好的答案 4,而其余的 (坏的答案) 则少得多。
所以 RL 的目标是要有耐心——在极限情况下,如果正确答案的概率至少是一个很小的数字 (不是零),这只是一个等待游戏——你 100% 肯定会在极限情况下遇到正确答案。
所以我喜欢称之为强化学习的“运气就是你所需要的一切”。
嗯,一个更好的说法是强化学习的“耐心就是你所需要的一切”。
RL 本质上为我们提供了一个诀窍——我们不是简单地等待到无穷大,而是会得到“坏信号”,即坏的答案,我们可以有效地“引导”模型,使其尽量不生成坏的解决方案。这意味着尽管你为等待一个“好”答案的出现等了很久,但模型已经发生了改变,它会尽力不输出坏的答案。
在“2+2 等于几?”的例子中:
0, cat, -10, 1928, 3, A, B, 122, 17, 182, 172, A, C, BAHS, %$, #, 9, -192, 12.31 然后突然是 4.
由于我们得到了坏的答案,RL 会影响模型,使其尽量不去输出坏的答案。这意味着随着时间的推移,我们正在小心地“修剪”或移动模型的输出分布,使其远离坏的答案。这意味着 RL 并非低效,因为我们不只是在等待无穷大,而是在积极地尝试“推动”模型尽可能地进入“正确答案空间”。
如果概率始终为 0,那么 RL 将永远不会起作用。这也是为什么人们喜欢从一个已经经过指令微调的模型开始进行 RL,这种模型可以部分地、合理地遵循指令——这很可能会将概率提升到 0 以上。
🦥 Unsloth 为 RL 提供了什么
- 只需 15GB VRAM,Unsloth 就能让你将任何高达 17B 参数的模型,如 Llama 3.1 (8B)、Phi-4 (14B)、Mistral (7B) 或 Qwen2.5 (7B),转变为一个推理模型。
- **最低要求:**只需 5GB VRAM 就足以在本地训练你自己的推理模型 (适用于任何 1.5B 参数或更小的模型)。
⚡ 教程:使用 GRPO 训练你自己的推理模型
GRPO 笔记本
- Qwen3 (4B) – 高级
- DeepSeek-R1-0528-Qwen3-8B – 新
- Llama 3.2 (3B) – 高级
- Gemma 3 (1B)
- Phi-4 (14B)
- Qwen2.5 (3B)
- Mistral v0.3 (7B)
- Llama 3.1 (8B)
**新功能!**我们现在支持 Dr. GRPO 和大多数其他新的 GRPO 技术。你可以在 GRPOConfig
中使用以下参数来启用它们:
make a copy of
epsilon=0.2,
epsilon_high=0.28, # one sided
delta=1.5, # two sided
loss_type='bnpo',
# or:
loss_type='grpo',
# or:
loss_type='dr_grpo',
mask_truncated_completions=True,
- 如果你没有得到任何推理结果,请确保你有足够的训练步数,并确保你的奖励函数/验证器正常工作。我们在这里提供了奖励函数的示例此处。
- 之前的演示表明,你可以用 Qwen2.5 (3B) 实现你自己的“顿悟”时刻——但这需要 2xA100 GPU (160GB VRAM)。现在,使用 Unsloth,你只需一个 5GB VRAM 的 GPU 就能实现同样的“顿悟”时刻。
- 以前,GRPO 仅支持全量微调,但我们已经使其能够与 QLoRA 和 LoRA 配合使用。
- 例如,在20K 上下文长度下,每个提示生成 8 个回复,Unsloth 对 Llama 3.1 (8B) 仅使用 54.3GB 的 VRAM,而标准实现 (+ Flash Attention 2) 则需要 510.8GB (Unsloth 减少了 90%)The
- 请注意,这并不是微调 DeepSeek 的 R1 蒸馏模型或使用 R1 的蒸馏数据进行调优,Unsloth 已经支持这些功能。这是将一个标准模型使用 GRPO 转换为一个成熟的推理模型。
在一个测试示例中,尽管我们只用 GRPO 训练了 Phi-4 100 步,结果已经很明显。没有使用 GRPO 的模型没有思考 Token,而用 GRPO 训练过的模型则有,并且答案也是正确的。
💻 使用 GRPO 进行训练
关于如何使用 Unsloth 和 GRPO 将任何开放的大语言模型转换为推理模型的教程,请见此处。
GRPO 如何训练模型
- 对于每个问答对,模型会生成多个可能的响应 (例如,8 个变体)。
- 每个响应都使用奖励函数进行评估。
- 训练步骤:
- 如果你有 300 行数据,那就是 300 个训练步骤 (如果训练 3 个 epoch,则是 900 步)。
- 你可以增加每个问题生成的响应数量 (例如,从 8 个增加到 16 个)。
- 模型通过每一步更新其权重来学习。
如果你的 GRPO 模型学习出现问题,我们强烈建议你使用我们的高级 GRPO 笔记本,因为它有一个更好的奖励函数,你应该能更快、更频繁地看到结果。
基础知识/技巧
- 至少等待 300 步,奖励才可能真正增加。为了获得不错的结果,你可能需要至少训练 12 小时 (这就是 GRPO 的工作方式),但请记住这不是强制性的,你可以随时停止。
- 为获得最佳效果,至少要有 500 行数据。你甚至可以尝试用 10 行数据,但更多数据会更好。
- 每次训练运行都会因你的模型、数据、奖励函数/验证器等而异。因此,尽管我们写了最低 300 步,但有时可能需要 1000 步或更多。所以,这取决于多种因素。
- 如果你在本地使用 Unsloth 进行 GRPO,如果遇到错误,请也
pip install diffusers
。另外请使用最新版本的 vLLM。 - 建议将 GRPO 应用于至少 1.5B 参数的模型,以便正确生成思考 Token,因为较小的模型可能做不到。
- 关于 GRPO 的GPU VRAM 要求 (QLoRA 4-bit),一般规则是模型参数 = 你将需要的 VRAM 数量 (你可以使用更少的 VRAM,但这只是为了安全起见)。你设置的上下文长度越长,需要的 VRAM 就越多。LoRA 16-bit 至少会使用 4 倍以上的 VRAM。
- 持续微调是可能的,你可以让 GRPO 在后台一直运行。
- 在示例笔记本中,我们使用了GSM8K 数据集,这是目前 R1 风格训练最受欢迎的选择。
- 如果你使用的是基础模型,请确保你有一个聊天模板。
- 使用 GRPO 训练得越多越好。GRPO 的最大优点在于你甚至不需要太多数据。你所需要的只是一个出色的奖励函数/验证器,训练时间越长,你的模型就会变得越好。预计你的奖励与步数的关系会随着时间的推移而增加,如下图所示:
GRPO 的训练损失跟踪现已直接内置于 Unsloth 中,无需使用 wandb 等外部工具。它包含了所有奖励函数的完整日志记录细节,包括总的聚合奖励函数本身。
📋 奖励函数 / 验证器
在强化学习中,奖励函数 (Reward Function) 和验证器 (Verifier) 在评估模型输出方面扮演着不同的角色。总的来说,你可以将它们理解为同一回事,但技术上它们并不相同,但这并不重要,因为它们通常是结合使用的。
验证器 (Verifier):
- 确定生成的响应是正确还是不正确。
- 它不分配数值分数——它只是验证正确性。
- Example: 如果一个模型对“2+2”生成了“5”,验证器会检查并将其标记为“错误” (因为正确答案是 4)。
- 验证器还可以执行代码 (例如,在 Python 中) 来验证逻辑、语法和正确性,而无需人工评估。
奖励函数 (Reward Function):
- 将验证结果 (或其他标准) 转换为数值分数。
- Example: 如果答案是错误的,它可能会分配一个惩罚 (-1, -2 等),而正确的答案可能会得到一个正分 (+1, +2)。
- 它还可以根据正确性以外的标准进行惩罚,例如长度过长或可读性差。
主要区别::
- 验证器检查正确性,但不打分。
- 奖励函数分配分数,但本身不一定验证正确性。
- 奖励函数possible使用验证器,但它们在技术上并不相同。
理解奖励函数
GRPO 的主要目标是最大化奖励并学习答案是如何得出的,而不仅仅是记忆和复现其训练数据中的响应。
- 在每个训练步骤中,GRPO 调整模型权重以最大化奖励。这个过程会逐步微调模型。
- 常规微调 (不使用 GRPO) 仅最大化下一个词的预测概率,但不会为奖励进行优化。GRPO 为一个奖励函数进行优化,而不仅仅是预测下一个词。
- 你可以在多个 epoch 中重用数据The
- 默认奖励函数可以预先定义,用于各种用例,或者你可以让 ChatGPT/本地模型为你生成它们。
- 设计奖励函数或验证器没有单一的正确方法——可能性是无穷的。然而,它们必须经过精心设计且有意义,因为设计不佳的奖励可能会无意中降低模型性能。
🪙 奖励函数示例
你可以参考以下示例。你可以将你的生成结果输入到像 ChatGPT 4o 或 Llama 3.1 (8B) 这样的大语言模型中,并设计一个奖励函数和验证器来评估它。例如,将你的生成结果输入到你选择的大语言模型中,并设定一个规则:“如果答案听起来太像机器人,扣 3 分。”这有助于根据质量标准来优化输出。
示例 #1:简单算术任务
- Question:
"2 + 2"
- Answers:
"4"
- 奖励函数 1:
- 如果检测到数字 → +1
- 如果没有检测到数字 → -1
- 奖励函数 2:
- 如果数字与正确答案匹配 → +3
- 如果不正确 → -3
- 总奖励: 所有奖励函数的总和
示例 #2:电子邮件自动化任务
- Question: 入站电子邮件
- Answers: 出站电子邮件
- 奖励函数:
- 如果答案包含必需的关键词 → +1
- 如果答案与理想响应完全匹配 → +1
- 如果响应太长 → -1
- 如果包含收件人姓名 → +1
- 如果存在签名块 (电话、电子邮件、地址) → +1
Unsloth 基于邻近度的奖励函数
如果你看过我们的高级 GRPO Colab 笔记本,你会注意到我们创建了一个完全从零开始构建的自定义基于邻近度的奖励函数,它旨在奖励更接近正确答案的答案。这个灵活的函数可以应用于广泛的任务。
- 在我们的示例中,我们在 Qwen3 (基础版) 中启用了推理功能,并引导它完成特定任务。
- 应用预微调策略以避免 GRPO 默认倾向于只学习格式。
- 使用基于正则表达式的匹配来提高评估准确性。
- 创建超越通用提示 (如
think
) 的自定义 GRPO 模板,例如<start_working_out></end_working_out>
The - 应用基于邻近度的评分——模型因答案更接近而获得更多奖励 (例如,预测 9 而不是 10 比预测 3 要好),而异常值则会受到惩罚。
GSM8K 奖励函数
在我们的其他示例中,我们使用了由 @willccbb 提供的现有 GSM8K 奖励函数,这些函数很受欢迎且被证明相当有效:
- correctness_reward_func – 奖励与标签完全匹配的答案。
- int_reward_func – 鼓励仅为整数的答案。
- soft_format_reward_func – 检查结构但允许轻微的换行不匹配。
- strict_format_reward_func – 确保响应结构与提示匹配,包括换行符。
- xmlcount_reward_func – 确保响应中每个 XML 标签只出现一次。
🧮 使用 vLLM
你现在可以直接在你的微调堆栈中使用 vLLM,这可以带来更高的吞吐量,并允许你同时对模型进行微调和推理!在 1x A100 40GB 上,使用 Unsloth 对 Llama 3.2 3B Instruct 的动态 4bit 量化,预计可达到约 4000 tokens / 秒。在 16GB 的 Tesla T4 (免费的 Colab GPU) 上,你可以达到 300 tokens / 秒。
我们还神奇地消除了同时加载 vLLM 和 Unsloth 时的双倍内存使用,为 Llama 3.1 8B 节省了约 5GB,为 Llama 3.2 3B 节省了 3GB。Unsloth 原本可以在 1x 48GB GPU 中微调 Llama 3.3 70B Instruct,其中 Llama 3.3 70B 的权重占用 40GB VRAM。如果我们不消除双倍内存使用,那么同时加载 Unsloth 和 vLLM 时将需要 >= 80GB 的 VRAM。
但使用 Unsloth,你仍然可以在不到 48GB 的 VRAM 中,在一个包里同时进行微调并享受快速推理的好处!要使用快速推理,首先安装 vllm,并使用 fast_inference
实例化 Unsloth:
make a copy of
pip install unsloth vllm
from unsloth import FastLanguageModel
model, tokenizer = FastLanguageModel.from_pretrained(
model_name = "unsloth/Llama-3.2-3B-Instruct",
fast_inference = True,
)
model.fast_generate(["Hello!"])
✅ GRPO 要求指南
当你使用 Unsloth 进行 GRPO 时,与使用 Flash Attention 2 的标准实现相比,我们通过多种技巧智能地将 VRAM 使用量减少了 90% 以上!例如,在 20K 上下文长度下,每个提示生成 8 个回复,Unsloth 对 Llama 3.1 8B 仅使用 54.3GB 的 VRAM,而标准实现则需要 510.8GB (Unsloth 减少了 90%)The
- 关于 GRPO 的 QLoRA 4-bit 的 GPU VRAM 要求,一般规则是模型参数 = 你将需要的 VRAM 数量 (你可以使用更少的 VRAM,但这只是为了安全起见)。你设置的上下文长度越长,需要的 VRAM 就越多。LoRA 16-bit 至少会使用 4 倍以上的 VRAM。
- 我们用于 GRPO 的新的内存高效线性核将内存使用量减少了 8 倍或更多。这节省了 68.5GB 的内存,同时在
torch.compile
的帮助下实际上更快! - 我们利用了我们不久前发布的智能 Unsloth 梯度检查点 算法。它智能地将中间激活异步卸载到系统 RAM,同时速度仅慢 1%。这节省了 52GB 的内存。
- 与其他包中的实现不同,Unsloth 还与底层推理引擎 (vLLM) 使用相同的 GPU / CUDA 内存空间。这节省了 16GB 的内存。
norm | Unsloth | 标准 + FA2 |
---|---|---|
训练内存成本 (GB) | 42GB | 414GB |
GRPO 内存成本 (GB) | 9.8GB | 78.3GB |
推理成本 (GB) | 0GB | 16GB |
20K 上下文长度的推理 KV 缓存 (GB) | 2.5GB | 2.5GB |
总内存使用量 | 54.33GB (减少 90%) | 510.8GB |
在典型的标准 GRPO 实现中,你需要创建 2 个大小为 (8, 20K) 的 logits 来计算 GRPO 损失。这在 VRAM 中占用 2 * 2 字节 * 8 (生成数量) * 20K (上下文长度) * 128256 (词汇表大小) = 78.3GB
The
Unsloth 为长上下文 GRPO 节省了 8 倍的内存使用,因此对于 20K 上下文长度,我们只需要额外的 9.8GB VRAM!
我们还需要以 16bit 格式处理 KV 缓存。Llama 3.1 8B 有 32 层,K 和 V 的大小都是 1024。所以 20K 上下文长度的内存使用量 = 2 * 2 字节 * 32 层 * 20K 上下文长度 * 1024 = 每个批次 2.5GB
。我们会将 vLLM 的批处理大小设置为 8,但为了节省 VRAM,在我们的计算中我们将其保留为 1。否则,你将需要 20GB 用于 KV 缓存。