torchtune 数据集五类数据一次讲透:从本地 csv 到训练的完整接入指南
【免费下载链接】torchtunePyTorch native post-training library项目地址: https://gitcode.com/GitHub_Trending/to/torchtune
torchtune 是 PyTorch 官方的后训练框架,它的数据集(dataset)体系决定了你的数据能不能顺利进模型。本文带你从一份本地 csv 出发,快速打通 torchtune 数据集的完整接入链路,覆盖 instruct、chat、DPO、持续预训练、多模态五类形态,讲清SFTDataset的三插槽设计、-100标签成因与常见踩坑,最后给一份可直接照做的接入清单。
一、一份本地 csv,三行接进训练
先拿到正反馈,再谈原理。假设你手里只有一个本地 csv,两列:question和answer,想让它喂给 torchtune 做 LoRA 微调。最短路径就三步:准备数据 → 建 tokenizer → 调instruct_dataset。
数据文件长这样(两列、表头即列名):
# data/support.csv # question,answer # 巴黎是哪个国家的首都?,法国。 # 世界上最高的山峰是什么?,珠穆朗玛峰。建一个 tokenizer,再调 builder,跑通就算成功一半:
from torchtune.models.qwen3 import qwen3_tokenizer from torchtune.datasets import instruct_dataset tok = qwen3_tokenizer(path="/tmp/Qwen3-0.6B/vocab.json", merges_file="/tmp/Qwen3-0.6B/merges.txt", max_seq_len=4096) ds = instruct_dataset(tokenizer=tok, source="csv", data_files="data/support.csv", column_map={"input": "question", "output": "answer"}, train_on_input=False, split="train") print(tok.decode(ds[0]["tokens"])) print(ds[0]["labels"]) # 用户问句部分全是 -100,只有答案参与 loss这里有个点值得记:instruct_dataset默认找input/output两列,你的列名是question/answer,就用column_map={"input": "question", "output": "answer"}把「预期列名 → 真实列名」对上去。
在 recipe 的 YAML 里同样这么写(tokenizer 由 recipe 传入,dataset 内不用重复):
dataset: _component_: torchtune.datasets.instruct_dataset source: csv data_files: data/support.csv column_map: input: question output: answer train_on_input: False split: train从 recipes/configs/qwen3/0.6B_lora_single_device.yaml 这类真实配置能看出,内置 builder(如alpaca_cleaned_dataset)和自定义 builder 都能挂在这个dataset:槽位下。跑通这一步,说明加载、分词、组标签这条链已经通了。
二、把数据流拆成四层看
换个视角,把流水线当工厂工序。torchtune 所有数据集都走同一条线,可以拆成四层,每层只回答「解决什么问题、输入输出是什么」。这样比背四阶段更容易落地。
- 数据加载层:解决「数据从哪来」。
SFTDataset.__init__把数据加载完全委托给 Hugging Face 的load_dataset——source传 HF 仓库名就从 Hub 拉,传"json"/"csv"/"text"再配data_files就读本地或 https 远程文件;**load_dataset_kwargs(如split、name)原样透传。可选filter_fn/filter_kwargs在预处理前过滤低质量样本。输入是配置,输出是一个 HF Dataset 对象。 - Message 标准化层:解决「任意格式怎么对齐」。
message_transform把一行原始样本转成Message列表——统一成system/user/assistant/ipython四种角色的「对话」。这是全体系的地基,torchtune/data/_messages.py 里InputOutputToMessages、ShareGPTToMessages、OpenAIToMessages、ChosenRejectedToMessages就是各形态的转换器。输入是原始 dict,输出是{"messages": [Message, ...]}。 - 模型转换层:解决「怎么变成模型能吃的 token」。
model_transform做分词、prompt 模板、图像变换等模型专属处理;文本任务直接把 tokenizer 当model_transform用。它的契约很硬:必须返回tokens和mask两个键,否则抛ValueError。输入是 Message 列表,输出是tokens/mask(多模态还多encoder_input)。 - 组批层:解决「怎么拼成 batch」。collater 做 padding 与 batch 组装,实现在 torchtune/data/_collate.py:
padded_collate_sft(通用 SFT)、padded_collate_tiled_images_and_mask(多模态 tile 图)、padded_collate_packed(打包样本)、padded_collate_dpo(偏好对)。recipe 按数据集类型选对应 collater。
真正的「逐样本执行」发生在SFTDataset.__getitem__内部组装的SFTTransform里(见 torchtune/datasets/_sft.py):先跑message_transform并validate_messages校验,再跑model_transform,最后由mask生成labels。这段正好解释了下一节的高频疑问。
三、五种数据形态,各找入口
数据长什么样,就用哪个入口。不再逐个任务长篇展开,统一用「数据长什么样 → 用哪个入口函数 → 关键字段怎么填」的三段式压缩呈现。
单轮文本(instruct)
数据是「一问一答」两列结构。入口instruct_dataset。关键字段:column_map(列名对齐)、train_on_input(用户问句是否计入 loss,默认 False)、new_system_prompt(给每条样本前置一条 system 消息)。内部由InputOutputToMessages完成 Message 组装。
多轮对话(chat)
数据是一个conversations/messages列,里面是 user-assistant 多轮来回。入口chat_dataset。关键字段:conversation_column(对话列名)、conversation_style(只支持sharegpt或openai两种,对应ShareGPTToMessages/OpenAIToMessages)、new_system_prompt。sharegpt 格式是{"from": "human"|"gpt", "value": ...},openai 格式是{"role": "user"|"assistant", "content": ...}。
from torchtune.datasets import chat_dataset ds = chat_dataset(tokenizer=tok, source="json", data_files="data/talk.json", conversation_column="dialogue", conversation_style="openai", train_on_input=False, split="train")偏好对(DPO)
数据是同一 prompt 下 chosen/rejected 两条回复,服务于 DPO 训练。入口preference_dataset。关键字段:column_map={"chosen": "...", "rejected": "..."}、train_on_input、new_system_prompt。它只接受 openai 风格对话,输出四组张量chosen_input_ids/chosen_labels/rejected_input_ids/rejected_labels,prompt 段全被 mask 成-100,只有 assistant 回复参与 loss——这正是 DPO 对比学习要的输入形态,batch 层用padded_collate_dpo组装。注意:偏好数据集不支持packed,设 True 会抛ValueError。
纯文本语料(持续预训练)
数据只含一个文本列,自监督微调基座。入口text_completion_dataset。关键字段:column(文本列名,默认text,本地 txt 直接用默认即可)、add_eos(默认 True)、split_across_pack。这是格式最简单的一类——不用 Message,直接tokenizer.encode后把 labels 右移一位、末尾补-100。
图文(多模态 VLM)
数据是 sharegpt 对话 + 一列图像路径,文本里含<image>占位符。入口multimodal_chat_dataset。关键字段:column_map(把对话列和图像列对齐,默认conversations/image)、image_dir(相对路径前缀)、image_tag(占位符,默认<image>)。一个样本目前支持单张图,且总是插到第一条 user 消息;图像会切成 tile,形状如[4, 3, 224, 224]。多模态数据集同样不支持packed。
from torchtune.datasets.multimodal import multimodal_chat_dataset from torchtune.models.llama3_2_vision import llama3_2_vision_transform mt = llama3_2_vision_transform(path="/tmp/.../tokenizer.model", prompt_template="torchtune.data.QuestionAnswerTemplate", max_seq_len=8192, image_size=560) ds = multimodal_chat_dataset(model_transform=mt, source="json", data_files="data/vqa.json", column_map={"conversations": "dialogue", "image": "img"}, image_dir="/data/vqa/", image_tag="<image>", split="train")一张表收尾
| 数据形态 | 入口 builder | 数据长什么样 | 关键字段 |
|---|---|---|---|
| 单轮文本 | instruct_dataset | 两列一问一答 | column_map、train_on_input、new_system_prompt |
| 多轮对话 | chat_dataset | 一个对话列 | conversation_column、conversation_style |
| 偏好对 | preference_dataset | chosen/rejected 对话 | column_map、train_on_input(不支持 packed) |
| 纯文本语料 | text_completion_dataset | 单文本列 | column、add_eos、split_across_pack |
| 图文 | multimodal_chat_dataset | sharegpt 对话 + 图像列 | column_map、image_dir、image_tag(不支持 packed) |
四、schema 对不上,自己写 transform
内置 builder 装不下时,补最后一块拼图。当你的列结构/媒体结构无法被上面任何 builder 覆盖时,官方推荐做法是「自定义 message transform +SFTDataset」两件拼。
from torchtune.data import Message from torchtune.modules.transforms import Transform from torchtune.datasets import SFTDataset class MyTransform(Transform): def __call__(self, sample): return {"messages": [ Message(role="user", content=sample["q"], masked=True, eot=True), Message(role="assistant", content=sample["a"], masked=False, eot=True), ]} def my_dataset(tokenizer, **kw): return SFTDataset(source="json", data_files="data/my.json", split="train", message_transform=MyTransform(), model_transform=tokenizer, **kw)dataset: _component_: data.dataset.my_datasetmasked=True/False直接决定哪些 token 计入 loss(对应-100逻辑);eot=True表示消息后追加结束符。多模态场景把图像对象放进Message的 content,model_transform换成对应 VLM 的 transform 即可。
五、这几个坑,先知道不翻车
集中排雷,省你调试时间。
labels里的-100从哪来:Message.masked=True会传导成 token 级mask,SFTTransform把mask=True的位置替换成CROSS_ENTROPY_IGNORE_IDX(即-100,定义在 torchtune/data/_common.py)。默认用户问句被 mask,所以不进 loss;且 labels 相对 logits 右移一位、末尾再补一个-100。train_on_input与 mask 的关系:它就是控制 user 消息 mask 与否的开关。较新的实现里它已被masking_strategy取代(train_on_assistant/train_on_all/train_on_last),同时传时以masking_strategy为准——train_on_input=True等价于train_on_all。注意多模态下 user 消息恒被 mask。column_map对齐规则:键永远是「预期列名」(input/output、chosen/rejected、conversations/image),值才是你数据里的真实列名;写反了会直接ValueError。Message媒体内容只接受图像对象本身:要传load_image(torchtune/data/_utils.py)产出的图像,不能只塞文件路径或 URL。multimodal_chat_dataset里的image_dir帮你拼完整路径,image_tag负责占位符↔图像的交错。packed有门槛:设packed=True要求 tokenizer 的max_seq_len已配置,且偏好/多模态数据集根本不支持 packing。split可取子集:默认"train",也能写"train[:10%]"这种 HF 语法快速调试。
六、从 0 到 1 接入清单
照着勾完,数据就进场了。
- 定形态:单轮 →
instruct_dataset;多轮 →chat_dataset;偏好 →preference_dataset;纯文本 →text_completion_dataset;图文 →multimodal_chat_dataset;都对不上 → 自定义SFTDataset+ transform。 - 定来源:HF 仓库名传
source;本地/远程文件传文件类型 +data_files;需要子集用split。 - 对齐列名:按各 builder 的预期列名填
column_map/conversation_column/column。 - 控 loss 范围:用
train_on_input(或masking_strategy)决定 user 是否进 loss,检查labels的-100分布是否符合预期。 - 配 tokenizer/transform:文本用
ModelTokenizer当model_transform;多模态用对应 VLM transform,并设image_dir/image_tag。 - 选 collater:recipe 里按数据集类型挂
padded_collate_sft/padded_collate_dpo/padded_collate_tiled_images_and_mask/padded_collate_packed。 - 想提速再开
packed:确认 tokenizer 已设max_seq_len、且任务支持 packing。
顺带一提,torchtune.datasets还内置了一批开箱即用的 builder——alpaca_dataset/alpaca_cleaned_dataset、grammar_dataset、samsum_dataset、slimorca_dataset、hh_rlhf_helpful_dataset、stack_exchange_paired_dataset、cnn_dailymail_articles_dataset、wikitext_dataset,以及组合工具ConcatDataset(多源拼接)和PackedDataset(样本打包);多模态侧另有the_cauldron_dataset、llava_instruct_dataset。它们本质都是上面这套「source+message_transform+model_transform」插槽的预填组合——理解这条线之后,选数据集、改列名、控 loss、写任意 schema 的自定义 pipeline,都能在同一套思路下完成。
【免费下载链接】torchtunePyTorch native post-training library项目地址: https://gitcode.com/GitHub_Trending/to/torchtune
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考