开源 AI 食谱文档
使用 LLM 作为评判员清理现有偏好数据集
并获得增强的文档体验
开始使用
使用 LLM 作为评判员清理现有偏好数据集
作者:David Berenstein 和 Sara Han Díaz
- 库: argilla, hf-inference-endpoints
- 组件: LoadDataFromDicts, UltraFeedback, KeepColumns, PreferenceToArgilla, InferenceEndpointsLLM, GlobalStep
在本教程中,我们将使用 distilabel 通过提供关于数据质量的 AI 反馈,利用 LLM 作为评判员来清理数据集。 distilabel 是一个为工程师设计的合成数据和 AI 反馈框架,他们需要基于经过验证的研究论文的快速、可靠和可扩展的管道。请在此处查看文档。
为了评估响应,我们将使用与 distilabel 集成的无服务器 HF 推理 API。这项服务是免费的,但有速率限制,允许您通过简单的 HTTP 请求在超过 150,000 个公共模型或您自己的私有模型上进行测试和评估,推理过程由 Hugging Face 共享基础设施托管,速度很快。如果您需要更多的计算能力,可以使用 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 推理端点。登录后可直接在本 notebook 中使用。
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]")
接下来,我们将打乱 `chosen` 和 `rejected` 列,以避免数据集中的任何偏见。
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`
- 输入列:`system`、`question`、`chosen`、`rejected`、`generations` 和 `order`,与加载的字典列表中的键相同。
- 输出列:`system`、`instruction`、`chosen`、`rejected`、`generations` 和 `order`。我们将使用 `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` 的 `UltraFeedback` 任务与 LLM
- 输入列:`instruction`, `generations`
- 输出列:`ratings`, `rationales`, `distilabel_metadata`, `model_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`
- 输入列:`system`、`instruction`、`chosen`、`rejected`、`generations`、`ratings`、`rationales`、`distilabel_metadata` 和 `model_name`
- 输出列:`instruction`, `chosen`, `rejected`, `generations` 和 `order`
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` 步骤
- 输入列:`instruction`、`generations`、`generation_models`、`ratings`
- 输出列:`instruction`、`generations`、`generation_models`、`ratings`
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 上更新