文章

从零开始的NLP:从影评分类到 Transformer

用可手算的小例子串起文本表示、词向量、RNN、Attention 与 Transformer,再看语言模型的训练、生成和计算成本。

从零开始的NLP:从影评分类到 Transformer

“电影好看”和“电影不好看”只差一个字,判断却可能完全相反。对人来说,这很容易;对模型来说,首先得解决一个更基础的问题:这些文字要变成什么数字,才能让后面的计算保留这种差别?

这篇文章从影评分类出发,沿着几个问题展开:词频能表达什么,词向量怎样学出来,为什么还需要处理顺序,以及 Attention 如何让不同位置交换信息。最后再把这些计算放回 Transformer,看看它如何训练、生成文本,又把计算和显存花在了哪里。

只要知道机器学习大致是“用数据调整参数,再预测新数据”,就可以开始阅读。全文较长,可以分三段读:

阅读范围主要问题
1—7:文本表示与词向量文字如何变成数字,这些数字如何学出来?
8—12:顺序与生成RNN、LSTM、语言模型和 Attention 各自改变了什么?
13—18:Transformer 与应用模型怎样计算、训练和评价,成本在哪里?

文中的微型数据集、向量和分数均为教学构造,不是真实训练结果或性能测试。除另有说明外,计算使用未舍入值,展示时保留三位小数;把展示值代回公式,末位可能略有差异。

公式放在数字例子之后,每节的练习可以按需展开。文末附有公式速查、术语表和参考文献;配套 Python 脚本 能复算主要例子,只需要 Python 标准库。

1. 我们到底要让计算机做什么

1.1 先把任务缩小到“给影评分类”

假设我们收集了下面六条评论,并由人给出标签:

编号评论人工标签
A电影好看好评
B剧情精彩好评
C电影难看差评
D剧情无聊差评
E电影不好看差评
F电影不难看好评

为了方便演示,我们把“不难看”归为好评。实际业务中它也可能被标为中性,因此真实项目应先明确标注标准。

模型要学习的是:看到新的评论,例如“这部电影挺精彩”,给出好评的概率。

整个过程与你熟悉的分类任务一样:

1
已经标注的评论 → 训练模型 → 新评论 → 好评概率 → 按阈值给出类别

困难在于,房价预测可以直接输入“面积 80、楼层 6”,影评却是一串文字。我们首先需要把文字整理成机器学习能使用的数值特征。

NLP,即自然语言处理,就是让计算机对人类语言完成分类、抽取、检索、翻译、生成等任务。

1.2 有些模型要输出一个标签,有些要输出一段文字

现在先记住三类输出:

输入想要的输出任务名称
电影很好看好评文本分类
小王住在上海人物:小王;地点:上海实体识别
我喜欢这部电影I like this movie.机器翻译

分类通常给整段文字一个结果;实体识别需要指出原文中的位置;翻译要生成一个长度可能不同的新句子。输出不同,后面的模型设计就会不同。

1.3 第一个方法:人写规则

可以先写一个打分表:

1
2
3
好看、精彩:每出现一次加 1 分
难看、无聊:每出现一次减 1 分
最后分数大于 0 就判为好评

它能处理 A—D,却会把 E“电影不好看”误判为好评。

你可以再补一条“看到‘不’就反转”,但“不是不好看,只是太长”又需要更细的规则。

规则的价值是清楚、便宜、容易控制。困难是语言组合太多,维护例外的工作会越来越多。

能否从已经标注的评论里,让模型自己学哪些词重要?

小练习:“情感分析”是不是只能预测一个连续分数?

不是。这里预测好评或差评就是分类;也可以预测 1—5 分,还可以分别评价“剧情”和“演技”。任务如何定义决定输出形式。

2. 把一句话拆开,再给每一块一个编号

2.1 “拆成什么”是一项选择

对“电影不好看”,先采用下面的切法:

1
电影不好看 → [电影, 不, 好看]

每一块称为一个 token,这个拆分过程称为 tokenization。

暂时可以把 token 理解成“模型一次接收的一个文字单位”。它不一定是完整的词:也可以是汉字、词的一部分或字节。

本文前半部分为了好读,手工按词切分;这不是声称所有实际分词器都会这样切。

2.2 建一张编号表

把六条评论里用到的词整理成词表:

编号词
0电影
1剧情
2好看
3精彩
4难看
5无聊
6不

那么:

1
2
电影好看   → [电影, 好看]     → [0, 2]
电影不好看 → [电影, 不, 好看] → [0, 6, 2]

这些数字只是编号。编号 4 不代表比编号 2 更强烈,“好看”和“精彩”的编号相邻也不代表它们在数学上更相似。

可以任意重新排列词表,只要整个模型始终使用同一套映射。

2.3 为什么不能只把编号直接塞进普通线性模型

假设你把“好看”的编号 2 直接当作特征数值,把“难看”的编号 4 直接当作特征数值。

普通数值运算会把 4 当成 2 的两倍。但词语没有这种大小关系,因此这个数值解释是错误的。

我们要用编号去“查表示”,而不是让编号本身承担语义。

2.4 如果模型遇到没见过的词

例如新评论是“镜头惊艳”。小词表里没有“镜头”和“惊艳”。

按整词处理的一个办法是用特殊编号 <UNK> 代表未知词。但不同未知词都变成同一符号,就丢掉了区别。

还可以换拆分粒度:

方案示例直接后果
按词[电影, 不, 好看]单位较完整,但需要收集很多词
按字[电, 影, 不, 好, 看]可组合新词,但输入更长
按子词英文 playing 可能拆为 [play, ing]可以复用词的一部分,实际切分依赖词表
按字节使用文本编码得到的字节能覆盖任意字节序列,但不保证序列短

常见的 BPE 子词方法,会反复合并训练文本里经常相邻出现的小单位。它学习的是一种常用片段的切分规则,不会自动知道这些片段是什么意思。1

单位越小,词表往往越容易覆盖文本,但句子往往越长;单位越大,句子可能更短,但词表更大、生僻词更难处理。

小练习:把所有 token 编号都加 100,只要同步修改查表关系,会改变句子含义吗?

不会。编号只是地址;真正提供信息的是编号对应的表示和后续计算。

3. 最简单的数值表示:统计每个词出现了几次

3.1 从一张计数表开始

沿用上一章的七个词,并固定列顺序:

1
[电影, 剧情, 好看, 精彩, 难看, 无聊, 不]

“电影好看”中,“电影”出现一次,“好看”出现一次,其他词没出现:

1
电影好看 → [1, 0, 1, 0, 0, 0, 0]

“电影不好看”则是:

1
电影不好看 → [1, 0, 1, 0, 0, 0, 1]

这样,每条评论都变成长度相同的一排数字。这排数字称为向量。这里向量的每一列都有明确含义:对应词出现的次数。

这就是 Bag of Words,词袋,简称 BoW。名字来自一个比喻:把所有词放进袋子里,知道袋子里有什么,但不知道原先排列顺序。

3.2 现在可以接上熟悉的分类器了

给每个词一个权重。下面先人为给值,下一章再学习如何更新:

词权重
电影、剧情0
好看、精彩+1
难看、无聊-1
不0

评论得分就是“次数 × 权重,再全部相加”。

1
2
电影好看:1×0 + 1×1 = 1
电影难看:1×0 + 1×(-1) = -1

为了把分数变成 0—1 之间的概率,使用 sigmoid 函数。先记住几个结果即可:

得分sigmoid 后的好评概率
-20.119
-10.269
00.500
10.731
20.881

于是“电影好看”的好评概率为 0.731,“电影难看”为 0.269。

如果你认识逻辑回归,到这里其实已经有了一个文本逻辑回归分类器。

用公式缩写:

\[z=w_1x_1+w_2x_2+\cdots+w_7x_7+b,\qquad p=\frac{1}{1+e^{-z}}\]

这里 x 是词频,w 是对应权重,b 是所有输入共享的偏置。偏置可以理解为看具体词之前的基础倾向。

3.3 词袋究竟丢了什么

看两句完全由相同词组成的话:

1
2
我 喜欢 你
你 喜欢 我

它们的词袋相同,但“谁喜欢谁”不同。

再看两条评价:

1
2
好看,不是难看。
难看,不是好看。

如果采用同样的切词规则并忽略标点,两句话的词频也相同,却表达相反的判断。

一旦不同输入被转换成完全相同的特征,后面的分类器再复杂也无法仅凭这些特征把它们区分开。

这比“某个模型还不够大”更根本:信息在进入模型前已经丢了。

3.4 TF-IDF:给到处出现的词少一点权重

换一个只用于计算的小文档集合:

1
2
3
D1:电影 好看
D2:电影 精彩
D3:电影 无聊

“电影”出现在全部三篇里,不能帮助区分这三篇。“好看”只出现在一篇里,区分度更高。

一种简单的 IDF 算法是:

1
IDF = ln(文档总数 ÷ 包含这个词的文档数)

ln 是自然对数。你暂时只需要知道:ln(1)=0,ln(3)≈1.099,数越大,结果也越大。

因此:

1
2
电影的 IDF = ln(3÷3) = 0
好看的 IDF = ln(3÷1) ≈ 1.099

本例采用原始计数作为 TF,即当前文档里词出现的次数。TF-IDF 把 TF 与 IDF 相乘。

若列顺序是 [电影, 好看, 精彩, 无聊],D1 会变成:

1
2
普通词频:[1, 1, 0, 0]
TF-IDF:[0, 1.099, 0, 0]

这里采用自然对数且不做平滑、归一化。IDF 也可采用其他对数底数;实际工具还可能加平滑、加常数或归一化,因此比较数值时要先对齐定义。2

词袋和 TF-IDF 计算便宜、容易检查,对关键词明确的分类任务很有用;它们依然无法恢复被丢掉的顺序,也不会自动把同义词视为相近。

小练习:把词频换成 TF-IDF,能区分“我喜欢你”和“你喜欢我”吗?

不能。同一文档集合下,相同词频仍会得到相同 TF-IDF 向量。换权重没有恢复词序。

4. 让权重自己学习:完整走一次“预测—算错多少—更新”

4.1 只看一个词,避免同时处理太多数字

现在先把输入简化为:只判断是否出现“好看”。

1
2
3
4
输入特征 x = 1,表示“好看”出现一次。
正确标签 y = 1,表示好评。
初始权重 w = 0。
为了简化,本例不使用偏置。

预测分数:z=w×x=0。

好评概率:p=sigmoid(0)=0.5。

模型目前没有倾向,就像在两个选项之间犹豫。

4.2 用一个数字表示这次预测有多差

对于这条正确答案为好评的样本,使用:

1
损失 = -ln(模型给好评的概率)

所以:

好评概率损失
0.12.303
0.50.693
0.90.105

正确答案的概率越高,损失越小。

对于差评样本,则关心差评概率 1-p。把两个情况合在一起,就是二分类交叉熵:

\[L=-\big[y\ln p+(1-y)\ln(1-p)\big]\]

这里的 \(y\in\{0,1\}\),\(p\) 是模型估计的好评概率。交叉熵惩罚模型没有把概率分配给正确答案;估计概率也不能直接当作经过验证的实际正确率。3

4.3 更新一次,观察发生了什么

对于本例的 sigmoid 与交叉熵组合,权重的梯度是:

1
2
3
梯度 = (预测概率 - 正确标签) × 输入特征
     = (0.5 - 1) × 1
     = -0.5

梯度指示损失上升的方向,因此我们朝相反方向更新。学习率先取 0.2:

1
2
3
新权重 = 旧权重 - 学习率 × 梯度
       = 0 - 0.2 × (-0.5)
       = 0.1

用新权重重新预测:

1
2
3
新分数 = 0.1×1 = 0.1
新好评概率 ≈ 0.525
新损失 ≈ 0.644

好评概率从 0.500 升到 0.525,损失从 0.693 降到 0.644。模型已经朝正确方向移动了一小步。

这个例子的学习率使损失下降了;一般情况下,学习率过大仍可能让损失上升。真实训练会对很多样本重复这个过程。样本之间可能产生不同甚至相反的更新,模型需要找到整体上较好的参数,而不是记住这一条样本。

4.4 后面的模型仍然沿用这条训练链

后面你会遇到词向量、RNN 和 Transformer。内部计算越来越复杂,但训练的基本循环没有改变:

1
输入 → 预测 → 与答案比较 → 算损失 → 算梯度 → 更新参数

反向传播就是高效计算这条计算链上各个参数的梯度。它不会直接接收“你要理解否定句”这种人类解释,而是根据训练误差调整数字。

小练习:如果相同输入“好看”的标签换成差评,初始 p=0.5,梯度会是什么?

(0.5-0)×1=0.5。更新会减小权重,让好评概率下降。这也说明错误标注会把学习推向错误方向。

5. 给模型一点顺序:相邻词组与 N-gram

5.1 不只统计单个词,也统计相邻词组

对“电影 不 好看”,除了三个单词,还可以记录:

1
2
电影_不
不_好看

这叫二元词组,即 bigram。它可以让分类器单独学到“不_好看”与差评相关。

三个连续 token 组成 trigram。统称 N-gram,其中 N 表示一个连续片段包含多少个 token。

它比单词词袋保留了更多局部顺序,却仍不一定保留整句结构。

5.2 先尝试一个小小的“续写器”

暂时离开影评,收集下面三句话:

1
2
3
我 喝 茶
我 喝 茶
我 喝 水

看到“喝”后,你会猜接下来是什么?

训练文本里,“喝”有三次作为前一个词,其中两次后面是“茶”,一次是“水”。所以可以估计:

1
2
P(茶 | 喝) = 2÷3
P(水 | 喝) = 1÷3

P(茶 | 喝) 读作:“已经知道前面是‘喝’的条件下,接下来是‘茶’的概率。”竖线右边是条件。

这样就有了一个最简单的语言模型:它根据前文预测下一个 token。

5.3 为什么叫 bigram 语言模型

因为这里统计的是“前一个词 + 当前词”这两个词的组合。

因此,N-gram 语言模型一般用前 N-1 个 token 预测当前 token:bigram 看前一个;trigram 看前两个。

如果要给整句话打分,可以把每一步概率相乘:

1
2
3
4
句子概率 = 第一个词的概率
         × 已知第一个词时第二个词的概率
         × 已知前面词时第三个词的概率
         × ……

上面的连乘来自概率链式法则;N-gram 另作一个近似,只保留最近的 N−1 个 token 作为条件。例如 bigram 将 \(P(w_t\mid w_{<t})\) 近似为 \(P(w_t\mid w_{t-1})\)。实际模型还会使用句首、句尾标记,明确句子如何开始和结束。4

5.4 没见过不等于不可能

上面的语料没有“喝 咖啡”。如果只按次数计算,它的概率就是零。

一种教学用办法是:给每个候选都先加一次。假设候选只有 [茶, 水, 咖啡]:

候选原次数加一次后新概率
茶233/6
水122/6
咖啡011/6

这叫平滑:为没见过的事件预留概率。这里的加一法便于手算,实际任务有更合适的平滑方法。4

5.5 为什么不能总是多记几个词

假设你想用完整前文“我今天下班之后特别想喝”来预测。很可能训练数据里一次都没出现过这段完整前文。

越长的组合越具体,也越难重复出现。词表大时,潜在组合数量增长得很快。

短窗口容易统计,但缺少远处信息;长窗口包含更多信息,但数据稀疏、存储增加。模型也难以把“喝茶”和“饮茶”之间的相似性共享起来。

让相似的词在数值表示上也有联系。

小练习:“加了 bigram 特征的分类器”和“bigram 语言模型”是一回事吗?

不是。前者把相邻词组当分类特征,输出类别;后者根据前一个 token 预测下一个 token 的概率。它们都用相邻词的统计,但任务不同。

6. 词向量:给每个词一张可以学习的“数值卡片”

6.1 为什么还需要另一种表示

假设分类训练里见过很多“好看”,很少见到“精彩”。词袋把这两个词放在完全不同的列,模型不会因为学好了“好看”就自动理解“精彩”。

我们希望每个词有一组可复用的特征。于是给每个词一排可学习的数字:

词第一维第二维
好看1.00.0
精彩0.80.2
难看-1.00.0
无聊-0.80.2
电影0.01.0

这张表是人为构造的,特意让“好看”和“精彩”靠近,便于演示。真实训练不会预先规定第一维必须是褒贬,也不能保证反义词位于相反方向。

每个词对应的这一排数字称为 word embedding,词嵌入或词向量。

6.2 Embedding 层做的事情其实很具体

1
2
输入“好看”的编号 → 查表 → 取出 [1.0, 0.0]
输入“电影”的编号 → 查表 → 取出 [0.0, 1.0]

整张表可以看作一个矩阵:矩阵只是多排等长向量叠起来。

如果有 10,000 个词,每个词用 128 个数表示,那么这张表的形状是:

1
10,000 行 × 128 列

一条有 20 个 token 的句子查表后,就得到:

1
20 行 × 128 列

这里有两个容易混淆的数字:20 是句子长度,128 是每个 token 的特征数量。

6.3 为什么有的教程先讲 one-hot

如果词表有五个词,“好看”位于第一项,那么 one-hot 表示就是:

1
[1, 0, 0, 0, 0]

只有对应位置为 1,其余为 0。拿它与 embedding 表做适当的矩阵乘法,结果恰好就是选中对应行。

所以,one-hot 乘 embedding 表与按编号查行,在数学上等价。实际程序通常直接查表,避免构造一大串零。

6.4 把词向量合成一句话,先试最简单的平均

“电影 好看”有两个词向量:

1
2
电影:[0.0, 1.0]
好看:[1.0, 0.0]

对应维度相加,再除以词数:

1
句子向量 = [(0+1)/2, (1+0)/2] = [0.5, 0.5]

若分类器权重是 [2, 0],不使用偏置,则:

1
2
得分 = 2×0.5 + 0×0.5 = 1
好评概率 = sigmoid(1) ≈ 0.731

“电影 精彩”的平均向量是 [0.4, 0.6],得分 0.8,好评概率约 0.690。

由于两个褒义词的向量相近,同一套分类权重可以对它们产生相似判断。这说明词向量如何帮助共享特征。

6.5 这些数字可以在影评训练时一起更新

第四章介绍的训练过程不仅能更新最后的分类权重,也能通过反向传播更新查到的词向量。

1
2
3
评论 → 查词向量 → 求平均 → 分类 → 损失
            ↑                    |
            └──── 梯度更新 ──────┘

如果“好看”所在的很多正面评论都判断错了,训练就会逐步调整相关数字,帮助降低整体损失。

这叫端到端学习:多个可学习部分围绕同一个任务目标一起调整。

6.6 得到了什么,还没有得到什么

得到了:每个词可以用较少的连续特征表示;相似词有机会共享信息;表示可以为任务调整。

没有自动得到:语序、多义词消歧、可靠的句子理解。

平均值不依赖顺序,所以“我喜欢你”和“你喜欢我”的平均词向量还是相同。

另外,静态词表中的“苹果”在“吃苹果”和“苹果发布手机”里查出的初始向量相同。后面还需要上下文加工。

小练习:词向量有 128 维,是否表示研究者提前列出了 128 种语言属性?

通常不是。每一维是训练得到的数值特征,往往无法单独命名;信息可能分散在多个维度中。

7. 不标注好评差评,也能训练词向量吗:Word2Vec

7.1 从原文中制造一道填空题

假设有一句:

1
我 喜欢 看 电影

把“看”作为中心词,左右各取一个词:

1
2
输入:[喜欢, 电影]
答案:看

答案本来就在原文里,不需要请人额外标注。这就是从文本自身构造监督信号。

CBOW 采用“周围词预测中心词”的训练方向。

7.2 用小数字完整走一次预测

为了缩小计算,本例只允许三个输出候选:[看, 吃, 买]。

假设输入词向量是:

1
2
3
喜欢:[1, 0]
电影:[0, 1]
平均:[0.5, 0.5]

再准备一张输出侧向量表:

1
2
3
看:[2, 2]
吃:[0, 0]
买:[1, 1]

每个候选与平均向量做点积。点积就是对应位置相乘再相加。

1
2
3
看的得分:0.5×2 + 0.5×2 = 2
吃的得分:0.5×0 + 0.5×0 = 0
买的得分:0.5×1 + 0.5×1 = 1

这些分数还不是概率:它们没有保证为正,也没有保证加起来等于 1。

7.3 Softmax:把多个候选分数变成一组概率

步骤只有两个:先对每个分数计算指数,再除以所有指数的和。

候选原分数指数除以总和 11.107
看27.3890.665
吃01.0000.090
买12.7180.245

三个概率相加为 1。正确答案是“看”,损失为:

1
-ln(0.665241…) ≈ 0.408

训练会调整输入词向量和输出侧向量,让大量真实上下文中的正确答案概率变高。

这里有两张向量表,是因为“作为输入提供特征”和“作为输出候选接受打分”承担不同角色。它们可以分别学习,不必相同。

7.4 还能手算一次词向量更新

沿用上面的例子。三个输出分数的梯度约为:

1
2
3
看:0.665 - 1 = -0.335
吃:0.090 - 0 =  0.090
买:0.245 - 0 =  0.245

平均输入向量收到的梯度,由这些数乘对应输出向量后相加:

1
2
(-0.335)×[2,2] + 0.090×[0,0] + 0.245×[1,1]
≈ [-0.425, -0.425]

平均操作把梯度平分给两个输入词,每个约得到 [-0.212,-0.212]。

学习率取 0.1,只展示输入侧更新:

1
2
喜欢:[1,0] - 0.1×[-0.212,-0.212] ≈ [1.021,0.021]
电影:[0,1] - 0.1×[-0.212,-0.212] ≈ [0.021,1.021]

这就是“词向量被学出来”的一次具体操作。完整训练通常还会更新输出侧;这里暂时固定输出侧,是为了单独观察输入向量如何变化。

7.5 Skip-gram 把预测方向倒过来

仍取“看”为中心,左右各一个词:

1
2
看 → 喜欢
看 → 电影

CBOW 是周围词预测中心词;Skip-gram 是中心词预测周围词。二者都是 Word2Vec 家族中的方法。5

如果“猫”和“狗”经常出现在相似语境中,它们会受到相似的训练压力,有机会形成相近的表示。但“好”和“坏”也会进入相似句式,因此相似向量不一定意味着同义。

7.6 词表太大时,为什么采用负采样

刚才只有三个候选,算三个分数即可。如果有 100,000 个候选,每个训练样本都完整打分就很贵。

负采样把任务改成:

1
2
真实附近词对:(看,电影)→ 应该判为真实共现
随机噪声词对:(看,香蕉)→ 应该判为抽样噪声

“噪声”只是这次抽样构造的标签,不表示这两个词在所有句子里绝不可能一起出现。

假设真实词对得分为 2,噪声词对得分为 -1:

1
2
3
真实词对被判为数据的概率:sigmoid(2) ≈ 0.881
噪声词对被判为噪声的概率:1-sigmoid(-1) = sigmoid(1) ≈ 0.731
合计损失:-ln(0.881)-ln(0.731) ≈ 0.440

我们只计算一个真实词对和少量噪声词对,而不是全部候选。但训练目标随之改变了:它主要学习区分词对,不直接提供全词表归一化的下一词概率。6

同样的上下文窗口下,CBOW 合并周围词后预测一次中心词,Skip-gram 则形成多个“中心词—周围词”训练对;实际速度与表示质量还取决于窗口、采样、语料和实现,不能仅凭名字判断。负采样减少打分量,同时改变目标。静态词向量仍需要后续模型结合当前句子消除歧义。56

小练习:Word2Vec 的训练答案来自哪里?需要每个词的人工语义标签吗?

答案来自原文中的邻近词或中心词,不需要人工给每个词标注含义。它从预测任务中学习可复用表示。

8. 词都认识了,为什么还是看不懂句子:RNN

8.1 平均词向量不记顺序

假设这两句话:

1
2
猫 追 狗
狗 追 猫

它们含有相同的词,因此词向量相加、求平均都会得到相同结果。

问题不是“猫”“狗”的词向量还没训练好,而是求和操作本来就不在乎顺序。

我们需要一种读完一个词之后,会更新记录、再接着读下一个词的计算。

8.2 先造一个极其简单的记事本

为了手算,假设词的特征只有一个数字:

1
2
3
猫:1
追:0
狗:2

这些是特征值,不是前面词表里的编号。数值仅用于演示顺序计算,不代表真实语义。

我们规定更新方式:

1
新记录 = 旧记录×0.5 + 当前词的特征

初始记录为 0。读“猫追狗”:

读到的词旧记录更新过程新记录
猫00×0.5+11
追11×0.5+00.5
狗0.50.5×0.5+22.25

读“狗追猫”:

读到的词旧记录更新过程新记录
狗00×0.5+22
追22×0.5+01
猫11×0.5+11.5

这次最终记录不同了:2.25 和 1.5。后面的模型终于有机会区分这两句话。

注意,这个小程序只说明“递归更新能够保留顺序差异”,不说明它已经懂得主语和宾语。

8.3 真正的 RNN 把一格记录扩展成很多格

真实模型的记录是一整个向量,叫隐藏状态 hidden state。例如每读一个词,就更新 128 个数。

1
初始状态 → 读“猫” → 状态1 → 读“追” → 状态2 → 读“狗” → 状态3

每一步使用同一套更新参数,而不是为每个位置单独建一套模型。

普通 RNN 的一种公式是:

\[h_t=\tanh(W_xx_t+W_hh_{t-1}+b)\]

逐项读:

符号含义
x_t第 t 个 token 的向量
h_(t-1)上一步记事本里的向量
W_x x_t把当前词加工成适合写入记录的信息
W_h h_(t-1)对已有记录进行加工
b偏置
tanh一个非线性函数,把每个结果压到 -1 到 1 之间
h_t更新后的记录

前面的手算例子省略了 tanh,并把矩阵缩成标量。它是结构演示,不是一个完整的标准 RNN 单元。

8.4 用这本记事本完成影评分类

1
2
3
4
5
电影 不 好看
    ↓ 按顺序查词向量、更新状态
最终状态
    ↓ 分类器
好评概率

训练仍然使用人工好评差评标签,仍然是第四章的预测、损失、梯度更新。只是梯度现在还要穿过多个时间步,调整状态更新参数和词向量。

8.5 普通 RNN 为什么容易忘记较早的信息

回到更新式“旧记录×0.5 + 新信息”。一个词的信息经过后面十次更新,就会被乘以:

1
0.5 的 10 次方 ≈ 0.000977

经过二十次:

1
0.5 的 20 次方 ≈ 0.000000954

早期信息的影响变得很小。反向学习时,也可能发生类似的连续缩小,叫梯度消失。若连续放大,则可能出现梯度爆炸。

真实 RNN 由矩阵和非线性函数决定,不是永远乘以 0.5;这个例子只用于说明“跨很多步连续相乘”的困难。

RNN 可以处理变长、有顺序的输入;流式推理时可保存固定大小状态。但每一步依赖上一步,时间维度上的计算难以全部同时进行,长期信息也容易在状态更新中丢失。7

小练习:RNN 处理 100 个词,需要为每个词准备不同的一套更新权重吗?

不需要。所有时间步共享更新权重,但每一步的输入和状态不同。

9. 让记事本学会保留和擦除:LSTM 与 GRU

9.1 不要每读一个词都以同样方式修改所有记录

想象一句较长的影评:

1
我不喜欢这部虽然演员很好、场景也很漂亮、但剧情混乱的电影。

前面的否定关系与后面的对象相隔很远。我们希望模型有能力保留重要信息,并选择性地加入新内容。

LSTM 增加了一份记忆状态,以及控制“保留多少、写入多少、输出多少”的门。

门 gate 在这里就是一组 0—1 之间的数。0 表示挡住,1 表示完全放行,中间值表示保留一定比例。它们也由网络根据输入和历史状态算出来,不是人写的 if 规则。

9.2 只看记忆中的一格

假设某一格原来是 0.8,这次模型算出:

1
2
3
旧记忆保留比例:0.9
新候选内容:0.5
新内容写入比例:0.2

那么:

1
新记忆 = 0.8×0.9 + 0.5×0.2 = 0.82

在理想化的门值下,保留比例为 1、写入比例为 0,旧记忆就原样保留;保留比例为 0,则旧内容被清除。实际 sigmoid 在有限实数输入下输出介于 0 和 1 之间的值,这里用端点说明极限情况。

再假设输出门为 0.7:

1
对外输出 = 0.7×tanh(0.82) ≈ 0.473

这里“记忆里保存什么”和“当前输出什么”已经可以有所区别。

9.3 再看公式,就能对应每一部分

\[c_t=f_t\odot c_{t-1}+i_t\odot g_t\] \[h_t=o_t\odot\tanh(c_t)\]
符号刚才例子中的值含义
c_(t-1)0.8旧记忆
f_t0.9遗忘门:旧记忆保留多少
g_t0.5新候选内容
i_t0.2输入门:新内容写入多少
o_t0.7输出门:当前暴露多少内容
c_t0.82新记忆
h_t约 0.473当前隐藏输出

符号 ⊙ 表示对应格子相乘。例如 [1,2] ⊙ [0.5,0.1] = [0.5,0.2]。

这些格子是可学习特征,不能默认某一格就叫“否定”。模型可能把一种语言关系分散表示在很多格中。

9.4 GRU 与双向模型分别改变什么

GRU 的全称是 Gated Recurrent Unit。它采用另一套较简化的门控更新方式,不像 LSTM 那样单独保留相同形式的两种状态。

一般来说,相同隐藏维度的 GRU 门控结构更少;效果是否更好需要实验。LSTM 和 GRU 都仍有逐步递归依赖。

如果已经拿到了完整句子,还可以从左往右读一遍、从右往左读一遍,再把两个方向的状态拼接。这叫双向 RNN 或双向 LSTM。

例如理解“苹果”时,右边是“很好吃”还是“发布手机”很有帮助。双向模型可以利用两侧信息。

但在一步一步续写时,未来词还不存在,不能把真实未来答案交给生成模型。

门控改善信息保留和梯度传播,但增加参数与计算,也不保证无限记忆;双向计算利用更多上下文,但要求这些上下文已经可用。7

小练习:LSTM 记忆更新里,若遗忘门为 1、输入门为 0,会怎样?

记忆状态原样保留。隐藏输出仍可能因输出门变化而不同。

10. 另一条处理顺序的路线:TextCNN 先寻找局部短语

10.1 不一定要逐词记忆,也可以滑动一个窗口

对句子:

1
这部 电影 不 太 好看

宽度为 3 的窗口依次看到:

1
2
3
[这部, 电影, 不]
[电影, 不, 太]
[不, 太, 好看]

模型可以学习一套在每个窗口都重复使用的打分规则,检测类似“不太好看”的局部模式。这就是文本卷积的一种直觉。

10.2 用一个小窗口手算

为了说明顺序,暂时用标量特征:

1
不:-1;太:0.5;好看:1

一个宽度为 3 的卷积核权重为 [2,1,1],不使用偏置:

1
2
原窗口 [不,太,好看]:2×(-1)+1×0.5+1×1 = -0.5
倒序   [好看,太,不]:2×1+1×0.5+1×(-1) = 1.5

因为窗口中不同位置使用不同权重,改变顺序会改变分数。真实模型使用多维词向量、多个卷积核和非线性函数。

常见分类方案还会取各窗口结果的最大值,表示“整句中有没有强烈出现某种模式”。这叫 max pooling,最大池化。

同一层的不同窗口可以并行计算,适合局部模式;远距离关系需要更大的感受野,例如堆叠多层、使用扩张卷积。最大池化还会弱化“具体出现在什么位置”的信息。8

小练习:窗口宽度只有 3 的单层卷积,能让相距 20 个词的两个位置在同一个局部窗口内直接交互吗?

不能。需要改变结构扩大感受野,或采用其他全局信息交互方式。

11. 从判断句子到写句子:语言模型如何训练与生成

11.1 把分类的选项从“好评差评”换成“词表中的 token”

回到续写任务。输入:

1
我 喜欢

模型输出:

下一个 token概率
电影0.6
音乐0.3
香蕉0.1

这与第七章 softmax 的形式一样。区别是这里依据前文预测下一个 token,预测器可以由 N-gram、RNN、LSTM 或后面的 Transformer 实现。

语言模型是一类任务或概率模型,不专指 Transformer。

11.2 训练答案怎样准备

原文只有一句:

1
我 喜欢 电影

加上句首 <BOS> 和句尾 <EOS> 后,可以得到四次预测:

已知内容正确的下一个 token
<BOS>我
<BOS> 我喜欢
<BOS> 我 喜欢电影
<BOS> 我 喜欢 电影<EOS>

在程序里,经常把输入序列和目标序列错开一位:

1
2
输入:[<BOS>, 我, 喜欢, 电影]
目标:[我, 喜欢, 电影, <EOS>]

每个位置都有正确答案,不需要人逐个出题。这叫自监督训练:监督信号由数据本身构造。

11.3 训练时给真实前文,生成时用自己刚写的前文

训练通常会给出真实历史,例如预测“电影”时,输入的“我喜欢”来自原文。这叫 teacher forcing。

生成时执行:

1
2
3
4
5
1. 输入“我”。
2. 预测并选择“喜欢”。
3. 把“喜欢”接到输入后面,得到“我喜欢”。
4. 再预测并选择“电影”。
5. 继续,直到出现结束标记或达到长度限制。

因此,生成早期如果选错词,后面的输入也会受到影响。训练和实际生成所遇到的前缀可能不同,这种差异常被称为 exposure bias。7

11.4 同一组概率,可以有不同的选词方式

对 [电影:0.6, 音乐:0.3, 香蕉:0.1]:

方法这一步怎么选需要知道的取舍
贪心 greedy直接选“电影”简单稳定,但逐步选最高不保证整句最好
随机采样按 0.6、0.3、0.1 的概率抽取同一输入可有不同输出,也可能抽到不合适的词
top-k,k=2保留电影和音乐,重新归一化为 2/3、1/3固定保留候选数量
top-p,p=0.8从大到小取到累计概率至少 0.8,此处取电影和音乐保留数量取决于分布形状
beam search继续探索多条候选前缀,保留若干高分路径增加推理工作;还要处理长度等因素

Temperature,温度,会改变概率分布的尖锐程度。可以直观理解为:较低温度更偏向原来高分的候选,较高温度更愿意考虑其他候选。

对于温度 \(T>0\),先把 softmax 之前的分数除以 T,再计算概率:

\[p_i(T)=\frac{\exp(z_i/T)}{\sum_j\exp(z_j/T)}\]

\(T=1\) 保持原分布;\(T\to0^+\) 时概率集中到最高分候选,并列最高分需要另行处理。有些接口把 temperature=0 约定为贪心解码,不能直接把 0 代入上式。温度不会自动增加知识,也不会把错误事实变正确。9

11.5 用困惑度看模型给真实文本分配了多少概率

假设三个真实下一词分别得到概率:

1
0.5、0.25、0.125

先算每个损失,再取平均:

1
2
3
损失:[0.693, 1.386, 2.079]
平均损失:1.386
困惑度:exp(1.386294…) = 4

exp 是指数函数,它与 ln 互为逆运算。困惑度也叫 perplexity,简称 PPL。

如果每一步都在四个候选间完全均匀分配概率,真实词概率都是 1/4,也会得到 PPL=4。这是一个直觉类比,不表示上面的模型每一步真的只有四个候选。

困惑度低说明真实文本在模型看来更可预测,不直接说明回答事实正确。比较不同模型时还要保持测试内容、分词和计分方式可比。4

小练习:模型在“我喜欢”后给“电影”0.6 的概率,是不是表示它必须选“电影”?

不是。还取决于解码方法。贪心会选它,随机采样可能选其他候选。

12. 翻译长句为什么困难:先认识 Attention,再认识 Q、K、V

12.1 翻译要同时处理输入句和输出句

输入:

1
我 喜欢 猫

希望输出:

1
I like cats

早期的一种做法是分成两部分:

1
输入句 → 编码器 encoder → 一个最终记录 → 解码器 decoder → 输出句

编码器和解码器都可以用 RNN/LSTM。编码器负责读,解码器根据读到的内容和已生成词继续写。

这种输入序列到输出序列的任务常称为 sequence-to-sequence,简称 Seq2Seq。输入输出长度不需要相同。

12.2 整段输入只留一个最终记录,会丢细节

短句可能够用;长句里的人名、时间、否定和修饰关系都要压进固定长度向量,容易出现遗漏。

一个改善方法是:保留编码器每一步的状态。生成每个输出词时,再从这些状态中选择性地读取信息。

这就是这里的 Attention,注意力。它是一套计算权重并加权组合信息的方法,不是模型产生了人类式的主观注意。

12.3 先假设模型已经算出三个相关性分数

假设正在生成 cats。对于三个输入位置,模型算出:

输入位置与当前生成步骤的相关性分数
我0
喜欢1
猫2

分数如何算,下一章再解释。这里先关注分数之后发生什么。

经过第七章学过的 softmax:

输入位置指数注意力权重
我1.0000.090
喜欢2.7180.245
猫7.3890.665

这次读取“猫”位置的比例最大。

12.4 按比例合成一个当前可用的上下文

假设三个位置保存的内容向量是:

1
2
3
我:[1,0]
喜欢:[0,1]
猫:[1,1]

按上面的权重相乘再相加:

1
2
3
当前上下文
= 0.090×[1,0] + 0.245×[0,1] + 0.665×[1,1]
= [0.755,0.910]

解码器将这个上下文与自己的当前状态结合,再预测输出 token。

注意力结果是一个向量,不是直接输出“cats”。预测词的输出层仍然需要存在。

下次生成另一个词时,可以重新算权重、得到不同上下文。模型不必每一步都依赖同一份压缩记录。

12.5 训练会自动调整对齐方式

通常只需要提供“输入句—正确翻译”样本。生成损失可以通过这些计算反向传播,调整打分网络、编码器和解码器。

不一定要人工逐词标注“cats 对应 猫”。注意力提供了一条可以学习软对齐的路径。10

模型可以反复访问输入的不同位置,减轻单个向量的瓶颈;但必须保存更多状态,并为输入与输出位置计算匹配分数。注意力权重也不能单独证明模型得出预测的原因;高权重和对最终预测的因果贡献不是同一个量。11

小练习:为什么生成“我”和生成“猫”对应的英文时,不应强制使用相同的输入权重?

不同输出步骤需要不同输入信息。注意力允许每一步重新决定如何组合输入状态。

13. Transformer 的核心计算:一句话里的词互相读取信息

13.1 从“输出读输入”,到“输入内部互相读”

上一章是翻译过程中,输出侧根据需要读取输入侧。这种两组表示之间的注意力叫交叉注意力,cross-attention。

现在考虑一句话:

1
小王把书递给小李,因为他想让小李看看。

我们希望“他”这个位置的表示能够结合其他词,获得关于它所指对象的线索。

让同一句话里的每个位置都可以按权重读取其他位置,叫 self-attention,自注意力。这提供了利用上下文的能力,不保证模型每次都能正确消除歧义。

1
2
3
原始词向量:这个 token 通常怎么表示
    ↓ 读取当前句子中其他位置的信息
上下文化表示:这个 token 在这句话里怎么表示

13.2 Q、K、V 分别在解决哪一步

上一章把“相关性分数已经算好”当作前提。现在解释一种具体的打分方式。

每个位置的输入向量经过三种加工,得到:

名称中文在计算里承担什么工作
Q:Query查询向量用来与各位置匹配
K:Key键向量用来接受匹配打分
V:Value值向量用来在匹配之后被加权读取

“查询”和“键”的匹配决定权重,“值”决定实际汇总的内容。

在这里的自注意力中,三者通过各自的可学习矩阵从同一组输入变换出来:Q=XW_Q、K=XW_K、V=XW_V。交叉注意力则由读取侧生成 Q,被读取侧生成 K 和 V。12

所谓矩阵变换,可以理解为给原来的每一维特征不同权重,再组合成新特征。这里没有人工给每个词写“我正在找主语”的文字指令。

13.3 从输入表开始,把一次自注意力算到底

为避免语义猜测,只用三个位置 A、B、C。每个位置有两个特征:

位置输入向量 X
A[1,0]
B[0,1]
C[1,1]

为了少算几步,让 Q 和 K 暂时保持输入不变,让 V 把第二维乘 2:

1
2
W_Q = W_K = [[1,0], [0,1]]
W_V       = [[1,0], [0,2]]

得到:

位置QKV
A[1,0][1,0][1,0]
B[0,1][0,1][0,2]
C[1,1][1,1][1,2]

实际模型的三套矩阵通常不同,这里只是选了方便手算的参数。

第一步:只看位置 A,把它的 Q 与每个 K 做点积。

1
2
3
A 对 A:1×1+0×0 = 1
A 对 B:1×0+0×1 = 0
A 对 C:1×1+0×1 = 1

第二步:缩放分数。

每个 Q/K 有两个数,所以除以 √2≈1.414:

1
[1,0,1] ÷ 1.414 ≈ [0.707,0,0.707]

这样做是为了控制点积的尺度。在常见的统计假设下,维度增加会使点积分数的波动变大,除以维度的平方根能缓和这个问题。

第三步:softmax。

1
2
3
指数:[2.028,1,2.028]
总和:5.056
权重:[0.401,0.198,0.401]

第四步:按权重组合 V。

1
2
3
A 的新表示
= 0.401×[1,0] + 0.198×[0,2] + 0.401×[1,2]
≈ [0.802,1.198]

位置 A 从原来的 [1,0] 变成了包含其他位置信息的结果。位置 B、C 也各自重复同样的过程,各自有自己的权重。

将所有位置的计算放在一起,就是常见公式:

\[\operatorname{Attention}(Q,K,V) =\operatorname{softmax}(QK^\top/\sqrt{d_k})V\]

若有 n 个输入位置,则 \(Q,K\in\mathbb{R}^{n\times d_k}\)、\(V\in\mathbb{R}^{n\times d_v}\),输出形状为 \(n\times d_v\)。这个结果还没有包含多头拼接、输出投影和残差连接。

此时公式的每一步都有对应:QK^T 一次性计算点积表,除以平方根缩放,softmax 将每行变成权重,最后乘 V 完成加权求和。12

13.4 为什么注意力表是“句子长度 × 句子长度”

本例有三个读取位置,每个位置都比较三个候选,所以产生 3×3 的分数表:

1
2
3
4
          读取 A  读取 B  读取 C
位置 A       ·      ·      ·
位置 B       ·      ·      ·
位置 C       ·      ·      ·

句子长 100 个 token,就有 100×100 个匹配分数。这是后面二次成本的来源。

13.5 生成时必须防止偷看答案:causal mask

训练序列为:

1
2
输入:我 喜欢 电影
目标:喜欢 电影 <EOS>

计算第一个位置时,如果允许直接看到第二个输入词“喜欢”,模型就可以偷看答案。

所以自回归模型使用因果遮罩,规定一个位置只能读取自己和前面的位置:

读取者我喜欢电影
我可读禁止禁止
喜欢可读可读禁止
电影可读可读可读

被禁止的分数在 softmax 前设为负无穷,使其权重变成 0。

回到 A、B、C 的例子,若 A 是第一个位置:

1
2
3
4
原分数:[0.707,0,0.707]
遮罩后:[0.707,-∞,-∞]
权重:[1,0,0]
输出:[1,0]

另外一种 padding mask 用来忽略补齐长度的占位符。它和防止看未来的 causal mask 目的不同,不能混为一谈。

13.6 还需要知道词序:位置编码

如果只做无位置特征、无额外结构限制的全自注意力,把输入行交换,输出也相应交换;它没有从中获得“原来谁在前谁在后”的额外线索。

一种办法是给每个位置一个向量,再与 token 向量相加:

1
进入网络的表示 = token 向量 + 位置向量

于是同一个词出现在第一位和第五位,会有不同输入。

原始 Transformer 使用正弦、余弦位置编码,也比较过可学习的位置嵌入。12 RoPE 则通过对 Q/K 做依位置变化的旋转,让点积体现相对位置信息;它不是简单地给输入加一个位置向量。13

13.7 多头注意力:并行做几套不同的匹配

一套 Q/K/V 只提供一套匹配方式。多头注意力让模型学习多套投影,各自计算注意力,再把结果拼接、加工。

例如总维度是 128,分成 4 个 head,每个 head 可以使用 32 维。不是必然为每个 head 都再准备完整的 128 维。

多个 head 有机会关注不同关系,但不保证“第一头专门学主语,第二头专门学否定”。这种功能不是人工指定的。

13.8 完整 Transformer 层还包括什么

一个常见层的示意流程是:

1
2
3
4
5
6
7
8
9
输入
 ↓ 归一化
多头注意力:在不同位置之间交换信息
 ↓ 与原输入相加(残差)
中间表示
 ↓ 归一化
前馈网络 FFN:加工每个位置自己的特征
 ↓ 与中间表示相加(残差)
输出,交给下一层

三项组件分别解决不同需要:

组件具体含义
FFN每个位置经过小型神经网络,例如 128 维→512 维→128 维;中间有非线性函数
残差连接把加工结果加回原表示,让网络容易保留原信息、学习增量变化
LayerNorm对当前 token 的特征做归一化,再使用可学习缩放与偏移,帮助稳定训练

例如 [1,3] 的均值是 2,减去均值后是 [-1,1]。这只是归一化中的一个步骤;完整 LayerNorm 还涉及方差、数值稳定项和可学习参数。

不同 Transformer 变体在归一化位置、激活函数和位置处理上会有差别。此处展示 Pre-LN 布局;Vaswani 等人的原始 Transformer 使用的是子层残差相加后再归一化的 Post-LN 布局。1214 这张图只画一个自注意力块,编码器—解码器模型的解码层还包含交叉注意力。

堆叠多层之后,模型可以反复交换与加工信息。最后按任务接分类层或词表预测层。

小练习:Attention 得到向量 [0.802,1.198] 后,是否已经输出了一个词?

没有。它产生的是新的特征表示,还需要后续层和输出头计算类别或 token 的概率。

14. “更强”要付多少钱:从数格子理解计算与显存

14.1 先分清三种成本

成本好理解的比喻在模型里是什么
参数存储保存多少张固定表格词向量表、各种权重矩阵
中间结果存储计算过程需要多少草稿纸激活、注意力矩阵、KV cache 等
运算量与运行时间做多少次计算、如何安排工人乘加运算、并行度、内存读写等

一句话从 100 个词变成 200 个词,模型参数可以不变,但草稿纸和运算会增加。

14.2 自注意力的二次增长,可以直接数出来

token 数量每个位置比较多少个位置匹配分数总数
4416
8864
1616256

长度翻倍,表格面积变为四倍。这就是标准全自注意力里 n² 的来源。

如果一句话长 4,096 个 token,一个 head 的表格有:

1
4,096×4,096 = 16,777,216 个元素

假设每个元素占 2 字节,显式保存这一张表就需要 32 MiB。32 个 head 合计 1 GiB。

这只计算一份表、不含 batch、其他层、梯度或别的中间结果。高效实现也不一定把整张表放入显存。

14.3 词表和特征维度也会增加成本

词表有 10,000 项,每个 token 128 维,则词向量表有 1,280,000 个数。每个数用 4 字节,约为 5.12 MB。

词表翻倍、维度不变,表格大小翻倍;维度也翻倍,则变成原来的四倍。

因此,更细的分词未必更便宜:词表可能变小,但输入可能更长;输入更长又会增加注意力工作。

14.4 为什么 Transformer 容易训练并行,生成却仍逐步进行

RNN 的第三个状态需要第二个状态,第二个状态需要第一个状态。存在时间步依赖。

Transformer 训练时完整输入已知。对同一层,可以同时计算多个位置,用 mask 保证不能看未来。不同层之间仍要逐层进行,并非整个模型只有一次计算。

自回归生成时,下一步输入要使用本步实际选出的 token。因此:

1
2
训练:答案序列已知,多个位置可以一起算。
生成:新 token 尚未选定,通常一步步向后写。

并行程度更高不等于数学运算一定更少,但常能更好地利用 GPU。

14.5 KV cache:把已经算过的内容保存下来

假设已经读完“我喜欢电影”,现在生成下一个 token。

在标准因果 Transformer 中,之前位置不会看到后来的词,因此这些位置已经计算出的 K/V 可以保留。生成新 token 时,计算新的 Q/K/V,再让新 Q 读取已有缓存。15

1
2
3
旧前缀:已有 K/V → 直接复用
新 token:计算新 K/V → 加入缓存
新 Q:与历史 K 做匹配,读取历史 V

这避免重复加工整个旧前缀,但历史缓存要占显存,而且新 token 通常仍要读取历史 K/V。使用缓存不代表每个生成步骤的全部成本都固定不变。

一种常见缓存大小估算是:

1
2
2 × 同时处理的序列数 × 层数 × 已缓存 token 数
  × KV head 数 × 每个 head 的维度 × 每个数的字节数

前面的 2 表示 K 和 V 两份。这个式子假设各层维度相同、K 与 V 等宽、每条序列缓存长度相同;估算的是缓存张量的数据量,不含预分配空位、分页元数据、量化尺度等实现开销。

假设单条序列、32 层、8,192 个 token、8 个 KV heads、每头 128 维、每个数 2 字节:

1
缓存 = 2×1×32×8192×8×128×2 字节 = 1 GiB

这仍不包括模型权重和其他开销。这里要使用 KV head 数,不能一律代入 Query head 数:普通多头注意力两者相同,GQA/MQA 会让多个 Query heads 共享 K/V。16

14.6 常见优化到底省了什么

方法主要动作得到什么付出或限制
KV cache保存旧位置的 K/V少做前缀重复计算缓存随长度增长
GQA/MQA 16多个 Query heads 共享较少 KV heads减少缓存与读取量改变模型参数化和表示分配
FlashAttention分块、融合计算,减少显存来回读写避免显式保存完整注意力表,改善效率全注意力的算术量仍随长度平方增长
量化 17用更少位数表示部分数值减少存储,某些硬件上可加速存在数值误差,加速依赖实现
缩短输入删除、截断或先检索再输入直接减少处理长度可能丢掉关键内容

FlashAttention 保持精确注意力的数学形式,主要改善计算组织和存储访问,不是把注意力替换成低秩近似。“精确”指算法没有对注意力作近似,不代表不同浮点实现的结果逐位相同。18

若关心复杂度,先限定为单条序列、单层、整段前向计算,并假设输入与隐藏维度同阶,FFN 中间维度与隐藏维度 d 成固定比例。长度为 n 时,普通稠密 RNN 约为 \(O(nd^2)\),标准 Transformer 层约为 \(O(nd^2+n^2d)\)。前一项包括投影和 FFN,后一项来自位置之间的交互;这里不计最后的全词表输出层。12

这不是使用 KV cache 后单步解码的成本。缓存长度为 n 时,单个新 token 在一层中的投影和 FFN 约为 \(O(d^2)\),读取完整历史的注意力约为 \(O(nd)\)。这些估算描述规模增长趋势,不给出实际耗时。15

参数量本身也要区分公开信息和猜测。例如《GPT-4 Technical Report》第 2 节明确说明没有披露模型大小,不能据此给 GPT-4 标上“100T 参数”等确定数字。19

小练习:输入长度翻倍,标准全注意力的匹配表有多大?模型权重也必须翻倍吗?

表格元素数变为四倍;模型权重不必变化。参数与运行时中间结果是不同的东西。

15. BERT、GPT、T5:同样使用 Transformer,训练题目却不同

15.1 为什么预训练能帮助新任务

如果只有几百条标注影评,从头训练一个复杂网络很容易学不好。

可以先让网络在大量原始文本上做自动构造的预测题,形成通用表示,再用影评标签进一步训练。

1
2
大量原始文本 → 预训练 → 已有语言相关表示
少量影评标签 → 任务适配 → 好评差评分类器

这种复用已有模型的做法属于迁移学习。预训练不是直接给模型逐条灌输词典定义,而是让它从训练任务中调整参数。

15.2 BERT:给你前后文,补出被遮住的部分

一个示意题目:

1
2
输入:这部电影非常 [MASK],我想再看一次。
答案:精彩

BERT 可以读取空白两侧的内容,因此右侧“想再看一次”也提供线索。这叫掩码语言建模,masked language modeling。

真实预训练不只使用这一种字面替换方式;原始 BERT 还有下一句预测任务。先理解“两侧上下文共同帮助恢复被选中 token”即可。20

拿它做影评分类时,可以在 [CLS] 等整句表示后接分类层;做实体识别时,可以在每个位置的表示后接标签预测层。

15.3 GPT 类因果语言模型:给你前文,接着写

题目变成:

1
2
输入:这部电影非常
答案:精彩

这里讨论 GPT 类模型的因果文本语言建模目标:用已知前文预测下一个 token。9生成时也自然地重复这个操作。

同一个生成接口可以表达很多任务:

1
2
3
请判断情感:这部电影很好看。答案:
请翻译:我喜欢电影。英文:
请总结下面这段文字:…… 摘要:

但把任务写成提示词,不保证模型在该任务上一定准确;能力与训练数据、训练目标、模型容量和提示有关。

15.4 T5:先把输入读完整,再生成另一个序列

T5 类编码器—解码器结构有两部分:编码器双向处理输入,解码器逐步生成输出,并读取编码器表示。

1
2
3
输入全文 → 双向编码器 → 输入的各位置表示
                             ↓ 交叉注意力
已生成输出 → 因果解码器 → 下一个输出 token

这种结构适合表达翻译、摘要等条件生成问题。T5 的预训练包括恢复被破坏的文本,并把多种任务写成文本到文本的形式。21

15.5 如何区分架构、训练任务和应用

名称属于哪一类解释
Transformer架构规定信息如何在网络中流动
预测下一个 token训练任务规定模型要答什么题
BERT、T5具体模型方案或家族组合特定架构与训练设计
影评分类、NER、翻译应用任务规定用户真正需要的输出
微调 fine-tuning训练操作从已有权重继续训练,使其适配数据或目标

不要把这些名字全部排成一条“谁取代谁”的队伍。BERT 做 NER 与 GPT 做生成可以是不同任务上的选择。

双向编码器便于利用完整输入做判断;因果模型便于连续生成;编码器—解码器明确分开读入与输出。固定分类任务可以只输出几个类别的分数,生成式完成同一任务通常需要更多输出计算。

小练习:为什么 BERT 可以看被遮词右边的内容,而自回归续写不能看真实的下一词?

二者答的题不同。填空任务提供空白两边的文本;续写任务中的未来文本尚不存在,给出它会泄漏答案。

16. 找出句子中的人名和地名:NER

16.1 从“整句一个答案”改成“每个位置一个答案”

输入:

1
小王 在 上海 工作

目标:

token标签
小王人物
在其他
上海地点
工作其他

这叫 Named Entity Recognition,命名实体识别,简称 NER。实际需要识别哪些实体类型,由任务定义。

模型可以先用 LSTM 或 Transformer 生成每个位置的上下文化表示,再为每个位置预测标签。

16.2 一个实体跨了多个 token 怎么办

假设分词结果是:

1
小王 在 北京 大学 工作

我们想把“北京大学”识别为一个组织,不能把“北京”单独当作地名。

这里采用 BIO 的 IOB2 规范,每个实体都以 B 标签开始:

tokenBIO 标签含义
小王B-PER一个人物实体的开始
在O不属于实体
北京B-ORG一个组织实体的开始
大学I-ORG继续上一个组织实体
工作O不属于实体

B 是 beginning,开始;I 是 inside,内部;O 是 outside,外部。PER、ORG 只是实体类型缩写。

16.3 为什么有时还需要 CRF

如果每个位置独立选最高概率标签,可能生成句首 I-ORG 一类不符合所采用 BIO 规范的序列。

这里使用线性链 CRF(条件随机场)给整条标签序列评分。它不仅看“这个词像什么标签”,还看“这个标签跟在前一个标签后面是否合适”。

例如,仅展示“北京 大学”两个位置,其他候选暂时忽略:

位置标签单位置分数
北京B-ORG2
北京O1
大学I-ORG1.5
大学O1.8

独立选择会选 B-ORG, O,第二个词被漏掉。

若模型学到转移分数 B-ORG → I-ORG 为 1,其他本例转移分数为 0:

1
2
3
[B-ORG, I-ORG]:2+1.5+1 = 4.5
[B-ORG, O]:2+1.8+0 = 3.8
[O, O]:1+1.8+0 = 2.8

联合评分就更倾向于把两个词组成完整实体。本例略去了起止转移分数。在线性链 CRF 中,训练时用前向算法计算序列概率的归一化项,解码时可用 Viterbi 算法找最高分路径;上面的加法只是路径分数,还不是归一化概率。

这里的转移分数是学习出来的软偏好。若要严格禁止不合法转移,需要明确加约束。22

16.4 为什么不能只看每个词的准确率

假设文章有 1,000 个 token,只有 20 个属于实体。一个把所有位置都预测成“其他”的模型,也有 98% token 准确率,但一个实体都没找出来。

NER 常按完整实体计算:类型和起止边界都正确,才算一次正确抽取。

若模型抽取出 10 个实体,其中 8 个正确,原文实际有 12 个实体:

1
2
3
精确率 precision:8/10 = 0.8
召回率 recall:8/12 ≈ 0.667
F1:两者的调和平均 ≈ 0.727

精确率问“找出来的有多少是对的”;召回率问“该找的找到了多少”。这里先汇总完整实体的正确数、预测数和标注数,再计算指标,相当于 micro 统计;若分母为零,需要说明评价工具采用的约定。22

独立 token 分类简单;联合标签建模增加结构一致性,但需要更多计算。生成式模型也能抽取实体,却需要另外检查原文对应、边界与输出格式。

小练习:原文实体是“北京大学”,模型只输出“北京”,能算一次完整正确的实体抽取吗?

在严格实体级评价中不能,边界不一致。仅仅认对其中一部分文字不够。

17. 从会续写到能回答:SFT、偏好优化、LoRA 与 RAG

17.1 会预测下一词,不等于已经学会按要求回答

设输入是:

1
2
问:这条影评是好评吗?“电影很好看。”
答:

我们希望回答“是,好评”。但只进行原始文本续写训练的模型,未必能稳定遵循这种问答格式。

于是可以提供很多“指令—合适回答”示例继续训练,称为 SFT,监督微调。

1
2
输入:请判断下面影评的情感:电影很好看。
目标回答:好评。

训练仍然可以使用下一词交叉熵,只是数据更接近我们期望的使用方式。有些实现只对回答部分计算损失。

17.2 如果两个回答都通顺,怎么表达“我更喜欢这个”

对于同一个问题,给出两个回答:

1
2
回答 A:好评。“很好看”表达了正面评价。
回答 B:不知道,电影和语言没有关系。

人工或其他评价流程可以标注 A 优于 B。这叫偏好数据。

一条典型的 RLHF 路线是:用偏好训练奖励模型,再用奖励信号优化生成模型,并限制它偏离参考模型过远。

DPO 则用偏好对直接构造训练损失,是另一种偏好优化方法。理解到这里即可,初学 NLP 不必先掌握强化学习优化细节。

这些训练能让行为更符合评价标准;但偏好质量、评价偏差和目标设计会影响结果,“更讨人喜欢”不自动等于“事实更准确”。23

17.3 LoRA:只学一个较小的权重改动

微调大模型时,更新全部参数可能很贵。LoRA 冻结原权重,用两个较小矩阵表达新增改动。

先看一个 4×4 的矩阵:它有 16 个参数。若只学一个 4×1 矩阵和一个 1×4 矩阵,两者相乘也得到 4×4 的改动,但只有 8 个可训练参数。

代价是:这种改动受结构限制,不能自由表达所有可能的 4×4 矩阵。

用公式写成:

\[W=W_0+\frac{\alpha}{r}BA,\qquad B\in\mathbb{R}^{d_{\mathrm{out}}\times r},\quad A\in\mathbb{R}^{r\times d_{\mathrm{in}}}\]

这里 r 是低秩维度,\(\alpha/r\) 是原论文采用的缩放系数;取该系数为 1 时,才简写为“原权重 + B×A”。缩放不会改变下面两张矩阵的参数个数。

如果原矩阵是 4,096×4,096,取中间维度 r=8:

1
2
原矩阵参数:4096×4096 = 16,777,216
LoRA 新增参数:4096×8 + 8×4096 = 65,536

这一个矩阵的可训练参数减少到原来的 1/256。但原权重仍要保存,前向计算仍要执行,训练还会使用激活等内存,不能把这个比例当作整套显存或耗时下降比例。24

LoRA 是“怎么更新参数”的方法,SFT 是“用什么训练任务和数据”的方法,二者可以组合。

17.4 RAG:把需要的资料找出来,再放到问题旁边

假设你问:

1
课程资料中的第 19 课讲什么?

假设我们有一套课程资料,其中第 19 课介绍命名实体识别。模型参数里不一定保存了这套课程的可靠信息,可以先检索文档,取得相关段落,再把问题和段落一起交给模型。

1
2
3
4
5
问题
 ↓ 检索
找到“第 19 课:命名实体识别”的相关内容
 ↓ 与问题一起放入上下文
模型回答

这叫 Retrieval-Augmented Generation,检索增强生成,简称 RAG。25

检索可以采用关键词匹配,也可以把问题和文档转换成向量,找相似项;还可以组合多种检索并重排。

对刚学过词向量的你,要注意:文档检索常需要适合句子或文档相似度的表示,不能默认随便平均一组词向量就一定检索得好。

一个不考虑长度归一化差异的玩具打分例子:问题向量为 [1,0],两个文档向量是 [0.9,0.1]、[0.1,0.9],用点积打分分别得到 0.9 和 0.1,于是优先返回第一篇。真实系统需要考虑向量训练目标、归一化、检索指标和语料组织。

更新文档可以提供新信息,不必每次重训模型;但检索会增加工作,找错材料或生成时误用材料仍会出错。RAG 不等于已经把资料永久训练进参数。

17.5 把这些名字放在各自的位置上

你要解决的问题对应方法
先获得可复用的语言相关能力预训练
学会按指定任务或格式回答SFT
学习哪一种回答更符合偏好RLHF、DPO 等偏好优化
减少微调时要更新的参数LoRA
获取当前外部资料RAG
执行计算、查询等操作工具调用及相应系统设计
小练习:给模型提供一份新课程文档作为上下文,是不是一定修改了它的权重?

不是。普通提示和 RAG 通常只是改变这次输入;修改权重需要训练或明确的参数更新过程。

18. 把知识落到实验:怎样知道模型真的学会了

18.1 一个完整影评实验的流程

1
2
3
4
5
6
7
8
1. 明确标签标准:好评、差评,是否需要中性。
2. 收集并检查评论与标签。
3. 划分训练集、验证集、测试集。
4. 用训练集建立词表或拟合 TF-IDF 等统计。
5. 先训练一个简单基线。
6. 用验证集选择设置、定位错误。
7. 在独立测试集报告结果。
8. 检查真实错误样例、延迟和资源成本。

不要把六条教学评论当成足以证明泛化能力的数据集。它们用于理解计算,真实实验需要更多样本和合理的划分。

训练集负责学参数,验证集帮助选配置,测试集评估最终表现。若不断根据测试集调整方法,它就不再是独立测试。自己拟合词表、IDF 或归一化统计时,也应限制在训练集内,避免把验证集和测试集的信息提前用于训练。3

18.2 换模型之前,先看它错在哪里

错误例子可能原因应检查什么
“不好看”判成好评否定组合处理不足训练样例、bigram、顺序模型
新词“惊艳”完全识别不了词表覆盖或表示不足分词、未知词、预训练表示
长影评漏掉最后的转折截断或长距离处理问题输入是否完整、状态或注意力行为
所有样本都判好评类别偏斜或训练问题标签分布、损失、预测概率
训练集很好、测试集很差过拟合或分布不同数据量、重复样本、领域差异
一改 batch size 结果异常实现问题padding、mask、损失归一化

这些是排查方向,不是只凭一个例子就能确定的诊断。需要继续检查数据与计算。

18.3 加入 padding 后,平均值也要认真算

两条评论长度不同,为了一起计算,可能补成相同长度:

1
2
短句:[电影, 好看, <PAD>]
长句:[电影, 不, 好看]

如果短句的两个词向量分别是 [0,1]、[1,0],正确平均值是 [0.5,0.5]。

即使 <PAD> 向量是零,若把分母错误地写成 3,也会变成 [0.333,0.333]。因此不只要忽略 padding 内容,还要用真实 token 数量计算平均。

在注意力和损失计算中,也要按需要排除 padding。特殊 token 的编号由实际词表决定,本文没有给 <PAD> 固定编号。

18.4 比较方法时,比较同一个问题

方案适合先验证什么主要限制
规则任务是否主要依靠少量明确模式覆盖与维护成本
TF-IDF + 线性分类器关键词信息是否已经足够顺序和语义共享有限
平均词向量 + 分类器共享词特征能否改善结果聚合后仍丢顺序
CNN局部短语模式是否重要感受野与位置保留
RNN/LSTM/GRU顺序与流式状态是否重要递归依赖与历史压缩
预训练 encoder通用上下文表示能否迁移模型与适配成本
生成式语言模型能否用统一接口处理多种输出生成成本、格式与事实可靠性

应固定或明确说明数据划分、评价标准和资源条件。不能只因为一个复杂模型分数较高,就断定原因一定是架构;预训练数据、训练时长、输入长度都可能不同。

18.5 学完后可以逐个完成的练习

练习要观察的结果说明你理解了什么
手算“电影不好看”的词袋得到七维计数文本表示
运行一次逻辑回归更新正确标签概率提高参数如何学习
交换同一句话的词序平均词向量不变,递归记录可能改变顺序信息
手算 CBOW 的三个候选分数得到 0.665、0.090、0.245词向量训练目标
手算一个 Q 对三个 K 的分数得到三项权重与汇总向量Attention
给注意力加 causal mask未来位置权重变为零防止答案泄漏
同一组概率换不同解码方式输出选择方式不同模型与解码的区别
严格核对 NER 边界部分识别不算完整实体正确任务评价

附录 A. 第一遍读完后,再看这些常见支线

这些内容有助于补齐演进关系,但不应挡在第一遍理解主线之前。

A.1 朴素贝叶斯:用词出现的概率来判断类别

假设在好评里出现“精彩”的概率估计为 0.4,在差评里为 0.02,两类先验概率各为 0.5。

只观察这一个词时,两个未归一化的类别分数是:

1
2
好评:0.5×0.4 = 0.2
差评:0.5×0.02 = 0.01

归一化后,好评概率为 0.2/(0.2+0.01)≈0.952。

这一步只是贝叶斯公式的一次计算,尚未用到“朴素”的条件独立假设。多词版本才会在给定类别后,按所选事件模型组合词的条件概率;这种简化便于估计,但语言里的词并不真的彼此独立。26

A.2 GloVe 与 fastText:词向量还有其他学习办法

GloVe 利用词的全局共现统计来学习向量。可以把它理解为先统计“哪些词经常一起出现”,再学习表示这些统计关系的数值。

fastText 把词向量与字符片段联系起来,例如让共享词形片段的词共享部分参数。这样对词形变化和未见过的整词可能更有帮助。

它们提供的是词表示方案,不自动解决整句话的语序或所有多义词问题。27

A.3 HMM 与 CRF:先把输出的顺序结构建模

HMM,隐马尔可夫模型,使用“状态转移”和“状态产生观测”的概率来描述序列。例如标签状态之间会转移,各标签生成某些词的可能性不同。

CRF 直接对“给定输入时,标签序列有多合适”进行建模。第十六章已经看到如何结合单位置分数与标签转移分数。

这条路线提醒我们:NLP 的序列结构不只存在于输入词之间,也存在于输出标签之间。22

A.4 上下文化表示并非 Transformer 首创

RNN、双向 LSTM 也能根据当前句子的上下文产生不同表示。Transformer 提供了一种更便于并行和直接跨位置交互的组织方式。

因此,不能把“静态 embedding → 上下文化表示”与“RNN → Transformer”简单等同。

A.5 这条阅读路线不等于发表时间线

本文先教静态词向量,再教 LSTM,是因为这种依赖顺序更容易理解。历史上 LSTM 早于 Word2Vec。

传统统计方法、循环网络、卷积网络、注意力和预训练也有长期并行发展的过程。每种方法服务的约束不同,不应理解为一次统一的升级换代。5、7、8、12

句法分析、关系和事件抽取、语音识别等也是相关领域的重要分支。本文只沿文本表示、序列建模和语言模型展开,不能代替整个 NLP 领域的知识地图。

附录 B. 公式速查

公式读法对应正文
z = w·x + b输入各项乘权重再相加第 3 章
sigmoid(z) = 1/(1+exp(-z))把一个分数转成 0—1 的数第 3—4 章
softmax(z)_i = exp(z_i)/Σ_j exp(z_j)把一组候选分数转成概率第 7 章
L = -ln p(正确答案)给正确答案的概率越小,惩罚越大第 4、7、11 章
新参数 = 旧参数 - 学习率×梯度朝降低损失的方向走一步第 4 章
句子均值 = 词向量之和/真实词数把变长输入汇总为固定长度第 6、18 章
h_t = tanh(W_x x_t + W_h h_(t-1) + b)用当前词和旧状态更新 RNN第 8 章
c_t = f_t⊙c_(t-1) + i_t⊙g_t旧记忆保留一部分,加上新信息第 9 章
h_t = o_t⊙tanh(c_t)从记忆产生当前隐藏输出第 9 章
Attention = softmax(QK^T/√d_k + mask)V打分、遮罩、转权重、加权读取第 13 章
PPL = exp(平均负对数概率)对平均语言模型损失做指数变换第 11 章
F1 = 2PR/(P+R)综合精确率 P 与召回率 R第 16 章

LSTM 门控的进一步细节。若想知道门的数值从哪来,将当前词向量与旧隐藏状态拼接,记为 z:

1
2
3
4
5
z = [当前输入; 旧隐藏状态]
遗忘门 f = sigmoid(W_f z + b_f)
输入门 i = sigmoid(W_i z + b_i)
候选内容 g = tanh(W_g z + b_g)
输出门 o = sigmoid(W_o z + b_o)

各个 W 和 b 都通过训练学习。这些式子再接第九章的记忆更新即可,不需要人为设置每一个门。

一个 Pre-LN 自注意力块的进一步细节。以 Pre-LN 布局、略去 dropout 为例:

1
2
U = X + MultiHeadAttention(LayerNorm(X))
Y = U + FFN(LayerNorm(U))

FFN 通常包含两个线性变换和中间非线性函数,各位置独立应用同一套参数。编码器—解码器模型的解码层还要加入交叉注意力;不同变体的归一化和 FFN 形式也可能不同。1214

附录 C. 术语表

术语这篇文章中的解释
corpus,语料用来学习或分析的一批文本
token模型使用的一个文字处理单位
vocabulary,词表token 与编号的对应表
token IDtoken 的地址编号,不是语义数值
vector,向量一排有固定长度的数字
matrix,矩阵多排等长数字组成的表
dimension,维度向量有多少个数,或数组各方向的大小
tensor,张量多维数值数组,向量和矩阵是常见例子
feature,特征模型用于预测的数值信息
parameter,参数训练时调整的数值,例如权重
embedding从离散编号查到的可学习向量表示
hidden state,隐藏状态网络内部在某个位置形成的表示或递归记录
context,上下文当前预测能使用的周围文本或历史信息
logitssoftmax 之前的候选分数
loss,损失衡量当前预测有多不符合训练目标的数
gradient,梯度参数变化如何影响损失的局部信息
backpropagation,反向传播沿计算链高效计算各参数梯度的方法
batch一次一起处理的一组样本
padding为了对齐形状补入的占位项
mask限制某些位置参与计算的规则或数值表
attention按匹配权重读取和组合信息
head一套注意力投影与计算分支
encoder处理输入并产生表示的部分
decoder根据可用信息产生输出序列的部分
pretraining,预训练先在较广的数据和目标上训练,供后续复用
fine-tuning,微调从已有参数出发继续训练
inference,推理使用模型计算输出,通常不更新参数
decoding,解码根据模型分数选择具体输出序列
trade-off,取舍为获得一种收益,需要付出的成本或接受的限制

附录 D. 复算文中的数字

下载配套脚本后,可以运行 python nlp_examples.py。

脚本只使用 Python 标准库,不下载数据、不训练大型模型、不改动任何数据文件。

它会依次打印词袋、TF-IDF、一次分类更新、一次 CBOW 输入向量更新、顺序记录、LSTM 单格、卷积窗口、采样候选、注意力、显存估算及评价指标。

脚本中的 RNN 记录、LSTM 单格和卷积窗口是正文的局部计算演示,不是完整模型实现。它们的意义是复算数字,不能用来证明真实 NLP 任务的效果。

参考文献与阅读说明

正文按概念转述资料,没有逐字引录论文段落。微型数据和手算结果用于解释计算,不对应文献中的实验数据。方法原理优先引用论文,工程行为引用官方文档。

Jurafsky 与 Martin 的《Speech and Language Processing》采用 2026 年 8 月 19 日第三版在线草稿;以下写出章节名,便于在后续版本调整编号时查找。动态教材与官方文档核对日期为 2026 年 9 月 10 日。教材目录

  1. Rico Sennrich, Barry Haddow, Alexandra Birch. 2016. Neural Machine Translation of Rare Words with Subword Units. ACL. BPE 子词分割,参见第 3 节。 ↩︎

  2. Christopher D. Manning, Prabhakar Raghavan, Hinrich Schütze. 2008. Introduction to Information Retrieval. Cambridge University Press, §6.2.1. IDF 定义;正文采用自然对数和原始词频,未做平滑或归一化。 ↩︎

  3. Daniel Jurafsky, James H. Martin. 2026. Speech and Language Processing, Ch. 4: Logistic Regression and Text Classification. sigmoid、交叉熵、梯度更新及数据划分。 ↩︎ ↩︎2

  4. Daniel Jurafsky, James H. Martin. 2026. Speech and Language Processing, Ch. 3: N-gram Language Models. 概率链式法则、N-gram 近似、平滑与困惑度。 ↩︎ ↩︎2 ↩︎3

  5. Tomas Mikolov, Kai Chen, Greg Corrado, Jeffrey Dean. 2013. Efficient Estimation of Word Representations in Vector Space. 第 3 节与图 1:CBOW 和 Skip-gram 的预测方向。 ↩︎ ↩︎2 ↩︎3

  6. Tomas Mikolov 等. 2013. Distributed Representations of Words and Phrases and their Compositionality. NeurIPS. §2.2、式 (4):负采样目标。实现可另看 TensorFlow 的 Word2Vec 教程,其批量损失写法不应与本文逐词对 sigmoid 损失直接混同。 ↩︎ ↩︎2

  7. Daniel Jurafsky, James H. Martin. 2026. Speech and Language Processing, Ch. 14: RNNs and LSTMs. 循环状态、梯度传播、门控与序列生成。 ↩︎ ↩︎2 ↩︎3 ↩︎4

  8. Yoon Kim. 2014. Convolutional Neural Networks for Sentence Classification. EMNLP. 卷积窗口、非线性与 max-over-time pooling。正文标量例子省略了非线性。 ↩︎ ↩︎2

  9. Daniel Jurafsky, James H. Martin. 2026. Speech and Language Processing, Ch. 7: Transformers and Pretraining. 因果语言模型、预训练与生成采样;按本次草稿章节名引用。 ↩︎ ↩︎2

  10. Dzmitry Bahdanau, Kyunghyun Cho, Yoshua Bengio. 2015. Neural Machine Translation by Jointly Learning to Align and Translate. ICLR. 预印本发表于 2014 年;输入表示瓶颈与可学习的软对齐。其加性打分不同于 Transformer 的缩放点积。 ↩︎

  11. Sarthak Jain, Byron C. Wallace. 2019. Attention is not Explanation. NAACL. 支持“不能仅凭注意力权重认定预测原因”这一限定,不等于否定所有解释方法。 ↩︎

  12. Ashish Vaswani 等. 2017. Attention Is All You Need. NeurIPS. §3.1—3.5、式 (1) 与表 1:Post-LN、注意力、位置编码及计算复杂度。本文含投影和 FFN 的成本是在这些组件上合并估算的。 ↩︎ ↩︎2 ↩︎3 ↩︎4 ↩︎5 ↩︎6 ↩︎7

  13. Jianlin Su 等. 2021. RoFormer: Enhanced Transformer with Rotary Position Embedding. RoPE 的旋转位置编码;此处年份采用预印本首次发表时间。 ↩︎

  14. Ruibin Xiong 等. 2020. On Layer Normalization in the Transformer Architecture. ICML, PMLR 119:10524–10533. Pre-LN 与 Post-LN 的位置区别及训练分析。 ↩︎ ↩︎2

  15. Hugging Face. How caching works. Transformers documentation. 自回归推理中的 KV 复用;正文缓存字节数由张量维度相乘估算。 ↩︎ ↩︎2

  16. Joshua Ainslie 等. 2023. GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints. EMNLP. 多个 Query heads 共享 KV heads,MHA、GQA 与 MQA 的关系。 ↩︎ ↩︎2

  17. Tim Dettmers, Mike Lewis, Younes Belkada, Luke Zettlemoyer. 2022. LLM.int8(): 8-bit Matrix Multiplication for Transformers at Scale. NeurIPS. 量化方法的一项具体研究;存储收益与运行速度应分别评价。 ↩︎

  18. Tri Dao, Daniel Y. Fu, Stefano Ermon, Atri Rudra, Christopher Ré. 2022. FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness. NeurIPS. 分块计算、减少 HBM 读写与注意力中间结果存储。 ↩︎

  19. OpenAI. 2023. GPT-4 Technical Report. 第 2 节明确说明报告没有披露模型大小等细节。 ↩︎

  20. Jacob Devlin, Ming-Wei Chang, Kenton Lee, Kristina Toutanova. 2019. BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding. NAACL. 预印本发表于 2018 年;§3.1 为 MLM 与下一句预测。 ↩︎

  21. Colin Raffel 等. 2020. Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer. JMLR 21(140):1–67. 预印本发表于 2019 年;文本到文本框架、编码器—解码器与去噪目标。 ↩︎

  22. Daniel Jurafsky, James H. Martin. 2026. Speech and Language Processing, Ch. 18: Sequence Labeling for Parts of Speech and Named Entities. 实体标注、线性链 CRF 与评价;HMM 另见 附录 A。 ↩︎ ↩︎2 ↩︎3

  23. Daniel Jurafsky, James H. Martin. 2026. Speech and Language Processing, Ch. 8: Post-training. 指令微调、偏好数据、RLHF 与 DPO。 ↩︎

  24. Edward J. Hu 等. 2022. LoRA: Low-Rank Adaptation of Large Language Models. ICLR. 预印本发表于 2021 年;§4.1 为低秩分解与 α/r 缩放。 ↩︎

  25. Daniel Jurafsky, James H. Martin. 2026. Speech and Language Processing, Ch. 11: Information Retrieval and RAG. 稀疏与稠密检索、重排及检索增强生成。 ↩︎

  26. Daniel Jurafsky, James H. Martin. 2026. Speech and Language Processing, Appendix B: Naive Bayes Classification. 贝叶斯分类与条件独立假设。 ↩︎

  27. Daniel Jurafsky, James H. Martin. 2026. Speech and Language Processing, Ch. 5: Embeddings. 分布式表示、Word2Vec、GloVe 与 fastText。 ↩︎

本文由作者按照 CC BY 4.0 进行授权