• Positional Encoding
  • Encoder
  • Decoder
  • Masked Attention
  • Cross-Attention
  • Feed Forward Network
  • Add & Norm

如果一开始就直接阅读论文结构图或代码,很容易陷入局部细节,却看不清这些模块为什么会被组合在一起。

本文将从 Transformer 出现的原因讲起,逐步解释注意力机制、自注意力、编码器、解码器,以及 Encoder-Decoder、Encoder-only 和 Decoder-only 三种常见架构。


为什么 RNN 之后还需要 Transformer

在 Transformer 出现之前,RNN、GRU 和 LSTM 是处理文本、语音和时间序列的主流模型。

假设输入句子是:

我正在学习深度学习。

RNN 会按照顺序依次处理每个 token:

正在

学习

深度

学习

每处理一个 token,RNN 都会更新一次隐藏状态:

Ht=f(Xt,Ht−1)��=�(��,��−1)

其中:

  • Xt�� 是当前时间步的输入;
  • Ht−1��−1 是上一时间步的隐藏状态;
  • Ht�� 是当前时间步的隐藏状态。

隐藏状态可以理解为模型对前文的记忆。

这种结构符合人类按顺序阅读的直觉,但也带来了两个明显问题。

RNN 难以充分并行

计算 Ht�� 之前,必须先得到 Ht−1��−1。

因此,第 10 个 token 必须等前 9 个 token 计算完成后才能处理。即使 GPU 非常擅长并行计算,RNN 仍然需要沿着时间轴逐步执行。

序列越长,等待的时间越多。

长距离信息需要层层传递

假设一句话中的第 100 个词需要参考第 1 个词。

在 RNN 中,第 1 个词的信息必须经过许多次隐藏状态更新,才能传递到第 100 个词。

随着传递距离增加,早期信息可能逐渐减弱。LSTM 和 GRU 通过门控机制缓解了这个问题,但没有改变“按时间步逐个计算”的基本方式。

Transformer 提出了一种不同的思路:

不再让信息沿序列一步一步传递,而是让序列中的任意两个 token 直接建立联系。

这个目标主要通过注意力机制实现。


Transformer 想解决什么问题

Transformer 最初用于机器翻译。

例如,把英文句子:

I love you.

翻译成中文:

我爱你。

这是一个典型的序列到序列任务:

英文源序列

模型

中文目标序列

输入和输出都是序列,而且长度不一定相同。

Transformer 保留了编码器—解码器的整体思想:

  • 编码器负责理解输入序列;
  • 解码器负责生成输出序列。

真正的变化在于:

Transformer 不再使用 RNN 逐步传递信息,而是使用注意力机制直接建立序列内部的关系。


注意力机制在做什么

注意力机制解决的问题非常直观:

面对大量信息,当前应该重点关注哪些部分?

假设要回答一个问题:

Transformer 为什么比 RNN 更容易并行?

面前有以下几条资料:

  1. Transformer 使用自注意力处理序列;
  2. 今天的天气很好;
  3. RNN 必须按照时间步逐步计算;
  4. 苹果是一种水果。

显然,第 1 条和第 3 条更重要。

注意力机制不会平均对待所有信息,而是根据当前任务,为不同信息分配不同权重。

最终输出可以表示为:

Output=∑iαiviOutput=∑�����

其中:

  • vi�� 表示第 i� 条信息;
  • αi�� 表示这条信息的注意力权重。

权重越大,说明当前更需要关注这条信息。

因此,注意力机制本质上是一种动态加权汇聚:

模型根据当前需求,动态决定每条信息应该贡献多少。


Query、Key 和 Value 是什么

注意力机制通常使用三个核心概念:

名称 缩写 直观含义
Query Q 我现在想找什么
Key K 每条信息用来匹配的特征
Value V 真正需要取出的内容

可以用图书馆查书来类比。

假设你想找一本介绍 Transformer 的书:

  • Query:你想查找“Transformer”;
  • Key:每本书的标题、关键词和分类标签;
  • Value:每本书实际包含的内容。

模型首先使用 Query 和每个 Key 比较,计算匹配程度。

匹配程度越高,对应 Value 的权重越大。

Query
当前想找什么

与每个 Key
计算匹配分数

Key 1

Key 2

Key 3

Softmax
得到注意力权重

对 Value 加权汇聚

Value 1

Value 2

Value 3

Key 和 Value 经常来自同一个对象,但承担的角色不同:

  • Key 用来判断这条信息是否相关;
  • Value 是确定相关后真正取出的内容。

缩放点积注意力如何计算

Transformer 使用缩放点积注意力:

Attention(Q,K,V)=softmax(QKT√dk)VAttention⁡(�,�,�)=softmax⁡(�����)�

这个公式可以拆成四个步骤。

第一步:计算 Query 和 Key 的匹配分数

S=QKT�=���

假设序列中有多个 Query 和多个 Key,那么 S� 是一个分数矩阵。

矩阵中的第 i� 行、第 j� 列表示:

第 i� 个 Query 和第 j� 个 Key 的匹配程度。

点积越大,通常表示二者越匹配。

第二步:缩放分数

S′=QKT√dk�′=�����

dk�� 是 Key 向量的维度。

当向量维度很高时,点积结果可能变得很大。如果直接送入 softmax,输出可能过于极端,例如:

[0.9999, 0.0001, 0.0000][0.9999, 0.0001, 0.0000]

这样会使训练不够稳定。

除以 √dk��,可以把分数缩放到更合适的范围。

第三步:使用 softmax 得到权重

A=softmax(QKT√dk)�=softmax⁡(�����)

例如,原始分数为:

[3.0, 1.0, 0.2][3.0, 1.0, 0.2]

经过 softmax 后可能变成:

[0.84, 0.11, 0.05][0.84, 0.11, 0.05]

这些权重都大于 0,并且总和等于 1。

第四步:使用权重汇聚 Value

O=AV�=��

也就是:

O=softmax(QKT√dk)V�=softmax⁡(�����)�

权重越大的 Value,对最终结果贡献越大。

因此,整个注意力公式可以理解为:

先判断应该关注谁,再把被关注的信息汇聚起来。


Q、K、V 是怎样产生的

在 Transformer 中,Q、K、V 通常不是原始输入,而是由输入向量经过三个不同的线性变换得到:

Q=XWQ�=���

K=XWK�=���

V=XWV�=���

其中:

  • X� 是输入序列的向量表示;
  • WQ��、WK�� 和 WV�� 是通过训练学习得到的权重矩阵。

虽然 Q、K、V 可能来自同一个输入 X�,但它们经过不同变换,因此承担不同角色:

  • WQ�� 学习如何表达“我想寻找什么”;
  • WK�� 学习如何表达“我可以怎样被匹配”;
  • WV�� 学习如何表达“我真正携带什么信息”。

什么是自注意力

自注意力,也叫 Self-Attention,是 Transformer 的核心组件。

它的特点是:

Query、Key 和 Value 都来自同一个序列。

假设输入句子是:

小明把书放在桌上,因为他马上还要看。

在处理“他”这个 token 时,自注意力可以让它直接关注“小明”,从而学习到两者之间的指代关系。

在自注意力中,输入序列 X� 同时生成 Q、K 和 V:

Q=XWQ�=���

K=XWK�=���

V=XWV�=���

然后计算:

SelfAttention(X)=softmax(QKT√dk)VSelfAttention⁡(�)=softmax⁡(�����)�

序列中的每个 token 都可以和其他 token 直接计算关系。

小明

把书

放在桌上

这与 RNN 有明显区别。

RNN 中,远距离信息需要经过多个时间步传递;自注意力中,两个位置可以通过一次注意力计算直接交互。


自注意力为什么适合并行计算

在 RNN 中,第 t� 个时间步依赖第 t−1�−1 个时间步,因此不能同时计算所有位置。

而在自注意力中,整个序列的 Q、K、V 可以同时计算。

所有 token 之间的关系也可以通过一次矩阵乘法得到:

QKT���

矩阵乘法非常适合 GPU 并行计算。

因此,在训练阶段,Transformer 通常比 RNN 更容易利用现代计算硬件。

不过需要注意:

Transformer 在训练时可以并行处理多个位置,但自回归模型在推理时仍然需要逐 token 生成。


为什么需要多头注意力

单个注意力头只能在一个表示空间中计算关系。

但语言中的关系是多种多样的。

一句话中可能同时存在:

  • 主语和谓语的关系;
  • 代词和指代对象的关系;
  • 局部词语搭配;
  • 长距离语义依赖;
  • 时间和地点关系;
  • 句法结构。

多头注意力的思想是:

让模型同时从多个不同角度观察同一个序列。

每个头都有自己独立的投影矩阵:

Qi=QWQi��=����

Ki=KWKi��=����

Vi=VWVi��=����

第 i� 个注意力头的输出为:

headi=Attention(Qi,Ki,Vi)head�=Attention⁡(��,��,��)

然后将所有头的结果拼接起来:

MultiHead(Q,K,V)=Concat(head1,…,headh)WOMultiHead⁡(�,�,�)=Concat⁡(head1,…,headℎ)��

输入 Q、K、V

注意力头 1

注意力头 2

注意力头 3

注意力头 4

拼接 Concat

线性变换

可以粗略理解为:

  • 一个头可能更关注语法关系;
  • 一个头可能更关注语义关系;
  • 一个头可能更关注局部关系;
  • 一个头可能更关注长距离依赖。

这些关注方式并不是人为规定的,而是模型在训练过程中自行学习出来的。

需要特别说明:

Self-Attention 和 Multi-Head Attention 不是同一个维度的概念。

Self-Attention 描述的是 Q、K、V 是否来自同一个序列;Multi-Head 描述的是注意力是否在多个子空间中并行计算。

因此,可以有:

  • 单头 Self-Attention;
  • 多头 Self-Attention;
  • 单头 Cross-Attention;
  • 多头 Cross-Attention。

为什么 Transformer 需要位置编码

自注意力虽然能处理 token 之间的关系,但它本身并不知道 token 的顺序。

例如:

我爱你。

和:

你爱我。

包含完全相同的三个词,但语序不同,含义也不同。

如果只把 token embedding 输入自注意力,模型更像是在处理一个无序集合。

因此,Transformer 需要额外加入位置信息。

输入向量通常写成:

Xt=E(xt)+Pt��=�(��)+��

其中:

  • E(xt)�(��) 是第 t� 个 token 的 embedding;
  • Pt�� 是第 t� 个位置的位置编码。

可以理解为:

  • Token Embedding:这个 token 是什么;
  • Position Encoding:这个 token 在哪里。

相加后得到的是:

位于这个位置上的这个 token。


正弦余弦位置编码

原始 Transformer 使用正弦余弦位置编码:

PE(pos,2i)=sin(pos100002i/d)��(���,2�)=sin⁡(���100002�/�)

PE(pos,2i+1)=cos(pos100002i/d)��(���,2�+1)=cos⁡(���100002�/�)

其中:

  • pos��� 表示 token 在序列中的位置;
  • d� 表示 embedding 总维度;
  • i� 表示维度对编号;
  • 偶数维使用 sinsin;
  • 奇数维使用 coscos。

不同维度使用不同频率的正弦和余弦函数。

低频维度变化较慢,高频维度变化较快,因此每个位置都能得到一组独特而有规律的位置表示。

位置编码并不一定只能使用正弦余弦。现代模型还会使用:

  • 可学习位置编码;
  • 相对位置编码;
  • 旋转位置编码;
  • 其他位置表示方法。

它们解决的核心问题相同:

告诉模型 token 的位置和顺序。


先理解完整的 Encoder-Decoder Transformer

原始 Transformer 采用 Encoder-Decoder 架构,最初用于机器翻译。

假设任务是英译法:

源句子:I love you.
目标句子:Je t'aime.

整体结构如下:

源语言序列

Embedding
加位置编码

Encoder

Encoder 输出

目标语言序列

Embedding
加位置编码

Decoder

Linear

Softmax

目标 token 概率

编码器负责理解源序列,解码器负责生成目标序列。

之所以先讲完整的 Encoder-Decoder,是因为它包含了 Transformer 中最核心的三种注意力形式:

  1. Encoder Self-Attention;
  2. Decoder Masked Self-Attention;
  3. Encoder-Decoder Cross-Attention。

理解了这套完整结构,再看 Encoder-only 和 Decoder-only 就会容易很多。


Encoder 的作用是什么

Encoder 的任务是:

把输入序列中的每个 token 转换成融合了上下文的信息表示。

例如,源句子是:

I love you.

输入 Encoder 之前,每个 token 主要只有自身的词义和位置信息。

经过 Encoder 后,love 的向量不再只是表示单词 love,而是表示:

在“I love you”这个句子上下文中的 love

Encoder 通常由多个相同的 Encoder Block 堆叠而成。

输入

多头自注意力

Add & Norm

前馈网络 FFN

Add & Norm

输出

每个 Encoder Block 主要包含:

  • Multi-Head Self-Attention;
  • Feed Forward Network;
  • 残差连接;
  • Layer Normalization。

Encoder 中的自注意力

Encoder 使用普通的多头自注意力。

它的 Q、K、V 都来自 Encoder 当前层的输入:

Q=XWQ,K=XWK,V=XWV�=���,�=���,�=���

因为完整源句子已经给出,所以 Encoder 中的每个位置都可以关注源序列中的所有位置。

例如源句子是:

I love you.

那么:

  • I 可以关注 Iloveyou
  • love 可以关注 Iloveyou
  • you 也可以关注完整句子。

Encoder 不需要因果 mask,因为它不是在逐步生成源序列,而是在理解已经完整给出的输入。

不过,如果一个 batch 中使用了 <pad> 补齐序列,通常会使用 padding mask,避免模型关注补齐位置。

因此,“Encoder 不使用 mask”更准确的说法是:

Encoder 不使用防止看见未来的因果 mask,但可能使用 padding mask。


Encoder 中的 FFN

自注意力完成的是不同 token 之间的信息交换。

交换完成后,每个 token 的向量还需要进一步进行非线性加工,这一步由 Position-wise Feed Forward Network 完成。

常见形式为:

FFN(x)=σ(xW1+b1)W2+b2FFN⁡(�)=�(��1+�1)�2+�2

其中,σ� 可以是 ReLU、GELU 等激活函数。

FFN 的特点是:

对序列中的每个位置,使用同一套前馈网络分别处理。

例如:

Token 1 向量

同一个 FFN

Token 2 向量

同一个 FFN

Token 3 向量

同一个 FFN

这里画成三个 FFN 是为了表示三个位置分别计算,但它们共享同一套权重。

可以这样记:

  • Attention:负责 token 与 token 之间的信息交流;
  • FFN:负责加工每个 token 自己的特征。

残差连接和 LayerNorm

Transformer 的每个主要子层外部都带有残差连接。

残差连接可以表示为:

Y=X+Sublayer(X)�=�+Sublayer⁡(�)

其中:

  • X� 是子层原始输入;
  • Sublayer(X)Sublayer⁡(�) 是注意力层或 FFN 的输出。

它的含义是:

保留原始信息,再加上子层学习到的新信息。

这样做有助于梯度传播,也让深层 Transformer 更容易训练。

Layer Normalization 则用于稳定每个 token 向量的数值分布。

可以粗略地理解为:

把每个 token 的特征调整到更适合后续网络处理的数值范围。

原始 Transformer 使用的是 Post-Norm 形式:

LayerNorm(X+Sublayer(X))LayerNorm⁡(�+Sublayer⁡(�))

现代模型中也常见 Pre-Norm 形式:

X+Sublayer(LayerNorm(X))�+Sublayer⁡(LayerNorm⁡(�))

二者顺序有所不同,但目的都是改善训练稳定性。


多层 Encoder 在做什么

一个 Encoder Block 只能完成一次信息交流和特征加工。

因此,Transformer 会堆叠多个 Encoder Block。

Embedding + 位置编码

Encoder Block 1

Encoder Block 2

Encoder Block 3

Encoder 最终输出

随着层数增加,token 表示会逐渐发生变化。

可以粗略理解为:

  • 较低层学习局部关系;
  • 中间层组合句法和语义信息;
  • 较高层形成更抽象的上下文表示。

这不是严格的固定分工,但有助于理解深层网络为什么需要堆叠多层。


Decoder 的作用是什么

Decoder 的任务是:

根据已经生成的目标端内容,并结合 Encoder 提供的源序列信息,预测下一个目标 token。

Decoder 也由多个 Decoder Block 堆叠而成。

目标序列输入

Masked 多头自注意力

Add & Norm

Encoder-Decoder Attention

Encoder 输出

Add & Norm

前馈网络 FFN

Add & Norm

输出

每个 Decoder Block 主要包含:

  1. Masked Multi-Head Self-Attention;
  2. Encoder-Decoder Attention;
  3. Feed Forward Network;
  4. 残差连接与 Layer Normalization。

Decoder 中的两种注意力承担不同作用。


Decoder 中的 Masked Self-Attention

Decoder 的第一种注意力是 Masked Self-Attention,也叫因果自注意力。

它的 Q、K、V 都来自 Decoder 自身:

Q=XdecWQ�=�dec��

K=XdecWK�=�dec��

V=XdecWV�=�dec��

但当前位置不能看到未来位置。

假设 Decoder 输入为:

<bos> Je t'aime .

当处理 Je 所在的位置时,它只能看到:

<bos> Je

不能看到后面的:

t'aime .

否则模型在训练时就会提前知道答案。

这种限制通过因果 mask 实现:

Mij={0,j≤i −∞,j>i���={0,�≤� −∞,�>�

将 mask 加到注意力分数上:

softmax(QKT√dk+M)softmax⁡(�����+�)

未来位置对应的分数会变成 −∞−∞,经过 softmax 后,其注意力权重变成 0。

因此,Masked Self-Attention 的作用是:

让 Decoder 只能根据当前位置以及之前的目标 token 进行计算,不能偷看未来。


Decoder 中的 Encoder-Decoder Attention

Decoder 的第二种注意力叫 Encoder-Decoder Attention,也称为 Cross-Attention。

在这一层中:

  • Query 来自 Decoder;
  • Key 和 Value 来自 Encoder 输出。

即:

Q=HdecWQ�=�dec��

K=HencWK�=�enc��

V=HencWV�=�enc��

它的直观含义是:

Decoder 拿着当前的生成需求,去查询 Encoder 中的源句子信息。

例如生成法语单词 t'aime 时,Decoder 可能会重点关注英文源句子中的 love 和 you

Decoder 当前表示
作为 Query

Cross-Attention

Encoder 输出
作为 Key 和 Value

与当前生成相关的源句信息

Decoder 中的两次“看”可以概括为:

  1. Masked Self-Attention:看目标端已经出现了什么;
  2. Cross-Attention:看源句子中应该关注哪里。

目标序列为什么要右移一位

训练机器翻译模型时,我们已经知道正确答案。

假设正确目标序列是:

Je t'aime . <eos>

Decoder 的输入是:

<bos> Je t'aime .

训练标签是:

Je t'aime . <eos>

对应关系如下:

Decoder 当前位置的输入 模型需要预测
<bos> Je
Je t'aime
t'aime .
. <eos>

所谓“右移一位”,就是:

在目标序列开头加入 <bos>,并让每个位置的输出去预测下一个 token。

这样,模型在每个位置上都会学习“根据已有前文预测后面的 token”。


训练时为什么可以并行处理 Decoder

看到 Decoder 逐 token 生成,很多初学者会认为训练时也必须一步一步执行。

实际上,训练时完整目标序列已经存在,因此可以把右移后的目标序列一次性输入 Decoder:

<bos> Je t'aime .

然后同时计算所有位置的输出。

Masked Self-Attention 会保证:

  • 第一个位置只能看第一个位置;
  • 第二个位置只能看前两个位置;
  • 第三个位置只能看前三个位置;
  • 以此类推。

因此:

  • 训练阶段可以并行计算多个位置;
  • 推理阶段因为未来 token 尚不存在,只能逐 token 生成。

推理阶段如何生成序列

推理时没有正确目标句子,因此 Decoder 只能从 <bos> 开始。

第一步:

输入:<bos>
预测:Je

第二步:

输入:<bos> Je
预测:t'aime

第三步:

输入:<bos> Je t'aime
预测:.

第四步:

输入:<bos> Je t'aime .
预测:<eos>

当生成 <eos>,或者达到最大长度时,生成过程结束。

Je

t'aime

.

实际系统中,模型不会总是简单选择概率最大的 token,还可能使用:

  • 贪心搜索;
  • 束搜索;
  • Top-k 采样;
  • Top-p 采样;
  • 温度调节。

这些方法决定了模型从概率分布中怎样选择下一个 token。


Encoder-Decoder Transformer 的完整流程

以英译法为例:

源句子:I love you.
目标句子:Je t'aime.

整个流程如下:

源序列 Token

源 Embedding + 位置编码

Encoder Block 1

Encoder Block 2

Encoder 最终输出

右移后的目标序列

目标 Embedding + 位置编码

Decoder Block 1

Decoder Block 2

线性输出层

Softmax

下一个目标 token 的概率

Encoder 负责理解完整源句子。

Decoder 先通过 Masked Self-Attention 查看目标端前文,再通过 Cross-Attention 查询 Encoder 输出,最后预测下一个目标 token。

这就是标准 Encoder-Decoder Transformer 的核心流程。


从完整架构理解 Encoder-only

理解完整的 Encoder-Decoder Transformer 后,Encoder-only 就比较容易了。

Encoder-only 模型只保留 Transformer 的 Encoder 部分。

输入序列

多层 Transformer Encoder

上下文表示

分类、抽取或理解任务

它使用普通的双向 Self-Attention。

也就是说,一个 token 可以同时看到它前面和后面的所有 token。

例如句子:

我今天去了公园。

处理“去了”时,模型既可以看到前面的“我今天”,也可以看到后面的“公园”。

这种结构非常适合需要完整上下文理解的任务,例如:

  • 文本分类;
  • 情感分析;
  • 命名实体识别;
  • 语义匹配;
  • 信息抽取;
  • 文本向量表示;
  • 检索和排序。

BERT 是典型的 Encoder-only 模型。


BERT 为什么适合文本理解

BERT 的核心预训练任务之一是掩码语言模型。

例如:

我今天去了 [MASK]

模型需要根据左右两侧上下文预测被遮挡的词。

它既能利用左边的“我今天去了”,也能利用右边可能出现的其他内容。

因此,BERT 学到的是双向上下文表示。

需要注意:

Encoder-only 并不是绝对不能用于生成,只是它本身最擅长的是编码和理解完整输入。

如果要让它进行生成,通常还需要额外设计输出结构。


从完整架构理解 Decoder-only

Decoder-only 模型只保留 Transformer Decoder 中的自回归生成部分。

它没有独立的 Encoder,因此也没有 Cross-Attention。

每个 Block 通常主要包含:

  • Masked Multi-Head Self-Attention;
  • FFN;
  • 残差连接;
  • LayerNorm。

Prompt 和已有 token

多层 Decoder-only Transformer

预测下一个 token

Decoder-only 会把任务说明、输入内容和已经生成的内容放在同一个序列中。

例如做翻译时,可以输入:

请把下面的英文翻译成中文:
I love you.
中文:

这些内容都作为前文 token。

模型使用 Masked Self-Attention 读取前文,然后继续生成:

我爱你。

它不需要单独的 Encoder,也不需要 Cross-Attention。

GPT 类模型属于 Decoder-only 架构。


GPT 为什么只靠预测下一个 token 就能完成很多任务

GPT 的基本训练目标是:

P(xt∣x1,x2,…,xt−1)�(��∣�1,�2,…,��−1)

也就是根据前面的 token,预测下一个 token。

表面上看,这只是文本续写任务。

但许多任务都可以转换成文本续写。

翻译

把下面的英文翻译成中文:
I love machine learning.
中文:

模型继续生成:

我喜欢机器学习。

问答

问题:Transformer 为什么需要位置编码?
回答:

模型继续生成答案。

分类

文本:这部电影非常精彩。
情感类别:

模型继续生成:

正面。

摘要

请总结下面这段文章:
……
摘要:

模型继续生成摘要。

这些任务表面上不同,但都可以统一成:

给定前文,生成后续 token。

这也是 Decoder-only 架构非常适合构建通用大语言模型的重要原因。


Encoder-only、Decoder-only 和 Encoder-Decoder 的关系

这三种架构不是三个毫无关联的模型。

它们都建立在 Transformer Block 和注意力机制之上,只是保留的模块不同。

Transformer 架构思想

Encoder-Decoder

Encoder-only

Decoder-only

理解输入并生成输出

重点理解完整输入

重点进行自回归生成

可以这样理解:

更多推荐