4.1 微调数据长什么样
指令微调(SFT)的数据本质是"问-答"对:给模型一个指令/问题,告诉它期望的回答。模型学的是"看到这样的输入,该生成这样的输出"。数据质量比数量更重要——1000 条高质量样本常胜过 10 万条噪声数据。
- 指令数据(Instruction Data)
- 由 instruction(指令)、可选 input(补充输入)、output(期望回答)组成的样本,SFT 的标准原料。
- chat template(对话模板)
- 把多轮对话拼成模型训练时见过的格式的模板,含 role 标记与特殊 token。必须与模型匹配,否则效果崩。
- Alpaca 格式
- 经典单轮格式:
{instruction, input, output}。简单直观,适合指令跟随类数据。 - ShareGPT 格式
- 多轮对话格式:
{"conversations": [{from, value}, ...]},用 human/gpt 交替,适合对话数据。 - formatting_func
- 一个把原始样本转成训练文本字符串的函数,传给 SFTTrainer,让它知道如何拼接你的字段。
- packing(打包)
- 把多条短样本拼进一个 max_seq_length 序列,减少 padding 浪费、提升吞吐。适合大量短样本。
- train/eval split(训练/验证划分)
- 留出一小部分数据(如 5%-10%)做验证,用来监控是否过拟合、判断何时停。
- EOS token
- 序列结束标记。训练文本末尾必须补 eos,否则模型学不会"何时停下",推理会停不住。
4.2 加载数据集
用 HuggingFace datasets 加载,来源可以是 Hub、本地 JSON/CSV/Parquet:
from datasets import load_dataset
# 从 Hub 加载 Alpaca 中文数据
ds = load_dataset("yahma/alpaca-cleaned", split="train")
# 或从本地 JSON(每行一个 {instruction, input, output})
# ds = load_dataset("json", data_files="data.json", split="train")
print(ds[0])
# {'instruction': '解释什么是光合作用', 'input': '', 'output': '光合作用是...'}
4.3 应用 chat template(推荐)
对 Instruct/Chat 模型,最稳的做法是用 Unsloth 的 get_chat_template 套上与模型匹配的模板,再把对话渲染成训练文本:
from unsloth.chat_templates import get_chat_template
tokenizer = get_chat_template(tokenizer, chat_template="qwen-2.5")
def to_chat(example):
msgs = [
{"role": "user", "content": example["instruction"]},
{"role": "assistant", "content": example["output"]},
]
text = tokenizer.apply_chat_template(
msgs, tokenize=False, add_generation_prompt=False)
return {"text": text}
ds = ds.map(to_chat)
print(ds[0]["text"][:200])
模板必须对齐模型
Qwen 用 qwen-2.5,Llama-3 用 llama-3.1,Gemma 用 gemma……用错模板 = 训练时的格式和模型认识的格式不一致,微调基本白费。
4.4 Alpaca 风格 formatting_func
若不想用 chat template,也可以自定义一个纯文本模板(注意末尾补 EOS):
EOS = tokenizer.eos_token
alpaca_tpl = """### 指令:
{}
### 输入:
{}
### 回答:
{}"""
def formatting_func(examples):
texts = []
for ins, inp, out in zip(examples["instruction"],
examples["input"], examples["output"]):
texts.append(alpaca_tpl.format(ins, inp, out) + EOS) # 必须补 EOS
return {"text": texts}
ds = ds.map(formatting_func, batched=True)
4.5 packing:短样本提速
packing=True 会把多条短文本拼进一个序列,减少 padding 空转,短样本场景吞吐可显著提升。长样本或需要精确样本边界时设 False。这个开关在第 5 章的 SFTTrainer 里设置。
4.6 划分训练集与验证集
split = ds.train_test_split(test_size=0.05, seed=3407)
train_ds, eval_ds = split["train"], split["test"]
print(len(train_ds), len(eval_ds)) # 训练 / 验证 条数
数据清洗清单
去重、去空 output、过滤超长/超短样本、统一格式、检查是否含个人隐私。清洗一遍常比加数据更能提升效果。
4.7 小结与下一步
- SFT 数据是"问-答"对;质量 > 数量,末尾务必补 EOS。
- Instruct 模型优先用 chat template(
get_chat_template),模板必须与模型匹配。 - Alpaca/ShareGPT 是常见格式;
formatting_func负责拼字段,packing 提升短样本吞吐。 - 下一章配置 SFTTrainer,把数据、模型、超参组装成一次训练任务。