核心目标
- 为什么用多头注意力
- 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 选择点乘注意力,主要原因是:
- 更适合矩阵乘法并行
- 在 GPU/TPU 上实现效率更高
- 和多头注意力结构更匹配
原始论文明确比较过这两种方式,并指出两者理论复杂度类似,但点乘注意力在实践中更快、更省计算,因为它能直接利用高效的矩阵乘法实现。
Scaled Dot-Product Attention
为什么 softmax 之前要除以 (\sqrt{d_k})
attention 的原始分数来自:
[ QK^T ]
如果 (Q) 和 (K) 的每个分量都满足均值为 0、方差为 1,那么它们点积后的方差大约会随着维度 (dk) 增大而增大。 也就是说,(dk) 越大,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 只负责其中一部分维度。
原因有两个:
保持总计算量不过度膨胀 如果 8 个 head 每个都还用完整维度,那参数量和计算量都会暴涨。
让每个 head 在自己的子空间里专门化 每个 head 只看一部分维度,更容易学到不同类型的关系。
原始论文中,每个 head 的维度通常设为 (d_{model}/h),这样多头后的总计算量与单头全维 attention 大致在同一数量级。
Encoder 和 Decoder 结构
Encoder 模块是什么
原始 Transformer 的一个 Encoder block 结构是:
在进入 Encoder stack 之前,输入还会先经过:
所以更完整的结构是:
其中每个 block 做两件事:
- 让每个 token 和整个输入序列做 self-attention
- 再用逐位置前馈网络做非线性变换
原始论文里的 Encoder 就是这样定义的。
Encoder 端和 Decoder 端如何交互
在原始的 encoder-decoder Transformer 中,decoder block 有三部分:
- masked self-attention
- encoder-decoder attention
- 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 的做法是:
也就是把位置编码直接加到输入 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 位于每个子层的残差相加之后,也就是:
也就是经典的 “Add & Norm”。
什么是 BatchNorm,它的优缺点是什么
BatchNorm 的做法是:
- 用 mini-batch 的均值和方差对激活做归一化
- 再用可学习参数做缩放和平移
BatchNorm 原论文说明,它能显著加快训练并提高效果。
优点:
- 稳定训练
- 常可用更大学习率
- 在 CNN 中效果很好
缺点:
- 依赖 batch size
- train/test 行为不同
- 对序列模型和小 batch 不够自然
前馈网络
Transformer 中的前馈网络是什么
Transformer block 里除了 attention,还包含一个前馈网络(FFN)。
原始论文给出的形式是:
[ FFN(x) = \max(0, xW1 + b1)W2 + b2 ]
也就是:
- 第一层线性变换
- 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 输入模型。 模型会:
- tokenizer 把文本变成 token ids
- token ids 经过 embedding
- 再经过多层 decoder-only Transformer block
- 同时把历史 token 的 K/V 缓存到 KV cache 里
Hugging Face 对 KV cache 的说明明确指出,缓存历史 K/V 是为了避免自回归生成时重复计算上下文。
第二步:生成下一个 token
在 prompt 前向结束后,模型会得到最后一个位置的 logits。 接着:
从最后一个位置 logits 中选出下一个 token
- 可以 greedy
- 可以 sampling
- 可以 beam search
- 把这个 token 接到原前缀后面
- 再进入下一轮生成
Hugging Face 的 generation 文档明确说,不同 decoding strategy 决定“下一个 token 怎么选”。
后续为什么不用把整段都重算一遍
因为有 KV cache。
后续每一步只需要:
- 输入新生成的那个 token
- 只为它计算新的表示和新的 K/V
- 把新的 K/V 接到历史 cache 后面
- 用当前 token 的 Q 和所有历史 K/V 做 attention
- 输出新的 logits
- 再选一个新 token
所以 decoder-only 的生成本质是:
这就是典型的自回归生成过程。KV cache 只是让这个过程更快,而不是改变它的本质。
还需要补充的两个问题
为什么 FFN 是逐位置(position-wise)的?
因为 attention 已经负责了跨 token 的交互,而 FFN 的职责是对每个 token 的当前表示做统一的非线性变换。原始论文明确说 FFN 是对 each position separately and identically 应用的。
为什么 Transformer 同时需要 residual 和 LayerNorm?
因为两者解决的问题不同:
- residual:帮助信息和梯度跨层传播
- LayerNorm:稳定表示分布
所以它们不是互相替代,而是组合使用,形成 “Add & Norm”。原始 Transformer 就是这样设计的。
最重要的结论
- 多头注意力的核心是:在不同表示子空间里并行建模不同关系。
- Q 和 K 分开,是为了让查询空间和键空间解耦,表达更灵活的匹配关系。
- scaled dot-product attention 里的 scaling,是为了让 softmax 输入更稳定。
- Encoder 的 self-attention 通常全可见,Decoder 的 self-attention 必须因果遮罩。
- LayerNorm 不依赖 batch 统计量,更适合 Transformer 这类序列模型。
- Transformer block 的两大核心部分是 attention 和 FFN。
- encoder-only 偏理解,decoder-only 偏生成,encoder-decoder 偏序列到序列转换。
- decoder-only 生成新 token 的本质,是“根据当前前缀预测下一个 token,再把它接回去继续生成”。
References
Transformer 核心
- Attention Is All You Need
https://papers.neurips.cc/paper/7181-attention-is-all-you-need.pdf
Transformer / LLM 入门
Hugging Face LLM Course — How do Transformers work?
https://huggingface.co/learn/llm-course/en/chapter1/4Hugging Face LLM Course — Transformer Architectures
https://huggingface.co/learn/llm-course/en/chapter1/6Hugging Face Course — Chapter 1 Summary
https://huggingface.co/docs/course/chapter1/10
Attention 实现细节
- PyTorch
scaled_dot_product_attention
https://docs.pytorch.org/docs/stable/generated/torch.nn.functional.scaled_dot_product_attention.html
Normalization
Layer Normalization
https://arxiv.org/abs/1607.06450Batch Normalization
https://proceedings.mlr.press/v37/ioffe15.html
Position Encoding
Self-Attention with Relative Position Representations
https://arxiv.org/abs/1803.02155RoFormer: Enhanced Transformer with Rotary Position Embedding
https://arxiv.org/abs/2104.09864Train Short, Test Long: Attention with Linear Biases (ALiBi)
https://arxiv.org/abs/2108.12409
Decoder-only 生成与缓存
Hugging Face Transformers — KV Cache
https://huggingface.co/docs/transformers/v4.44.2/en/kv_cacheHugging Face Transformers — Generation Strategies
https://huggingface.co/docs/transformers/generation_strategies