奖励模型是一面哈哈镜

RLHF 里最被低估的失效模式不是 reward hacking,而是标注者偏好的不一致性如何被模型放大成一种稳定的人格缺陷。

大家讨论 RLHF 的失效模式时,第一个想到的总是 reward hacking——模型找到了奖励函数的漏洞,输出一些得分很高但毫无用处的东西。

这确实会发生,但它有个好处:很显眼。模型开始疯狂输出”作为一个 AI 助手,我很乐意帮您”的时候,任何人都能看出不对。

真正麻烦的是那些不显眼的。

不一致性会被放大,而不是被平均

直觉上,我们会认为多个标注者的偏好噪声应该互相抵消,最后留下”平均偏好”。

但奖励模型不是在拟合平均值,它是在拟合一个排序。当标注者 A 认为详细的回答更好、标注者 B 认为简洁的回答更好,模型学到的不是”中等长度最好”,而是一个在两种模式之间摇摆的、内部矛盾的判据。

然后 PPO 会去优化这个矛盾的判据。结果是模型找到某种”两边都不得罪”的表达方式——通常表现为大量的限定语、免责声明和模糊表述。

rθ(x,y)EaA[ra(x,y)]+ϵ(x,y)标注者间分歧r_\theta(x, y) \approx \mathbb{E}_{a \sim \mathcal{A}}\big[\, r_a(x, y) \,\big] + \underbrace{\epsilon(x, y)}_{\text{标注者间分歧}}

那个 ϵ\epsilon 项不是随机噪声。它和输入强相关——在有争议的话题上大,在事实性问题上小。所以模型学会了:在争议话题上变得含糊,是一种可靠的得分策略。

怎么发现它

看标注者间一致性(inter-annotator agreement)是不够的,因为它是个全局统计量。我们的做法是按话题分桶来看:

python
from collections import defaultdict
import numpy as np

def agreement_by_topic(annotations, topics):
    """
    annotations: {(sample_id, annotator_id): preferred_index}
    返回每个话题的两两一致率
    """
    by_topic = defaultdict(list)

    for sid, topic in topics.items():
        votes = [v for (s, _), v in annotations.items() if s == sid]
        if len(votes) < 2:
            continue
        # 两两比较,统计一致的比例
        pairs = [(a, b) for i, a in enumerate(votes) for b in votes[i+1:]]
        agree = sum(1 for a, b in pairs if a == b) / len(pairs)
        by_topic[topic].append(agree)

    return {t: float(np.mean(v)) for t, v in sorted(by_topic.items())}

跑出来的结果通常很有启发性:事实类问题一致率能到 0.9 以上,而涉及价值判断的话题往往掉到 0.55——只比随机猜好一点。

在一致率 0.55 的数据上训奖励模型,等于在教模型模仿一个精神分裂的评判者。

我们的应对

不是什么高明的技术,就是三条笨办法:

  1. 分领域训练奖励模型,而不是一个通吃。至少把”事实性”和”风格偏好”拆开。
  2. 一致率低于阈值的样本直接丢弃,而不是取多数票。多数票在 0.55 一致率下几乎没有信息量。
  3. 给标注者写更严格的规范,并且定期用同一批样本做校准测试。

第 3 条最费力,收益最大。我们花了三周重写标注规范,一致率从 0.61 提到 0.78,比任何算法改进的效果都明显。

数据标注是一个需要设计的系统,不是一个需要外包的任务。


如果你觉得我某个判断是错的,欢迎写信讨论。