配置数据集以进行微调¶
本教程将指导您如何设置数据集以进行微调。
如何快速上手内置数据集
如何使用 Hugging Face Hub 上的任意数据集
如何使用指令、聊天或文本补全数据集
如何从代码、配置文件或命令行配置数据集
如何完全自定义您自己的数据集
了解如何 从配置中配置组件
数据集是微调工作流的核心组成部分,它们充当“方向盘”,指导大型语言模型(LLM)生成特定用例的内容。许多公开分享的开源数据集已成为微调大型语言模型的热门选择,并且是训练模型的良好起点。torchtune 提供了下载外部社区数据集、加载自定义本地数据集或创建自己的数据集的工具。
内置数据集¶
要使用库中内置的数据集之一,只需导入并调用数据集构建函数。 您可以在 此处 查看所有支持的数据集列表。
from torchtune.datasets import alpaca_dataset
# Load in tokenizer
tokenizer = ...
dataset = alpaca_dataset(tokenizer)
# YAML config
dataset:
_component_: torchtune.datasets.alpaca_dataset
# Command line
tune run full_finetune_single_device --config llama3/8B_full_single_device \
dataset=torchtune.datasets.alpaca_dataset
Hugging Face 数据集¶
我们为 Hugging Face hub 上的数据集提供一流的支持。在底层,我们所有的内置数据集和数据集构建器都使用 Hugging Face 的 load_dataset() 来加载您的数据,无论是本地数据还是 hub 上的数据。
您可以在任一构建器的 source 参数中传入 Hugging Face 数据集路径,以指定要从 Hub 下载的数据集。此外,所有构建器均支持 load_dataset() 所支持的任意关键字参数。您可在 Hugging Face 的 文档 中查看完整列表。
from torchtune.datasets import text_completion_dataset
# Load in tokenizer
tokenizer = ...
dataset = text_completion_dataset(
tokenizer,
source="allenai/c4",
# Keyword-arguments that are passed into load_dataset
split="train",
data_dir="realnewslike",
)
# YAML config
dataset:
_component_: torchtune.datasets.text_completion_dataset
source: allenai/c4
split: train
data_dir: realnewslike
# Command line
tune run full_finetune_single_device --config llama3/8B_full_single_device \
dataset=torchtune.datasets.text_completion_dataset dataset.source=allenai/c4 \
dataset.split=train dataset.data_dir=realnewslike
设置最大序列长度¶
我们所有训练配方中使用的默认 collator padded_collate() 会将样本填充到批次内的最大序列长度,而不是全局最大长度。如果您希望在全局范围内设置最大序列长度的上限,可以在数据集构建器中使用 max_seq_len 进行指定。数据集中任何长于 max_seq_len 的样本都将在 truncate() 中被截断。
除了 TextCompletionDataset 的情况外,分词器的 EOS ID 会被确保为最后一个标记。
通常,您希望每个数据样本中返回的最大序列长度与模型的上下文窗口大小相匹配。 您也可以根据硬件限制降低该值,以减少内存占用。
from torchtune.datasets import alpaca_dataset
# Load in tokenizer
tokenizer = ...
dataset = alpaca_dataset(
tokenizer=tokenizer,
max_seq_len=4096,
)
# YAML config
dataset:
_component_: torchtune.datasets.alpaca_dataset
max_seq_len: 4096
# Command line
tune run full_finetune_single_device --config llama3/8B_full_single_device \
dataset.max_seq_len=4096
样本打包¶
您可以使用任何单个数据集构建器通过传入
packed=True 来使用样本打包。这需要对数据集进行一些预处理,可能会
延长首次批量的时间,但根据数据集的不同,可以显著提高训练速度。
from torchtune.datasets import alpaca_dataset, PackedDataset
# Load in tokenizer
tokenizer = ...
dataset = alpaca_dataset(
tokenizer=tokenizer,
packed=True,
)
print(isinstance(dataset, PackedDataset)) # True
# YAML config
dataset:
_component_: torchtune.datasets.alpaca_dataset
packed: True
# Command line
tune run full_finetune_single_device --config llama3/8B_full_single_device \
dataset.packed=True
自定义非结构化文本语料库¶
对于持续预训练,通常采用与预训练相似的数据设置来执行简单的文本补全任务。这意味着不需要指令模板、聊天格式,且特殊标记最少(仅包含 BOS 和 EOS)。若要指定非结构化文本语料库,您可以使用 text_completion_dataset() 构建器配合 Hugging Face 数据集或自定义本地语料库。以下是为本地文件进行指定的方法:
from torchtune.datasets import text_completion_dataset
# Load in tokenizer
tokenizer = ...
dataset = text_completion_dataset(
tokenizer,
source="text",
data_files="path/to/my_data.txt",
split="train",
)
# YAML config
dataset:
_component_: torchtune.datasets.text_completion_dataset
source: text
data_files: path/to/my_data.txt
split: train
# Command line
tune run --nproc_per_node 4 full_finetune_distributed --config llama3/8B_full \
dataset=torchtune.datasets.text_completion_dataset dataset.source=text \
dataset.data_files=path/to/my_data.txt dataset.split=train
自定义指令数据集和指令模板¶
如果你有一个自定义的指令数据集,而该数据集尚未在库中提供,
你可以使用 instruct_dataset() 构建器并指定
源路径。指令数据集通常包含多个文本列,并按照提示模板进行格式化。
要对大型语言模型(LLM)针对特定任务进行微调,一种常见的方法是创建一个固定的指令模板,以引导模型生成具有特定目标的输出。指令模板本质上是一种用于为模型结构化输入的修饰性文本。它与具体模型无关,并像其他任何文本一样被正常分词,但它可以帮助模型更好地适应预期的响应格式。例如,AlpacaInstructTemplate 按以下方式组织数据:
"Below is an instruction that describes a task, paired with an input that provides further context. "
"Write a response that appropriately completes the request.\n\n"
"### Instruction:\n{instruction}\n\n### Input:\n{input}\n\n### Response:\n"
这是一个使用 AlpacaInstructTemplate 格式化的示例:
from torchtune.data import AlpacaInstructTemplate
sample = {
"instruction": "Classify the following into animals, plants, and minerals",
"input": "Oak tree, copper ore, elephant",
}
prompt = AlpacaInstructTemplate.format(sample)
print(prompt)
# Below is an instruction that describes a task, paired with an input that provides further context.
# Write a response that appropriately completes the request.
#
# ### Instruction:
# Classify the following into animals, plants, and minerals
#
# ### Input:
# Oak tree, copper ore, elephant
#
# ### Response:
#
我们为摘要和语法修正等常见任务提供other instruct templates <data>。如果您需要为自定义任务创建自己的指令模板,您可以从InstructTemplate继承并创建您自己的类。
from torchtune.datasets import instruct_dataset
from torchtune.data import InstructTemplate
class CustomTemplate(InstructTemplate):
# Define the template as string with {} as placeholders for data columns
template = ...
# Implement this method
@classmethod
def format(
cls, sample: Mapping[str, Any], column_map: Optional[Dict[str, str]] = None
) -> str:
...
# Load in tokenizer
tokenizer = ...
dataset = instruct_dataset(
tokenizer=tokenizer,
source="my/dataset/path",
template="import.path.to.CustomTemplate",
)
# YAML config
dataset:
_component_: torchtune.datasets.instruct_dataset
source: my/dataset/path
template: import.path.to.CustomTemplate
# Command line
tune run full_finetune_single_device --config llama3/8B_full_single_device \
dataset=torchtune.datasets.instruct_dataset dataset.source=my/dataset/path \
dataset.template=import.path.to.CustomTemplate
自定义聊天数据集和聊天格式¶
如果你有一个自定义的聊天/对话数据集,而该数据集尚未在库中提供,
你可以使用 chat_dataset() 构建器并指定
源路径。聊天数据集通常只有一个列,其中包含用户和助手之间的多轮
来回消息。
聊天格式类似于指令模板,不同之处在于它们将系统、用户和助手消息格式化为消息列表(参见 ChatFormat),适用于对话数据集。这些格式可以像指令数据集一样进行配置。
以下是使用 Llama2ChatFormat 格式化消息的方式:
from torchtune.data import Llama2ChatFormat, Message
messages = [
Message(
role="system",
content="You are a helpful, respectful, and honest assistant.",
),
Message(
role="user",
content="I am going to Paris, what should I see?",
),
Message(
role="assistant",
content="Paris, the capital of France, is known for its stunning architecture..."
),
]
formatted_messages = Llama2ChatFormat.format(messages)
print(formatted_messages)
# [
# Message(
# role="user",
# content="[INST] <<SYS>>\nYou are a helpful, respectful and honest assistant.\n<</SYS>>\n\n"
# "I am going to Paris, what should I see? [/INST] ",
# ),
# Message(
# role="assistant",
# content="Paris, the capital of France, is known for its stunning architecture..."
# ),
# ]
请注意,系统消息现已整合到用户消息中。如果您创建自定义的 ChatFormats,还可以添加更高级的行为。
from torchtune.datasets import chat_dataset
from torchtune.data import ChatFormat
class CustomChatFormat(ChatFormat):
# Define templates for system, user, assistant messages
# as strings with {} as placeholders for message content
system = ...
user = ...
assistant = ...
# Implement this method
@classmethod
def format(
cls,
sample: List[Message],
) -> List[Message]:
...
# Load in tokenizer
tokenizer = ...
dataset = chat_dataset(
tokenizer=tokenizer,
source="my/dataset/path",
split="train",
conversation_style="openai",
chat_format="import.path.to.CustomChatFormat",
)
# YAML config
dataset:
_component_: torchtune.datasets.chat_dataset
source: my/dataset/path
conversation_style: openai
chat_format: import.path.to.CustomChatFormat
# Command line
tune run full_finetune_single_device --config llama3/8B_full_single_device \
dataset=torchtune.datasets.chat_dataset dataset.source=my/dataset/path \
dataset.conversation_style=openai dataset.chat_format=import.path.to.CustomChatFormat
多个内存数据集¶
也可以在多个数据集上进行训练,并使用我们的 ConcatDataset 接口分别配置它们。您甚至可以混合指令和聊天数据集或其他自定义数据集。
# YAML config
dataset:
- _component_: torchtune.datasets.instruct_dataset
source: vicgalle/alpaca-gpt4
template: torchtune.data.AlpacaInstructTemplate
split: train
train_on_input: True
- _component_: torchtune.datasets.instruct_dataset
source: samsum
template: torchtune.data.SummarizeTemplate
column_map:
output: summary
split: train
train_on_input: False
- _component_: torchtune.datasets.chat_dataset
...
本地和远程数据集¶
要使用保存在本地硬盘上的数据集,只需指定文件类型为
source 并通过任何数据集构建函数传递 data_files 参数。我们支持 Hugging Face 的 load_dataset 支持的所有
文件类型,包括 csv、json、txt 等。
from torchtune.datasets import instruct_dataset
# Load in tokenizer
tokenizer = ...
# Local files
dataset = instruct_dataset(
tokenizer=tokenizer,
source="csv",
split="train",
template="import.path.to.CustomTemplate"
data_files="path/to/my/data.csv",
)
# Remote files
dataset = instruct_dataset(
tokenizer=tokenizer,
source="json",
split="train",
template="import.path.to.CustomTemplate"
data_files="https://rajpurkar.github.io/SQuAD-explorer/dataset/train-v2.0.json",
# You can also pass in any kwarg that load_dataset accepts
field="data",
)
# YAML config - local files
dataset:
_component_: torchtune.datasets.instruct_dataset
source: csv
template: import.path.to.CustomTemplate
data_files: path/to/my/data.csv
# YAML config - remote files
dataset:
_component_: torchtune.datasets.instruct_dataset
source: json
template: import.path.to.CustomTemplate
data_files: https://rajpurkar.github.io/SQuAD-explorer/dataset/train-v2.0.json
field: data
# Command line - local files
tune run full_finetune_single_device --config llama3/8B_full_single_device \
dataset=torchtune.datasets.chat_dataset dataset.source=csv \
dataset.template=import.path.to.CustomTemplate dataset.data_files=path/to/my/data.csv
完全自定义的数据集¶
更高级的任务和不适合InstructDataset、ChatDataset和TextCompletionDataset提供的模板化和处理的数据集格式可能需要您创建自己的数据集类以获得更大的灵活性。让我们通过一个示例来了解您需要做什么,这个示例是PreferenceDataset,它为RLHF偏好数据提供了自定义功能。
如果你查看 PreferenceDataset 类的代码,
你会发现它与 InstructDataset 类非常相似,只是在偏好数据中对选择和拒绝样本进行了一些调整。
chosen_message = [
Message(role="user", content=prompt, masked=True),
Message(role="assistant", content=transformed_sample[key_chosen]),
]
rejected_message = [
Message(role="user", content=prompt, masked=True),
Message(role="assistant", content=transformed_sample[key_rejected]),
]
chosen_input_ids, c_masks = self._tokenizer.tokenize_messages(
chosen_message, self.max_seq_len
)
chosen_labels = list(
np.where(c_masks, CROSS_ENTROPY_IGNORE_IDX, chosen_input_ids)
)
rejected_input_ids, r_masks = self._tokenizer.tokenize_messages(
rejected_message, self.max_seq_len
)
rejected_labels = list(
np.where(r_masks, CROSS_ENTROPY_IGNORE_IDX, rejected_input_ids)
)
对于可以从配置中轻松自定义的特定数据集,您可以创建一个构建函数。这是用于 stack_exchanged_paired_dataset() 的构建函数,它创建了一个配置为使用来自 Hugging Face 的配对数据集的 PreferenceDataset。请注意,我们还必须添加一个自定义指令模板。
def stack_exchanged_paired_dataset(
tokenizer: ModelTokenizer,
max_seq_len: int = 1024,
) -> PreferenceDataset:
return PreferenceDataset(
tokenizer=tokenizer,
source="lvwerra/stack-exchange-paired",
template=StackExchangedPairedTemplate(),
column_map={
"prompt": "question",
"chosen": "response_j",
"rejected": "response_k",
},
max_seq_len=max_seq_len,
split="train",
data_dir="data/rl",
)
现在,我们可以轻松地从配置文件或命令行指定自定义数据集。
# This is how you would configure the Alpaca dataset using the builder
dataset:
_component_: torchtune.datasets.stack_exchanged_paired_dataset
max_seq_len: 512
# Command line - local files
tune run full_finetune_single_device --config llama3/8B_full_single_device \
dataset=torchtune.datasets.stack_exchanged_paired_dataset dataset.max_seq_len=512