首页 / 第二部分 · 注意力和 Transformer / 第 06 篇

第 06 篇 · 第二部分 · 注意力和 Transformer

Transformer 全貌:编码器、解码器与多头注意力

前几篇把各个零件逐一拆开讲解:注意力是什么、Q/K/V 怎么来的、多头在做什么。这篇把零件装回整机,展示一条数据从底层输入、逐层向上,经过哪些环节,每一环又被改写成什么样。不必被"编码器""解码器"这类名字难住,拼装之后会发现,真正核心的部件只有四个,只是被反复排列组合。

一、先把整机和流水线摆出来

Transformer 是 2017 年 Vaswani 那篇《Attention Is All You Need》提出来的,做的任务是机器翻译:把一句英文变成一句法文。名字里的 Transform 是"变换",简单说,它就是一台反复改写表示的机器。

不宜把它想象成某种玄妙的"网络":它更像一摞结构相同的积木,数据从底部进入,每经过一块就被改写一次,越往上,向量承载的内容越接近任务想要的结果。整条流水线大致是这样:

  • 句子先切成 token,每个 token 查表得到一个向量(词嵌入);
  • 再叠加一份位置信息(位置编码),因为它自己不知道顺序;
  • 进 编码器:N 个结构相同的块,每块里做一次多头自注意力,再做一次前馈网络;
  • 如果任务需要"生成",再进 解码器:N 个块,每块多了一段交叉注意力,用来读编码器的输出;
  • 末端再过一层线性层加 softmax,得到下一个词的概率分布。

原论文里 N 取 6,也就是编码器堆 6 块、解码器堆 6 块。到后来 GPT-3 这种模型,单边能堆到 96 层。层数变了,块里的东西没变。

这里的"表示"不是比喻。每个位置被改写的过程中,始终带着一个和它同长度的向量往前走,层与层之间传递的就是这些向量本身。可以想象成给每个词配了一张不断被涂改的卡片:进第一层时上面写的是词本身,中间几层不停往里添上下文,到顶层,这张卡片已经写满了"它在这句话里扮演什么角色"的信息。

二、输入是怎么进来的:词嵌入加位置编码

词表里每个 token 都对应一个 dmodel 维向量,存在一张巨大的嵌入矩阵里。所谓嵌入,本质就是查表:token 的整数 ID 是行号,取出来就是它这行的向量。原论文取 dmodel=512,如今常见的是 768、4096 这种量级。

麻烦在于,纯注意力对顺序无感——"我打你"和"你打我"输入进去,光靠点积算不出区别。所以得额外给每个位置造一份同维度的编码向量,和词嵌入直接相加。

为什么能相加而不冲突?因为 dmodel 足够宽,语义与位置两组信息叠加在同一批维度上也不会互相淹没,模型在训练中会学会分别读取它们。相加之后,送进第一层的就是一个 n × dmodel 的矩阵,n 是序列长度。位置编码这套技术后面单独开一篇讲,这里先记住它存在。

补一句量级:词表几万、维度几百到几千,光是这张嵌入表就有几千万到上亿参数,它和后面那摞块是分开的两笔开销。想扩充词表或增加层数,这两笔开销要分开计算,不宜混在一起估算。

三、编码器块:自注意力 + 前馈网络 + 残差 + 归一化

扒开一个编码器块,里面就两段:一段多头自注意力,一段前馈网络。每段外面还套着残差连接,做完再做一次归一化。整块的核心公式其实很朴素:

y = LayerNorm( x + Sublayer(x) )

Sublayer 就是"多头注意力"或者"前馈网络"其中一个。原论文把这个顺序叫 Post-LN——先算子层,加残差,再归一化。后来大家发现改成 Pre-LN(先归一化再进子层)训练更稳,GPT-2 之后的 GPT 一系基本都采用了 Pre-LN。

有个细节最该记住:每个子层进去是 n × d,出来还是 n × d,形状一点不变。正因为形状不变,这些块才能像积木一样往上叠,叠多少层都行。这是 Transformer 能堆深的物理前提。

四、残差连接:给深层网络留一条退路

网络越深越难训练,是长期存在的问题。梯度从后往前传,每经过一层都要乘一串矩阵,乘得多了就越乘越小,浅层那几个子层基本收不到训练信号,也就是所谓的梯度消失。

ResNet(He 等,2015)提出了一个方法:让某一层的输出变成 F(x) + x,多出一条直连通道,把输入原封不动地复制到输出。反向传梯度时,这条通道的导数恒等于 1,等于给梯度修了一条不衰减的近道。

打个比方:传话游戏传到队尾,"今天下雨取消活动"很容易变成"今天下雪照常集合"。但只要手里留有一版原话,随时可以对照,就不会偏离太远。残差连接就是那条留底的原话。

好处还不止保住梯度。有了这条近道,每个子层不必从零重建整个表示,只要学"需要改动的那一小块"就行。学增量,永远比学全量容易。Transformer 每个子层都套残差,这也是它能堆到几十上百层的底气。

五、LayerNorm:为什么它被放在这个位置

残差一路累加,数值尺度会慢慢漂移,越往后漂移越明显。需要不时地把数据调整回一个稳定的范围,这就是归一化的作用。

为什么用 LayerNorm 而不是更常见的 BatchNorm?因为 BatchNorm 是按 batch 这一维统计均值和方差的,可 NLP 里句子长短不一、训练 batch 又常开得小,统计量波动很大,推理时还要依赖训练期间积累的历史均值。LayerNorm 换了个统计口径:只对单条样本自己的特征维度算均值和方差,跟 batch 完全无关,序列再乱也不怕。这是 Ba 等 2016 年那篇给的思路。

它放在哪儿也有讲究。Post-LN 是把归一化压在子层之后,浅层的数值容易随层数累积而发散,训练时得靠 warmup 慢慢加热学习率;Pre-LN 放在子层之前,梯度更平稳,往往能省掉 warmup。它本身不改变张量形状,只把每一行特征重新缩放平移,好让后面的子层在一个干净的数值范围上计算。

归一化还带来一个颇为实用的副作用:它让每层输入都落在相近的数值范围里,前层与后层面对的数值分布大体一致,超参数不必为每一层单独微调。这种细微的一致性累积起来,往往决定了模型能否堆到几十层而不失稳。

六、前馈网络:注意力之外的另一半算力

前馈网络听着平平无奇,其实就是一个两层全连接中间夹个激活:

FFN(x) = W₂ · ReLU( W₁ · x )

中间那层通常放大 4 倍,dmodel=512 就达到 2048。这个放大不可忽视:它占用了整个 Transformer 约三分之二的参数量。注意力负责"词与词之间横向交换信息",FFN 负责"在每个位置上纵向加工特征"——一个对外联络,一个对内加工。

Geva 等 2020 那篇有个很有意思的视角:把 FFN 看成一组键值记忆。第一层的 W₁ 每一行像一个"模式探测器",负责识别输入里有没有某种特征;第二层的 W₂ 是配套的输出,键对上了就往结果里输出对应的内容。可解释性研究沿着这条线索深入探究,发现里面存入了大量具体事实和固定短语。

所以别把 FFN 当附属零件。模型"记住"的知识,相当一部分是堆在这儿的,而不是分散在注意力权重里。

粗略估算一下它的容量:dmodel 取 768、中间层 3072,一层 FFN 就是 768×3072×2 约 470 万个参数,堆 12 层就是五千多万,体量比嵌入表还大。

七、解码器块:掩码自注意力与交叉注意力

解码器块比编码器块多了一段,总共三段,顺序是掩码自注意力、交叉注意力、前馈网络,每段照样套残差和归一化。

第一段是掩码自注意力。生成时必须防止模型偷看后面的词,否则预测"下一个"就变成了抄答案。做法是在 softmax 之前,把未来位置的分数设成负无穷,softmax 之后那些位置的权重自然归零。位置 t 只能看到 1 到 t。

第二段是交叉注意力,也就是编码器和解码器的接头处。这里的 Q 来自解码器自己,K 和 V 全部来自编码器的输出。翻译的时候,解码器拿着"我这步正想写什么"去原文那堆向量里检索,决定这一步该参考原句的哪块——词对齐关系基本就是在这儿长出来的。

用一句话概括两边的分工:编码器一门心思读输入,解码器一边读输入一边写输出。前者是读者,后者是边看边写的作者。

交叉注意力的开销也值得多看一眼:它的打分矩阵两边不对等,行数是解码器当前长度,列数是编码器输出长度。做长文档问答时,这一步常常是显存消耗最大的地方。

八、Encoder-only / Decoder-only / Encoder-Decoder 三种形态

后来大家发现这三段可以按需取用,分化出三支流派,各司其职。

  • Encoder-only,代表是 BERT(Devlin 等,2018)。只留编码器,双向看完整句,擅长理解和判别:情感分类、抽取式问答、命名实体识别。
  • Decoder-only,代表是 GPT 一系。只留解码器,靠因果掩码只往左看,专注"下一个词",天生适合生成。
  • Encoder-Decoder,代表是 T5(Raffel 等,2019)。两边都要,适合输入输出都是序列的活:翻译、摘要、改写。

怎么选?问自己三个问题:要不要双向看(理解类任务要)、要不要接着往下写(生成类任务要)、输入和输出是不是两段不同的序列(是的话得两边都留)。

还需说明一点:这三种形态并无先进与否之分,取舍由任务决定。把单向模型用于抽取式任务,或把双向模型改造成逐词生成,都是与结构本身的特性对抗,事倍功半。

九、它强在哪:并行、可扩展、通用

把整机走一遍,能看清它取代 RNN 的三条理由。

并行。RNN 必须逐词串行处理,GPU 的大量核心处于空闲状态。Transformer 把整句一次性展开,所有位置的注意力同时计算,硬件利用率高。

可扩展。形状不变的积木,配上残差和 LayerNorm,让它能一直往深里堆、往宽里放。后面讲的尺度定律之所以有意义,前提就是它真的堆得动。

通用。同一套结构,翻译、分类、生成、写代码全能用,换的只是训练目标和输入的数据,不改骨架。

过完整机也会发现,真正被反复复用的就四件东西:注意力、前馈网络、残差、归一化。它漏掉的唯一一块拼图是"顺序感"——输入里得额外写入位置信息,这事下一篇文章专门处理。

如果用一句话概括整机:它把"读"和"写"拆成两列,用注意力把同层各位置横向串起来,再用前馈网络在每个位置上纵向加工一遍,外面套残差和归一化保证堆得深。其余的关键,全在数据、参数和目标搭配得是否恰当。

参考资料

  1. Ashish Vaswani 等, Attention Is All You Need, NeurIPS 2017. arXiv:1706.03762(编码器解码器整机结构的原始出处)
  2. Kaiming He 等, Deep Residual Learning for Image Recognition, CVPR 2016. arXiv:1512.03385(残差连接的来龙去脉)
  3. Jimmy Lei Ba, Jamie Ryan Kiros, Geoffrey E. Hinton, Layer Normalization, 2016. arXiv:1607.06450(LayerNorm 的原始论文)
  4. Jacob Devlin 等, BERT: Pre-training of Deep Bidirectional Transformers, NAACL 2019. arXiv:1810.04805(Encoder-only 的代表)
  5. Mor Geva 等, Transformer Feed-Forward Layers Are Key-Value Memories, EMNLP 2021. arXiv:2012.14913(把 FFN 看作键值记忆)
  6. Colin Raffel 等, Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer (T5), 2019. arXiv:1910.10683(Encoder-Decoder 的代表)