Skip to content

C.4 GRPO 与 Reward Model


GRPO Loss

一句话记忆

同 prompt 采 G 条回答,reward 在组内做 z-score 归一化当 advantage,然后套 PPO 的 clipped loss,再加 KL 惩罚。没有 Critic。

伪代码

# 1. 同一 prompt 采样 G 条 completion
completions = [generate(prompt) for _ in range(G)]

# 2. 对每条打分
rewards = [reward_fn(c) for c in completions]   # [G]

# 3. 组内归一化 → advantage
advantages = (rewards - mean(rewards)) / (std(rewards) + eps)  # [G]

# 4. PPO clipped loss(用组内 advantage)
ratio = exp(new_logp - old_logp)
surr1 = ratio * advantages
surr2 = clip(ratio, 1-eps, 1+eps) * advantages
policy_loss = -min(surr1, surr2).mean()

# 5. KL 惩罚(相对 reference model)
kl = kl_penalty(log_probs, ref_log_probs)

# 6. 总 loss
loss = policy_loss + kl_coeff * kl

记忆方法

GRPO = Group Relative Policy Optimization。和 PPO 的对比:

PPOGRPO
Advantage 来源Critic 预测 V(s)V(s) → GAE组内 reward 归一化
需要几个模型4 个(actor, critic, ref, rm)2~3 个(actor, ref, rm/verifier)
KL可选几乎必加
采样方式单条 rollout同 prompt 采 G 条

口诀:"PPO 砍掉 Critic,换成组内 z-score,其余照抄"

Python 实现

python
import numpy as np

def grpo_advantages(rewards):
    """
    rewards: [num_prompts, G]  每个 prompt 的 G 条回答的 reward
    """
    mean = rewards.mean(axis=1, keepdims=True)
    std = rewards.std(axis=1, keepdims=True)
    return (rewards - mean) / (std + 1e-8)

def grpo_policy_loss(new_logps, old_logps, advantages, clip_eps=0.2):
    """和 PPO clipped loss 完全相同"""
    ratio = np.exp(new_logps - old_logps)
    surr1 = ratio * advantages
    surr2 = np.clip(ratio, 1 - clip_eps, 1 + clip_eps) * advantages
    return -np.minimum(surr1, surr2).mean()

PyTorch 实现

python
import torch
import torch.nn.functional as F

def grpo_loss(log_probs, old_log_probs, ref_log_probs,
              rewards, clip_eps=0.2, kl_coeff=0.05):
    """
    log_probs:     [B, G, seq_len]  当前策略
    old_log_probs: [B, G, seq_len]  采样时策略
    ref_log_probs: [B, G, seq_len]  参考策略
    rewards:       [B, G]           组内 reward
    B = num_prompts, G = group_size
    """
    B, G = rewards.shape

    # 1. 组内归一化
    advantages = (rewards - rewards.mean(dim=1, keepdim=True)) \
                 / (rewards.std(dim=1, keepdim=True) + 1e-8)
    # [B, G] → [B, G, 1] 以广播到 seq_len 维度
    advantages = advantages.unsqueeze(-1)

    # 2. 序列级 log_prob 求和(每条 completion)
    # 假设 log_probs 已按有效 token 求和: [B, G]
    seq_logp = log_probs.sum(dim=-1)       # [B, G]
    seq_old  = old_log_probs.sum(dim=-1)
    seq_ref  = ref_log_probs.sum(dim=-1)

    # 3. Clipped policy loss
    ratio = torch.exp(seq_logp - seq_old)
    adv = advantages.squeeze(-1)            # [B, G]
    surr1 = ratio * adv
    surr2 = torch.clamp(ratio, 1 - clip_eps, 1 + clip_eps) * adv
    policy_loss = -torch.min(surr1, surr2).mean()

    # 4. KL 惩罚
    log_ratio = seq_logp - seq_ref
    kl = (torch.exp(log_ratio) - 1 - log_ratio).mean()

    return policy_loss + kl_coeff * kl

Reward Model(Bradley-Terry 模型)

一句话记忆

chosen 分数比 rejected 高 \Rightarrow sigmoid 后接近 1 \Rightarrow -log 接近 0。就一行:-log_sigmoid(r_chosen - r_rejected)

伪代码

r_w = reward_model(chosen_input)     # chosen 的 reward 标量
r_l = reward_model(rejected_input)   # rejected 的 reward 标量

loss = -log(sigmoid(r_w - r_l))

记忆方法

Bradley-Terry 模型假设人类偏好概率为:

P(ywyl)=σ(r(x,yw)r(x,yl))P(y_w \succ y_l) = \sigma(r(x, y_w) - r(x, y_l))

训练目标就是最大化这个概率的对数,等价于最小化 -log_sigmoid(diff)

口诀:"RM 训练就是 pairwise 交叉熵"

Python 实现

python
def log_sigmoid(x):
    return -np.logaddexp(0, -x)

def reward_model_loss(r_chosen, r_rejected):
    """r_chosen, r_rejected: [B]"""
    return -log_sigmoid(r_chosen - r_rejected).mean()

PyTorch 实现

python
def reward_model_loss(r_chosen, r_rejected):
    """
    r_chosen:  [B]  reward model 对 chosen 的打分
    r_rejected: [B]  reward model 对 rejected 的打分
    """
    return -F.logsigmoid(r_chosen - r_rejected).mean()

面试追问:DPO 和 RLHF-PPO 的关系

面试官常问"DPO 相比 PPO 的优劣",准备这个对比表:

维度PPO-RLHFDPO
需要 Reward Model否(隐式学习)
需要 Critic
需要 Reference Model可选必须
在线/离线在线(需要采样)离线(只用偏好数据)
训练成本高(4 个模型)低(2 个模型)
奖励黑客风险有(RM 可被钻空子)较低(无显式 RM)
理论最优性更强(可以持续探索)受限于离线数据质量
适用场景大规模在线训练偏好数据充足的场景

易错点

易错说明
GRPO 的 advantage 是组内归一化不是全局归一化,是同一个 prompt 的 G 条回答之间比较
GRPO 没有 value loss没有 Critic,所以没有 value loss,这是和 PPO 的核心区别
Reward Model 要 detach训练 RM 时 chosen/rejected 的 reward 都要参与梯度,但训练 policy 时 RM 要冻结
GRPO 的 KL 是对每条序列的不是 token 级别,通常是对整条 completion 的 log_prob 求和后再算 KL
DPO 隐式学到了 RMDPO 的 log_ratio_w - log_ratio_l 本质上就是隐式 reward 差值
G 的大小通常 G=4~16,太小 advantage 估计噪声大,太大采样成本高
RLVR 场景reward 来自规则验证器(如代码执行、数学答案检查),不是 RM 打分

Built for reusable bilingual course delivery