torchtune 数据集接入指南:5 类任务从数据格式到训练配置一次跑通
【免费下载链接】torchtunePyTorch native post-training library项目地址: https://gitcode.com/GitHub_Trending/to/torchtune
数据都备齐了,怎么喂进训练循环?你的 json、csv 列名五花八门,torchtune 的 torchtune 数据集 builder 却只认固定格式。这篇指南回答三个问题:你的任务该用哪个入口函数、数据要长什么样、YAML 里怎么写。读完你可以直接改配置跑通 instruct、chat、DPO 偏好、继续预训练、多模态 VLM 这 5 类微调任务。
机制一图流:所有任务共用一条"标准化工厂"流水线
torchtune 的数据侧本质是一条流水线:任何来源的原始样本都要先"改包装"成统一规格,再进模型。数据加载委托给 Hugging Face 的load_dataset;之后每条样本先被message transform翻译成统一的Message列表(角色标注为 system / user / assistant / ipython 的"对话气泡"),再被model transform(通常就是模型 tokenizer)转成tokens和mask,最后由 collater 拼成 batch。这套流水线实现在 torchtune/datasets/_sft.py,你配置里选的各个 builder 只是给三个插槽预填了不同的 transform。
两个决定训练行为的关键细节都在这里:mask=True的位置在labels中写成-100(交叉熵忽略索引),对应 token 不参与 loss;labels相对输入右移一位、末尾补一个-100,见 torchtune/datasets/_sft.py 的SFTTransform.__call__。
选路指南:按任务对号入座
先查这张表定位你的任务,再跳到对应小节抄作业:
| 你的任务 | 入口函数 | 数据格式 | 所在小节 |
|---|---|---|---|
| 单轮指令微调(instruct) | instruct_dataset | 两列:input/output | SFT 指令数据集 |
| 多轮对话微调(chat) | chat_dataset | 一列消息列表,sharegpt或openai风格 | Chat 多轮对话数据集 |
| DPO / 偏好对齐 | preference_dataset | 两列消息列表:chosen/rejected | 偏好数据集 |
| 继续预训练 | text_completion_dataset | 一个文本列,默认text | 继续预训练数据集 |
| 文本+图像 VLM 微调 | multimodal_chat_dataset | sharegpt 对话列 + 图像路径列 + 文本占位符 | 多模态数据集 |
分任务实操
SFT 指令数据集:两列格式 + 列名重映射
格式要求:每条样本是"用户 prompt 一列、模型响应一列",默认列名input/output。最小样例:
[{"input": "What time is it in London?", "output": "It is 10:00 AM in London."}]最小代码(本地 json;从 Hugging Face 加载时把source换成 repo 名即可):
from torchtune.models.gemma import gemma_tokenizer from torchtune.datasets import instruct_dataset tok = gemma_tokenizer(path="path/to/tokenizer.model", max_seq_len=8192) ds = instruct_dataset( tokenizer=tok, source="json", data_files="my_data.json", split="train", )配置写法:
dataset: _component_: torchtune.datasets.instruct_dataset source: json data_files: my_data.json split: train column_map: input: question # 你的列名 → 框架期望的列名 output: answer💡 最易错的参数是column_map:key 永远是框架默认列名(input/output),value 才是你数据里的真实列名,方向写反会直接 KeyError。
Chat 多轮对话数据集:指定对话列与风格
格式要求:一个"消息列表"列,角色名必须是sharegpt(human/gpt+from/value)或openai(user/assistant+role/content)两种标准风格之一。最小样例:
[{"conversations": [ {"from": "human", "value": "What is the answer to life?"}, {"from": "gpt", "value": "The answer is 42."} ]}]最小代码:
from torchtune.datasets import chat_dataset ds = chat_dataset( tokenizer=tok, source="json", data_files="my_data.json", conversation_column="conversations", conversation_style="sharegpt", split="train", )配置写法:
dataset: _component_: torchtune.datasets.chat_dataset source: json data_files: my_data.json conversation_column: conversations conversation_style: sharegpt # 或 openai split: train⚠️ 最易错的是conversation_style与数据实际风格不匹配:两种内置转换器都不认的角色名会解析失败,此时不要硬凑参数,走下一节自定义 transform。
偏好数据集:DPO 用 chosen/rejected 双列
格式要求:chosen与rejected两列,各是一条完整消息列表,且 prompt 部分必须完全一致;消息格式只支持 openai 风格(role/content)。最小样例:
[{"chosen_conversations": [ {"role": "user", "content": "Hole in my trousers?"}, {"role": "assistant", "content": "Fix the hole."}], "rejected_conversations": [ {"role": "user", "content": "Hole in my trousers?"}, {"role": "assistant", "content": "Take them off."}]}]最小代码:
from torchtune.datasets import preference_dataset ds = preference_dataset( tokenizer=tok, source="json", data_files="my_prefs.json", column_map={"chosen": "chosen_conversations", "rejected": "rejected_conversations"}, split="train", )配置写法:
dataset: _component_: torchtune.datasets.preference_dataset source: json data_files: my_prefs.json column_map: chosen: chosen_conversations rejected: rejected_conversations split: train💡 最易错的点:取一条样本会得到chosen_input_ids/chosen_labels与rejected_input_ids/rejected_labels两组张量,prompt 部分统一 mask 成-100,只有 assistant 响应进 loss——这正是 DPO 对比学习需要的输入形态;另外偏好数据集不支持packed,设了会直接抛错(见 torchtune/datasets/_preference.py)。
继续预训练数据集:单文本列自监督
格式要求:只需一个文本列,默认列名text,本地.txt纯文本行直接用默认值即可。最小代码:
from torchtune.datasets import text_completion_dataset ds = text_completion_dataset( tokenizer=tok, source="json", column="text", data_files="corpus.json", split="train", )配置写法:
dataset: _component_: torchtune.datasets.text_completion_dataset source: text # 纯文本 .txt 用 text;json/csv 用对应类型 data_files: corpus.txt column: text split: train⚠️ 最易错的是add_eos:默认True,每条样本结尾追加 EOS token;按max_seq_len截断时会刻意保留 EOS 不被裁掉(见 torchtune/datasets/_text_completion.py)。继续预训练场景通常保持默认;微调场景想控制句尾行为时再显式设置。
多模态数据集:对话 + 图像列 + 占位符
格式要求:sharegpt 风格对话列,外加一列图像路径;文本里写图像占位符(如<image>)标记图片插入位置。最小样例:
[{"dialogue": [ {"from": "human", "value": "<image>What time is it on the clock?"}, {"from": "gpt", "value": "It is 10:00 AM."}], "image_path": "images/clock.jpg"}]最小代码(model_transform用 VLM 的 transform,而不是纯 tokenizer):
from torchtune.models.llama3_2_vision import llama3_2_vision_transform from torchtune.datasets.multimodal import multimodal_chat_dataset mt = llama3_2_vision_transform(path="path/to/tokenizer.model", max_seq_len=8192, image_size=560) ds = multimodal_chat_dataset( model_transform=mt, source="json", data_files="my_data.json", column_map={"conversations": "dialogue", "image": "image_path"}, image_dir="/home/user/dataset/", image_tag="<image>", split="train", )配置写法:
dataset: _component_: torchtune.datasets.multimodal.multimodal_chat_dataset source: json data_files: my_data.json column_map: conversations: dialogue image: image_path image_dir: /home/user/dataset/ image_tag: "<image>" split: train💡 最易错的是image_dir:数据里是相对路径时,它负责拼出完整本地路径;不传则按当前工作目录解析,图片"找不到"多半栽在这里。另外当前实现每个样本只支持单张图像,且固定加到第一条 user 消息上。
内置 builder 不匹配时:自定义数据集三步法
内置 builder 覆盖不了你的 schema 时,官方路径是"自己写 message transform,其余复用现成流水线"。三步完成。
第一步,写 transform,把原始样本翻译成Message列表:
# data/message_transform.py from torchtune.data import Message from torchtune.modules.transforms import Transform class MyMessageTransform(Transform): def __call__(self, sample): return {"messages": [ Message(role="user", content=sample["input"], masked=True), Message(role="assistant", content=sample["output"]), ]}masked=True的消息对应 token 在 loss 中被忽略(labels里是-100);masked默认False,assistant 响应默认参与训练。
第二步,写一个薄 builder,把 transform 包进SFTDataset:
# data/dataset.py from torchtune.datasets import SFTDataset from data.message_transform import MyMessageTransform def custom_dataset(tokenizer, **load_dataset_kwargs): return SFTDataset( source="json", data_files="my_data.json", message_transform=MyMessageTransform(), model_transform=tokenizer, # 文本数据直接传 tokenizer **load_dataset_kwargs, )第三步,YAML 里把dataset指向你的 builder:
dataset: _component_: data.dataset.custom_dataset多模态自定义时,图像用load_image(torchtune/data/_utils.py)读成张量后以{"type": "image", "content": tensor}放进Message的 content;model_transform换成对应 VLM 的 transform。
踩坑清单
- 现象:报 KeyError 或某列读不到 →原因:列名和 builder 默认值对不上 →解法:用
column_map重映射,key 写框架默认列名、value 写你的真实列名。 - 现象:训练 loss 里 prompt 部分没被忽略(或反过来全被忽略)→原因:
train_on_input默认False,用户 prompt 一律 mask 成-100→解法:确认真实意图,需要 prompt 参与训练时显式设train_on_input: True。 - 现象:设
packed: True后启动报 ValueError →原因:PackedDataset依赖 tokenizer 的max_seq_len→解法:在 tokenizer 配置里补上max_seq_len。 - 现象:多模态任务图片加载失败或路径错乱 →原因:数据中是相对路径,
image_dir没配或配错 →解法:image_dir指向图像根目录,框架自动拼接完整路径。 - 现象:自定义
model_transform时抛 "Must return 'tokens' and 'mask' as keys" →原因:SFTTransform对 model transform 有输出契约,两个键缺一不可 →解法:你的 transform 返回 dict 必须同时含tokens和mask。 - 现象:想给偏好数据集加速而开 packing →原因:
PreferenceDataset明确不支持packed=True→解法:保持默认,靠 batch 并行提吞吐。
收尾
一条主线贯穿全部任务:SFTDataset把数据拆成source + message_transform + model_transform三个插槽,你换任务只是换插槽里预填的 transform,管道本身不动。
- 先按"选路指南"表确认任务类型和列名,再决定要不要写
column_map。 - 本地数据统一走
source(文件类型)+data_files+split三件套,HF 数据只传 repo 名,加载语义完全跟随load_dataset。 - 列名、风格、格式三样都对不上时,别在参数上硬凑,按三步法写一个 message transform,成本最低。
【免费下载链接】torchtunePyTorch native post-training library项目地址: https://gitcode.com/GitHub_Trending/to/torchtune
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考