Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

6.1 大语言模型:从自监督预训练到对齐

第 2 讲已经把 Transformer 讲清楚了:一堆自注意力块,喂进一段 token 序列,输出每个位置上的下一个 token 分布。大语言模型(large language model, LLM)后来做的事,说穿了简单到令人怀疑——把这个结构放到极致地大、喂进人类能收集到的大部分文本,然后只学一件事:预测下一个 token。

本节要回答四个问题:这件简单的事凭什么能学出语法、事实与推理痕迹(6.1.1–6.1.2)?一段文本怎样变成模型眼里的 token(6.1.3)?数据从哪来、怎么洗(6.1.4)?「续写器」怎样变成一个你会去用的助手(6.1.5–6.1.6)?最后两小节处理两个在工程里最容易被低估的约束:上下文窗口与推理成本(6.1.7)。

6.1.1 自监督语言建模与困惑度

定义 6.1.1 · 自监督语言建模(next-token prediction)

给定一段文本 x=(x1,…,xT)\boldsymbol x=(x_1,\dots,x_T),每个 xtx_t 取自词表 V\mathcal V(∣V∣=V|\mathcal V|=V)。自回归语言模型把序列的联合概率按链式法则分解为

pθ(x)=∏t=1Tpθ(xt∣x<t),p_\theta(\boldsymbol x)=\prod_{t=1}^{T}p_\theta(x_t\mid x_{\lt t}),

训练目标是平均负对数似然(就是第 1 讲的交叉熵,在词表上做 softmax):

L(θ)=−1T∑t=1Tlog⁡pθ(xt∣x<t).\mathcal L(\theta)=-\frac1T\sum_{t=1}^{T}\log p_\theta(x_t\mid x_{\lt t}).

关键在于监督信号来自数据本身:第 tt 个位置的标签就是文本中真实出现的第 tt 个 token。因此任何一段网页、书籍、代码、对话记录都能变成训练样本,不需要任何人工标注——这就是「自监督(self-supervised)」的含义。

预测下一个 token 为什么能学到这么多

「下一个词预测」听起来太简单,凭什么能学出语法、事实甚至解题?一个直观是:要稳定压低整段文本的困惑度,模型不能只记表层词频,它必须隐式学到「谁和谁共现」「什么事实为真」「什么推理成立」——否则在长尾词、长距离依赖与稀有句式上立刻付代价。用一句话概括这条路线的信念:好的概率预测 = 好的压缩 = 好的理解。

必须诚实:这只是一种解释。模型内部到底「学到」了什么、有没有类似人类的语义结构,仍是开放问题,证据有限;而「压缩即理解」这个等式本身在文献里也仍有争论(见 6.2.3 对合成数据与数据墙的讨论)。不要把它当定理用。

定义 6.1.2 · 困惑度(perplexity, PPL)

对一个长度为 TT 的序列,模型在该序列上的困惑度定义为平均负对数似然的指数:

PPL=exp⁡(−1T∑t=1Tlog⁡pθ(xt∣x<t))=exp⁡(L).\mathrm{PPL}=\exp\Bigl(-\frac1T\sum_{t=1}^{T}\log p_\theta(x_t\mid x_{\lt t})\Bigr)=\exp(\mathcal L).

它可读作「模型在每一步平均在多少个等可能的 token 之间犹豫」:PPL=1\mathrm{PPL}=1 表示完全确定且全对;PPL=V\mathrm{PPL}=V 表示与在词表上均匀乱猜无异。

困惑度为什么常被误读

两个陷阱同时存在。其一,PPL 是逐 token 平均的,长文本里大量高度可预测的功能词会把平均值压得很低,因此「PPL 很低」完全可能与「关键事实说错」共存。其二,PPL 只在同一 tokenizer、同一语料上可比:换了分词方式,TT 都变了,两个数字放在一起没有意义。所以当有人用「我们的模型 PPL 更低」论证更强时,先问三件事:分词器是否一致?评测集是否与训练集去重?是逐 token 还是逐字节平均?(最后一条见 6.1.3 的「每字节比特数」讨论。)

命题 6.1.1 · 交叉熵、困惑度与最优压缩长度

设测试序列的真实分布为 pp、模型分布为 qq。用最优算术编码器(arithmetic coding)以 qq 为模型压缩该序列,所需的期望码长(以比特计)为

Ep[−log⁡2q(x)]=H(p)+DKL(p∥q)  比特,\mathbb E_{p}\bigl[-\log_2 q(\boldsymbol x)\bigr]=H(p)+D_{\mathrm{KL}}(p\lVert q)\ \ \text{比特},

其中 H(p)H(p) 是序列的香农熵。因此:① 最小化交叉熵 == 最小化以模型为编码器的压缩长度;② PPL=2H2(q)\mathrm{PPL}=2^{H_2(q)}(以 2 为底时),困惑度正是「平均每 token 用多少个比特」的指数形式。

推导(两步,可跳)

(i) 最优码长期望长度。 对符号分布 qq,前缀码的平均码长下界由香农信源编码定理给出为 H(q)H(q);算术编码在长块上可逼近到 H(q)+2nH(q)+\frac{2}{n} 以内(nn 为块长),因此工程上常把 −q-q 的对数当码长直接使用。

(ii) 换测度产生的额外长度。 设实际信源是 pp,而我们按 qq 分配码长 −log⁡2q(x)-\log_2 q(\boldsymbol x),则期望长度

Ep[−log⁡2q]=Ep[−log⁡2p−log⁡2qp]=H(p)+DKL(p∥q).\mathbb E_p\bigl[-\log_2 q\bigr]=\mathbb E_p\Bigl[-\log_2 p-\log_2\frac{q}{p}\Bigr]=H(p)+D_{\mathrm{KL}}(p\lVert q).

由于 DKL≥0D_{\mathrm{KL}}\ge0(Jensen 不等式),且当且仅当 q=pq=p 时取等,故以 qq 编码的平均代价在任何情况下都不低于真实熵,多出来的部分恰好是模型与真实分布之间的 KL。■\blacksquare

∎
这条命题真正买到了什么

它把「训练语言模型」和「压缩数据」在数学上焊在一起:你在最小化的那个交叉熵,字面上就是压缩码长的期望。这解释了几件事:① 为什么「更好的语言模型 = 更短的压缩」这个直觉不是修辞;② 为什么数据里重复内容(6.1.4)会让损失虚低——重复的文本可压缩性极高,模型学「复读」就能降损失;③ 为什么换 tokenizer 后 PPL 不可比——分子分母都换了尺子。但它不解释为什么压缩到极致会产生「能解题」的系统,这条推论仍然只是假设。

例 6.1.1 · 手算困惑度与「数据重复的代价」

(a) 某模型在 10 个 token 的测试片段上给出平均负对数似然 L=0.693\mathcal L=0.693 nat,求 PPL。

(b) 同一段文本在语料中重复了 kk 次,模型把这段记忆下来后,其上的平均负对数似然降到 L′=0.01\mathcal L&#x27;=0.01 nat。若原测试集有 60% 的 token 来自这类重复片段,估计膨胀后的整体 PPL。

解

(a) PPL=e0.693≈2\mathrm{PPL}=e^{0.693}\approx2。读法:模型平均在「2 个等可能选项」之间犹豫,等价于每个 token 约 0.693/0.693=10.693/0.693=1 比特。

(b) 拆分测试集:重复子集 0.6,非重复子集 0.4。设非重复部分保持 L=0.693\mathcal L=0.693(nat),则整体平均

Lˉ=0.6×0.01+0.4×0.693=0.006+0.277=0.283 nat,PPL=e0.283≈1.33.\bar{\mathcal L}=0.6\times0.01+0.4\times0.693=0.006+0.277=0.283\ \text{nat},\qquad \mathrm{PPL}=e^{0.283}\approx1.33 .

即 PPL 从约 2.02.0 降到约 1.331.33——看起来模型强了三分之一,但非重复部分的能力一点没变,降幅全部来自记忆。这就是数据去重(6.1.4)必须做的定量理由:不去重时,评测指标会系统性地说谎。■\blacksquare

∎

6.1.2 三段式流程:预训练 → SFT → 对齐

预训练只给你一个极度擅长续写的模型,它不天然会「回答问题、遵守格式、拒绝有害请求」。从「续写器」到「助手」,工业界收敛到一条三段式流水线。

三段式流水线(现代默认配方)
阶段 数据形态 目标函数 学到什么 算力占比(量级)
① 预训练(pre-training) 原始文本 / 代码 / 文档,万亿级 token 下一 token 交叉熵 语言能力、世界知识、格式与风格分布 绝大多数(常 ≳95%)
② 监督微调(SFT / instruction tuning) 「指令 → 期望回答」成对数据,百万级样例 同一交叉熵,只在回答 token 上回传损失 听指令、按格式答、拒答模式 很小
③ 偏好对齐(preference alignment) 同一提示的多个回答及其偏好排序 RLHF(RM + PPO)或 DPO 类直接偏好损失 有用、诚实、无害的倾向 很小

三阶段缺一不可:只有 ①,模型会热情地把你的问题续写成更多问题;只有 ①+②,模型会照做但不知道「哪种答法更好」;跳过 ② 直接做 ③ 在实践中几乎不成立(DPO 类方法的参考模型默认是 SFT 后的模型)。

三个阶段各自在「移动什么」

把预训练想成学会全部人类文本的概率分布——其中当然也包含「怎么流畅地说错话」「怎么敷衍地拒答」。② 和 ③ 不改变模型「会什么」,而是移动概率质量:把「有用且守规」的回答抬上去、把「有害或敷衍」的压下去。

一个常见但证据有限的说法是「对齐只让模型更愿意表现,不教新知识」。它大体符合直觉(对齐数据量比预训练小好几个数量级),但「对齐能否顺带激发出预训练里已有、却未显露的能力」仍存争议,不宜当定论。更稳的说法是:对齐主要改行为分布,副带效应尚在研究中。

定义 6.1.3 · 指令微调与偏好对齐

指令微调:在「指令 + 期望回答」数据上做监督微调,损失仍为交叉熵,但通常只在回答部分计算损失(把指令 token 的损失掩掉,mask):

LSFT=−1∣A∣∑t∈Alog⁡pθ(yt∣指令,y<t),\mathcal L_{\mathrm{SFT}}=-\frac1{|\mathcal A|}\sum_{t\in\mathcal A}\log p_\theta(y_t\mid \text{指令},y_{\lt t}),

其中 A\mathcal A 是回答 token 的位置集合。

偏好对齐:给定提示 xx 与两个回答 ywy_w(更受偏好)、yly_l,用 Bradley–Terry 模型训奖励 rϕr_\phi 或用 DPO 直接优化策略(细节见第 5 讲 5.6):

LDPO=−log⁡σ(βlog⁡πθ(yw∣x)πref(yw∣x)−βlog⁡πθ(yl∣x)πref(yl∣x)).\mathcal L_{\mathrm{DPO}}=-\log\sigma\Bigl(\beta\log\frac{\pi_\theta(y_w\mid x)}{\pi_{\mathrm{ref}}(y_w\mid x)}-\beta\log\frac{\pi_\theta(y_l\mid x)}{\pi_{\mathrm{ref}}(y_l\mid x)}\Bigr).

为什么 SFT 要「只对回答算损失」

如果连指令部分也算损失,模型会被训练去预测用户的提问——而提问是推理时由用户给定的、完全不确定的。把损失的算力花在「复述用户的问题」上,既浪费又会让模型倾向于在回答里重复指令。掩掉指令损失,等价于声明:输入是条件,输出才是要建模的随机变量。这就是「指令跟随」在实现层面的全部技术含量。

DPO 那一行则说明:偏好对齐不需要显式奖励模型,它把「相对偏好」直接写成一个关于策略与参考模型对数比之差的序数损失。πref\pi_{\mathrm{ref}} 是锚,β\beta 控制允许偏离锚多远——β\beta 越小,模型越敢离开 SFT 分布,也越容易钻偏好的空子。

例 6.1.2 · 一条指令样例在三阶段里分别长什么样

给定同一个用户请求「把这句话改写得更简洁:本方案的主要目的是为了提升系统的整体运行效率」。写出它在三段数据里的形态。

解

(a) 预训练阶段:这句话只是网页里的一句普通文本,没有「指令」概念。模型学的是让它作为续写的一部分概率更高。

(b) SFT 阶段:数据是一条三元组(指令,输入,回答):

指令:把这句话改写得更简洁。
输入:本方案的主要目的是为了提升系统的整体运行效率。
回答:本方案旨在提升系统运行效率。

损失只加在回答的 token 上。模型学到的是「看到『改写得更简洁』这个模式 → 输出更短的版本」。

(c) 偏好对齐阶段:同一提示下的两个回答被打分:

回答 偏好 可能的原因
「本方案旨在提升系统运行效率。」 更受偏好 ywy_w 简洁、保留了原意
「该方案的核心目标在于:通过各种手段有效提升系统在整体层面的运行效率。」 较差 yly_l 更长、更「官方腔」,与「更简洁」相悖

注意这里没有任何新知识被注入:改写能力在预训练时已具备,SFT 教会它在什么触发条件下调用,偏好数据把它在「简洁 vs 冗长」这条轴上的概率质量挪了一格。这正是「对齐移动分布」的具体含义。■\blacksquare

∎
三段式流程的四个常见误解
  1. 「SFT 之后模型就对齐好了,RLHF 是锦上添花」:SFT 只教「照做」,不教「做得更好」。在开放式任务上,SFT 模型的输出会是训练集风格的平均值;偏好对齐负责的正是「同一指令下的多种合理答法里选哪种」。
  2. 「对齐是给模型打补丁,所以去掉补丁就回到原始能力」:对齐确实集中在很小的参数更新里(这也是 LoRA 式对齐能工作的原因),但「能干净剥离」在实践上并未被普遍证实,与「对齐改行为不改知识」是两个不同的命题,不要混。
  3. 「指令数据越多越好,可以自动生成到无穷」:合成指令数据是常见做法,但它的质量受种子数据与筛选器限制;纯自动扩增容易出现风格单一、难度分布塌缩、甚至把生成模型的偏差固化进去(见 6.2.3)。
  4. 「SFT 的损失曲线下降就说明微调成功」:SFT 数据规模小,损失很快降到极低(接近记忆),此时训练损失几乎没有信息量,必须用留出的指令集与下游评测判断(见 6.7.3)。

6.1.3 Tokenizer:BPE 的原理与影响

模型看不见字符,只看见整数 id。把字符串映射成 id 序列的那套东西叫分词器(tokenizer)。它常被当成预处理细节,实际上是决定模型成本、长度与多语言公平性的架构级选择。

定义 6.1.4 · 字节级 BPE(byte-level byte-pair encoding)

给定语料 C\mathcal C 与初始符号表(字节级:256 个字节),BPE 反复执行贪心合并:

(a,b)⋆=arg⁡max⁡(a,b) countC(ab),把语料中所有 ab 替换为新符号 c, c←a ⁣⋅ ⁣b,(a,b)^\star=\arg\max_{(a,b)}\ \mathrm{count}_{\mathcal C}(ab),\qquad \text{把语料中所有 } ab \text{ 替换为新符号 } c,\ c\leftarrow a\!\cdot\!b,

直到词表达目标规模 VV(现代 LLM 常取 V∈[3×104,2×105]V\in[3\times10^4,2\times10^5])。编码时不再全局最优,而是按学到的合并规则顺序贪心切分;同一段文本在不同实现下可能切分不同(这是 tokenizer 复现性的常见坑)。

字节级(byte-level)的意思是:词表建立在 UTF-8 字节上,因此任意字符串都能编码,不存在未登录词(UNK)。

BPE 到底在权衡什么

它用统计频率近似「什么该是一个单位」。高频串(the、ing、的)合成一个 token,罕见串退回到字节或短片。于是产生一条极强的经验规律:一个 token 承载的信息量取决于它在训练语料里有多常见。这直接决定三件事:

  • 成本:API 按 token 计费、注意力按 token 平方增长,同样的中文文本在不同分词器下 token 数可能相差近一倍;
  • 有效长度:上下文窗口是按 token 计的,所以「128K 窗口」在不同语言里的实际字符容量并不相同;
  • 多语言公平:以英文为主的语料训出的词表,稀有语言要用更多 token 表达同样意思,等价于被收取更高费用、享有更短窗口。
例 6.1.3 · token 数、成本与「同一条指令的三种报价」

某服务的定价为每 100 万输入 token 收费 CC。现有一段中文提示词,共 600 个汉字。

情形 平均每 token 覆盖的字符 token 数 相对成本
A:英文主导词表 1.0 600 1.00×
B:中英混合词表 1.5 400 0.67×
C:优化过的中文词表 2.0 300 0.50×

求三种情形下相同请求的成本比,并说明这为什么不是「实现了加速」。

解

token 数与成本成正比(其余条件不变时):600:400:300=2:1.33:1600:400:300=2:1.33:1。情形 C 相对 A 省一半。

但这不是模型更快或更聪明:参数量、每一层计算量都没变,变的只是「同一段文本被切成多少个单位」。因此:

  1. 任何「每秒 token 数」的吞吐对比,必须先固定 tokenizer,否则不可比;
  2. 任何「同价位下支持更长文本」的宣称,要问清是 token 数更长还是字符数更长;
  3. 反过来说,改词表是真实收益:它能降低服务成本、扩大有效窗口、改善小语种可用性——这正是近年新模型普遍重训词表的原因。■\blacksquare
∎
分词器的工程影响(可跳到 [6.1.4](#sec-6.1.4))
  • 数字与代码:数字被切碎会显著损害算术与代码能力(模型必须在碎片间重建数位结构)。常见做法是把数字按单个数字位切分(digit-level split),让位置对齐可学。
  • 空白与换行:是否把前导空格并入 token 影响代码缩进与格式敏感性;这也是「换词表后微调数据要重编码」的原因。
  • 每字节比特数(bits-per-byte, BPB):跨 tokenizer 比较模型时,用「每字节的比特数」而不是 PPL,可以把不同分词尺子归一化(相关讨论见 Pimentel et al. 的 BPE Is Not All You Need 一类工作;具体编号需核实)。
  • 词表大小也是旋钮:词表越大,单 token 越「重」(embedding 与输出层参数 ∝Vd\propto Vd,softmax 更贵),但序列更短。VV 的选择是「序列长度 × 词表规模」的显式权衡。

6.1.4 数据规模与质量:去重、过滤与配比

在 6.2 会看到 Chinchilla 的结论把「数据量」抬成了与参数量同级的第一类公民。既然如此,数据工程就成了预训练里回报最高的环节——它比改架构便宜得多。

数据管线四步:抽取 → 过滤 → 去重 → 配比
步骤 做什么 典型手段 主要风险
抽取 从网页/文档抽正文 正文抽取(如 trafilatura 类工具)、语言识别 样板文字、导航栏、模板残留被当成语料
过滤 扔掉低质与有害文本 启发式规则(长度、符号比、重复行占比)+ 分类器打分(CCNet 式质量分) 过滤过狠会误伤方言、口语与少数群体文本,并把基准答案一起删/留
去重 移除近重复 精确哈希 + MinHash / LSH 近似去重、后缀数组做子串级去重 去重力度与保留多样性的权衡;跨 epoch 也要控重复
配比 决定各来源混合比例 领域权重(代码 / 数学 / 多语 / 网页)、温度采样调权、退火阶段调数据 配比过拟合评测集;小语种被主流语言淹没

收益排序(经验共识):质量过滤与去重通常比「换架构微调」带来更大的一次性收益;其后是中期训练(mid-training)阶段的数据调度与退火式高质量数据注入。

去重为什么是「最便宜的能力提升」

回到 例 6.1.1:模型在重复文本上会迅速变成复读机,损失下降但能力没变。更糟的是三条连锁后果——① 重复样本在梯度里被加权,相当于隐式地把训练分布改了;② 评测集若含重复,分数虚高(这就是污染的一种形态,见 6.7.2);③ 记忆化(memorization)加剧,带来隐私与版权风险(见 第 7 讲)。

所以去重不是「整洁癖」,而是让梯度与真实分布对齐的必要条件。同一逻辑也解释了为什么「多轮 epoch 重复训练」在 LLM 上不常用:重复的收益会递减,接近记忆化后甚至有害。

例 6.1.4 · 一次数据混合的收益核算(对照表分析)

某团队在固定的 1B 参数模型与固定 20B token 预算下做了四组对照(数字为示意,用于说明核算方法,非任何论文实测值):

组 处理 有效 token 验证集 PPL 备注
G1 原始爬取,不处理 20.0B 12.4 含大量样板与重复
G2 仅启发式过滤 16.5B 11.2 语料变干净但样本变少
G3 过滤 + 精确去重 14.0B 10.1 重复被移除
G4 过滤 + 精确去重 + MinHash 近重去重 12.6B 9.4 近重复(模板改写)也被移除

问:为什么 G4 用的数据最少却最好?若把 G4 的语料再重复一遍凑回 20B token 训练,你预期 PPL 如何变化?

解

为什么最好:从 G1 到 G4,有效 token 在减少,但每个 token 的信息量在增加。低质文本(样板、乱码、机器生成垃圾)的交叉熵很低但对能力贡献极小,它们占据了算力;近重复文本更是接近零边际信息。因此「20B 原始 token」的有效信息量可能远小于「12.6B 干净 token」。

形式化地:设每 token 对模型分布的有效梯度贡献为 gig_i,训练收益 ∝∑igi\propto \sum_i g_i 而非 NN。过滤与去重做的是提高平均 gig_i,代价是降低 NN。只要前者收益更大(经验上如此),净效果为正。

重复一遍凑回 20B 的预期:PPL 会变差(相对 G4 的 9.4)。因为重复把平均 gig_i 拉低,同时显式地把梯度权重分配给已学样本。理论上重复同一数据到无穷不会带来额外信息(在参数容量与优化理想情况下),实践中在大约数轮之后就基本没有增益,并伴随记忆化风险。这正是「数据墙」讨论的起点(见 6.2.3)。■\blacksquare

∎
数据工程的四条常见误解
  1. 「数据越多越好」:正确的表述是「有效 token 越多的数据越好」。原始 token 数是一个成本项,不是一个质量指标。
  2. 「去重只需要对训练集做」:评测集与训练集的交叉重复才是污染的主要来源;两边都要去重,且评测集要在训练数据的时间线之后构建(见 6.7.2)。
  3. 「合成数据可以无限扩增」:合成数据必须配筛选器与分布控制,否则会放大自身偏差、塌缩多样性。它的性质与限度仍在争论中(6.2.3)。
  4. 「配比是超参,调就完了」:配比直接决定模型的能力结构与风险结构(哪些语言的用户被系统性怠慢),属于产品决策而非纯超参。

6.1.5 指令数据:从哪来、怎么造

SFT 的质量几乎完全由指令数据决定,而它不能像预训练那样从互联网上抓——互联网上没有人替你写好「指令 → 理想回答」这一对。

指令数据的四条来源与各自的偏置
来源 做法 优势 引入的偏置
人工撰写 标注员按任务清单写指令与答案 质量高、可控 昂贵;标注员风格与知识边界进入模型
真实用户日志 从产品埋点收集真实请求 分布最真实 隐私与合规成本;长尾有害请求混入
模板化生成 用任务模板 + 已有语料批量造对 便宜、可覆盖宽任务面 句式呆板、难度分布集中;格式泛化差
强模型蒸馏 用更强模型的输出来构造答案(含推理轨迹) 质量高、可批量 继承教师模型的错误与风格;有使用条款约束

工程上的共识做法是混合:少量高质量人工种子 → 模板与蒸馏扩增 → 用筛选(规则 + 模型打分)与多样性控制(按任务/长度/难度分桶配额)保持分布宽阔。

为什么「指令数据多样性」比「数量」重要

SFT 的目标不是让模型记住答案,而是让它归纳出「什么样的输入对应哪一类响应结构」——是一张映射表,不是一本答案集。因此覆盖面的价值高于单题的价值:一条「写 SQL」的样例与一条「写正则」的样例,彼此不可替代。

这也解释了一个反直觉现象:把 1 万条高度同质的样例扩到 10 万条,往往几乎不涨点;而加入几百条全新任务类型的样例,可能立刻改善泛化。广度优先于深度,是 SFT 与预训练相反的一条规律。

例 6.1.5 · 判断一批指令数据能否用(清单式分析)

你收到一批 5 万条 SFT 数据,要求在不训练的前提下给出接受 / 退回的判断。请给出检查表与判据。

解

检查表(按发现问题概率排序)

检查项 具体做法 退回判据(示例阈值)
重复率 精确 + 近重(MinHash)统计 近重占比 > 15% 需先去除
任务类型分布 按任务标签统计熵与占比 单一任务 > 40%,或覆盖任务 < 8 类
长度分布 指令与回答长度的分位数 回答长度集中在单一区间(如全是 1–2 句)
格式泄漏 检查回答是否含「作为一个 AI 模型」等模板腔 模板腔占比高 → 训练后语气僵硬
拒答配比 统计「应该拒答」与「应当照做」的比例 拒答样例过多 → 过度保守;过少 → 安全缺口
答案正确性抽样 抽 200 条人工核验 错误率 > 5% 需整批重造
与评测集重叠 与目标基准做 n-gram / 语义比对 存在重叠即需剔除(否则污染)

结论模板:先做三项零成本统计(重复率、任务分布、长度分布),再抽样核验正确性。任何一项不达标就先治理再训练——在 SFT 上,数据治理的边际收益远高于调参。■\blacksquare

∎

6.1.6 上下文窗口与 KV cache 的工程影响

「上下文窗口」(context window)指模型一次前向能读入的最大 token 数。它从早期的 1–2K 涨到今天的 10510^5–10610^6 量级,这个变化不只是「能塞更多字」——它同时改变了成本结构与系统设计方式。

定义 6.1.5 · 注意力成本与 KV cache

对长度 LL、层数 nlayern_{\text{layer}}、KV 头数 nkvn_{\text{kv}}、每头维度 dhd_h、批大小 BB、精度 bb 字节:

  • 注意力计算量:O(L2d)\mathcal O(L^2 d)(每层),序列越长越平方增长;
  • KV cache 显存:bytes=2 B L nlayer nkv dh b\text{bytes}=2\,B\,L\,n_{\text{layer}}\,n_{\text{kv}}\,d_h\,b(系数 2 是 K 与 V;实现细节见第 9 讲)。

两条结论:装长上下文的能力受显存限制(KV cache 随 LL 线性增长),而算长上下文的代价随 LL 平方增长。

为什么「长窗口」是显存问题,不只是算法问题

对话里每生成一个 token,历史长度就 +1,cache 就长大一点。以一个常见配置估算(B=1B=1、L=105L=10^5、nlayer=80n_{\text{layer}}=80、nkv=8n_{\text{kv}}=8、dh=128d_h=128、b=2b=2):

2×1×105×80×8×128×2 字节≈3.3×1010 字节≈33 GB.2\times1\times10^5\times80\times8\times128\times2\ \text{字节}\approx 3.3\times10^{10}\ \text{字节}\approx 33\ \text{GB}.

也就是说,单条 10 万 token 的会话就要约 33 GB 的缓存(此估算为量级示意,未计入分页与碎片开销)。这解释了工程上为什么必须有:GQA/MQA 降 nkvn_{\text{kv}}、分页式 cache(PagedAttention 一类)、滑窗与 sink token 保留、KV 量化、以及前缀缓存复用。窗口大小是一个被显存预算买断的数字。

长上下文带来的四个设计改变
  1. RAG 的边界移动:过去「检索几段」是因为塞不下;现在可以把整个代码库或整份合同放进去。但「能读」不等于「能用」——中间位置的检索准确率通常低于首尾(「lost in the middle」现象),因此检索仍然有价值(见 6.6.3)。
  2. 缓存成为一等公民:把稳定的系统提示与文档前缀做成可复用的前缀 cache,能把重复请求的成本降一个量级;这也反过来要求把易变内容放在后面(见 6.7.5)。
  3. 注意力模式改变:长上下文的评测必须分段测量(不同深度、不同位置),单一平均分掩盖位置偏差。
  4. 代理指标失效:窗口从 8K 到 128K,常见的「大海捞针」式测试(needle-in-a-haystack)容易被当作能力证明,但它测的是检索 + 复制,不是长程推理。

6.1.7 推理成本、延迟与量化部署

训练成本是一次性的,推理成本是每次调用都要付的。本节最后一小节把成本结构算清楚,为 6.7.5 的部署一节做铺垫。

推理侧的三张账
账目 决定因素 常用杠杆 代价
显存账 权重(∝N\propto N)+ KV cache(∝L\propto L) 量化(4bit 权重)、GQA、分页 cache、KV 量化 极低比特会有质量损失
算力账 每 token 前向 FLOPs(≈2N\approx 2N 量级)+ 序列平方项 批处理(batch)提高利用率、投机解码 单请求延迟与吞吐互相挤压
延迟账 首个 token 时间(prefill)+ 每 token 解码时间 前缀缓存、更小的 draft 模型、分离式部署 工程复杂度

关键区分:吞吐(tokens/s 总)与延迟(单请求响应时间)是两个相反的优化目标。增大批处理提高吞吐但抬高单请求延迟;要同时改善,只能靠算法(投机解码、前缀复用)或硬件。

为什么「量化」几乎是无脑正确的一步

现代后训练量化(post-training quantization)把权重压到 4bit,在大模型上通常带来很小的质量损失,却把权重显存降到约 1/4,并因为访存瓶颈的缓解而提升解码速度。原因在于解码阶段是访存受限(memory-bound)而非算力受限:瓶颈在读权重,不在算乘法。所以「少读字节」几乎直接等于「更快」。

代价与边界:量化友好度与模型规模、离群值数量相关(逐层误差补偿、保护显著通道、分组量化都是为了处理离群值);而 KV cache 的量化比权重量化更敏感,通常更保守。「4bit 无损」这类绝对说法应当替换为条件陈述:在什么模型、什么评测上,掉了多少分。

三个需要在部署前问清的问题
  1. 「你的窗口多大」问的是 token 还是字符?(6.1.3)不同语言的字符容量差别很大。
  2. 「成本多少」问的是每 token 还是每请求? 长系统提示会让「每请求」成本远高于「每 token」的直觉估算,除非前缀被缓存复用。
  3. 「延迟多少」问的是首 token 还是整体? 对交互式产品首 token 时间决定体验,对批处理任务吞吐决定成本。
即时自测 · 6.1

Q1 写出自监督语言建模的损失,并解释「自监督」在数据层面意味着什么。

Q2 已知某片段平均负对数似然 L=1.2\mathcal L=1.2 nat,求 PPL;若该片段的 70% token 属于训练集里重复出现的模板文本(模型其上 L=0.05\mathcal L=0.05),定性说明为什么这个 PPL 不能用来比较模型能力。

Q3 为什么 SFT 要 mask 掉指令 token 的损失?

Q4 同一段 600 字中文提示,在 A 词表下 600 token、B 词表下 320 token。能否据此说 B 词表的模型「推理更快」?为什么?

Q5 估算一层 80 层、nkv=8n_{\text{kv}}=8、dh=128d_h=128 的模型在 10 万 token、单条会话、BF16 下的 KV cache 显存量级,并说出两个把该数字压下来的工程手段。

参考要点

Q1 L=−1T∑tlog⁡pθ(xt∣x<t)\mathcal L=-\frac1T\sum_t\log p_\theta(x_t\mid x_{\lt t});「自监督」指监督信号由数据自身提供(第 tt 位标签即真实第 tt 个 token),因此不需要任何人工标注,任意文本都能用于训练。

Q2 PPL=e1.2≈3.32\mathrm{PPL}=e^{1.2}\approx3.32。若 70% 是记忆型模板(L=0.05\mathcal L=0.05),其余 30% 保持 L\mathcal L 为训练外同难度文本的水平,则整体均值被记忆项大幅拉低;改变模板的重复次数就能人为改变 PPL,而真实能力不变。因此跨模型比较 PPL 必须先对齐分词器、去重程度与测试集构成(例 6.1.1)。

Q3 因为推理时指令由用户给定、无需模型预测;把指令纳入损失会让模型学习「生成用户的问题」,浪费容量并诱发回答中复述指令。掩掉指令损失等于声明「输入是条件,输出才是建模对象」。

Q4 不能。token 数变少只是因为编码粒度不同,模型参数量与每 token 计算量未变;「每秒 token 数」在两个不同 tokenizer 之间不可比。tokenizer 改变带来的是成本、有效窗口、语言公平性的收益,不是单步速度。(跨分词器比较能力应改用每字节比特数 BPB。)

Q5 2×1×105×80×8×128×2 字节≈3.3×10102\times1\times10^5\times80\times8\times128\times2\ \text{字节}\approx3.3\times10^{10} 字节 ≈33\approx33 GB(量级示意)。压下来的手段(任答两个):① 用 GQA/MQA 降低 nkvn_{\text{kv}};② KV cache 分页与复用(PagedAttention / 前缀缓存);③ KV 量化到 8bit 或更低;④ 滑窗注意力 / 保留 sink token 丢弃中段;⑤ 降低单会话保留的历史长度、把长文档放到可检索的库而不是常驻上下文。

延伸阅读
  • Vaswani et al., Attention Is All You Need(2017,arXiv:1706.03762)——骨干架构,本讲的起点(第 2 讲已详讲)。
  • Radford et al., Language Models are Unsupervised Multitask Learners(GPT-2,2019,无 arXiv,OpenAI 技术报告)——「零样本多任务」的最早系统性展示,本节「预测下一个 token 能学到什么」的历史锚点。
  • Brown et al., Language Models are Few-Shot Learners(GPT-3,2020,arXiv:2005.14165)——上下文学习与大模型规模的第一次大规模展示(第 5 讲与 6.3 都会回到它)。
  • Sennrich et al., Neural Machine Translation of Rare Words with Subword Units(2015,arXiv:1508.07909)——BPE 用于神经网络的原始论文。
  • Lee et al., Deduplicating Training Data Makes Language Models Better(2021,arXiv:2107.06499)——去重的实证收益,本节 6.1.4 的主要依据。
  • Wenzek et al., CCNet: Extracting High Quality Monolingual Datasets from Web Crawl Data(2019,arXiv:1911.00359)——启发式 + 分类器式质量过滤的经典配方。
  • Penedo et al., The FineWeb Datasets: Decanting the Web for the Finest Text Data at Scale(2024,arXiv:2406.17557)——大规模数据管线的公开实践记录,含去重与过滤的消融。
  • Ouyang et al., Training Language Models to Follow Instructions with Human Feedback(InstructGPT,2022,arXiv:2203.02155)——三段式流程与 RLHF 的系统化描述。
  • Rafailov et al., Direct Preference Optimization: Your Language Model is Secretly a Reward Model(2023,arXiv:2305.18290)——DPO 的原始论文。
  • Wei et al., Finetuned Language Models Are Zero-Shot Learners(FLAN,2021,arXiv:2109.01652)——指令微调的最早系统性证据之一。
  • Kwon et al., Efficient Memory Management for Large Language Model Serving with PagedAttention(2023,arXiv:2309.06180)——vLLM 与分页 KV cache(6.7.5 部署节的必读)。
  • Liu et al., Lost in the Middle: How Language Models Use Long Contexts(2023,arXiv:2307.03172)——长上下文位置偏差的实证研究,6.1.6 的直接依据。
  • 斯坦福 CS336 Language Modeling from Scratch(stanford-cs336.github.io)——把分词器、Transformer、训练与对齐逐步实现一遍的公开课程,本节的硬核配套。
  • Karpathy 的 nanochat(github.com/karpathy/nanochat)——分词 → 预训练 → SFT → 强化学习的端到端最小实现,适合把本节三段式流程跑一遍。

本节小结:大语言模型 = 自监督预训练(预测下一个 token,损失即压缩码长,命题 6.1.1)+ SFT(只对回答算损失,教「照做」)+ 偏好对齐(移动概率质量,改倾向而非注入知识)。语言之外的三件工程事实同等重要:tokenizer 决定成本与窗口的有效容量、去重与过滤决定有效 token 的质量、KV cache 决定长上下文的可行边界。

但上面所有讨论都悬在一个默认假设上:「更大就更好」。这个假设在 2020–2022 年被写成了公式,又在 2023 年被一组更仔细的实验改写。下一节就来讲这条经验规律的两次修订,以及伴随它而来的最大争议——能力涌现到底是真的突变,还是度量尺子的假象。