一、接上第 9 讲留下的三个问题

第 9 讲拼出了自注意力的完整计算,但留了三个没处理的问题:

一次注意力只有一种"检索视角"——第 9 讲的例子里,Query 和 Key 只用一组矩阵投影,相当于每个词只能带着一个问题去检索。但现实中,一个词往往需要同时问好几个不同的问题(“谁是这句话的主语"“这个代词指的是谁"“这个词的语气是什么”),一组 Q/K/V 装不下这么多视角。

加权平均是线性组合,非线性去哪了——自注意力的最后一步是"用 softmax 权重对 Value 加权求和”,这本质上是一次线性组合。第 5 讲证明过:没有非线性,表达能力不会真正提升。softmax 本身虽然是非线性函数,但它只负责"算出权重该是多少”,权重算出来之后,“用这些权重去混合 Value"这一步依然是纯线性的加权平均。

堆叠很多层会不会训不动——第 9 讲结尾提到,单层注意力的汇聚能力有限,需要堆叠很多层。但第 6 讲讲过,网络越深,反向传播的梯度要连乘越多次局部导数,越容易消失或爆炸——这是不是又要撞上第 2 讲 RNN 撞过的那堵墙?

这一讲依次解决这三个问题,把解决方案拼装成一个完整的、后面全部课程反复出现的基本单元:Transformer 模块(Transformer block)。

二、打个比方:一次团队会议

把一个 Transformer 模块要做的事,想象成一场团队会议:

多头注意力,是会上同时有好几位不同专长的专家(语法专家、语义专家、指代消解专家……),各自独立地检索、各自形成意见,最后把所有人的意见汇总起来。

前馈层,是会议纪要发下去之后,每个人拿回自己的工位,独立地把汇总意见做一遍深加工,不再和别人交流。

残差连接,是每一次修改都在"原稿基础上追加批注”,而不是每次都推倒重写一份新稿子——不管这次讨论产生了多少新意见,原稿的内容永远可以被追溯回去。

LayerNorm,是开会前主持人先要求"大家发言音量统一",防止某个人嗓门太大盖过所有人、或者太小没人听见。

三、把每一块拼出来

多头注意力:同时检索好几个视角

第 9 讲的自注意力,只用一组 Wq, Wk, Wv 算一次。**多头注意力(multi-head attention)**的做法,是同时准备 h 组不同的、更小的投影矩阵,各自独立地做一遍第 9 讲的整套计算,最后把 h 个结果拼在一起,再过一次线性投影:

headᵢ = Attention(X·Wᵢ^Q, X·Wᵢ^K, X·Wᵢ^V)     ← 第 i 个"专家"独立检索

MultiHead(X) = Concat(head₁, ..., head_h) · Wᴼ   ← 拼接所有专家的意见,再汇总投影

⭐ 一个容易被误解的地方:多头不是把计算量除以头数——如果总的向量维度是 d,切成 h 个头,每个头的维度是 d/h,h 个头算完之后,拼回去还是 d 维,最后还要多做一次 Wᴼ 投影。总的计算量和参数量并没有比单头少,多出来的是"允许模型同时学习多种互不相同的检索模式"这个能力——这才是多头真正要买的东西。

接着第 9 讲的手算例子往下走。第 9 讲用 Wv=2×单位矩阵 算出了"头 1"的结果:

头 1 输出₁ = [1.340, 0.660]
头 1 输出₂ = [0.660, 1.340]

假设"头 2"用同样的 Wq=Wk=单位矩阵(所以打分和权重跟头 1 完全一样:0.670/0.330),但 Wv'=3×单位矩阵:

头 2 输出₁ = 0.670×[3,0] + 0.330×[0,3] = [2.01, 0.99]
头 2 输出₂ = 0.330×[3,0] + 0.670×[0,3] = [0.99, 2.01]

拼接位置 1 的两个头:[1.340, 0.660, 2.01, 0.99](4 维)。取一个简单的 Wᴼ——把头 1、头 2 对应维度各取一半平均:

最终输出₁ = 0.5×(1.340+2.01), 0.5×(0.660+0.99) = [1.675, 0.825]

这就是多头注意力的完整流程:各自独立检索、拼接、再投影汇总——这一讲没有引入任何新的数学工具,Wᴼ 依然是第 3 讲讲过的矩阵乘法。

前馈层:把"跨位置搬运信息"和"位置内部加工"分开

多头注意力做完之后,紧接着是一个前馈层(feed-forward layer,FFN),形式就是第 5 讲讲过的"一层+非线性+一层":

FFN(x) = σ(x·W₁ + b₁)·W₂ + b₂

⭐ 这里有一个值得明确点破的分工:自注意力负责"跨位置搬运信息"(把其他位置的内容按相关程度混合进来);前馈层负责"位置内部的独立加工"——FFN 对每个位置的向量分别处理,不同位置之间互不干扰,不像注意力那样互相参考。这正是第一节提出的第二个问题的答案:非线性表达能力不是自注意力这一层负责补的,是前馈层负责补的,两者分工明确,各司其职。

⚠️ 关于时效性:前馈层中间那个隐藏维度(W₁ 投影到的维度),实践中通常会比输入维度宽好几倍(常见做法是宽 4 倍左右),这样能给"位置内部加工"留出更大的中间计算空间。具体宽多少属于会变化的工程选择,但"中间层比输入输出层更宽"这个设计思路,比具体的倍数更值得记住。

残差连接:给梯度留一条不会衰减的路

现在处理第一节的第三个问题:层数堆多了,会不会重新撞上第 6 讲的梯度消失?

残差连接(residual connection)的做法极其简单:不要求每一层直接算出"新的表示应该是什么",而是让每一层只需要算出"在原来的基础上应该调整多少",再把这个调整量加回原始输入:

y = F(x) + x

F 可以是这一讲讲的多头注意力,也可以是前馈层——重点在"+x“这个动作本身。用第 6 讲的链式法则算一下这条设计对梯度意味着什么:

dy/dx = dF/dx + 1

⭐ 这一步是这一讲最关键的数学:不管 F 这条路径的局部导数 dF/dx 有多小(第 6 讲说过,深层网络里这个数字很容易被连乘到接近 0),梯度里始终有一个不会消失的”+1"项——因为"直接抄一遍 x“这条捷径的导数恒等于 1。哪怕 F 这一层这次没学到什么有用的东西(dF/dx≈0),梯度依然能原封不动地穿过这一层,传给更早的层。残差连接不是让每一层变得更聪明,是给梯度专门留了一条不会衰减的路,堆叠几十甚至上百层才第一次变得可行。

LayerNorm:统一发言音量

数据流过一层又一层之后,数值的大小(尺度)会漂移——某些维度可能变得很大,某些变得很小,训练会因此变得不稳定。LayerNorm(层归一化)的做法,是对每一个 token 自己的向量,把它调整成均值 0、标准差 1 的标准形态,再乘一个可学习的缩放 γ、加一个可学习的偏移 β(让网络在需要时能自己找回合适的尺度):

LayerNorm(x) = γ × (x − μ) / σ + β

μ 和 σ 是这一个向量自己内部所有数字的均值和标准差(不是很多个样本之间比较,是同一个向量自己"横着"算)。

小例子:某个 token 的向量是 x = [1, 3, 8]:

均值 μ = (1+3+8)/3 = 4
方差 = ((1−4)²+(3−4)²+(8−4)²)/3 = (9+1+16)/3 ≈ 8.667
标准差 σ ≈ 2.944

归一化(取 γ=1, β=0):
(1−4)/2.944 ≈ −1.019
(3−4)/2.944 ≈ −0.340
(8−4)/2.944 ≈  1.359

三个数字的均值变成 0,波动幅度也被统一到了一个标准区间——不管这个向量原本数值有多大或多小,经过 LayerNorm 之后都会落进一个稳定的范围,这正是它要解决的"数值漂移"问题。

组装成一个完整的 Transformer 模块

把四块拼在一起,就是一个完整的 Transformer 模块:

输入 x
  │
  ├─▶ LayerNorm ─▶ 多头注意力 ─┐
  │                            +(残差相加)
  └────────────────────────────┘
  │
  ├─▶ LayerNorm ─▶ 前馈层 ──────┐
  │                            +(残差相加)
  └────────────────────────────┘
  │
输出(维度和输入 x 完全一样)

⚠️ 图里 LayerNorm 放在多头注意力/前馈层之前(叫 Pre-LN),这是目前更常见的排布方式;最早的 Transformer 论文把 LayerNorm 放在残差相加之后(Post-LN)。两种排布各有训练稳定性上的细微差别,属于会继续演化的工程细节,但"每个子模块都配一次归一化、外面套一层残差"这个骨架,是不会变的部分。

⭐ 这个模块的输出维度和输入维度完全相同——这不是巧合,是故意设计的:正因为输入输出同维度,才能把很多个这样的模块直接首尾相连堆叠起来,第一个模块的输出就是第二个模块的输入,反复堆叠几十层,就是一个完整的 Transformer。

四、这一讲的代价

  • 多头不是免费的:如前面强调的,拼接后多出的 Wᴼ 投影、以及维护多组独立的 Wq,Wk,Wv,本身就是额外的参数和计算——买到的是"多视角"的能力,不是"更省"的计算。
  • 残差连接缓解但不彻底解决深度训练难题:它保证梯度不会因为连乘而完全归零,但不保证网络一定能学得又快又好——超深的网络依然需要配合 LayerNorm、合适的初始化方式、训练初期逐步调大学习率(“warmup”,第 13 讲会提到)等多种工程手段协同,残差连接只是其中最关键的一块,不是唯一一块。
  • LayerNorm 的具体位置和形式仍在演化:如上面提到的 Pre-LN/Post-LN 之争,以及后来出现的一些变体,都是在同一个"归一化以稳定训练"的目标下的不同实现,具体哪种最优会随研究进展变化。

五、和后面课程的关系

  • 第 11 讲要讲的是这些 Transformer 模块具体怎么被组织成一个完整模型(Decoder-only 还是 Encoder-Decoder),以及"该往哪看"这件事在生成任务里还有一层额外的限制(不能看到未来的词)——这一讲拼好的模块是两种架构共用的积木。
  • **第 12 讲(MoE)**要改造的正是这一讲的前馈层:把一个前馈层换成很多个"专家"前馈层,每次只激活其中一小部分,用来在不显著增加计算量的前提下扩大模型的参数容量。
  • 第 22 讲讲 KV Cache 时,头的数量和每个头的维度,直接决定了要缓存的 K、V 占多少显存——这一讲定义的"头"这个单位,会在那一讲重新变成一个具体的工程账。
  • Lab 4 要把这一讲的全部四块——多头注意力、前馈层、残差连接、LayerNorm——拼装成一个可以真正运行的 mini-Transformer 模块。

六、本讲小结

  • 多头注意力:把一组大的 Q/K/V 投影拆成多组更小的,各自独立做一遍第 9 讲的注意力计算,拼接后再投影汇总——买到的是"同时学习多种检索模式"的能力,不是计算量的节省。
  • 前馈层:σ(xW₁+b₁)W₂+b₂,第 5 讲讲过的结构原样搬来,负责"位置内部的独立加工”,和注意力"跨位置搬运信息"的分工互补。
  • ⭐ 残差连接 y=F(x)+x:不管 F 的局部导数多小,梯度里始终有恒等于 1 的一项穿过去——这是让几十上百层网络能被训练的关键设计,直接回应第 6 讲的梯度消失问题。
  • LayerNorm:对每个 token 自己的向量做均值 0、标准差 1 的归一化,再配一对可学习的缩放和偏移,防止数值在层间流动时漂移失控。
  • 四块拼在一起,就是一个输入输出同维度的 Transformer 模块——同维度这个设计使得很多个模块可以直接堆叠,这是整个 Transformer 架构"能够变深"的结构基础。

思考题

  1. 本讲的多头例子里,如果把"头 2"的 Wv' 换成 1×单位矩阵(和头 1 的 Wv 不同,也和例子里用的 3 不同),重新算一遍位置 1 拼接前的两个头的输出,以及用同样的 Wᴼ(各取一半平均)算出的最终输出。
  2. 为什么说"多头不是把计算量除以头数"?如果总维度 d=512,切成 8 个头,每个头维度是多少?和不切头、直接用一组 d=512 的 Q/K/V 相比,总的参数量(Wq,Wk,Wv 三个矩阵加起来)大致是同一个量级还是明显更小?
  3. 用 dy/dx = dF/dx + 1 这个式子解释:如果一个 100 层的网络全部用残差连接搭建,即便其中 50 层的 dF/dx 都恰好是 0(这一层"什么都没学到"),最终从输出传回最开始输入的梯度会不会变成 0?
  4. LayerNorm 的例子里,如果把 x=[1,3,8] 换成 x=[100,300,800](所有数字乘以 100),重新算一遍归一化后的结果,和原来的 [-1.019,-0.340,1.359] 相比有什么变化?这说明 LayerNorm 对"整体数值大小"是不是不敏感?
  5. 这一讲说"前馈层对每个位置独立处理,不同位置互不干扰"——如果一个 Transformer 模块只有前馈层、完全去掉多头注意力,反复堆叠很多层,这个模型有没有能力做到"让’苹果’的表示参考上下文里的’公司’一词"(回忆第 9 讲的例子)?为什么?