开源 AI 食谱文档

使用法学 LLM 清理现有偏好数据集

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

Open In Colab

使用法学 LLM 清理现有偏好数据集

作者:David BerensteinSara Han Díaz

在本教程中,我们将使用 distilabel 通过提供关于数据质量的 AI 反馈,使用法学 LLM 清理数据集。distilabel 是一个合成数据和 AI 反馈框架,适用于需要基于经过验证的研究论文构建快速、可靠且可扩展的管道的工程师。查看此处的文档。

为了评估响应,我们将使用与 distilabel 集成的无服务器 HF 推理 API。这是免费的,但有速率限制,允许您通过简单的 HTTP 请求,在 Hugging Face 共享基础设施上快速推理,测试和评估超过 150,000 个公共模型或您自己的私有模型。如果您需要更多计算能力,可以使用Hugging Face 推理终端部署您自己的推理终端。

最后,为了进一步管理数据,我们将使用Argilla,它允许我们提供关于数据质量的人工反馈。Argilla 是一款协作工具,适用于需要为其项目构建高质量数据集的 AI 工程师和领域专家。查看此处的文档。

开始使用

安装依赖项

要完成本教程,您需要通过 pip 安装 distilabel SDK 和一些第三方库。

!pip install "distilabel[hf-inference-endpoints]"
!pip install "transformers~=4.0" "torch~=2.0"

让我们进行所需的导入

import random

from datasets import load_dataset

from distilabel.llms import InferenceEndpointsLLM
from distilabel.pipeline import Pipeline
from distilabel.steps import (
    KeepColumns,
    LoadDataFromDicts,
    PreferenceToArgilla,
)
from distilabel.steps.tasks import UltraFeedback

您需要一个 HF_TOKEN 才能使用 HF 推理终端。登录即可在本笔记本中直接使用它。

import os
from huggingface_hub import login

login(token=os.getenv("HF_TOKEN"), add_to_git_credential=True)

(可选)部署 Argilla

您可以跳过此步骤或将其替换为任何其他数据评估工具,但您的模型质量会因缺乏数据质量而受到影响,因此我们建议您查看您的数据。如果您已经部署了 Argilla,则可以跳过此步骤。否则,您可以按照本指南快速部署 Argilla。

同时,您需要将 Argilla 作为 distilabel 额外组件安装。

!pip install "distilabel[argilla, hf-inference-endpoints]"

数据集

在本例中,我们将清理一个偏好数据集,因此我们将使用 Hugging Face Hub 中的Intel/orca_dpo_pairs数据集。

dataset = load_dataset("Intel/orca_dpo_pairs", split="train[:20]")

接下来,我们将混洗 chosenrejected 列,以避免数据集中的任何偏差。

def shuffle_and_track(chosen, rejected):
    pair = [chosen, rejected]
    random.shuffle(pair)
    order = ["chosen" if x == chosen else "rejected" for x in pair]
    return {"generations": pair, "order": order}


dataset = dataset.map(lambda x: shuffle_and_track(x["chosen"], x["rejected"]))
dataset = dataset.to_list()

(可选)创建自定义步骤

步骤是 distilabel 管道中的一个块,用于操作、生成或评估数据等任务。提供了一组预定义的步骤,但您也可以创建您自己的自定义步骤。与上一节中预处理数据不同,可以使用自定义步骤来混洗列。此步骤应位于单独的模块中,以便导入并在管道中使用。在这种情况下,管道将首先使用 LoadDataFromHub 步骤加载 orca_dpo_pairs 数据集,然后应用 ShuffleStep

# "shuffle_step.py"
from typing import TYPE_CHECKING, List
from distilabel.steps import GlobalStep, StepInput

if TYPE_CHECKING:
    from distilabel.steps.typing import StepOutput

import random


class ShuffleStep(GlobalStep):
    @property
    def inputs(self) -> List[str]:
        return ["instruction", "chosen", "rejected"]

    @property
    def outputs(self) -> List[str]:
        return ["instruction", "generations", "order"]

    def process(self, inputs: StepInput) -> "StepOutput":
        outputs = []

        for input in inputs:
            chosen = input["chosen"]
            rejected = input["rejected"]
            pair = [chosen, rejected]
            random.shuffle(pair)
            order = ["chosen" if x == chosen else "rejected" for x in pair]

            outputs.append({"instruction": input["instruction"], "generations": pair, "order": order})

        yield outputs
from shuffle_step import ShuffleStep

定义管道

要清理现有的偏好数据集,我们将需要定义一个包含所有必要步骤的 Pipeline。但是,类似的工作流程也可用于清理 SFT 数据集。下面,我们将详细介绍每个步骤。

加载数据集

我们将使用刚刚混洗的数据集作为源数据。

  • 组件:LoadDataFromDicts
  • 输入列:systemquestionchosenrejectedgenerationsorder,与加载的字典列表中的键相同。
  • 输出列:systeminstructionchosenrejectedgenerationsorder。我们将使用 output_mappings 重命名列。
load_dataset = LoadDataFromDicts(
    data=dataset[:1],
    output_mappings={"question": "instruction"},
    pipeline=Pipeline(name="showcase-pipeline"),
)
load_dataset.load()
next(load_dataset.process())

评估响应

为了评估响应的质量,我们将使用meta-llama/Meta-Llama-3.1-70B-Instruct,应用 UltraFeedback 任务,该任务根据不同的维度(帮助性、诚实性、指令遵循、真实性)判断响应。对于 SFT 数据集,您可以使用PrometheusEval代替。

  • 组件:使用 InferenceEndpointsLLM 的 LLM 的 UltraFeedback 任务
  • 输入列:instructiongenerations
  • 输出列:ratingsrationalesdistilabel_metadatamodel_name

对于您的用例并为了改进结果,您可以使用任何您选择的其他 LLM

evaluate_responses = UltraFeedback(
    aspect="overall-rating",
    llm=InferenceEndpointsLLM(
        model_id="meta-llama/Meta-Llama-3.1-70B-Instruct",
        tokenizer_id="meta-llama/Meta-Llama-3.1-70B-Instruct",
        generation_kwargs={"max_new_tokens": 512, "temperature": 0.7},
    ),
    pipeline=Pipeline(name="showcase-pipeline"),
)
evaluate_responses.load()
next(
    evaluate_responses.process(
        [
            {
                "instruction": "What's the capital of Spain?",
                "generations": ["Madrid", "Barcelona"],
            }
        ]
    )
)

仅保留所需列

我们将摆脱不需要的列。

  • 组件:KeepColumns
  • 输入列:systeminstructionchosenrejectedgenerationsratingsrationalesdistilabel_metadatamodel_name
  • 输出列:instructionchosenrejectedgenerationsorder
keep_columns = KeepColumns(
    columns=[
        "instruction",
        "generations",
        "order",
        "ratings",
        "rationales",
        "model_name",
    ],
    pipeline=Pipeline(name="showcase-pipeline"),
)
keep_columns.load()
next(
    keep_columns.process(
        [
            {
                "system": "",
                "instruction": "What's the capital of Spain?",
                "chosen": "Madrid",
                "rejected": "Barcelona",
                "generations": ["Madrid", "Barcelona"],
                "order": ["chosen", "rejected"],
                "ratings": [5, 1],
                "rationales": ["", ""],
                "model_name": "meta-llama/Meta-Llama-3.1-70B-Instruct",
            }
        ]
    )
)

(可选)进一步数据管理

您可以使用 Argilla 进一步管理您的数据。

  • 组件:PreferenceToArgilla 步骤
  • 输入列:instructiongenerationsgeneration_modelsratings
  • 输出列:instructiongenerationsgeneration_modelsratings
to_argilla = PreferenceToArgilla(
    dataset_name="cleaned-dataset",
    dataset_workspace="argilla",
    api_url="https://[your-owner-name]-[your-space-name].hf.space",
    api_key="[your-api-key]",
    num_generations=2,
)

运行管道

下面,您可以看到完整的管道定义

with Pipeline(name="clean-dataset") as pipeline:

    load_dataset = LoadDataFromDicts(data=dataset, output_mappings={"question": "instruction"})

    evaluate_responses = UltraFeedback(
        aspect="overall-rating",
        llm=InferenceEndpointsLLM(
            model_id="meta-llama/Meta-Llama-3.1-70B-Instruct",
            tokenizer_id="meta-llama/Meta-Llama-3.1-70B-Instruct",
            generation_kwargs={"max_new_tokens": 512, "temperature": 0.7},
        ),
    )

    keep_columns = KeepColumns(
        columns=[
            "instruction",
            "generations",
            "order",
            "ratings",
            "rationales",
            "model_name",
        ]
    )

    to_argilla = PreferenceToArgilla(
        dataset_name="cleaned-dataset",
        dataset_workspace="argilla",
        api_url="https://[your-owner-name]-[your-space-name].hf.space",
        api_key="[your-api-key]",
        num_generations=2,
    )

    load_dataset.connect(evaluate_responses)
    evaluate_responses.connect(keep_columns)
    keep_columns.connect(to_argilla)

现在让我们运行管道并清理我们的偏好数据集。

distiset = pipeline.run()

让我们检查一下!如果您已将数据加载到 Argilla,则可以在 Argilla UI 中开始注释

您可以将数据集推送到 Hub 以与社区共享,并嵌入它以浏览数据

distiset.push_to_hub("[your-owner-name]/example-cleaned-preference-dataset")

结论

在本教程中,我们展示了构建使用 distilabel 清理偏好数据集的管道的详细步骤。但是,您可以为自己的用例自定义此管道,例如清理 SFT 数据集或添加自定义步骤。

我们使用偏好数据集作为起点,并混洗了数据以避免任何偏差。接下来,我们使用模型通过无服务器 Hugging Face 推理 API,按照 UltraFeedback 标准评估了响应。最后,我们保留了需要的列,并使用 Argilla 进行了进一步的管理。

< > 在 GitHub 上更新