跳到主要内容

分类微调 — 把会续写的 GPT 改成垃圾短信分类器

这一章讲一件事: 拿第 07 章搬好权重的预训练 GPT,改造成一个只能回答 「垃圾 / 不垃圾」的分类器——全过程:换输出头、冻主干、训 5 轮、看准确率。 这是全书「阶段 3」的第一种微调,也是理解「为什么预训练值钱」的最好例子: 改动不到 1% 的参数,就换来一个 95% 准确率的专用工具。

1. 这一章讲什么

第 01 章说过微调有两类:分类微调和指令微调。这一章做前者。 选的例子是垃圾短信识别——书里的理由很实在:数据集小、任务直观、笔记本几分钟训完1。 但重点不在短信,在手法:「一台只会续写的机器,怎么变成一台只做判断的机器」, 这套手法对任何分类任务通用。

2. 顶层全景

手术前后对比:

手术前(预训练 GPT):输入一条文本 → 每个位置输出 50,257 维 logits → 管「下一个词是什么」
手术后(分类器): 输入一条短信 → 只看最后一个位置的输出 → 2 维 → 管「是不是垃圾」

手术内容:
① 数据:5,572 条短信 → 下采样到 747/747 → 70%/10%/20% 切三份
② 换头:out_head 从 768→50,257 换成 768→2
③ 冻结:主干全部设 requires_grad=False,只留新头 + 最后一个块 + 最终归一化可训
④ 训练:同一个交叉熵、同一个 AdamW,只是损失只算最后一个位置
⑤ 评估:准确率 = 猜对的比例

图说:模型的 99% 原封不动;「分类能力」是预训练白送的,微调只是给它接上一个出口。

3. 核心原理

3.1 先分清两类微调,以及各自的价码

第 01 章给过名字,这里给实感。指令微调:训练数据是「指令+期望(人希望它给出的)回答」对, 成品模型能按各种指令办事——灵,但数据要得多、算力要得多。 分类微调:训练数据是「文本+类别」对,成品只能输出训练时见过的那几个类—— 死板,但便宜得多2

书里给的选择标准很直白:要「按各种自然语言指令干活」选前者; 要「把东西精确分进预定类别」(情感分析——判断一段文字是夸还是骂——、垃圾识别)选后者。 专才比通才好造,这是第一个判断3

还有一个先行实验给微调的必要性定了性:书让没微调过的预训练模型直接回答 「这条是不是垃圾?答 yes 或 no」——它根本不理指令,只是把问题续写了一遍。 只会续写 ≠ 会办事,这就是微调存在的理由4

3.2 数据:5,572 条短信里的三门课

数据集是 UCI 的 SMS Spam Collection,5,572 条手机短信,各带 ham(正常)/ spam(垃圾)标签5。 第一课是类别不平衡:正常短信 4,825 条,垃圾只有 747 条——直接训, 模型学会的最优策略是「永远答正常」,准确率 86% 还没用。 书里的处理是下采样:从 4,825 条正常里随机抽 747 条,凑成 747/747 的平衡集6。 代价明说:丢掉了四千多条数据;书里注明还有其他处理不平衡的办法,超出范围7

第二课是不等长。批处理要求一批样本一样长,短信却长短不一。 两条路:全部截到最短(丢内容),或全部补到最长(第 02 章的 PAD 出场: 拿 <|endoftext|> 的 ID 50256 补位)。选补长,因为「截到最短」可能把信息砍光8。 这个数据集里最长的短信编码后是 120 个词元——离模型 1,024 的上限还很远9

第三课是切三份:70% 训练、10% 验证、20% 测试。 验证集用来反复调超参,测试集只在最后摸一次——摸多了,测试集也会变成另一种训练集10。 最终得到 130 个训练批、19 个验证批、38 个测试批(批大小 8)11

3.3 主走查:一条短信的完整旅程

现在跟一条真实短信走完全程。"You are a winner you have been specially selected to receive $1000 cash or a $2000 award."——训练集里的典型垃圾短信。

第一步,编码与补位。 分词器编成一串词元 ID,尾部补 50256 凑够 120 个; 标签 spam → 112

第二步,过模型。 结构和预训练一模一样,只有最后一层换了: 原来是 768→50,257 的输出头(每个位置猜下一个词), 现在是 768→2 的小线性层(每个位置只有两个数)。为什么是 2 不是 1? 二分类(只分「是/否」两类的任务)用一个输出节点也能做,但要换损失函数(训练时算「差多远」的那把尺子的具体公式);两个节点配同一个交叉熵, 还能原样推广到三类、十类13

第三步,只看最后一个位置。 模型照旧给 120 个位置各吐一行 2 维输出, 但只用第 120 行。为什么偏偏是最后?回到第 04 章的因果掩码: 每个词元只许看自己及之前——于是最后一个词元是唯一一个「看全了整条短信」的位置, 它的输出行信息最全14。这个「只看最后」的技巧,是因果架构送给分类任务的礼物。

第四步,出标签。 两个数谁大就是谁;argmax 直接作用在 logits 上, 连 softmax 都省(第 05 章的单调性结论)15。微调前, 这一步对训练集的准确率是 46.25%——还不如抛硬币(二分类瞎猜是 50%)—— 因为新换的输出头还是随机权重16

3.4 微调:换的不是循环,是「算什么、看什么」

训练函数和预训练几乎是同一份代码,只有三处不同17:

  • 损失只算最后一个位置:model(input)[:, -1, :] 喂给交叉熵; 其余 119 个位置的输出不参与——它们没有「该输出什么」的答案;
  • 评估换成准确率:分类正确数 ÷ 总数;但准确率不可导(没法拿它算梯度), 所以训练时优化的仍是交叉熵——拿一个可导的尺子当代理,去顶一个不可导的目标18;
  • 冻结:先把全模型设成不可训,再单独放开新输出头、最后一个 transformer 块、 最终层归一化。作者明说:只训新头理论上够,但他实验发现多放开一层效果明显更好19。 「冻结」(freeze)就是把参数的 requires_grad 设成 False,反向传播不再更新它们。

真实配置与结果:AdamW、lr=5e-5、5 轮,M3 MacBook Air 约 6 分钟,V100/A100 上半分钟20。 日志的真实读数:第 1 轮训练准确率 70%,第 3 轮 90%,第 4 轮 100%; 最终全量评估:训练 97.21% / 验证 97.32% / 测试 95.67%21

这三个数的读法也是一课:三者接近 = 几乎没过拟合(对照第 06 章的 0.39/6.45 鸿沟); 验证略高于测试很常见——超参本来就是照着验证集调的,它天然占了点便宜22

4. 作者的判断与证据

有证据的: 数据集构成、补位到 120、46.25% 的起点、5 轮日志、97.21/97.32/95.67 的终评—— 全部是书里印的真实运行结果591621

作者的判断:

  • 「只训最后一层往往就够,因为低层学到的是通用语言结构」——经验规律,书里指向附录 B 的实验文献23
  • 「多放开最后一个块效果更好」——作者自己的实验结论,性质是经验之谈19
  • 下采样只是众多处理不平衡的手段之一,书里选它是因为简单7

判断(我们的,不是书里的): 这一章最重要的数字不是 95.67%,而是 46.25% → 97% 的跳跃 只动了模型约 1% 的参数。它实证了第 01 章讲的两段式分工——通用能力在预训练里,微调只做适配 (这是复述,01 章的原话是「预训练出基座,再微调成工具」)—— 语言理解已经在主干里,微调只是接出口。这就是「基座模型」商业模式的全部技术基础。 如果错,会错在: 如果任务和预训练分布差得太远(比如让它读心电图), 「只动 1%」就不够了,要放开更多层甚至从头训——第 09 章换 355M 模型就是一个预演。

5. 边界与局限

  • 平衡数据集是教学化处理;真实垃圾检测面对的就是 86:14 的不平衡, 工程上更常用加权损失或阈值(判定线上那个数:输出分超过它才判「垃圾」)调整,书里明说超范围7

  • 「只看最后一个词元」依赖因果掩码;换双向架构(如 BERT)就不是这个做法。

  • 95.67% 是这个小而干净的数据集上的成绩,不能外推(把这里的成绩当成别处的保证)到真实邮件网关。

  • 模型只输出「是/否」,不会解释理由;要可解释性得另想办法,不在本书。

6. 可带走的

  1. 分类微调 = 换输出头 + 冻结主干 + 只算最后一个位置的损失;手术量约 1% 的参数。

  2. 为什么只动 1% 就够:预训练已经把语言学完了,微调只接出口。

  3. 「只看最后一个词元」不是任意选择:因果掩码下只有它看全了输入。

  4. 类别不平衡要先处理;下采样最简单,代价是丢数据。

  5. 准确率不可导,拿交叉熵当代理去优化——「优化的目标」和报告的指标(最后拿给人看的那个数,这里是准确率)可以是两把尺。

  6. 三份数据的纪律:训练调参、验证调超参、测试只摸一次。

  7. 微调前后各量一次基线(46% vs 97%),没有基线的准确率没有意义。

  8. 冻结用 requires_grad=False;作者的经验:新头 + 最后一块 + 最终归一化是个甜点。

7. 原文地图

主题原书章原文位置
两类微调与价码6 Fine-tuning for classificationtext/14-ch06-6-fine-tuning-for-classification.txt:47(搜「most common ways to fine-tune language models」) · text/14-ch06-6-fine-tuning-for-classification.txt:105(搜「Choosing the right approach」)
未微调模型不听指令同上text/14-ch06-6-fine-tuning-for-classification.txt:674(搜「struggling to follow instructions」)
数据集与下采样同上text/14-ch06-6-fine-tuning-for-classification.txt:214(搜「4825」) · text/14-ch06-6-fine-tuning-for-classification.txt:219(搜「undersample」)
补位与 120 词元同上text/14-ch06-6-fine-tuning-for-classification.txt:307(搜「Pad all messages」) · text/14-ch06-6-fine-tuning-for-classification.txt:431(搜「120」)
换头与为什么两个节点同上text/14-ch06-6-fine-tuning-for-classification.txt:686(搜「single output node」)
只看最后词元同上text/14-ch06-6-fine-tuning-for-classification.txt:987(搜「the only token with access to data from all the」)
冻结与放开最后一块同上text/14-ch06-6-fine-tuning-for-classification.txt:783(搜「freeze」) · text/14-ch06-6-fine-tuning-for-classification.txt:808(搜「ably improve the predictive performance」)
准确率当代理与初始 46%同上text/14-ch06-6-fine-tuning-for-classification.txt:1142(搜「46.25%」) · text/14-ch06-6-fine-tuning-for-classification.txt:1151(搜「not a differentiable function」)
5 轮日志与终评同上text/14-ch06-6-fine-tuning-for-classification.txt:1350(搜「70.00%」) · text/14-ch06-6-fine-tuning-for-classification.txt:1468(搜「97.21%」)

Footnotes

  1. 出处:「6 Fine-tuning for classification」第 119 段(text/14-ch06-6-fine-tuning-for-classification.txt:119,搜「intuitive and useful example」)。

  2. 出处:「6 Fine-tuning for classification」第 105 段(text/14-ch06-6-fine-tuning-for-classification.txt:105,搜「Choosing the right approach」)。

  3. 出处:「6 Fine-tuning for classification」第 102 段(text/14-ch06-6-fine-tuning-for-classification.txt:102,搜「highly specialized」)。

  4. 出处:「6 Fine-tuning for classification」第 674 段(text/14-ch06-6-fine-tuning-for-classification.txt:674,搜「struggling to follow instructions」)。

  5. 出处:「6 Fine-tuning for classification」第 204 段(text/14-ch06-6-fine-tuning-for-classification.txt:204,搜「5,572」)。 2

  6. 出处:「6 Fine-tuning for classification」第 219 段(text/14-ch06-6-fine-tuning-for-classification.txt:219,搜「undersample」)。

  7. 出处:「6 Fine-tuning for classification」第 223 段(text/14-ch06-6-fine-tuning-for-classification.txt:223,搜「beyond the scope of this book」)。 2 3

  8. 出处:「6 Fine-tuning for classification」第 306 段(text/14-ch06-6-fine-tuning-for-classification.txt:306,搜「Truncate all messages」)。

  9. 出处:「6 Fine-tuning for classification」第 432 段(text/14-ch06-6-fine-tuning-for-classification.txt:432,搜「120 tokens」)。 2

  10. 出处:「6 Fine-tuning for classification」第 264 段(text/14-ch06-6-fine-tuning-for-classification.txt:264,搜「70%」)。

  11. 出处:「6 Fine-tuning for classification」第 555 段(text/14-ch06-6-fine-tuning-for-classification.txt:555,搜「130 training batches」)。

  12. 出处:「6 Fine-tuning for classification」第 330 段(text/14-ch06-6-fine-tuning-for-classification.txt:330,搜「1212, 318, 262」)。

  13. 出处:「6 Fine-tuning for classification」第 686 段(text/14-ch06-6-fine-tuning-for-classification.txt:686,搜「single output node」)。

  14. 出处:「6 Fine-tuning for classification」第 987 段(text/14-ch06-6-fine-tuning-for-classification.txt:987,搜「the only token with access to data from all the」)。 原文:「the last token in a sequence accumulates the most information since it is the only token with access to data from all the previous tokens」。

  15. 出处:「6 Fine-tuning for classification」第 1074 段(text/14-ch06-6-fine-tuning-for-classification.txt:1074,搜「softmax function here is optional」)。

  16. 出处:「6 Fine-tuning for classification」第 1142 段(text/14-ch06-6-fine-tuning-for-classification.txt:1142,搜「46.25%」)。 2

  17. 出处:「6 Fine-tuning for classification」第 1253 段(text/14-ch06-6-fine-tuning-for-classification.txt:1253,搜「train_model_simple function used for pretraining the model」)。

  18. 出处:「6 Fine-tuning for classification」第 1151 段(text/14-ch06-6-fine-tuning-for-classification.txt:1151,搜「not a differentiable function」)。

  19. 出处:「6 Fine-tuning for classification」第 808 段(text/14-ch06-6-fine-tuning-for-classification.txt:808,搜「ably improve the predictive performance」)。 2

  20. 出处:「6 Fine-tuning for classification」第 1324 段(text/14-ch06-6-fine-tuning-for-classification.txt:1324,搜「minutes on an M3 MacBook Air laptop computer」)。

  21. 出处:「6 Fine-tuning for classification」第 1350 段(text/14-ch06-6-fine-tuning-for-classification.txt:1350,搜「70.00%」)与第 1468 段(text/14-ch06-6-fine-tuning-for-classification.txt:1468,搜「97.21%」)。 2

  22. 出处:「6 Fine-tuning for classification」第 1474 段(text/14-ch06-6-fine-tuning-for-classification.txt:1474,搜「somewhat higher than the test set」)。

  23. 出处:「6 Fine-tuning for classification」第 776 段(text/14-ch06-6-fine-tuning-for-classification.txt:776,搜「lower layers generally capture」)。