RM-R1 测试题答案

⚠️ 请先独立作答后再查看答案!

答案对应 [[RM-R1_测试题]]


Part A:概念理解

A1. 传统 RM 直接输出一个黑盒分数;RM-R1 先生成评估标准和推理链,再输出最终偏好判断,使决策过程可解释


A2. 奖励模型的作用:替代人类对模型生成内容进行质量评分,从而为强化学习训练提供连续的奖励信号。

可以替代人工标注是因为:

  • 奖励模型本身是从人工标注的偏好数据中训练出来的
  • 一旦训练好,它能够实时、大批量地对新生成内容评分
  • 这将少量人工标注的"品味"扩展到海量自动评分,大幅降低标注成本

A3. GRPO 的改进:去掉了需要独立训练的 Critic 网络,改用组内相对比较来估计优势(advantage)。具体做法:对同一提示生成 n 个回答,以组内平均奖励为基线,每个回答的优势 = 自身奖励 - 组平均奖励。

本项目中每个提示生成 7 个样本(n=7)。


A4. 奖励函数返回 +1.0

分析:

  • 函数检查输出的最后 80 个字符
  • 找到 <answer>[[B]]</answer>,提取出 B
  • ground_truth 是 "model_b",对应的是 B
  • 判断正确,返回 +1.0
📝 注意

输出中间出现的 [[A]][[B]] 不影响结果,因为函数只看最后 80 个字符。


A5. KL 散度衡量当前训练策略和参考策略(训练前的原始模型)之间的差异。在 PPO 中它作为惩罚项,防止策略模型在训练过程中偏离初始模型太远(避免"奖励黑客"和训练崩溃)。

KL 系数 = 0.001 说明惩罚力度很小,允许模型在追求更高奖励时进行较大幅度的参数更新,但仍保留基本的稳定性约束。


A6. FSDP(全分片数据并行):将模型参数、梯度、优化器状态均匀分片存储到多张 GPU 上,每张 GPU 只存整个模型的 1/N(N=GPU数量)。

核心区别

  • DataParallel:每张 GPU 存完整模型副本 → 显存占用 = 完整模型大小
  • FSDP:每张 GPU 只存 1/N 的参数 → 显存占用 ≈ 完整模型大小 / N

对于 7B 参数的模型(约14GB fp16),4 张 GPU 用 FSDP 每卡只需约 3.5GB 用于参数存储。


A7. 这解决了位置偏见(position bias) 问题。

如果训练数据中总是 B 获胜,模型可能学到"不管内容如何,B 更好"的虚假规律。通过随机交换 A/B 并翻转标签,确保"获胜方"以相等概率出现在 A 位置和 B 位置,强迫模型真正理解内容差异而非记住位置。


A8. 因为 RM-R1 的推理链本身需要大量 token:

  • 生成评估标准:约 100-300 tokens
  • 分析两个回答:约 300-800 tokens
  • 最终判断:约 20 tokens
  • 总计可能需要 500-1000+ tokens

而输入(提示词 + 两个客服回答)通常在 500-2000 tokens 之间。输出空间必须足够大,否则模型无法完成完整的推理链。


Part B:项目结构

B1. 完整数据处理流水线:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
第1步:generate_customer_service_data.py
  → 生成 customer_service_dataset_1/2/3.jsonl(约3400条原始样本)

第2步:merge_and_split_dataset.py
  → 合并3个文件,打乱(seed=42),切分
  → 输出:train.jsonl(3000条)+ test.jsonl(400条)

第3步:rm_r1/dataset/mix_data/preprocess_data.py
  → 向每条数据的 context_messages 开头插入系统提示词
  → 输出:train_with_sys.jsonl + test_with_sys.jsonl

第4步(训练时):rl_dataset.py 中的 RubricRMDataset
  → 加载 train_with_sys.jsonl,tokenize,封装为 PyTorch Dataset

B2. 防止将推理过程中提到的 A/B 误判为最终答案。

例如模型可能在分析时说:“假设回答[[A]]更好的话…” 或 “虽然[[B]]在某方面…",这些中间内容不是最终判断。只检查最后 80 个字符,确保捕获的是最终的 <answer>[[X]]</answer> 标记,而不是推理中途的提及。


B3. 填表答案:

文件主要职责
main_ppo.py训练入口:解析配置、初始化 Ray 集群、加载模型和奖励函数、启动训练
ray_trainer.pyGRPO 训练主循环:协调 Rollout/Reward/PPO Update 各阶段
rl_dataset.pyPyTorch 数据集类:加载 JSONL,tokenize,返回训练批次
lm_as_judge.py奖励函数:解析模型输出,与真实标签比对,返回 +1 或 -1
convert_fsdp_to_hf.py模型格式转换:将分片的 FSDP 检查点合并为标准 HuggingFace 格式

B4.

  • rollout 批大小 = 32:每个训练步中,从数据集取出 32 个提示,让模型分别生成回答,收集经验样本
  • PPO mini-batch = 8:在用这 32 个提示的经验更新模型参数时,每次梯度计算使用 8 个样本(即 32/8 = 4 次梯度更新)

mini-batch 比 rollout 批大小小是因为:

  • 梯度计算的显存需求远高于推理
  • 小 mini-batch 允许在有限显存下完成更新
  • 多次小批量更新(而非一次大批量)能提供更稳定的梯度

B5.

技术解决的问题
Ray多 GPU 任务调度和通信,协调 Actor/Critic/Rollout 等不同角色的 worker
FSDP模型参数分片存储,减少每张 GPU 的显存占用,使大模型训练成为可能
vLLMRollout 阶段的高速推理,支持连续批处理,比普通 generate 快 5-10 倍
Flash Attention 2加速注意力计算(约 2 倍),降低训练时长序列的显存需求

B6.

  • 100 步 保存一次
  • 保存为 FSDP 分片格式(每张 GPU 各存自己负责的参数分片)
  • 使用时需运行 convert_fsdp_to_hf.py 将分片合并为标准 HuggingFace 格式,才能用 from_pretrained 加载

Part C:代码理解

C1. apply_chat_template 的作用:将对话列表(包含 role 和 content 的字典列表)按照特定模型的格式规范转换为 token ID 序列

例如 Qwen 模型有自己的特殊标记格式:

1
2
3
<|im_start|>system\n你是...<|im_end|>\n
<|im_start|>user\n[客户问题]...<|im_end|>\n
<|im_start|>assistant\n   ← add_generation_prompt=True 会添加这个,提示模型开始生成

这样模型才能理解对话结构,而不是把所有文本拼接在一起。


C2. winner 字段的值为 "model_a""model_b",表示哪个回答更好(人工标注的真实标签)。

在训练中它被用作:

  • 存储在每个样本的 reward_model.ground_truth 字段
  • 在奖励函数 lm_as_judge_match() 中与模型预测结果对比
  • 决定该训练步的奖励是 +1.0 还是 -1.0

C3. 4 个回答的奖励:+1, -1, +1, -1

组平均奖励 = (1 + (-1) + 1 + (-1)) / 4 = 0

各回答的相对优势:

  • 回答1(+1):优势 = 1 - 0 = +1.0(被强化)
  • 回答2(-1):优势 = -1 - 0 = -1.0(被抑制)
  • 回答3(+1):优势 = 1 - 0 = +1.0(被强化)
  • 回答4(-1):优势 = -1 - 0 = -1.0(被抑制)

C4. 系统提示词要求的输出格式:<answer>[[A]]</answer><answer>[[B]]</answer>

使用特殊标记格式的原因:

  1. 易于解析:正则表达式可以精确提取 [[A]][[B]],不会与正文混淆
  2. 抗干扰性:推理过程中如果提到"回答A"也不会被误判(奖励函数只看最后的 <answer> 标签)
  3. 格式强制:模型在训练中学会必须输出这种格式才能获得正奖励

C5. do_sample=False 表示使用贪婪解码(Greedy Decoding):每一步都选择概率最高的 token,不进行随机采样。

评估时使用这种方式的原因:

  • 确定性:同一输入每次输出相同结果,评估结果可重现
  • 代表性强:最高概率路径最能代表模型的"最优判断”
  • 公平比较:不同模型在相同输入上的比较不受随机性干扰

C6.

文件区别使用场景
train.jsonl只有用户消息,没有系统提示词用于快速检查数据内容、数据分析
train_with_sys.jsonl在每条数据开头加入了完整系统提示词(指导模型生成推理链+最终判断的指令)实际训练时使用这个文件

系统提示词告诉模型"你是评估专家,请生成评估标准并输出 <answer>[[X]]</answer>",这是训练RM-R1行为模式的关键。


Part D:优化与设计思考

D1. 这是长度偏见(Length Bias) 问题:模型不理解内容,只是学到了"更长 = 更好"的虚假规律。

项目的预防措施:

  • 生成时控制长度:在 generate_customer_service_data.py 中,确保生成的 A/B 两个回答长度差异不超过 20%(通过提示词约束生成器)
  • 长度相近的对比:这样模型无法通过长度来区分好坏,被迫学习内容质量

D2. 分析改为密集奖励(+2/+1/-1)的优缺点

✅ 优点:

  • 提供更细粒度的学习信号,模型不仅被鼓励答对,还被鼓励生成高质量推理
  • 可能提升推理链的可读性和有用性

❌ 缺点:

  • 需要额外评估推理链质量:谁来判断推理链质量高低?如果用另一个模型评估,引入了新的偏差;如果人工评估,成本高
  • 奖励设计的主观性:"+2 对应高质量"的标准难以量化,可能导致训练不稳定
  • 奖励黑客风险:模型可能学会生成"看起来高质量"但实际空洞的推理链来骗取高分
  • 当前稀疏奖励已经有效:+1/-1 已被实验证明效果良好,复杂化可能带来收益有限的代价

建议:先在当前简单奖励上充分优化,再考虑引入推理质量奖励。


D3. 在单张 24GB 显卡上训练的优化措施(至少3种):

  1. LoRA 微调(Parameter-Efficient Fine-Tuning):只训练模型中约 0.1% 的参数(低秩矩阵),其余参数冻结。显存从全参数微调的 ~60GB 降至 ~15GB 左右。

  2. 4-bit 量化(QLoRA):将模型权重量化为 4-bit 存储,基础模型显存从 14GB(fp16)降至约 4GB,再配合 LoRA 训练。

  3. 梯度检查点(Gradient Checkpointing):训练前向传播时不保存中间激活,在反向传播时重新计算,以计算时间换显存空间(显存减少约 30-50%)。

  4. 减小批大小:将 rollout 批大小从 32 减到 4-8,PPO mini-batch 减到 2-4,配合梯度累积。

  5. 减少 GRPO 采样数 n:从 7 减到 3-4,减少推理时的并发显存占用。

  6. Flash Attention 2:减少注意力计算的显存占用(已在项目中启用,但确认开启)。


D4. 扩展到英文金融场景需要的数据层修改:

  1. 语言切换

    • generate_customer_service_data.py 中的提示词改为英文
    • chat_prompt_chinese.py 中的中文模板改为英文
    • 修改系统提示词为英文
  2. 场景替换

    • 将 15 个中文电商场景(物流、退换货等)替换为金融场景(贷款审批、账户安全、投资建议等)
    • 重新设计好/差回答的评判标准(金融场景更注重合规性、准确性,而非温度)
  3. 质量标准调整

    • 数据生成提示词中"好回答"的定义需要改变(客服强调同理心,金融强调准确合规)
    • 注意金融场景中的免责声明要求
  4. 模型基座选择

    • 考虑使用英文能力更强的基模型(如 Llama 3 系列而非 Qwen 系列)
  5. 评估指标

    • 增加合规性校验,确保金融场景中的回答不含违规内容

D5. 一次完整 GRPO 训练步骤:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
【Rollout 阶段】
从数据集取出 32 个提示 →
对每个提示,用当前策略模型生成 7 个不同回答(共 32×7=224 个候选回答)


【Reward 阶段】
对每个回答运行 lm_as_judge:
- 检查最后 80 个字符中是否有 <answer>[[A/B]]</answer>
- 与 ground_truth 对比
- 返回 +1.0(正确)或 -1.0(错误)
→ 得到 224 个奖励值


【Advantage 计算(GRPO 核心)】
对每个提示(32个),取其 7 个回答的奖励:
组平均 = 7个奖励的均值
每个回答的优势 = 自身奖励 - 组平均
(相对比较:比本组平均好的被强化,差的被抑制)


【策略更新(PPO Update)】
用 224 个 (样本, 优势) 对,以 mini-batch=8 分批更新模型:
- 计算 PPO Clipped Loss(防止更新幅度过大)
- 加入 KL 惩罚项(防止偏离参考模型太远)
- 反向传播,更新 Actor 参数


【下一步】
重复以上过程,直到训练结束(or 每 100 步保存检查点)

#LLM #RewardModel #答案 #S3