Transformer 通俗详解:从注意力机制到 BERT 与 GPT

Transformer 是现代深度学习中最重要的模型架构之一。

机器翻译、文本分类、智能问答、代码生成、大语言模型,甚至图像识别、语音处理和多模态模型,都在大量使用 Transformer。

我们熟悉的 BERT、GPT、T5、ViT 等模型,虽然用途不同,但都建立在 Transformer 的基本思想之上。

对于初学者来说,Transformer 并不容易理解。第一次接触它时,通常会同时遇到许多概念:

  • Self-Attention
  • Multi-Head Attention
  • 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:

flowchart LR A[我] --> B[正在] B --> C[学习] C --> D[深度] D --> E[学习]

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

\[H_t=f(X_t,H_{t-1}) \]

其中:

  • \(X_t\) 是当前时间步的输入;
  • \(H_{t-1}\) 是上一时间步的隐藏状态;
  • \(H_t\) 是当前时间步的隐藏状态。

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

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

RNN 难以充分并行

计算 \(H_t\) 之前,必须先得到 \(H_{t-1}\)

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

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

长距离信息需要层层传递

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

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

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

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

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

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


Transformer 想解决什么问题

Transformer 最初用于机器翻译。

例如,把英文句子:

I love you.

翻译成中文:

我爱你。

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

flowchart LR A[英文源序列] --> B[模型] B --> C[中文目标序列]

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

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

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

真正的变化在于:

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


注意力机制在做什么

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

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

假设要回答一个问题:

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

面前有以下几条资料:

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

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

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

最终输出可以表示为:

\[\text{Output}=\sum_i \alpha_i v_i \]

其中:

  • \(v_i\) 表示第 \(i\) 条信息;
  • \(\alpha_i\) 表示这条信息的注意力权重。

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

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

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


Query、Key 和 Value 是什么

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

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

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

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

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

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

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

flowchart LR Q[Query<br/>当前想找什么] --> S[与每个 Key<br/>计算匹配分数] K1[Key 1] --> S K2[Key 2] --> S K3[Key 3] --> S S --> W[Softmax<br/>得到注意力权重] W --> O[对 Value 加权汇聚] V1[Value 1] --> O V2[Value 2] --> O V3[Value 3] --> O

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

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

缩放点积注意力如何计算

Transformer 使用缩放点积注意力:

\[\operatorname{Attention}(Q,K,V) = \operatorname{softmax} \left( \frac{QK^T}{\sqrt{d_k}} \right)V \]

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

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

\[S=QK^T \]

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

矩阵中的第 \(i\) 行、第 \(j\) 列表示:

\(i\) 个 Query 和第 \(j\) 个 Key 的匹配程度。

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

第二步:缩放分数

\[S'=\frac{QK^T}{\sqrt{d_k}} \]

\(d_k\) 是 Key 向量的维度。

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

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

这样会使训练不够稳定。

除以 \(\sqrt{d_k}\),可以把分数缩放到更合适的范围。

第三步:使用 softmax 得到权重

\[A= \operatorname{softmax} \left( \frac{QK^T}{\sqrt{d_k}} \right) \]

例如,原始分数为:

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

经过 softmax 后可能变成:

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

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

第四步:使用权重汇聚 Value

\[O=AV \]

也就是:

\[O= \operatorname{softmax} \left( \frac{QK^T}{\sqrt{d_k}} \right)V \]

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

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

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


Q、K、V 是怎样产生的

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

\[Q=XW_Q \]

\[K=XW_K \]

\[V=XW_V \]

其中:

  • \(X\) 是输入序列的向量表示;
  • \(W_Q\)\(W_K\)\(W_V\) 是通过训练学习得到的权重矩阵。

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

  • \(W_Q\) 学习如何表达“我想寻找什么”;
  • \(W_K\) 学习如何表达“我可以怎样被匹配”;
  • \(W_V\) 学习如何表达“我真正携带什么信息”。

什么是自注意力

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

它的特点是:

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

假设输入句子是:

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

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

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

\[Q=XW_Q \]

\[K=XW_K \]

\[V=XW_V \]

然后计算:

\[\operatorname{SelfAttention}(X) = \operatorname{softmax} \left( \frac{QK^T}{\sqrt{d_k}} \right)V \]

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

flowchart LR A[小明] <--> B[把书] A <--> C[放在桌上] A <--> D[他] B <--> C B <--> D C <--> D

这与 RNN 有明显区别。

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


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

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

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

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

\[QK^T \]

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

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

不过需要注意:

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


为什么需要多头注意力

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

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

一句话中可能同时存在:

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

多头注意力的思想是:

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

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

\[Q_i=QW_i^Q \]

\[K_i=KW_i^K \]

\[V_i=VW_i^V \]

\(i\) 个注意力头的输出为:

\[\operatorname{head}_i = \operatorname{Attention}(Q_i,K_i,V_i) \]

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

\[\operatorname{MultiHead}(Q,K,V) = \operatorname{Concat} (\operatorname{head}_1,\dots,\operatorname{head}_h)W^O \]

flowchart LR X[输入 Q、K、V] --> H1[注意力头 1] X --> H2[注意力头 2] X --> H3[注意力头 3] X --> H4[注意力头 4] H1 --> C[拼接 Concat] H2 --> C H3 --> C H4 --> C C --> O[线性变换]

可以粗略理解为:

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

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

需要特别说明:

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 需要额外加入位置信息。

输入向量通常写成:

\[X_t=E(x_t)+P_t \]

其中:

  • \(E(x_t)\) 是第 \(t\) 个 token 的 embedding;
  • \(P_t\) 是第 \(t\) 个位置的位置编码。

可以理解为:

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

相加后得到的是:

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


正弦余弦位置编码

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

\[PE(pos,2i) = \sin \left( \frac{pos}{10000^{2i/d}} \right) \]

\[PE(pos,2i+1) = \cos \left( \frac{pos}{10000^{2i/d}} \right) \]

其中:

  • \(pos\) 表示 token 在序列中的位置;
  • \(d\) 表示 embedding 总维度;
  • \(i\) 表示维度对编号;
  • 偶数维使用 \(\sin\)
  • 奇数维使用 \(\cos\)

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

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

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

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

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

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


先理解完整的 Encoder-Decoder Transformer

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

假设任务是英译法:

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

整体结构如下:

flowchart LR S[源语言序列] --> SE[Embedding<br/>加位置编码] SE --> EN[Encoder] EN --> M[Encoder 输出] T[目标语言序列] --> TE[Embedding<br/>加位置编码] TE --> DE[Decoder] M --> DE DE --> L[Linear] L --> SM[Softmax] SM --> O[目标 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 堆叠而成。

flowchart TB X[输入] --> A[多头自注意力] A --> N1[Add & Norm] N1 --> F[前馈网络 FFN] F --> N2[Add & Norm] N2 --> Y[输出]

每个 Encoder Block 主要包含:

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

Encoder 中的自注意力

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

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

\[Q=XW_Q,\qquad K=XW_K,\qquad V=XW_V \]

因为完整源句子已经给出,所以 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 完成。

常见形式为:

\[\operatorname{FFN}(x) = \sigma(xW_1+b_1)W_2+b_2 \]

其中,\(\sigma\) 可以是 ReLU、GELU 等激活函数。

FFN 的特点是:

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

例如:

flowchart LR A[Token 1 向量] --> F1[同一个 FFN] B[Token 2 向量] --> F2[同一个 FFN] C[Token 3 向量] --> F3[同一个 FFN]

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

可以这样记:

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

残差连接和 LayerNorm

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

残差连接可以表示为:

\[Y=X+\operatorname{Sublayer}(X) \]

其中:

  • \(X\) 是子层原始输入;
  • \(\operatorname{Sublayer}(X)\) 是注意力层或 FFN 的输出。

它的含义是:

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

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

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

可以粗略地理解为:

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

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

\[\operatorname{LayerNorm}(X+\operatorname{Sublayer}(X)) \]

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

\[X+\operatorname{Sublayer}(\operatorname{LayerNorm}(X)) \]

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


多层 Encoder 在做什么

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

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

flowchart TB X[Embedding + 位置编码] --> E1[Encoder Block 1] E1 --> E2[Encoder Block 2] E2 --> E3[Encoder Block 3] E3 --> O[Encoder 最终输出]

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

可以粗略理解为:

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

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


Decoder 的作用是什么

Decoder 的任务是:

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

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

flowchart TB X[目标序列输入] --> A[Masked 多头自注意力] A --> N1[Add & Norm] N1 --> C[Encoder-Decoder Attention] E[Encoder 输出] --> C C --> N2[Add & Norm] N2 --> F[前馈网络 FFN] F --> N3[Add & Norm] N3 --> Y[输出]

每个 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=X_{\text{dec}}W_Q \]

\[K=X_{\text{dec}}W_K \]

\[V=X_{\text{dec}}W_V \]

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

假设 Decoder 输入为:

<bos> Je t'aime .

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

<bos> Je

不能看到后面的:

t'aime .

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

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

\[M_{ij}= \begin{cases} 0,&j\leq i\ -\infty,&j>i \end{cases} \]

将 mask 加到注意力分数上:

\[\operatorname{softmax} \left( \frac{QK^T}{\sqrt{d_k}}+M \right) \]

未来位置对应的分数会变成 \(-\infty\),经过 softmax 后,其注意力权重变成 0。

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

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


Decoder 中的 Encoder-Decoder Attention

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

在这一层中:

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

即:

\[Q=H_{\text{dec}}W_Q \]

\[K=H_{\text{enc}}W_K \]

\[V=H_{\text{enc}}W_V \]

它的直观含义是:

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

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

flowchart LR D[Decoder 当前表示<br/>作为 Query] --> A[Cross-Attention] E[Encoder 输出<br/>作为 Key 和 Value] --> A A --> C[与当前生成相关的源句信息]

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>,或者达到最大长度时,生成过程结束。

flowchart LR B["<bos>"] --> J["Je"] J --> T["t'aime"] T --> P["."] P --> E["<eos>"]

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

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

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


Encoder-Decoder Transformer 的完整流程

以英译法为例:

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

整个流程如下:

flowchart TB S[源序列 Token] --> SE[源 Embedding + 位置编码] SE --> EN1[Encoder Block 1] EN1 --> EN2[Encoder Block 2] EN2 --> EM[Encoder 最终输出] T[右移后的目标序列] --> TE[目标 Embedding + 位置编码] TE --> DE1[Decoder Block 1] EM --> DE1 DE1 --> DE2[Decoder Block 2] EM --> DE2 DE2 --> LM[线性输出层] LM --> SM[Softmax] SM --> O[下一个目标 token 的概率]

Encoder 负责理解完整源句子。

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

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


从完整架构理解 Encoder-only

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

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

flowchart LR X[输入序列] --> E[多层 Transformer Encoder] E --> R[上下文表示] R --> T[分类、抽取或理解任务]

它使用普通的双向 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。
flowchart LR P[Prompt 和已有 token] --> D[多层 Decoder-only Transformer] D --> N[预测下一个 token] N --> P

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

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

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

这些内容都作为前文 token。

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

我爱你。

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

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


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

GPT 的基本训练目标是:

\[P(x_t\mid x_1,x_2,\dots,x_{t-1}) \]

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

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

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

翻译

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

模型继续生成:

我喜欢机器学习。

问答

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

模型继续生成答案。

分类

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

模型继续生成:

正面。

摘要

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

模型继续生成摘要。

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

给定前文,生成后续 token。

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


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

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

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

flowchart TB T[Transformer 架构思想] T --> ED[Encoder-Decoder] T --> EO[Encoder-only] T --> DO[Decoder-only] ED --> EDT[理解输入并生成输出] EO --> EOT[重点理解完整输入] DO --> DOT[重点进行自回归生成]

可以这样理解:

Encoder-only

保留 Encoder,移除 Decoder。

特点是:

每个 token 可以查看完整上下文。

适合理解类任务。

Decoder-only

保留自回归 Decoder,移除 Encoder 和 Cross-Attention。

特点是:

每个 token 只能查看自己以及前面的 token。

适合生成类任务。

Encoder-Decoder

同时保留 Encoder 和 Decoder。

特点是:

Encoder 先理解输入,Decoder 再根据输入生成输出。

适合输入序列到输出序列的转换任务。


三种 Transformer 架构对比

架构 主要注意力 能否看到后文 是否有 Cross-Attention 常见用途 代表模型
Encoder-only 双向 Self-Attention 可以 没有 分类、抽取、理解 BERT
Decoder-only Masked Self-Attention 不可以 没有 对话、续写、代码生成 GPT
Encoder-Decoder Encoder Self-Attention、Decoder Masked Self-Attention、Cross-Attention Encoder 可以,Decoder 不可以 翻译、摘要、序列转换 原始 Transformer、T5

需要注意的是,“理解”和“生成”只是它们各自更自然、更擅长的方向,并不是绝对边界。

例如,Decoder-only 也能完成分类任务,只需要把分类转换成生成标签文本。


Transformer 为什么能够取得成功

Transformer 的成功并不是由某一个模块单独造成的,而是多个特点共同作用的结果。

更容易并行训练

训练时,多个 token 的表示可以通过矩阵运算同时计算,比 RNN 更适合 GPU 和 TPU。

更容易建模长距离关系

任意两个 token 无论相距多远,都可以通过一次注意力计算直接建立联系。

架构容易扩展

Transformer Block 可以不断堆叠,也可以扩大隐藏维度、注意力头数量和训练数据规模。

任务形式容易统一

翻译、摘要、问答、分类、对话等任务,都可以由不同 Transformer 架构或不同输入格式完成。

可以处理多种数据

Transformer 不只用于文本,还被应用于:

  • 图像;
  • 音频;
  • 视频;
  • 时间序列;
  • 多模态数据;
  • 蛋白质序列。

Transformer 的局限

Transformer 并不是没有缺点。

标准注意力的计算量较高

对于长度为 \(n\) 的序列,注意力矩阵大小为:

\[n\times n \]

标准自注意力的时间和空间复杂度通常为:

\[O(n^2) \]

当序列变得很长时,计算量和显存占用会快速增长。

自注意力不天然包含顺序

Transformer 必须额外使用位置编码,才能感知 token 的顺序。

自回归推理仍然是串行的

Decoder-only 和 Encoder-Decoder 模型虽然训练时可以并行处理多个位置,但推理时必须等上一个 token 生成后,才能生成下一个 token。

大型模型训练成本很高

大规模 Transformer 往往需要大量数据、计算资源和存储空间。

注意力权重不等于完整解释

注意力权重可以帮助我们观察模型关注了哪些位置,但不能简单地把它当成模型全部的推理过程。


初学者常见误解

Attention 就是 Transformer

不是。

Attention 是一种信息匹配和汇聚机制。

Transformer 是由注意力、FFN、残差连接、LayerNorm、位置编码等模块组成的完整架构。

Q、K、V 是三个不同的输入句子

不一定。

在 Self-Attention 中,Q、K、V 都来自同一个序列,只是经过不同线性变换。

在 Cross-Attention 中,Q 和 K、V 才来自不同模块。

Encoder 使用 Masked Self-Attention

原始 Transformer 的 Encoder 使用普通 Self-Attention,可以看到完整源序列。

Masked Self-Attention 主要用于自回归 Decoder,用来防止看到未来 token。

Decoder 一定有 Cross-Attention

不是。

只有 Encoder-Decoder 架构中的 Decoder 才需要 Cross-Attention。

Decoder-only 模型没有 Encoder,因此也没有 Cross-Attention。

Self-Attention 是多头注意力的一种

这两个概念描述的不是同一件事。

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

训练 Decoder 时必须逐 token 运行

不是。

训练时目标序列已经存在,可以一次输入右移后的完整目标序列,再通过因果 mask 防止信息泄露。

推理时才必须逐 token 生成。

位置编码会破坏词向量中的语义

位置编码确实会改变 embedding 的数值,但它不是简单破坏语义,而是把“词义”和“位置”组合在同一个表示中。

模型会在训练过程中学习如何使用这种混合信息。


怎样从整体上理解 Transformer

把所有细节暂时放下,可以用下面几句话概括 Transformer。

Encoder 中:

每个 token 通过 Self-Attention 查看完整输入序列,并逐层形成融合上下文的表示。

Encoder-Decoder 架构的 Decoder 中:

先通过 Masked Self-Attention 查看已经出现的目标端内容,再通过 Cross-Attention 查询 Encoder 输出,最后预测下一个 token。

Encoder-only 中:

只保留对完整输入进行双向理解的 Encoder。

Decoder-only 中:

只保留根据前文不断预测下一个 token 的自回归结构。


总结

Transformer 的核心变化,是把序列建模的重点从“逐步传递隐藏状态”转变为“直接计算 token 之间的关系”。

它的核心模块包括:

  • Self-Attention;
  • Multi-Head Attention;
  • Positional Encoding;
  • Feed Forward Network;
  • Residual Connection;
  • Layer Normalization;
  • Masked Self-Attention;
  • Cross-Attention。

标准 Encoder-Decoder Transformer 提供了一套最完整的结构:

  • Encoder 使用 Self-Attention 理解源序列;
  • Decoder 使用 Masked Self-Attention 读取目标端前文;
  • Decoder 再使用 Cross-Attention 查询 Encoder;
  • 最终逐 token 生成目标序列。

在此基础上,又形成了两种常见架构:

  • Encoder-only,以 BERT 为代表,更擅长理解完整输入;
  • Decoder-only,以 GPT 为代表,更擅长自回归生成;
  • Encoder-Decoder,以原始 Transformer 和 T5 为代表,更适合序列到序列转换。

可以用一句话概括 Transformer:

Transformer 使用注意力机制,让每个 token 能够直接获取与自己相关的信息,并通过多层结构逐步形成对序列的理解或生成结果。



posted @ 2026-06-13 11:56  icuic  阅读(3)  评论(0)    收藏  举报