核心目标

  • 为什么用多头注意力
  • Q / K / V 分别在做什么
  • attention 为什么用点乘、为什么要 scaled
  • Encoder / Decoder 的结构分别是什么
  • 位置编码、残差、LayerNorm、BatchNorm、前馈网络分别起什么作用
  • decoder-only 模型是怎么一步一步生成新 token 的
  • encoder-only、decoder-only、encoder-decoder 各适合什么任务

架构图

引用自 https://github.com/An-Jhon/Hand-Drawn-Transformer

Transformer

Transformer-Decoder

Transformer-Encoder

Transformer-Encoder

Transformer-Decoder

Transformer-Decoder


多头注意力

为什么使用多头注意力,而不是一个头

多头注意力的核心作用是:让模型在不同表示子空间里并行地关注不同类型的关系

单头注意力当然也能工作,但它只能学到一套注意力模式。
多头注意力则可以让不同 head 分别关注不同的信息,比如:

  • 有的 head 更关注近距离依赖
  • 有的 head 更关注长距离依赖
  • 有的 head 更关注句法关系
  • 有的 head 更关注实体之间的对应关系

所以,多头注意力并不是“把一个头简单复制很多份”,而是给模型提供了并行的、多视角的关系建模能力。原始 Transformer 论文明确说明,多头注意力可以让模型同时在不同表示子空间中关注信息,而单头注意力会削弱这种能力。

为什么 Q 和 K 使用不同的权重矩阵,而不是直接自己和自己点乘

Q 和 K 虽然都来自输入表示,但它们承担的角色不同:

  • Q(Query):当前 token 想找什么
  • K(Key):每个 token 提供什么可被匹配的信息
  • V(Value):匹配成功后真正取走的内容

如果 Q 和 K 使用同一个投影矩阵,那 attention score 更接近一种“自相似度”计算,表达能力会受限。
而把 Q 和 K 分开,模型就能学习更灵活的匹配关系,也就是:

  • 查询空间和键空间可以不同
  • 匹配关系不必对称
  • 不同 head 也能学出不同的匹配模式

原始论文就是分别使用 (W^Q)、(W^K)、(W^V) 三组矩阵。

为什么 attention 选择点乘而不是加法

常见的 attention 打分方式有两类:

  • 加法注意力(additive attention)
  • 点乘注意力(dot-product attention)

Transformer 选择点乘注意力,主要原因是:

  1. 更适合矩阵乘法并行
  2. 在 GPU/TPU 上实现效率更高
  3. 和多头注意力结构更匹配

原始论文明确比较过这两种方式,并指出两者理论复杂度类似,但点乘注意力在实践中更快、更省计算,因为它能直接利用高效的矩阵乘法实现。


Scaled Dot-Product Attention

为什么 softmax 之前要除以 (\sqrt{d_k})

attention 的原始分数来自:

[
QK^T
]

如果 (Q) 和 (K) 的每个分量都满足均值为 0、方差为 1,那么它们点积后的方差大约会随着维度 (d_k) 增大而增大。
也就是说,(d_k) 越大,attention score 的数值通常越大。

这样会带来一个问题:

  • softmax 输入太大
  • softmax 输出会变得非常极端
  • 很多位置接近 0 或 1
  • 梯度变小,训练不稳定

所以 Transformer 在 softmax 之前会做:

[
\frac{QK^T}{\sqrt{d_k}}
]

这样做的效果是把 score 的尺度压回更稳定的范围,让 softmax 不容易饱和。原始论文明确给出了这个解释。

如何对 padding 做 mask

padding mask 的作用是:屏蔽掉那些只是补齐长度、并不是真实 token 的位置

常见做法是在 softmax 之前,把 padding 位置对应的 attention score 设成一个极小值(理论上写作 (-\infty)):

  • 有效 token:保留原分数
  • padding token:设为 (-\infty)

这样经过 softmax 之后,padding 位置的权重就会变成 0。
这里要区分两种 mask:

  • padding mask:遮掉 pad
  • causal mask / sequence mask:遮掉未来 token

这两者不是一回事。原始论文在 decoder 里写到,用 mask 把非法连接设为 (-\infty);padding mask 也是同样思想。


多头注意力里的降维

为什么每个 head 要降维

多头注意力通常把总 hidden dim 切成多个 head,每个 head 只负责其中一部分维度。

原因有两个:

  1. 保持总计算量不过度膨胀
    如果 8 个 head 每个都还用完整维度,那参数量和计算量都会暴涨。

  2. 让每个 head 在自己的子空间里专门化
    每个 head 只看一部分维度,更容易学到不同类型的关系。

原始论文中,每个 head 的维度通常设为 (d_{model}/h),这样多头后的总计算量与单头全维 attention 大致在同一数量级。


Encoder 和 Decoder 结构

Encoder 模块是什么

原始 Transformer 的一个 Encoder block 结构是:

1
2
3
4
Multi-Head Self-Attention
-> Add & LayerNorm
-> Position-wise Feed-Forward Network
-> Add & LayerNorm

在进入 Encoder stack 之前,输入还会先经过:

1
token embedding + positional encoding

所以更完整的结构是:

1
2
3
token ids
-> embedding + positional encoding
-> N 层 Encoder blocks

其中每个 block 做两件事:

  1. 让每个 token 和整个输入序列做 self-attention
  2. 再用逐位置前馈网络做非线性变换

原始论文里的 Encoder 就是这样定义的。

Encoder 端和 Decoder 端如何交互

在原始的 encoder-decoder Transformer 中,decoder block 有三部分:

  1. masked self-attention
  2. encoder-decoder attention
  3. feed-forward network

其中第二部分就是 Encoder 和 Decoder 的交互点。

这里一定要记清:

  • Q 来自 decoder 当前层表示
  • K 和 V 来自 encoder 输出

也就是说,decoder 会先根据已经生成的前缀形成自己的查询表示,然后再去“读取”encoder 编码后的输入信息。原始论文明确是这样定义 cross-attention 的。

Decoder 自注意力和 Encoder 自注意力有什么区别

两者核心形式相同,但有一个关键区别:

  • Encoder self-attention:通常可以看到整个输入序列
  • Decoder self-attention:必须加 causal mask,只能看到当前位置及之前的 token

为什么 decoder 必须这样做?
因为 decoder 是自回归生成模型,在训练时它的目标是“根据前文预测下一个 token”。如果当前位置能看到未来 token,就会信息泄露。原始论文明确指出,decoder 需要 mask 掉后续位置。


并行化

Transformer 的并行化体现在哪里

Transformer 相比 RNN 的一个重要优势是:在训练时,整个序列的很多位置可以并行计算

例如:

  • self-attention 可以一次算出一整个序列的关系
  • 前馈网络可以对所有位置并行做变换

这和 RNN 不一样。RNN 必须按时间步一步一步往后算,而 Transformer 在训练时可以把整段序列一起送进去。原始论文也把“更强的并行化能力”列为 Transformer 的重要优点。

Decoder 可以并行化吗

要分开看:

训练时可以并行化。
因为训练通常使用 teacher forcing,整个目标序列已知,模型可以一次性处理所有位置,只要用 causal mask 保证每个位置不能偷看未来。

推理时不能跨时间步完全并行。
因为推理是自回归生成:

  • 先生成第 1 个新 token
  • 再基于它生成第 2 个
  • 再生成第 3 个

所以推理时跨 token 仍然是串行的,只能在“单步内部”并行。KV cache 可以减少重复计算,但不能把生成过程变成完全并行。Hugging Face 对 KV cache 的说明也明确强调,生成是 token by token 的。


词向量和位置编码

为什么输入词向量后要乘以 (\sqrt{d_{model}})

你之前的理解是反的。
原始 Transformer 论文写的是:embedding 之后要乘以 (\sqrt{d_{model}}),也就是放大,而不是缩小。

直觉上可以这样理解:

  • embedding 本身的尺度可能偏小
  • 后面还要与 positional encoding 相加
  • 乘上 (\sqrt{d_{model}}) 可以让 token embedding 的量级更合适

这里要注意,原论文并没有像解释 scaled attention 那样给出详细数学推导,所以这个点你知道“做了什么”和“大致为什么这样做”就够了。

什么是位置编码,它有什么意义

self-attention 本身并不天然感知顺序。
如果不给模型提供位置信息,那么“猫追狗”和“狗追猫”只看 token 集合可能非常接近,但它们的语义显然不同。

所以 Transformer 需要显式注入位置信息。
原始 Transformer 的做法是:

1
input representation = token embedding + positional encoding

也就是把位置编码直接加到输入 embedding 上。它的意义是:

  • 让模型知道 token 的先后顺序
  • 让 attention 能区分不同位置的关系

原始论文使用的是固定的 sinusoidal positional encoding。

位置编码的优缺点

优点:

  • 结构简单
  • 不依赖 RNN / CNN 就能表达顺序
  • 易于和 attention 结构结合

缺点:

  • 原始绝对位置编码对相对距离关系表达不够直接
  • 更长上下文的外推能力有限
  • 后来很多工作因此提出了更灵活的位置编码方式

其它位置编码技术

除了原始 Transformer 的绝对位置编码,还有很多后续方案。

Learned absolute positional embedding

直接学习每个位置的向量表示。

优点:

  • 模型自己学位置表示

缺点:

  • 超出训练长度时外推能力通常较弱

Relative positional encoding

不直接强调“绝对第几个位置”,而强调 token 之间的相对距离。Shaw 等人的工作就是代表。

优点:

  • 更自然地表达相对距离关系

缺点:

  • 实现更复杂

RoPE(Rotary Position Embedding)

把位置信息编码进 Q/K 的旋转中。RoFormer 明确把它作为一种能将相对位置信息自然融入 self-attention 的方法。

优点:

  • 对相对位置建模更自然
  • 现代 LLM 常用

缺点:

  • 长上下文外推效果和具体频率设计有关

ALiBi

不把位置编码加到 embedding 上,而是直接给 attention score 加线性距离偏置。ALiBi 的论文强调它在长度外推上表现不错。

优点:

  • 简单
  • 长上下文外推效果好
  • 不需要显式位置 embedding

缺点:

  • 表达方式更偏“距离偏置”,不是传统 embedding 形式

残差结构、LayerNorm、BatchNorm

什么是残差结构,它有什么意义

Transformer 在每个子层外面都加了残差连接,然后再做 LayerNorm,也就是论文里的 “Add & Norm”。

如果一个子层输出是 (F(x)),那么残差大致可以理解成:

[
x + F(x)
]

它的意义是:

  • 让原始信息更容易跨层传递
  • 让梯度更容易传播
  • 缓解深层网络训练困难

原始论文明确在每个子层外用了 residual connection followed by layer normalization。

为什么 Transformer 用 LayerNorm 而不是 BatchNorm

这里要纠正一个常见误解:

  • BatchNorm 依赖 batch 的均值和方差
  • LayerNorm 不依赖 batch 统计量,而是对单个样本的隐藏维度做归一化

LayerNorm 论文明确指出,BatchNorm 的效果依赖 mini-batch size,而 LayerNorm 在训练和测试时计算方式一致,更适合 RNN 和序列模型。

Transformer 选择 LayerNorm,主要因为:

  • 序列长度可能变化
  • batch size 可能较小
  • 更希望 train/test 逻辑一致
  • 不想依赖 batch 统计量

LayerNorm 在 Transformer 里的位置

在原始 Transformer 中,LayerNorm 位于每个子层的残差相加之后,也就是:

1
SubLayer -> Add -> LayerNorm

也就是经典的 “Add & Norm”。

什么是 BatchNorm,它的优缺点是什么

BatchNorm 的做法是:

  • 用 mini-batch 的均值和方差对激活做归一化
  • 再用可学习参数做缩放和平移

BatchNorm 原论文说明,它能显著加快训练并提高效果。

优点:

  • 稳定训练
  • 常可用更大学习率
  • 在 CNN 中效果很好

缺点:

  • 依赖 batch size
  • train/test 行为不同
  • 对序列模型和小 batch 不够自然

前馈网络

Transformer 中的前馈网络是什么

Transformer block 里除了 attention,还包含一个前馈网络(FFN)。

原始论文给出的形式是:

[
FFN(x) = \max(0, xW_1 + b_1)W_2 + b_2
]

也就是:

  • 第一层线性变换
  • ReLU 激活
  • 第二层线性变换

而且它是 position-wise 的,也就是说:
对每个 token 位置分别、独立地应用同一套前馈网络。

前馈网络的意义和优缺点

你可以把 Transformer block 分成两个职责:

  • attention:负责 token 和 token 之间交互
  • FFN:负责单个 token 内部表示的非线性变换

优点:

  • 简单
  • 计算高效
  • 给每个位置提供更强表达能力

缺点:

  • 不直接建模 token 间关系
  • 这部分必须由 attention 来负责

学习率、Dropout、Mask

Transformer 的学习率是怎么设定的

原始 Transformer 并不是简单用固定学习率,而是用了非常经典的 Noam learning rate schedule

[
lrate = d_{model}^{-0.5}\cdot \min(step^{-0.5},\ step \cdot warmup^{-1.5})
]

也就是:

  • 前期 warmup,学习率逐步升高
  • 后期随 step 增大而逐步衰减

论文中还明确写了 warmup_steps = 4000。优化器用的是 Adam。

Dropout 放在哪里?测试时要注意什么

原始 Transformer 使用了 residual dropout:

  • 在每个子层输出上做 dropout,再进入 Add & Norm
  • 在 embedding 和 positional encoding 相加之后也做 dropout
  • base model 的 dropout rate 是 0.1

测试/推理时要特别注意:

  • 必须切到 model.eval()
  • 否则 dropout 仍会随机丢弃部分激活
  • 结果就会不稳定

这点和你前面 PyTorch 学到的 train() / eval() 完全一致。

残差结构会不会把未来 token 的信息绕过 mask,造成泄露?

不会。

因为如果 masked self-attention 本身已经正确应用了 causal mask,那么它的输出里就不会包含未来 token 信息。残差连接只是把“当前位置已有的合法输入表示”加回来,并不会凭空引入未来信息。

所以:

  • mask 限制的是 attention 子层的信息流
  • residual 只是保留当前位置已有表示
  • 不会绕过 mask 造成未来信息泄露

三类 Transformer 架构

encoder-only、decoder-only、encoder-decoder 的区别和典型应用

encoder-only

特点是:输入序列里的每个位置通常都可以看到整个输入。
所以它更适合做“理解输入”的任务。

典型任务:

  • 文本分类
  • 命名实体识别
  • 抽取式问答

典型模型:

  • BERT
  • DistilBERT
  • ModernBERT

decoder-only

特点是:当前位置只能看见自己和左边的 token。
所以天然适合自回归生成。

典型任务:

  • 文本续写
  • 对话
  • 通用文本生成

典型模型:

  • GPT
  • LLaMA
  • Gemma

encoder-decoder

特点是:先由 encoder 编码输入,再由 decoder 在生成时通过 cross-attention 读取 encoder 输出。
最适合“输入一个序列,输出另一个序列”的任务。

典型任务:

  • 机器翻译
  • 文本摘要
  • 生成式问答

典型模型:

  • T5
  • BART
  • Marian

decoder-only 模型如何生成一个新 token

一个新 token 是怎么在 decoder-only Transformer 里被生成出来的

这个过程最好分成两段看:

第一步:prefill

先把整段 prompt 输入模型。
模型会:

  1. tokenizer 把文本变成 token ids
  2. token ids 经过 embedding
  3. 再经过多层 decoder-only Transformer block
  4. 同时把历史 token 的 K/V 缓存到 KV cache 里

Hugging Face 对 KV cache 的说明明确指出,缓存历史 K/V 是为了避免自回归生成时重复计算上下文。

第二步:生成下一个 token

在 prompt 前向结束后,模型会得到最后一个位置的 logits。
接着:

  1. 从最后一个位置 logits 中选出下一个 token

    • 可以 greedy
    • 可以 sampling
    • 可以 beam search
  2. 把这个 token 接到原前缀后面

  3. 再进入下一轮生成

Hugging Face 的 generation 文档明确说,不同 decoding strategy 决定“下一个 token 怎么选”。

后续为什么不用把整段都重算一遍

因为有 KV cache。

后续每一步只需要:

  1. 输入新生成的那个 token
  2. 只为它计算新的表示和新的 K/V
  3. 把新的 K/V 接到历史 cache 后面
  4. 用当前 token 的 Q 和所有历史 K/V 做 attention
  5. 输出新的 logits
  6. 再选一个新 token

所以 decoder-only 的生成本质是:

1
2
3
4
当前前缀
-> 预测下一个 token
-> 把这个 token 接回前缀
-> 继续预测

这就是典型的自回归生成过程。KV cache 只是让这个过程更快,而不是改变它的本质。


还需要补充的两个问题

为什么 FFN 是逐位置(position-wise)的?

因为 attention 已经负责了跨 token 的交互,而 FFN 的职责是对每个 token 的当前表示做统一的非线性变换。原始论文明确说 FFN 是对 each position separately and identically 应用的。

为什么 Transformer 同时需要 residual 和 LayerNorm?

因为两者解决的问题不同:

  • residual:帮助信息和梯度跨层传播
  • LayerNorm:稳定表示分布

所以它们不是互相替代,而是组合使用,形成 “Add & Norm”。原始 Transformer 就是这样设计的。


最重要的结论

  1. 多头注意力的核心是:在不同表示子空间里并行建模不同关系。
  2. Q 和 K 分开,是为了让查询空间和键空间解耦,表达更灵活的匹配关系。
  3. scaled dot-product attention 里的 scaling,是为了让 softmax 输入更稳定。
  4. Encoder 的 self-attention 通常全可见,Decoder 的 self-attention 必须因果遮罩。
  5. LayerNorm 不依赖 batch 统计量,更适合 Transformer 这类序列模型。
  6. Transformer block 的两大核心部分是 attention 和 FFN。
  7. encoder-only 偏理解,decoder-only 偏生成,encoder-decoder 偏序列到序列转换。
  8. decoder-only 生成新 token 的本质,是“根据当前前缀预测下一个 token,再把它接回去继续生成”。

References

Transformer 核心

Transformer / LLM 入门

Attention 实现细节

Normalization

Position Encoding

Decoder-only 生成与缓存