NEW暗黑模式现已上线 🌓 Label Studio 1.18.0 版本发布

创建高质量的人类反馈强化学习数据集

指南

人工智能已迅速成为现代技术不可或缺的一部分,从语音助手到自动驾驶汽车都由其驱动。然而,这些模型的好坏完全取决于它们的训练数据。为了创建准确有效的模型,我们需要确保训练数据具有多样性且无偏见。这正是人类反馈发挥作用的地方。通过积极获取来自不同来源的输入,我们可以提高数据质量并创建更精确的模型。

但是,我们该如何在不给人类带来标注海量数据负担的情况下整合这些反馈呢?这正是RLHF和Label Studio的用武之地。RLHF是一种通过中等规模标注数据集模拟人类反馈的技术。Label Studio是一个开源工具,可让您为几乎任何任务创建自己的数据集。在本博客中,我们将展示如何使用Label Studio创建自己的数据集,并训练一个RLHF奖励模型,从而在不牺牲团队时间和精力的情况下,将人类反馈整合到您的机器学习模型中。

关于上述概念的完整笔记本可在我们的GitHub仓库中找到。

RLHF简介

基于人类反馈的强化学习(RLHF)是一种前景广阔的新方法,用于训练语言模型,直接将人类偏好整合到训练过程中。传统语言模型(LM)的训练目标是预测下一个词元,而微调通常意味着为语言模型提供输入和人工整理的期望输出。但这些方法在捕捉创造力、准确性和可理解性等复杂人类价值观方面可能存在局限。RLHF通过训练语言模型以优化人类反馈形式的奖励,旨在解决这些局限性。

RLHF流程包含三个核心步骤:收集人类反馈、训练奖励模型,以及使用奖励模型对语言模型进行微调。下方展示了相关步骤的示意图。

基于人类反馈的强化学习

在开始调优之前,我们需要一个已经通过经典预训练目标进行预训练的语言模型。这些大型语言模型(LLMs)通常基于海量训练数据进行训练,能够学习到令人印象深刻的人类语言及其他领域的表征。我们的LLM将成为适应我们自身数据集的起点。

为了优化我们的LLM,我们将使用奖励模型来模拟人类反馈。该奖励模型接收任意文本并为其评分,评估人类对其的感知质量。为了训练这个模型,我们需要从LLM中收集提示-生成对数据集。接下来,我们将让人工标注员对初始语言模型生成的文本输出进行排序。这些排序结果将在训练过程中用于教导奖励模型人类认为提示-生成结果的质量如何,同时保持标注过程尽可能简单,只需判断"哪个结果更好"。

在奖励模型训练完成后,初始语言模型会通过强化学习进行微调,利用奖励模型来优化模型的输出。奖励函数由偏好模型和一个约束条件组成,该约束限制了LLM在每一步之间的变化幅度。奖励模型用于计算一个标量化的"偏好度"概念,将其与初始模型的文本进行比较,从而计算两者差异的惩罚项。最终传递给RL更新规则的奖励是偏好模型奖励与惩罚项之间的差值。

RLHF使语言模型能够开始将基于通用文本数据语料库训练的模型与复杂的人类价值观对齐。它代表了一种有前景的新方法,将人类反馈直接整合到训练过程中,可能对自然语言处理和其他AI应用产生深远影响。

在以下章节中,我们将详细说明每个步骤,展示如何在自己的数据上训练奖励模型。

创建自定义数据集

收集人工反馈步骤

在本节中,我们将创建一个用于训练奖励模型的自定义数据集。该数据集始于一系列针对语言模型的提示词。提示词可以非常多样化,例如类似ChatGPT的对话式提示、摘要提示,甚至是要求严格输出的技术性问题。这些提示词将通过大语言模型多次传递(通常只需2次)以获得不同的响应。一个简单的提示生成示例如下所示。

{
  "prompt": "The quick brown fox...",
  "answer1": "jumps over the lazy dog.",
  "answer2": "bags few lynx.",
}

提示和响应随后会提供给数据标注人员,由其决定哪个更优。这些人工反馈将被整合到系统中。通过人工标注的排序,我们可以学习一个模型,用于评估语言模型响应质量的分值。

让我们创建自己的数据集。我们将从为LLM准备一组提示开始。接下来,我们将使用GPT-2为这些提示生成预测结果。请注意,为了简化流程我们使用的是GPT-2,因为现代LLM需要多块GPU和更复杂的基础设施配置。

prompts = [
  "What is the latest news on the stock market?",
  "What is the current state of the economy?",
  "What are the latest developments in technology?"
]


def generate_examples(prompt_list, 
                      model_name='gpt2',
                      max_length=50,
                      num_return_sequences=2,
                      seed=42):
  generator = pipeline('text-generation',
                       model=model_name,
                       device=0)
  set_seed(seed)
  examples = []
  for prompt in prompt_list:
    result = generator(prompt,
                       max_length=max_length,
                       num_return_sequences=num_return_sequences)
    example = {'prompt': prompt}
    for i, res in enumerate(result):
      answer = res['generated_text']
        .lstrip()
        .removeprefix(prompt)
        .strip()
    example[f'answer{i + 1}'] = answer
    examples.append(example)
    print(json.dumps(example, indent=2))
return examples


generated_examples = generate_examples(prompts)

我们现在已经准备好了一个待标注的提示-生成对数据集。

使用Label Studio标注我们的数据集

在Label Studio中使用自定义界面进行提示排序

我们现在可以在Label Studio中对这些提示进行排序以创建数据集。首先,我们可以按照此处的说明启动Label Studio。

一旦我们运行label studio,就可以使用Pairwise Classification template创建一个新项目。这些模板本身非常灵活,因此我们会做一些小的调整让它看起来更美观。该模板的配置如下所示。

<?xml version="1.0" encoding="UTF-8"?>
<View>
  <Style>* { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: 'Roboto', sans-serif; line-height: 1.6; background-color: #f0f0f0; } .container { margin: 0 auto; padding: 20px; background-color: #ffffff; border-radius: 5px; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.1), 0 6px 20px 0 rgba(0, 0, 0, 0.1); } .prompt { padding: 20px; background-color: #0084ff; color: #ffffff; border-radius: 5px; margin-bottom: 20px; box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.1), 0 3px 10px 0 rgba(0, 0, 0, 0.1); } .answers { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 20px; } .answer-box { flex-basis: 49%; padding: 20px; background-color: rgba(44, 62, 80, 0.9); color: #ffffff; border-radius: 5px; box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.1), 0 3px 10px 0 rgba(0, 0, 0, 0.1); } .answer-box p { word-wrap: break-word; } .answer-box:hover { background-color: rgba(52, 73, 94, 0.9); cursor: pointer; transition: all 0.3s ease; } .lsf-richtext__line:hover { background: unset; } .answer-box .lsf-object { padding: 20px }
  </Style>
  <View className="container">
    <View className="prompt">
      <Text name="prompt" value="$prompt" />
    </View>
    <View className="answers">
      <Pairwise name="pw" toName="answer1,answer2" selectionStyle="background-color: #27ae60; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.2); border: 2px solid #2ecc71; cursor: pointer; transition: all 0.3s ease;" />
      <View className="answer-box">
        <Text name="answer1" value="$answer1" />
      </View>
      <View className="answer-box">
        <Text name="answer2" value="$answer2" />
      </View>
    </View>
  </View>
</View>

一旦我们获得了人工标注的结果,就可以导出数据并训练奖励模型了。

奖励模型

构建和训练奖励模型本身可能就是一个挑战。这些模型的规模往往与我们最初使用的大型语言模型(LLM)相当,并且可能需要复杂的训练技术。trlX库使这一过程变得简单得多。

trlX

TrlX 是一个分布式训练框架,专注于使用强化学习(RL)微调大型语言模型。它实现了多种RL算法,并简化了这些技术与LLM训练流程的集成。下面展示的训练示例是对trlX库中Summary Example的扩展。

加载数据

我们可以使用PairwiseDataset类来对数据集中选定和被拒绝的响应进行标记化处理。

class PairwiseDataset(Dataset):
  
  def __init__(self, pairs, tokenizer, max_length):
    self.chosen_input_ids = []
    self.chosen_attn_masks = []
    self.rejected_input_ids = []
    self.rejected_attn_masks = []
    
    for pair in tqdm(pairs):
      chosen, rejected = pair["chosen"], pair["rejected"]
      chosen_encodings_dict = tokenizer(
        "<|startoftext|>" + chosen + "<|endoftext|>",
        truncation=True,
        max_length=max_length,
        padding="max_length",
        return_tensors="pt",)
      rejected_encodings_dict = tokenizer(
        "<|startoftext|>" + rejected + "<|endoftext|>",
        truncation=True,
        max_length=max_length,
        padding="max_length",
        return_tensors="pt",)

    self.chosen_input_ids.append(chosen_encodings_dict["input_ids"])
    self.chosen_attn_masks.append(chosen_encodings_dict["attention_mask"])
    self.rejected_input_ids.append(rejected_encodings_dict["input_ids"])
    self.rejected_attn_masks.append(rejected_encodings_dict["attention_mask"])


  def __len__(self):
    return len(self.chosen_input_ids)


  def __getitem__(self, idx):
    return (
      self.chosen_input_ids[idx],
      self.chosen_attn_masks[idx],
      self.rejected_input_ids[idx],
      self.rejected_attn_masks[idx],)

我们还提供了一个整理器,用于创建训练奖励模型的批次。

class DataCollatorReward:
  def __call__(self, data):
    batch = {}
    batch["input_ids"] = torch.cat([f[0] for f in data] + [f[2] for f in data])
    batch["attention_mask"] = torch.cat([f[1] for f in data] + [f[3] for f in data])
    batch["labels"] = torch.tensor([0] * len(data) + [1] * len(data))
    return batch

更多详情,请参阅trlX摘要示例

训练

为了训练我们的奖励模型,我们从一个自定义偏好数据集开始,该数据集加载了两个样本:一个是被选中的样本,另一个是被拒绝的样本。每个样本的真实标签(即标签)来自人类反馈,其中0表示被选中的样本,1表示被拒绝的样本。

通过使用trlx,我们可以在这个偏好数据集上高效训练奖励模型,最小化真实标签的负对数似然。这种方法使我们能够有效学习奖励函数,从而在我们的RLHF框架中指导强化学习过程。

总体而言,trlx是一个强大的工具,使我们能够高效且有效地通过人类反馈训练模型。通过使用trlx训练奖励模型,我们能够优化RLHF框架的性能,最终提供更加个性化和有效的医疗健康建议。

Trainer(
  model=model,
  args=training_args,
  train_dataset=train_dataset,
  compute_metrics=compute_metrics,
  eval_dataset=val_dataset,
  data_collator=data_collator,).train()

在示例笔记本中,我们还整合了Weights & Biases来跟踪训练进度。

使用PPO进行LLM训练

当我们的奖励模型完成训练后,我们可以将成对的示例输入模型,并根据模型认为它们的优劣程度获得奖励。现在我们可以使用这个模型来调整我们的LLM,持续模拟人类反馈。

TrlX 推荐使用 accelerate 库 通过 PPO 来调优大语言模型。这个过程可能消耗大量资源且存在各种陷阱,因此我们建议读者参考 这篇文章 获取关于使用 PPO 调优的更多细节。

结论

随着AI模型日益复杂,融入人类反馈以提升质量并减少潜在偏见变得愈发重要。虽然RLHF是模型训练期间模拟人类反馈的有效方法,但仍需要人工标注来指导其决策。本文展示了如何利用Label Studio生成自定义偏好数据集,并训练奖励模型来模拟人类反馈。现在正是您尝试的好时机!查看GitHub上的完整示例,或联系我们了解更多

相关内容

  • 每个人都在(无意中)作弊

    AI基准测试正在悄然失效。研究表明,数据泄露、排行榜操纵和激励错配正在夸大模型性能。本文探讨了改革的四大支柱:治理、透明度、广谱指标和监督,并概述了企业如何通过集中式基准管理平台建立信任。

    尼古拉·柳比莫夫

    2025年5月13日

  • 提升标注质量和速度的3种标注团队操作手册

    每个机器学习团队都不尽相同,您的标注工作流程也应如此。本指南将解析三种常见的标注团队配置方案,以及如何定制您的工具和流程来提升质量、速度和规模。

    Alec Harris

    2025年5月7日

  • 您的RAG系统可能失败的七种情况及解决方法

    RAG系统承诺提供更准确的人工智能响应,但由于检索错误、幻觉和不完整答案等问题,它们往往表现不佳。本文探讨了七种常见的RAG系统故障——从遗漏排名靠前的文档到格式错误——并提供了实用解决方案来提高检索准确性、排序质量和响应质量。了解如何优化您的RAG系统,确保其提供可靠、具备上下文感知能力的人工智能响应

    米凯拉·卡普兰

    2025年3月19日