trl_grpo_reasoning_advanced_reward.ipynb 逐格说明

这份 notebook 是上一份基础 GRPO notebook 的升级版。
如果前一份在回答:

GRPO 训练最小闭环长什么样?

那么这一份在回答:

如果只靠一个 reward 不够,怎样把 RL 后训练做成一个更完整的系统?

和前面课程的对应关系

Cells 1-3:安装依赖

!pip install transformers datasets trl bitsandbytes peft trackio

新增的关键包

这说明这份 notebook 比上一份更工程化:

Cell 5:GPU 环境检测

这一格的作用和前面 00_check_env.ipynb 很像:

为什么这一步在高级版里更重要

因为这份 notebook 用的是:

如果 GPU 条件不够,很容易直接 OOM。

Cell 7:导入核心库

这格把整个系统用到的组件一次性摆出来。

初学者可以分组记

模型相关

RL 训练相关

LoRA 相关

数据相关

跟踪相关

为什么这格看起来比前面的 notebook 更复杂

因为你现在已经进入:

Cells 9-11:模型选择与量化加载

Cell 9:模型名和最大序列长度

model_name = "Qwen/Qwen2.5-3B-Instruct"
max_seq_length = 2048

和前面最小实验的对照

模型明显更大,所以后面必须引入量化。

Cell 10:BitsAndBytesConfig(...)

这格和 Chapter2 可以直接对照。

bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.float16,
    bnb_4bit_use_double_quant=True,
)

你应该重点记住什么

为什么这很关键

3B 模型如果完全按普通方式加载,很多普通教学 GPU 很难稳跑。
量化是让它“装得下”的第一步。

Cell 11:加载量化模型和 tokenizer

model = AutoModelForCausalLM.from_pretrained(
    model_name,
    quantization_config=bnb_config,
    device_map="auto",
    trust_remote_code=True,
    torch_dtype=torch.float16,
)

这一格和前面 Qwen 最小实验怎样对照

你们前面写的是:

这里是:

device_map="auto"

表示让 Hugging Face 自动决定模型放到哪里:

pad_token

这一格仍然保留了和前面一致的修补逻辑:

if tokenizer.pad_token is None:
    tokenizer.pad_token = tokenizer.eos_token

说明到了 RL 阶段,这些 tokenizer 基本功仍然没有消失。

Cell 13:LoRA 配置

lora_config = LoraConfig(
    r=16,
    lora_alpha=32,
    target_modules=["q_proj", "v_proj"],
    lora_dropout=0.1,
    bias="none",
    task_type=TaskType.CAUSAL_LM,
)

和前面基础 GRPO notebook 对照

配置很接近,但这里把参数说明写得更清楚了。

为什么还是 LoRA

因为即使进入 RL 后训练:

这正是第 13 章最想让学生建立的感觉:

SFT 和 RL 后训练并不是两条完全无关的路,它们共享同一套“量化 + LoRA + tokenizer + 生成”的骨架。

Cells 15-17:数据格式和 GSM8K

Cell 15:定义结构化输出格式

这里定义了一组标记:

为什么这和上一份 notebook 不同

上一份用的是:

这一份改成了另一套标签,但本质没变:

Cell 16:数据处理函数

extract_hash_answer(text)

GSM8K 的标准答案里常常带 #### 42 这种结构。
这个函数的作用就是把最终数值提出来。

process_dataset_example(example)

把原始 GSM8K 样本转成:

其中 prompt 仍然是标准 chat 结构:

[
  {"role": "system", "content": system_prompt},
  {"role": "user", "content": question},
]

这和前面课程如何互相印证

说明即使到了 RL 后训练:

Cell 17:加载并处理 GSM8K

dataset = load_dataset("openai/gsm8k", "main", split="train")
dataset = dataset.map(process_dataset_example)

这里初学者最值得看什么

这一步和前面所有“先 print 一条样本再训练”的习惯完全一致。

Cells 19-23:多奖励系统

这是整份 notebook 最核心的部分。

Cell 19:预编译 regex

这里先把格式匹配规则编好:

为什么先预编译

因为 reward function 会被反复调用。
先编译好 regex,后面计算更快、更清楚。

Cell 20:match_format_exactly

这个 reward 最严格。

逻辑

它的作用是:

Cell 21:match_format_approximately

这是一个更温和的 reward。

逻辑

不是“全对才给分”,而是:

为什么要这样设计

因为如果只有严格格式 reward,模型在早期很可能几乎一直拿不到分。
而这种“部分奖励”能给它更平滑的学习信号。

Cell 22:check_answer_correctness

这是内容正确性的主 reward。

分级打分

为什么不是只有对 / 错

因为推理任务里,“接近正确”有时也值得给一点正反馈。
这比单纯的 0/1 reward 更柔和。

Cell 23:check_numbers_extraction

这个 reward 不直接看答案全不全对,而是看:

它为什么有价值

因为推理输出里经常会出现这种情况:

这个 reward 就是在单独奖励“把最终数值说清楚”这件事。

Cells 25-28:训练配置和跟踪

Cell 25:GRPOConfig(...)

这格是高级版训练的总配置中心。

重点参数

初学者最该看懂的几项

gradient_accumulation_steps=8

和前面 Qwen 最小实验完全同类:

max_prompt_length / max_completion_length

这两项在 RL 后训练里特别重要,因为:

max_grad_norm=0.1

这是梯度裁剪。
RL 训练比普通 SFT 更容易不稳定,所以这里更强调控制梯度爆炸。

Cell 26:trackio.init(...)

这一格是在做实验追踪初始化。

它记录什么

为什么这一步值得学生形成感觉

因为从这一格开始,RL 后训练明显更像“实验系统工程”了,而不只是一个 notebook。

Cell 28:GRPOTrainer(...)

trainer = GRPOTrainer(
    model=model,
    reward_funcs=[
        match_format_exactly,
        match_format_approximately,
        check_answer_correctness,
        check_numbers_extraction,
    ],
    args=training_args,
    train_dataset=dataset,
)

这一格最值得看什么

你现在可以明显看到:

这就是这份 notebook 的真正升级点。

Cell 30:开始训练

这里打印了很多提示:

初学者最该知道什么

到了 RL 阶段,训练监控比 SFT 更重要。
因为:

Cells 32-35:可视化和测试

Cell 32:trackio.show(...)

启动可视化仪表盘。

它的作用

帮助你看:

Cell 34:test_model(...)

这个函数和前面 Qwen 最小实验的推理函数非常像,只是多了更细的生成参数。

关键参数

为什么 RL 推理更强调这些参数

因为 reasoning 输出往往不是一个固定短答案,而是:

生成参数会明显影响输出质量和稳定性。

Cell 35:测试一个 GSM8K 题目

这一格在做最终人工检查:

这一步为什么非常重要

因为多奖励训练的目标,最终必须回到“输出行为是否变好了”。

Cells 37-39:清理资源

remove_trackio_project(...)

删掉本地 trackio 数据库,避免缓存占太多空间。

torch.cuda.empty_cache()gc.collect()

这是训练后清理 GPU 和 Python 内存的标准习惯。

这也说明:

给零基础学生的最短总结

  1. 这份 notebook 仍然沿用“量化 + LoRA + chat prompt”这条主线
  2. 真正升级的地方在于:reward 不再只有一个,而是形成了多奖励系统
  3. 多奖励系统的目标,是把“格式正确”“答案正确”“可抽取答案”等行为一起塑造出来
  4. 从这一步开始,RL 后训练更像一个完整实验系统,而不只是一个最小可运行示例