指令微调 — 把「会续写」教成「会听话」
这一章讲三件事: 指令数据从哪来、怎么造(三路来源,以及「用模型造数据」的两个发动机); 数据工程的三条经验(格式、规模、精炼——为什么精挑 9000 条能抵 52000 条); 和每个想动手的人最关心的 LoRA 显存账(108GB 怎么变成 13.6GB)。 主走查: LoRA 的一笔账——8.4M 个低秩(秩是「矩阵里真正独立的成分有多少」, 低秩矩阵能用两个小矩阵的乘积近似表示)参数,凭什么顶替 67 亿个参数的训练。
1. 指令微调在干什么:换数据,不换引擎
第 01 章说过,预训练完的模型像刚毕业的学生——有知识,没上过岗前培训。 指令微调就是那场岗前培训:拿「任务描述 + 输入 + 期望(人希望)输出」格式的数据继续训练, 让模型学会「听懂你要它干什么」1。原书反复强调一个定性:它是解锁而不是注入—— 知识早在预训练时就在那里了,这一步只是把已有的能力「叫醒」成听指令的形式2。
它跟预训练的关系是「同一台引擎,换数据换损失」:优化器、并行方案、混合精度全部沿用第 06 章, 只改两处——数据换成指令格式;损失换成只算输出部分(输入部分的 token 不计分), 这叫序列到序列损失3。批量和学习率都比预训练小几个量级: 预训练批量是百万 token 级,这里 InstructGPT(175B)批量只有 8、学习率 5.03×10⁻⁶; Alpaca(7B)批量 128、学习率 2×10⁻⁵4。多轮对话(一问一答连续多个来回的对话)数据还有个省算力的技巧: 整段对话只跑一遍前向,用掩码让损失只落在每一轮的「回答」上, 不用每轮重算整段历史5。
2. 指令数据三路:各有各的病
原书把指令数据的构造分三路6。三路没有谁能独挑大梁,实战靠混—— 这一节先把三路摆清,§6 的实验会告诉你它们各自补什么。
| 路 | 怎么造 | 代表 | 病 |
|---|---|---|---|
| NLP 任务改写 | 给传统 NLP 数据集(翻译、摘要、分类)的输入输出对加上任务描述 | FLAN v2(约 2000 万条) | 任务面窄,缺「聊天感」 |
| 真人对话 | 真实用户提问 + 人写或模型写的回答 | ShareGPT(用户问 + ChatGPT 答)、OpenAssistant、Dolly | 答案质量参差;ShareGPT 的回答其实是模型写的 |
| 模型合成 | 让大模型自己生成指令与回答,再过滤 | Self-Instruct、Alpaca(52K) | 多样性受种子与教师模型限制 |
第一路有个关键实验:给 NLP 数据集加任务描述后微调,指令遵循能力明显提升; 把任务描述拿掉、只用输入输出对微调,泛化能力显著变差—— 「告诉模型它在干什么」这一步本身就是训练信号的一部分7。 第二路的标杆是 InstructGPT 的做法:收集真实用户向 API 提过的问题, 标注员再补写一批(开放生成、头脑风暴等),另一批标注员手写回答8。 第三路最值得细看,因为它把「造数据」从人海战术变成了流水线——下一节。
3. 合成数据的两个发动机
3.1 Self-Instruct:175 个种子滚出 52K 条
Self-Instruct 的流程是原书图示过的经典流水线9:
人工写 175 个种子任务 ──→ 随机抽几个当示例,让大模型仿造新指令
↑ │
│ ↓
└──────── 过滤后加回任务池 ── 过滤:与池里太像的删、太长太短的删、
模型答不了的删、输入输出重复的删
循环往复,任务池越滚越大。GPT-3 滚出 52K 条;Alpaca 用更强的 text-davinci-003
同样方法滚出 Alpaca-52K(约 40% 的指令带输入)。
图说:人只出了 175 个种子的力气,剩下全是模型生的、机器筛的。
3.2 Evol-Instruct:把简单题演化成难题
Self-Instruct 的毛病是生成的题偏简单、偏同质。WizardLM 的 Evol-Instruct 加了一道「演化」: 拿已有指令让模型改写得更难——深度演化五招(加约束、深化问题、具体化、加推理步骤、复杂化输入), 广度演化一路(换个更冷门的主题);改完再由模型作答,形成新的难数据10。 后处理同样靠模型:让 ChatGPT 对比演化前后,改动太小的删;答出「sorry」的删; 标点连词过多的删11。这套「深度+广度」的双轴演化后来扩展到数学(WizardMath)和代码(WizardCoder)12。
4. 关键因素:格式、规模、精炼
原书把「什么样的指令数据算好」拆成三个因素,每个都有实验数字13:
格式。 任务描述要留(§2 的实验);带不带示例混着训更好——FLAN-T5 把 「带示例」与「不带示例」的指令数据混训,两种场景下都涨;掺入思维链数据能 额外提升推理。 但不是塞得越多越好:往指令里加「避免事项、理由、建议」这类看似贴心的内容, 可能反而有害14。
规模。 FLAN-T5 的剂量实验:指令数据从 0.18M 加到 17.26M 条,性能一路涨, 但过 7.2M 条之后明显放缓——堆量有天花板15。另一个极端是「少而精」: LIMA 只用 1000 条人工精选数据微调 65B 模型,对话测试就拿到了满意成绩; Alpaca 的 52K 条合成数据,让 7B 模型在对话评测上逼近 text-davinci-00316。 两件事并起来读:数量决定下限的上限,质量决定效率。
精炼。 既然堆量放缓,能不能挑?Alpagasus 用 GPT-4 给 Alpaca 的 52K 条打分, 只留分数最高的 9000 条,微调效果与用全部 52K 条相当17。 作者团队的 YuLan 用困惑度给指令测难度,太简单和太难的都扔 (过拟合与训练不稳多由它们引起);又用知乎的 293 个话题标签改写指令,把多样性铺满18。
5. 训练策略:数据怎么排兵布阵
混合三路数据时有两条实战纪律。其一,给每个数据源设上限: FLAN v2 的最终配比是 FLAN 46%、T0 27.9%、NIV2 24.2%、思维链 1.8%, 各源上限 30K/20K/5K/100K 条——防止大源淹没小源19。 其二,分阶段:YuLan 先用大规模 NLP 任务数据打底,再用对话与合成数据教聊天; 第二阶段要掺一部分 NLP 数据,否则会发生灾难性遗忘——学了新的、忘了旧的, 这是神经网络续训的常见病20。 还有一个模糊地带的做法:把指令数据提前掺进预训练(GLM-130B 掺了约 5%; MiniCPM 在预训练与微调之间加一道「退火」工序混训)——01 章两阶段流水线的边界, 在实践中本来就是相互渗透的21。
6. LoRA 主走查:108GB 怎么变成 13.6GB
全参数微调的显存账第 06 章算过:16P 字节,7B 模型就是 107,814,649,856 字节 ≈ 108GB—— 一张 80GB 的卡都装不下。LoRA(低秩适配)是绕开这笔账的主流办法, 它的出发点是一个研究发现:模型适配具体任务时,参数的更新量其实「虚胖」—— 那个巨大的更新矩阵可以用低秩结构近似:数学上,一个 H×H 的更新矩阵 ΔW, 能被两个瘦长矩阵的乘积 A·Bᵀ 逼近(A 是 H×R、B 是 H×R,R 远小于 H, R 就是秩)22。
LoRA 的做法:冻结原来的参数矩阵 W0(一个字都不动,冻结=不参与训练、不更新), 只训练旁边外挂的 A 和 B;前向计算变成 h = W0·x + A·Bᵀ·x; 训练完把 A·Bᵀ 合并回 W0,推理时没有任何额外开销23。
显存账(全是书里的真数,LLaMA-7B:L=32,H=4096,取 R=8):
要训的参数:P_LoRA = 8LHR(只挂在注意力四个矩阵上)
= 8 × 32 × 4096 × 8 = 8,388,608 ≈ 8.4M
—— 是全模型 67 亿参数的约 0.12%
显存 = 冻结部分(只存不训):2P(16 位存参数)
+ 可训部分:2P_LoRA(参数) + 14P_LoRA(梯度+优化器状态)
= 2P + 16P_LoRA
= 13,611,048,960 字节 ≈ 13.6GB
对照:全参数 16P = 108GB。108 → 13.6,省了约 87%。
图说:108GB 是「全模型参数+梯度+优化器都要存」;
13.6GB 是「全模型只存不训 + 8.4M 个小参数的全套训练状态」。
变体两个,各补一刀:AdaLoRA 不再所有矩阵用同一个秩, 按各矩阵对训练损失的重要性动态分配——重要的多给秩,不重要的少给24; QLoRA 把冻结的底座再压到 4 位存储(量化,第 11 章细讲)、低秩部分保持 16 位, 显存从 LoRA 的约 2P 再降到 0.5P——65B 模型一张 48GB 的 A6000 就能微调25。
LoRA 之外还有三类参数高效微调,在大模型上用得较少,原书只作简介: 适配器(在层与层之间串一个「先压扁再还原」的小网络,只训它)、 前缀微调(给每层的 key/value 拼一段 10~100 个虚拟 token 的可训练前缀)、 提示微调(只在输入嵌入层加可训练向量)——三者都冻结原模型,差别在外挂的位置26。
7. 本书自做实验:哪种数据补哪种能力
原书 7.4 节是作者团队的实证专场,三组实验都用 LLaMA 系、Alpaca 系设置,数字全部可核27。
第一组:全参数微调要几张卡(表 7.1)。 Alpaca 52K 条、训 3 遍、上下文 512, 开 ZeRO-3+bfloat16+激活重算:7B = 2 卡 3.0 小时;13B = 4 卡 3.1 小时; 33B = 8 卡 6.1 小时;65B = 16 卡 11.2 小时(A800-80G)。 ——对照第 01 章那句「一台 8 卡服务器几天能做完」,这里把「几天」精确到了小时。
第二组:数据类型决定能力(表 7.2,本章最该记住的一张表)。 用三种数据分别微调 LLaMA-2,评测两路:对话(AlpacaFarm,与 text-davinci-003 比胜率,50% = 打平) 与 NLP 任务(MMLU/BBH)28:
| 数据(7B) | 对话胜率 | MMLU | BBH |
|---|---|---|---|
| FLAN v2(NLP 改写) | 12.38 | 50.25 | 40.63 |
| ShareGPT(真人对话) | 55.53 | 49.66 | 35.91 |
| Alpaca(合成) | 46.58 | 46.48 | 36.25 |
| Alpaca + 复杂度/多样性 | 52.92 | ≈47 | ≈36 |
读法:数据格式越像下游任务,效果越好——FLAN v2 在 NLP 任务上最强, 对话上却惨败(12.38,意味着九成对局输给了对照模型);ShareGPT 恰好反过来。 把 Alpaca 加复杂度、加多样性,对话胜率从 46.58 提到 52.92,逼近 ShareGPT; 13B 上多样性版从 48.51 提到 58.2029。同一数据下 13B 全面胜 7B (BBH 用 FLAN 从 40.63 到 45.47)——底座的规模仍然兜底30。
第三组:LoRA 的资源账(表 7.3)。 同样的 Alpaca 微调换 LoRA(R=16): 卡数从 2/4/8/16 降到 1/1/1/2;但 33B 和 65B 上,光冻结的参数就把显存占满, 批量只能开 1,训练时间反而拉长(33B 要 10.2 小时,全参数只要 6.1)—— LoRA 省的是显存,不一定省时间31。
判断(我们的,不是书里的): 表 7.2 是全书「数据决定论」最硬的一块证据—— 它和第 03 章「变体差在数据不在 结构」、第 04 章 YuLan 配比实验说的是同一件事: 这个时代的模型工程,很大程度上是数据工程。 指令微调阶段的「配方玄学」 (混多少、怎么挑),其实都能像作者这样用对照实验算清楚。 如果错,会错在: 表 7.2 的结论是「LLaMA-2 + 2023 年数据生态」下的快照; 如果将来底座模型在预训练里就吃饱了对话数据,三类数据的边际差异可能缩小—— 但「数据格式要匹配下游任务」这条原则本身,至今没有反例。
8. 作者的判断与证据
- 自家实验(最硬): 表 7.1~7.3 全部来自作者团队的实跑27; YuLan 的困惑度挑数据、293 话题改写、多阶段策略来自他们自己的模型训练1820。
- 有论文的他人实验: FLAN-T5 的 7.2M 放缓15、Alpagasus 的 9000≈52K17、 LIMA 的 1000 条16、LoRA 的低秩假设与显存公式2223,均有原论文。
- 作者的工程判断: 「先 NLP 后对话的多阶段」「第二阶段掺 NLP 防遗忘」 「指令里塞建议可能有害」是作者基于文献与自家经验的建议,不是单一实验结论1420。
9. 边界与局限
- 表 7.2 的评测口径里,对话胜率由 ChatGPT 自动评判——模型判官有偏好(第 15 章展开), 绝对分值会随判官而变,相对排序更可信。
- 「9000 条抵 52K」依赖 GPT-4 当裁判挑数据;裁判的口味会渗进被选中的数据。
- LoRA 的低秩假设在「需要大量新知识注入」的场景(如全新领域)可能不够—— 那本来也不是指令微调该干的活(第 01 章:它是解锁不是注入)。
- 指令合成高度依赖教师模型;教师没有的能力(比如更新的知识),合成数据也教不会。
10. 可带走的
- 指令微调 = 预训练引擎 + 指令数据 + 只算输出的损失;批量与学习率比预训练小几个量级;
- 指令数据三路:NLP 改写(保任务正确率)、真人对话(给聊天感)、模型合成(补多样性)——实战靠混,各源设上限;
- 任务描述本身是训练信号:拿掉它,泛化显著变差;
- Self-Instruct:175 个种子 → 模型仿造 → 过滤回池 → 52K;Evol-Instruct 负责把简单题演化难;
- 规模曲线:7.2M 条后收益放缓;精挑 9000 条可抵 52K 条——质量决定效率;
- 多阶段训练:先 NLP 打底再教对话,第二阶段掺旧数据防灾难性遗忘;
- LoRA:冻结底座,只训低秩外挂;LLaMA-7B 显存 108GB → 13.6GB,可训参数仅 8.4M(0.12%),训完合并零推理开销;
- QLoRA 再砍一刀:底座 4 位存储,0.5P 显存,65B 单卡可微调;
- 表 7.2 的读法:数据格式越像下游任务效果越好;没有一种数据能补全所有能力;
- LoRA 省显存不省时间:大模型上批量被压到 1,33B 反而比全参数慢。
11. 原文地图
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| 指令实例三要素 | 7.1 | text/33-ch07-01-7-1-construction-of-instruction-datasets.txt:3(搜「task description」) |
| NLP 改写与任务描述实验 | 7.1.1 | text/33-ch07-01-7-1-construction-of-instruction-datasets.txt:13(搜「significantly diminished」) |
| FLAN v2 约 20M | 7.1.1 | text/33-ch07-01-7-1-construction-of-instruction-datasets.txt:15(搜「20M instruction instances」) |
| InstructGPT 与 ShareGPT | 7.1.2 | text/33-ch07-01-7-1-construction-of-instruction-datasets.txt:19(搜「queries submitted by users」) · text/33-ch07-01-7-1-construction-of-instruction-datasets.txt:21(搜「ShareGPT」) |
| Self-Instruct 流程与 175 种子 | 7.1.3 | text/33-ch07-01-7-1-construction-of-instruction-datasets.txt:47(搜「175 high-quality」) · text/33-ch07-01-7-1-construction-of-instruction-datasets.txt:77(搜「text-da vinci-003」) |
| Evol-Instruct 双轴 | 7.1.3 | text/33-ch07-01-7-1-construction-of-instruction-datasets.txt:107(搜「in-depth evolution and in-breadth evolution」) · text/33-ch07-01-7-1-construction-of-instruction-datasets.txt:131(搜「minimal differences」) |
| 格式:混训与「塞建议有害」 | 7.1.4 | text/33-ch07-01-7-1-construction-of-instruction-datasets.txt:141(搜「mixed prompting training」) · text/33-ch07-01-7-1-construction-of-instruction-datasets.txt:145(搜「adverse effects」) |
| 规模:7.2M 放缓/LIMA/Orca | 7.1.4 | text/33-ch07-01-7-1-construction-of-instruction-datasets.txt:149(搜「7.2M」) · text/33-ch07-01-7-1-construction-of-instruction-datasets.txt:151(搜「a thousand high-quality」) · text/33-ch07-01-7-1-construction-of-instruction-datasets.txt:153(搜「five million」) |
| 精炼:Alpagasus 与 YuLan | 7.1.4 | text/33-ch07-01-7-1-construction-of-instruction-datasets.txt:159(搜「9000 top-scoring」) · text/33-ch07-01-7-1-construction-of-instruction-datasets.txt:157(搜「293 commonly used topic labels」) |
| 指令微调效果三层面 | 7.1.5 | text/33-ch07-01-7-1-construction-of-instruction-datasets.txt:171(搜「77M to 540B」) · text/33-ch07-01-7-1-construction-of-instruction-datasets.txt:175(搜「50% performance improvement」) |
| seq2seq 损失与超参 | 7.2.1 | text/34-ch07-02-7-2-instruction-tuning-strategies.txt:9(搜「sequence-to-sequence loss」) · text/34-ch07-02-7-2-instruction-tuning-strategies.txt:11(搜「5.03」) |
| 多轮掩码 | 7.2.1 | text/34-ch07-02-7-2-instruction-tuning-strategies.txt:13(搜「masking mechanism」) |
| 混配比与上限 | 7.2.2 | text/34-ch07-02-7-2-instruction-tuning-strategies.txt:23(搜「46%」) |
| 多阶段与防遗忘 | 7.2.2 | text/34-ch07-02-7-2-instruction-tuning-strategies.txt:27(搜「catastrophic forgetting」) |
| 预训练掺指令 | 7.2.2 | text/34-ch07-02-7-2-instruction-tuning-strategies.txt:31(搜「approximately 5%」) |
| LoRA 低秩原理 | 7.3.1 | text/35-ch07-03-7-3-parameter-efficient-fine-tuning.txt:13(搜「intrinsic rank」) · text/35-ch07-03-7-3-parameter-efficient-fine-tuning.txt:17(搜「freeze the original matrix」) |
| LoRA 显存账 108→14GB | 7.3.1 | text/35-ch07-03-7-3-parameter-efficient-fine-tuning.txt:29(搜「8, 388, 608」) |
| AdaLoRA 与 QLoRA | 7.3.1 | text/35-ch07-03-7-3-parameter-efficient-fine-tuning.txt:33(搜「dynamic low-rank」) · text/35-ch07-03-7-3-parameter-efficient-fine-tuning.txt:35(搜「single A6000」) |
| 其他 PEFT 三法 | 7.3.2 | text/35-ch07-03-7-3-parameter-efficient-fine-tuning.txt:47(搜「bottleneck network」) · text/35-ch07-03-7-3-parameter-efficient-fine-tuning.txt:61(搜「10 and 100」) |
| 表 7.1 全参数资源 | 7.4.1 | text/36-ch07-04-7-4-code-practice-and-empirical-analysis.txt:11(搜「Table 7.1」) |
| 表 7.2 数据对照 | 7.4.2 | text/36-ch07-04-7-4-code-practice-and-empirical-analysis.txt:85(搜「Table 7.2」) · text/36-ch07-04-7-4-code-practice-and-empirical-analysis.txt:207(搜「closely resembles downstream task formats」) |
| 表 7.3 LoRA 资源 | 7.4.3 | text/36-ch07-04-7-4-code-practice-and-empirical-analysis.txt:231(搜「Table 7.3」) · text/36-ch07-04-7-4-code-practice-and-empirical-analysis.txt:273(搜「batch size to 1」) |