两段代码都叫GRPO梯度仍可能不同。差异未必来自实现错误组内奖励的标准差口径、回答掩码与损失归约都在定义优化目标。只有把这些选择写出来公式与实现才能逐项对上。DeepSeekMath论文于2024年提出GRPO它不是十月新算法。TRL当前文档则提供多种损失和奖励缩放选择。main文档在持续变化不能将它的默认值倒写成原论文的唯一实现。先看两个回答的权重设同一题有两份回答长度分别为2和4个有效token。按序列先平均再对序列平均每份回答总权重相同把所有有效token直接平均长回答贡献更多。以下夹具暂不包含ratio、clip与KL只演示归约差别不能作为完整训练器。import math def group_advantage(rewards): m sum(rewards) / len(rewards) sd math.sqrt(sum((x-m)**2 for x in rewards) / len(rewards)) return [(x-m) / sd if sd else 0.0 for x in rewards] def reductions(values, masks): totals [sum(v*m for v, m in zip(vs, ms)) for vs, ms in zip(values, masks)] lengths [sum(ms) for ms in masks] assert all(n 0 for n in lengths) return (sum(t/n for t, n in zip(totals, lengths))/len(lengths), sum(totals)/sum(lengths)) assert group_advantage([3, 3]) [0.0, 0.0] assert group_advantage([0, 2]) [-1.0, 1.0] a, b reductions([[1, 1, 999, 999], [3, 3, 3, 3]], [[1, 1, 0, 0], [1, 1, 1, 1]]) assert a 2.0 and math.isclose(b, 14/6) print(sequence_mean , a, token_mean , round(b, 6))代码显式采用总体标准差分母是组大小G。如果实现选择无偏样本标准差优势幅度就会改变组大小为1还会遇到无定义问题。全组奖励相同的情况应有确定处理不能让NaN流入反向传播。掩码位置比变量名更重要提示词、padding和回答的token集合要分开。EOS是否计入、截断回答是否保留、工具调用与工具结果是否都训练都会改变有效长度。示例中的999没有进入损失是因为掩码为零若先平均整段再乘一个序列标记padding已经污染了分母。完整GRPO还需检查当前策略与采样策略的概率比、clip位置、参考策略的KL形式以及更新轮数。把所有回答先拼成一长串再算组均值会混淆不同题目的奖励把KL系数设为零则改变了目标不能仍称“完全按原式复现”。复现实验应锁定论文版本与训练器commit记录loss_type、奖励缩放、beta、截断规则、采样次数及随机种子。本文环境没有PyTorch未运行自动微分或模型训练上方标准库计算只验证组优势与两种归约的数值差异。训练质量、吞吐和显存收益均未测量。本地验证上方各 Python 代码块独立保存后在 Python 3.9.6 的临时目录以python3 example.py执行退出码均为 0输出分别为sequence_mean 2.0 token_mean 2.333333。数据为文中教学夹具不是模型、GPU或线上性能测量。论文初版2024-02-05TRL为持续维护文档不将其访问日期当作版本发布日期。