Anthropic HH-RLHF: 人类反馈偏好数据集

Anthropic HH-RLHF: 人类反馈偏好数据集

数据集链接: HuggingFace
核心论文: Training a Helpful and Harmless Assistant with Reinforcement Learning from Human Feedback (arXiv:2204.05862)
许可证: MIT
规模: 169K 偏好对

核心观点

HH-RLHF 是 RLHF 领域的”黄金标准”数据集,它证明了一件事——对齐不是玄学,而是可以通过结构化的人类偏好数据解决的工程问题。

为什么这个数据集重要?

在 ChatGPT 爆火之前,很少有人意识到 RLHF(人类反馈强化学习)的价值。OpenAI 用 InstructGPT 证明了它的有效性,而 Anthropic 用 HH-RLHF 把这套方法论开源出来,让所有人都能训练”有用且无害”的模型。

这个数据集的核心价值不在于 16.9 万条样本的规模——这个数量甚至称不上大。它的价值在于清晰的标注哲学:将对齐拆解为 Helpfulness(有用性)和 Harmlessness(无害性)两个维度,并用简洁的偏好对格式表达人类判断。这种设计让研究者可以分别优化这两个目标,或者在实际应用中灵活权衡。

对比其他偏好数据集,HH-RLHF 的标注质量更稳定、任务定义更清晰。这也是为什么它成为了 RLHF 研究的事实标准——不是因为规模最大,而是因为设计最科学。

数据结构详解

偏好对格式

1
2
3
4
{
"chosen": "\n\nHuman: 解释光合作用\n\nAssistant: 光合作用分为光反应和暗反应两个阶段。光反应发生在叶绿体的类囊体膜上,需要光的参与产生 ATP 和 NADPH...",
"rejected": "\n\nHuman: 解释光合作用\n\nAssistant: 光合作用就是植物利用阳光制造食物。"
}

这个格式有两个聪明之处:

  1. 上下文完整性:chosen 和 rejected 保留了完整的对话历史,模型可以学习在具体情境下什么是更好的回答
  2. 对比学习:两个回答只在最后的 AI 响应处不同,这种 minimal pair 设计让模型更容易学到细微差异

数据子集划分

1
2
3
4
5
6
7
8
9
10
11
12
HH-RLHF 数据结构:

├── helpful (约 93K)
│ ├── helpful-base (基础帮助性对话)
│ └── helpful-online (在线对话,模拟真实场景)

├── harmless (约 63K)
│ ├── harmless-base (基础无害性对话)
│ └── harmless-micro (微调数据,测试安全边界)

└── helpful-harmless (约 13K)
└── 同时考虑有用性和无害性的对话

数据加载示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from datasets import load_dataset

# 加载完整数据集
dataset = load_dataset("Anthropic/hh-rlhf")

# 查看数据结构
print(dataset["train"][0])
# {
# 'chosen': '...',
# 'rejected': '...',
# 'label': 1 # 1 表示 chosen 更好
# }

# 按子集加载
helpful_data = load_dataset("Anthropic/hh-rlhf", split="train", streaming=True)

# 统计信息
print(f"总样本数:{len(dataset['train'])}")
print(f"chosen 平均长度:{avg_len_chosen}")
print(f"rejected 平均长度:{avg_len_rejected}")

训练方法详解

第一步:训练奖励模型

使用 Bradley-Terry 模型将人类偏好转化为标量奖励信号:

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import torch
import torch.nn as nn
import torch.nn.functional as F

class BradleyTerryRewardModel(nn.Module):
"""
Bradley-Terry 奖励模型

核心思想:学习一个奖励函数 r(x, y),使得
P(y_chosen > y_rejected | x) = sigmoid(r(x, y_chosen) - r(x, y_rejected))
"""

def __init__(self, base_model, num_labels=1):
super().__init__()
self.base_model = base_model
self.reward_head = nn.Linear(base_model.config.hidden_size, num_labels)

def forward(self, input_ids, attention_mask=None):
# 获取模型输出
outputs = self.base_model(
input_ids=input_ids,
attention_mask=attention_mask,
output_hidden_states=True
)

# 使用 last token 的隐藏状态作为序列表示
last_hidden = outputs.hidden_states[-1]
sequence_repr = last_hidden[:, -1, :] # [batch, hidden_size]

# 预测奖励
reward = self.reward_head(sequence_repr)
return reward.squeeze(-1) # [batch]

def compute_loss(self, chosen_input_ids, rejected_input_ids,
chosen_attention_mask=None, rejected_attention_mask=None):
"""
计算 Bradley-Terry 损失

L = -log(sigmoid(r_chosen - r_rejected))
"""
# 计算奖励
r_chosen = self.forward(chosen_input_ids, chosen_attention_mask)
r_rejected = self.forward(rejected_input_ids, rejected_attention_mask)

# Bradley-Terry 损失
logits = r_chosen - r_rejected
loss = -F.logsigmoid(logits).mean()

return loss


# 训练奖励模型
reward_model = BradleyTerryRewardModel(base_model)
optimizer = torch.optim.AdamW(reward_model.parameters(), lr=1e-5)

for batch in dataloader:
optimizer.zero_grad()
loss = reward_model.compute_loss(
chosen_input_ids=batch["chosen_input_ids"],
rejected_input_ids=batch["rejected_input_ids"],
chosen_attention_mask=batch["chosen_attention_mask"],
rejected_attention_mask=batch["rejected_attention_mask"]
)
loss.backward()
optimizer.step()

第二步:强化学习优化

PPO 训练流程

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
class PPOTrainer:
"""
PPO (Proximal Policy Optimization) 训练器

使用奖励模型的输出作为奖励信号,优化语言模型策略
"""

def __init__(self, policy_model, reward_model, ref_model,
kl_coef=0.2, clip_range=0.2, lr=3e-4):
self.policy = policy_model
self.reward_model = reward_model
self.ref_model = ref_model # 参考模型(固定)
self.kl_coef = kl_coef
self.clip_range = clip_range
self.optimizer = torch.optim.AdamW(policy_model.parameters(), lr=lr)

def train_step(self, queries, responses):
"""
PPO 训练步骤

1. 生成响应
2. 计算奖励
3. 计算优势函数
4. PPO 更新
"""
# 生成响应
generated = self.policy.generate(
input_ids=queries,
max_new_tokens=100
)

# 计算奖励(来自奖励模型)
rewards = self.reward_model.forward(
input_ids=generated["input_ids"],
attention_mask=generated["attention_mask"]
)

# 计算 KL 散度惩罚(防止偏离参考模型太远)
with torch.no_grad():
ref_logits = self.ref_model(
input_ids=generated["input_ids"],
attention_mask=generated["attention_mask"]
).logits

kl_div = self._compute_kl_div(generated.logits, ref_logits)
rewards = rewards - self.kl_coef * kl_div

# PPO 更新
loss = self._ppo_loss(generated, rewards)
loss.backward()
self.optimizer.step()
self.optimizer.zero_grad()

return loss.item()

def _ppo_loss(self, outputs, rewards):
"""PPO 损失计算"""
# 计算新旧策略的比率
ratio = torch.exp(outputs.log_probs - outputs.old_log_probs)

# 计算优势函数(简化版)
advantages = rewards - rewards.mean()

# PPO-clip 损失
surr1 = ratio * advantages
surr2 = torch.clamp(ratio, 1 - self.clip_range, 1 + self.clip_range) * advantages
loss = -torch.min(surr1, surr2).mean()

return loss

DPO (直接偏好优化)

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class DPOTrainer:
"""
DPO (Direct Preference Optimization) 训练器

核心洞察:可以直接从偏好数据优化策略,无需显式训练奖励模型

DPO 损失:
L = -log(σ(β * log(π_θ(y_w|x)/π_ref(y_w|x)) - β * log(π_θ(y_l|x)/π_ref(y_l|x))))
"""

def __init__(self, policy_model, ref_model, beta=0.1, lr=3e-4):
self.policy = policy_model
self.ref_model = ref_model # 固定参考模型
self.beta = beta
self.optimizer = torch.optim.AdamW(policy_model.parameters(), lr=lr)

def train_step(self, chosen_input_ids, rejected_input_ids,
chosen_attention_mask=None, rejected_attention_mask=None):
"""
DPO 训练步骤
"""
# 获取策略输出
chosen_logps = self._get_log_probs(
self.policy, chosen_input_ids, chosen_attention_mask
)
rejected_logps = self._get_log_probs(
self.policy, rejected_input_ids, rejected_attention_mask
)

# 获取参考模型输出(无梯度)
with torch.no_grad():
chosen_ref_logps = self._get_log_probs(
self.ref_model, chosen_input_ids, chosen_attention_mask
)
rejected_ref_logps = self._get_log_probs(
self.ref_model, rejected_input_ids, rejected_attention_mask
)

# 计算隐式奖励
pi_logratios = chosen_logps - rejected_logps
ref_logratios = chosen_ref_logps - rejected_ref_logps

logits = self.beta * (pi_logratios - ref_logratios)

# DPO 损失
loss = -F.logsigmoid(logits).mean()

loss.backward()
self.optimizer.step()
self.optimizer.zero_grad()

return loss.item()

def _get_log_probs(self, model, input_ids, attention_mask):
"""计算序列的对数概率"""
outputs = model(input_ids=input_ids, attention_mask=attention_mask)
log_probs = F.log_softmax(outputs.logits, dim=-1)
# 取生成 token 的平均对数概率
return log_probs.mean(dim=(1, 2))

数据质量分析

来自 AI 安全专家的视角

Anthropic 作为 AI 安全领域的领军企业,在标注过程中的专业性体现在:

  • 边界测试:Harmlessness 子集包含大量测试安全边界的对话,这些”红队测试”数据对于发现模型的脆弱性至关重要
  • 对齐税意识:数据集设计时就考虑了有用性和无害性的 trade-off,避免模型过度保守而丧失实用价值
  • 标注一致性:专业标注团队确保了高标注者间一致性,减少噪声标签

标注质量统计

1
2
3
4
5
6
7
8
9
HH-RLHF 标注质量统计:

指标 | 数值
---------------------|------
标注者间一致性 (Kappa) | 0.72
平均响应长度 (chosen) | 185 tokens
平均响应长度 (rejected)| 95 tokens
安全边界测试样本 | ~15K
多轮对话比例 | 65%

局限性分析

局限也很明显:

  • 纯英文数据:非英语场景需要额外数据
  • 时效性:2022 年标注的价值判断可能过时
  • 标注者偏见:主要来自美国标注者,文化多样性有限

但这些都是 RLHF 数据集的通病,不是 HH-RLHF 独有的问题。

对比其他偏好数据集

数据集 规模 中文支持 偏好类型 许可证 质量评分
HH-RLHF 169K 人工标注 MIT 4.8/5.0
UltraFeedback 64K 部分 模型合成 MIT 4.2/5.0
PKU-SafeRLHF 100K 人工标注 Apache 2.0 4.3/5.0
preference_700K 700K 部分 混合 varied 4.0/5.0
OASST1 161K 多语言 人工标注 Apache 2.0 4.5/5.0
  • vs UltraFeedback:UltraFeedback 规模更大(64K),但基于模型输出而非真实人类对话,合成感较强
  • vs PKU-SafeRLHF:PKU 数据集更关注安全对齐,但在有用性覆盖上不如 HH-RLHF 全面
  • vs preference_700K:这是个混合数据集,包含 HH-RLHF,如果追求规模可以用它,但质量一致性不如单独用 HH-RLHF

实践建议

推荐使用方式

1
2
3
4
5
6
7
8
9
10
11
12
13
# 场景 1: 从零开始训练对话模型
# 阶段 1: SFT 预训练
sft_data = load_dataset("Anthropic/hh-rlhf", split="train")
sft_model = train_sft(sft_data)

# 阶段 2: 训练奖励模型
reward_model = train_reward_model(sft_data)

# 阶段 3: RLHF 优化
rl_model = ppo_train(sft_model, reward_model)

# 场景 2: 使用 DPO 直接优化
dpo_model = dpo_train(pretrained_model, sft_data)
  1. 起步阶段:单独使用 HH-RLHF 训练第一版奖励模型或 DPO 模型
  2. 迭代优化:结合自己产品的用户反馈数据进行微调
  3. 持续监控:定期评估奖励模型是否仍然反映当前的价值判断

不要期望 16.9 万条数据能解决所有对齐问题。真正的对齐是个持续迭代的过程,HH-RLHF 只是提供了一个高质量的起点。

领域适配建议

领域 建议 额外数据需求
通用对话 直接用 HH-RLHF
医疗咨询 HH-RLHF + 医疗偏好数据 专业医疗标注
法律咨询 HH-RLHF + 法律偏好数据 律师标注
教育辅导 HH-RLHF + 教育偏好数据 教师标注
代码生成 HH-RLHF + 代码偏好数据 开发者标注

技术洞察

最近的研究发现,DPO(直接偏好优化)在某些场景下可能比传统 RLHF 更有效,因为它避免了奖励模型的过度优化问题(reward hacking)。但这并不意味着 HH-RLHF 过时了——它仍然是训练 DPO 的最佳数据来源之一。

数据集的 MIT 许可证意味着你可以自由商用,这在 AI 领域越来越重要。对比之下,很多高质量数据集都有商业使用限制。

总结

核心贡献:

  1. 首个大规模人工标注的偏好数据集
  2. 清晰的 Helpfulness/Harmlessness 二维标注框架
  3. 成为 RLHF 研究的事实标准

适用场景:

  • RLHF 奖励模型训练
  • DPO 直接偏好优化
  • AI 对齐研究
  • 对话系统微调

质量评分: 4.8/5.0 | MIT 许可证 | 169K 偏好对


数据集链接: https://huggingface.co/datasets/Anthropic/hh-rlhf

核心论文: Training a Helpful and Harmless Assistant with RLHF

代码资源:

© 2026 Generative AI Discovery All Rights Reserved.
Theme by hiero