几个月前,我们推出了 distilabel
,这是一个使用 LLM 进行合成数据生成和 AI 反馈的 Python 库。当时,我们从一个简单的方法开始,用户可以使用单个 LLM(称为 generator
,生成器)生成合成数据,然后使用另一个 LLM(称为 labeller
,标注器)对其进行标注。这种方法在许多场景中都很有用,尤其是在生成偏好数据集时。 благодаря 于第一个版本,我们已经生成并公开分享了具有影响力的数据集,例如 argilla/distilabel-capybara-dpo-7k-binarized、argilla/OpenHermesPreferences、argilla/distilabel-intel-orca-dpo-pairs 等,这些数据集已被用于训练多个 SOTA 模型。我们还看到 distilabel
在社区中的采用率不断提高,并涌现出很酷的社区项目,例如 davanstrien/haiku。
话虽如此,我们意识到之前的实现不适用于更复杂的合成数据生成管道,例如 DEITA,它需要运行多个 LLM 和更复杂的步骤。最重要的是,我们希望使该项目更易于扩展,并使社区更容易贡献。 决定很明确:我们需要从头开始重写该库,以解决这个问题,并使其更具可扩展性、可维护性和可伸缩性。
今天,我们很高兴宣布 distilabel 1.0.0
,这是该库的新版本,它带来了新的架构,允许构建使用 LLM 的复杂数据处理管道,并希望使社区更容易创建和共享合成数据生成管道。
管道、步骤、任务和 LLM
这个新版本的 distilabel
允许构建具有任意数量的 Step
(步骤)或 Task
(任务)的 Pipeline
(管道),它们可以相互连接,因此一个步骤或任务的输出将作为另一个步骤或任务的输入。它不再是关于一个 generator
(生成器)和一个 labeller
(标注器),而是关于一系列可以链接在一起以构建使用 LLM 的复杂数据处理管道的步骤。
Step
(步骤)是一个更通用的节点,它依赖于一个不需要使用 LLM
或模型的基础类。每个 Step
的输入是一个数据批次,其中包含字典列表,每个字典代表数据集的一行,键是列名。然后,一个 Step
可以
- 从字典中添加或删除键,以修改最终数据集的列。
- 过滤掉字典,以从数据集中删除行。
- 向批次中添加新字典,以向数据集中添加新行。
此外,Step
(步骤)提供了一个简单的生命周期,公开了一个 load
方法,该方法可用于创建将在 process
方法中使用的必要资源,process
方法是实际数据处理完成的地方。最后,每个 Step
(步骤)都可以定义一个运行时参数列表,这些参数可用于配置每个管道执行的 Step
(步骤)的行为。
在基本思想的基础上,除了普通的 Step
(步骤)之外,distilabel
还提供了两种额外的步骤,分别是 GeneratorStep
(生成器步骤)和 GlobalStep
(全局步骤)。
GeneratorStep
(生成器步骤)是从源加载数据(例如,从 Hugging Face Hub 的数据集)或生成新数据(例如,使用 SelfInstruct
和主题列表)的节点,因此它们是管道的起始节点,不需要任何传入边。
另一方面,GlobalStep
(全局步骤)的工作方式与 Step
(步骤)完全相同,但它们一次接收来自先前步骤的所有数据,从而允许聚合来自先前步骤的数据或执行需要完整数据集的操作,例如过滤掉重复的行。
从 Step
(步骤)概念继续,我们从以前的版本发展了 Task
(任务)概念,现在 Task
(任务)是一个 Step
(步骤),它知道如何使用 LLM
来执行特定任务,例如文本生成、演变指令或响应、判断文本质量等。
管道执行
对于这个新版本,我们还更改了管道的执行方式。在以前的版本中,执行是顺序的,这意味着首先执行 generator
(生成器),然后执行 labeller
(标注器)。
现在,执行是并行的,使用多个进程,每个进程执行管道的不同步骤。创建子进程时,它将执行步骤的 load
方法,然后它将开始处理从输入队列接收的批次。生成的批次将通过输出队列发送回主进程,在那里它们将被分发到管道中的下一步骤。
对于第一个版本,我们决定使用 Python 标准库中的 multiprocessing
模块来管理子进程,并进行单节点管道执行,这对于大多数情况来说已经足够了。 话虽如此,我们对架构的设计进行了深入思考,以便将来添加对分布式执行的支持,使用像 Ray
这样的库。
共享管道
这个新版本的 distilabel
的主要目标之一是使社区更容易创建和共享合成数据生成管道。为了实现这一目标,我们添加了一个新功能,允许将管道序列化为 JSON 或 YAML 文件,并从文件中加载回来,从而可以调整管道的运行时参数并再次运行它。此外,将生成的数据集推送到 Hugging Face Hub 将自动将管道也推送到 Hub,并在数据集卡片中添加对管道的良好描述,从而使将来更容易重新执行管道。
如果您不是脚本人员 👨🏻💻?...
不用担心,我们为您考虑周全!我们还添加了一个 CLI,允许从文件或 URL 获取管道的信息
distilabel pipeline info --config "https://hugging-face.cn/datasets/distilabel-internal-testing/instruction-dataset-with-llama3/raw/main/pipeline.yaml"
并从文件或 URL 运行管道
distilabel pipeline run --config "https://hugging-face.cn/datasets/distilabel-internal-testing/instruction-dataset-with-llama3/raw/main/pipeline.yaml" \ --param load_dataset.repo_id=distilabel-internal-testing/instruction-dataset-mini \ --param load_dataset.split=test \ --param generate_with_llama3.llm.generation_kwargs.max_new_tokens=512 \ --param generate_with_llama3.llm.generation_kwargs.temperature=0.7
差异概述
先前版本和当前版本之间的主要区别在于
distilabel ≤ 0.6.0 | distilabel ≥ 1.0.0 | |
---|---|---|
LLM 数量 | 最多 2 个 | 从 0 到 N(不强制使用 LLM) |
任务数量 | 最多 2 个(生成器和标注器) | 从 1 到 N |
集成 | OpenAI、vLLM、Llama.cpp、Transformers、Inference Endpoints、Together、Anyscale、Ollama 和 Vertex AI | 与以前相同,但也包括 Cohere、Azure OpenAI 和 LiteLLM |
流程 | Generator (生成器)→ Labeller (标注器) | 任意 → … → 任意(其中 … 可以是任意数量的任务) |
执行 | 顺序 | 并行 |
贡献的难易程度 | 中等-困难 | 容易 |
Argilla | 集成在每个管道上 | 分离,随时遵循即插即用方法 |
层级结构 | LLM | Pipeline (管道) > Step (步骤) > Task (任务) (> LLM ) |
语法 | 生成器和标注器 | 任意,由用户定义 |
方法 | 链式 Python 函数 | DAG(有向无环图) |
共享 | 难以共享管道 | 由于序列化和 CLI,易于共享管道 |
先前版本
- 仅适用于
generator-labeller
(生成器-标注器)场景 - 难以扩展/维护
- 不适用于大多数合成数据生成管道
from datasets import load_datasetfrom distilabel.llm import OpenAILLMfrom distilabel.pipeline import pipelinefrom distilabel.tasks import TextGenerationTaskdataset = ( load_dataset("HuggingFaceH4/instruction-dataset", split="test[:10]") .remove_columns(["completion", "meta"]) .rename_column("prompt", "input"))task = TextGenerationTask()generator = OpenAILLM(task=task, max_new_tokens=512)pipeline = pipeline("preference", "instruction-following", generator=generator)dataset = pipeline.generate(dataset)
当前版本
- 可以有任意数量的任何类型的步骤(不仅限于 LLM)
- 更具可扩展性、可维护性和可伸缩性
- 对于本地 LLM,由于步骤并行运行,可能需要更多计算资源
from distilabel.llms import OpenAILLMfrom distilabel.pipeline import Pipelinefrom distilabel.steps import LoadDataFromDictsfrom distilabel.steps.tasks import TextGenerationwith Pipeline() as pipeline: load_dataset = LoadDataFromDicts( name="load_dataset", data=[ { "instruction": "Write a short story about a dragon that saves a princess from a tower.", }, ], ) text_generation = TextGeneration( name="text_generation", llm=OpenAILLM(model="gpt-4"), ) load_dataset.connect(text_generation) ...if __name__ == "__main__": distiset = pipeline.run( parameters={ "text_generation": { "llm": { "generation_kwargs": { "temperature": 0.7, "max_new_tokens": 512, } } }, ... }, ) distiset.push_to_hub( "distilabel-internal-testing/instruction-dataset-mini-with-generations" )
接下来是什么?
您可以查看 distilabel
的 GitHub 存储库 和 文档,以了解有关新版本的更多信息,并开始创建您自己的合成数据生成管道。
我们希望这个新版本的 distilabel
将使社区更容易创建和共享合成数据生成管道,并有助于普及合成数据生成和 AI 反馈的使用。我们很高兴看到社区将使用这个新版本的 distilabel
构建什么,并且我们期待您的反馈和贡献!