🦙 第1章 大模型的基础理论
📄 一句话概括

一个大模型要过三段训练:预训练学语言,指令微调学听话,偏好学习学分寸。 三段的目标函数不一样,数据形态不一样,成本差着几个数量级。 这一节把三段的损失各算一遍,并且说清楚:本书第 3、5 章做的微调,停在哪一段。

📝 本章和前面几章的关系

41 课 图解深度学习 里有反向传播的推导, 43 课 深度学习入门教室 里有训练循环的写法。 这一节不推公式,只讲三段训练各自「在什么数据上、算哪个位置的损失」。

一、第一段:无监督预训练

目标只有一句话:看着前面的词,猜下一个词。猜错了算交叉熵,反向传播改参数。 它为什么叫「无监督」?因为标签是现成的——下一个词本身就是答案,不需要人来标。 一整本书、一整个网页,每一处都是训练样本。 这就是它能吃下 2 万亿 token 的原因。换成人工标注,同样规模的语料要几百年。

代价在算力。Llama 2 的预训练用了 2 万亿 token,几千张 A100 跑几个月。 这一段的成本,比后面两段加起来还高两个数量级。 这一段的产出叫基座模型。 它会续写,但不会听话——你问它「帮我总结这段」,它可能接着给你编一段「帮我总结这段」的后文, 因为在它的世界里,网页上出现这句话之后,跟的往往还是类似的话。

二、第二段:指令微调

第二段喂的是「提问加回答」的成对数据,让人写标准答案,模型照着学。这叫监督微调,简称 SFT。 关键的一个技术细节是损失屏蔽:提问那一段不算损失,只算回答那一段。 因为提问是用户写的,模型不需要学会生成提问,它只需要学会「接着提问往下答」。 为什么要屏蔽,可以从梯度看:不屏蔽的话,提问段也会回传梯度,模型会被推着去学「怎么提问」。 这在数据量大的时候影响不大,在数据量小的时候会把模型带偏成「自问自答」。

这一段的数据量比预训练小四五个数量级。Llama 2 用了十万条量级的人工标注对话。 2023 年有一篇叫 LIMA 的工作更极端:只用一千条精选数据,效果就相当能打。 这说明这一段拼的不是量,是质。 还有一处容易忽略:多轮对话要拼成一条完整序列,前面的轮次也要进上下文,但只有助手说的话算损失。 第 4 章会专门处理这件事。

三、第三段:基于人类反馈的微调

第二段之后模型会答了,但答得未必合人心意——太啰嗦、太保守、该拒绝的不拒绝。 第三段解决的是「哪个答法更好」,而不是「标准答案是什么」。 做法分两步。先让人对同一个问题的多个回答排序,用这些排序训一个奖励模型,让它学会给回答打分。 再用强化学习(PPO)让模型去最大化这个分数。 直接最大化会出问题:模型会找到奖励模型的漏洞,输出一堆「看起来高分」的废话。 所以加一个 KL 惩罚,约束新模型不要离第二段的结果太远。

2023 年有个更简单的做法叫 DPO:不算奖励模型,直接把「好答案比差答案概率高多少」写成一个损失, 一步优化到位。省掉一整个模型和一轮采样,工程上友好得多。 这一段的成本介于两者之间:数据量比 SFT 还小,但要人做排序,标注更贵; 算力比预训练省得多,但要跑采样,比 SFT 慢。

四、三段之外,还有第四件事

实际工业流程里,三段之后还要做对齐与安全:红队测试、拒答训练、上下文蒸馏。 这些不在本书范围内,但要知道它们存在——开源模型和能上线的模型,差别常常在这一步。 把三段摆在一起,普通开发者能碰的只有第二段。第一段要几千张卡,第三段要人做排序。 所以这本书第 3 章、第 5 章讲的「微调」,全部是第二段,外加以 LoRA 为代表的省显存做法。

五、动手 Demo:三段训练,三种损失,各算一遍

这一节不训模型,只把三段的损失函数各写一遍、各算一遍,看它们的数长什么样。 预训练段用十二个词的序列算逐位交叉熵; 指令微调段对比「整段都算」与「只算答案段」两种算法的参与位置数与平均损失; 偏好学习段用一组构造好的对数概率算 DPO 损失。

# 第一段:每个位置都算交叉熵
for i in range(len(seq) - 1):
    ce = -math.log(softmax(logits[i])[seq[i + 1]])

# 第二段:提问段遮掉,只算答案段
loss_all = mean([ce(i) for i in range(len(ids) - 1)])
loss_ans = mean([ce(i) for i in range(len(prompt), len(ids) - 1)])

# 第三段:DPO,好答案与差答案相对参考模型的优势差
margin = (lp_w - ref_w) - (lp_l - ref_l)
loss = -math.log(1.0 / (1.0 + math.exp(-beta * margin)))

实跑输出:

--------------------------------------------------------------------
三段训练:预训练、指令微调、偏好学习,损失各算一遍
--------------------------------------------------------------------


  ① 预训练:整段都算损失
  --------------------------------------------------------------------
| 看到 | 该预测 | 交叉熵 |
|---|---|---:|
| 客 | 户 | 2.66 |
| 户 | 要 | 2.96 |
| 要 | 求 | 2.64 |
| 求 | 改 | 2.74 |
| 改 | 图 | 2.80 |
| 图 | 纸 | 2.16 |

  11 个位置全算,平均交叉熵 2.633 纳特,困惑度 13.92。
  ! 预训练的数据不需要人标,因为「下一个字」本身就是标签——这就是「无监督」这三个字的实际含义。

  ② 指令微调:只算答案那一段
  --------------------------------------------------------------------
| 算法 | 参与的位置数 | 平均损失 |
|---|---:|---:|
| 整段都算 | 9 | 3.556 |
| 只算答案段 | 4 | 3.447 |

  同一批数据,只算答案段时参与的位置从 9 个降到 4 个。
  这里两组损失差得不多(3.556 对 3.447),因为权重是随机抽的,本来就没学会什么。
  真正的作用不在损失值,在于梯度从哪些位置回传:遮掉提问段,模型就不会被推着去学「怎么提问」。
  ! 为什么要把提问那段遮掉:提问是用户写的,模型不需要学会「生成提问」,
  它只需要学会「接着提问答」。遮掉就是告诉它这一段不记账。

  ③ 偏好学习:比较两个回答
  --------------------------------------------------------------------
| 量 | 当前模型 | 参考模型 |
|---|---:|---:|
| 好答案的对数概率 | -2.10 | -2.30 |
| 差答案的对数概率 | -3.40 | -3.10 |

  相对参考模型的优势差 = 0.500,乘上 beta=0.1 后取 -log sigmoid,损失 0.6685。
  这个损失只关心「好答案比差答案高多少」,不关心好答案的绝对概率。
  ! 所以 RLHF 教的是「哪个答法更好」,不是「标准答案是什么」——前者是排序,后者是抄写。
  这就是它跟指令微调最根本的区别。

  ④ 三段的数据与代价
  --------------------------------------------------------------------
| 阶段 | 数据 | 标注成本 | 算力 |
|---|---|---|---|
| 预训练 | 几万亿 token 的网页与书 | 不需要人标 | 几千张卡跑几个月 |
| 指令微调 | 几万到几百万条问答对 | 要人写答案 | 几张卡跑几小时到几天 |
| 偏好学习 | 几万条「这两个哪个好」 | 要人打分排序 | 比微调更轻,但要先训奖励模型 |

  三段里最贵的是第一段,最便宜的是第三段,但第三段最依赖人。
  ! 本书第 3、5 章要做的微调,都停在第二段——普通人手上没有能跑第一段的机器,也不需要跑第三段。

第一段那张表,每行是「看到某个字、该预测下一个字、扣多少分」。 十一个位置全算,平均交叉熵 2.633 纳特,换成困惑度是 13.92。 词表是十二个词,所以「完全瞎猜」的基准是 12,13.92 说明这个随机初始化的模型还没学到东西。 这一段最该记住的是那句话: 预训练的数据不需要人标,因为「下一个字」本身就是标签。「无监督」这三个字说的不是「没人管」, 是「不用人写答案」。 第二段的两组数字差得不多(3.556 对 3.447),因为权重是随机抽的,本来就没学会什么。 但参与的位置数从 9 个降到 4 个,这个差别是实打实的:梯度只从答案段回传。 为什么要遮提问,从梯度看最清楚。不遮的话,模型会被推着去学「用户会怎么问」; 遮掉之后,它只学「接着这个问题该怎么答」。数据量越小,这个区别越明显。 第三段算出来 0.6685。 这个数本身没有意义,有意义的是它的结构:它只看「好答案比差答案高多少」,相对参考模型算, 所以不关心好答案的绝对概率。这就是 RLHF 与 SFT 最根本的区别——一个学排序,一个学抄写。 最后那张成本表要竖着看:预训练几千张卡跑几个月,指令微调几张卡跑几小时, 偏好学习算力更省但要人做排序。三段里最贵的第一段,恰好是本书碰不到的那一段。

30 秒实验

  1. 把第二段的 prompt 长度从 5 改成 2,看「只算答案段」的参与位置数与平均损失怎么变。 想一想:如果提问占了整条序列的九成,遮掉之后还剩多少训练信号?
  2. 把第三段的 beta 从 0.1 改成 1.0,损失会变成多少? 再想想 beta 调大意味着「更贴近参考模型」还是「更敢偏离」。
  3. 把第一段的词表从 12 扩到 120,重新随机初始化,看平均交叉熵跑到多少。 它跟 log(120) 是什么关系?

常见误区

  1. 以为「无监督预训练」是不需要人参与。 它不需要人标答案,但需要人决定喂什么、洗成什么样——第 1.3 节整节都在讲人在哪里使劲。
  2. 以为 SFT 数据越多越好。 一千条精选能顶十万条凑数,因为这一段学的是「格式与口吻」,不是「知识」。 知识在预训练那一段就进去了。
  3. 以为 RLHF 是「让模型更聪明」。 它不让模型变聪明,它让模型的输出更符合人的偏好——偏好和正确是两件事,一个讨喜但答错的模型, 在偏好分数上可能很高。
自测三问(点开对答案) 1. 为什么指令微调要把提问那一段的损失遮掉? —— 因为提问是用户给的,不是模型该生成的东西。 遮掉之后梯度只从答案段回传,模型学的是「接着问往下答」。 不遮的话,模型会被推着去学「用户会怎么问」,数据量小时会退化成自问自答。 2. KL 惩罚在 RLHF 里管什么? —— 管「别跑太远」。只最大化奖励,模型会去找奖励模型的漏洞,输出看着高分实际没用的东西。 KL 惩罚把新模型拽在 SFT 结果附近,让它在「讨喜」和「还算正常」之间取平衡。 3. 这本书为什么只做第二段的微调? —— 第一段要几千张卡跑几个月,个人和小团队没有;第三段要人做大量排序标注,成本比算力还高。 第二段配 LoRA 之后,一张消费级显卡就能跑, 而且效果对绝大多数「让它按我的格式说话」的需求已经够了。

下一节讲怎么判断训出来的模型到底行不行——评测这件事,比想象中难。

相关笔记