Skip to content
Gains Summary
Main Navigation 首页 / Home
C++ 编程 / C++ Programming
系统与高性能 / Systems & Performance
Web 开发 / Web Development
人工智能 / Artificial Intelligence
工业软件 / Industrial Software
其他内容 / Other Topics
C++ 编程 / C++系统与性能 / SystemsWeb 开发 / Web人工智能 / AI工业软件 / Industrial

外观

Sidebar Navigation

← 人工智能 / Artificial Intelligence

大语言模型 / Large Language Models

1. LLM 前置知识学习路线 / A Prerequisite Learning Path for Large Language Models

2. 神经网络基础 - 从零理解 AI 的"计算单元" / Neural Network Fundamentals from Artificial Neurons

3. Token 与上下文窗口 - LLM 的计费与记忆单位 / Tokens and Context Windows as the Units of LLM Cost and Memory

4. 解码策略 - 控制 LLM 输出的艺术 / Decoding Strategies for Controlling LLM Output

5. 消息角色 - 构建 Agent 对话的基础 / Message Roles as the Foundation of Agent Conversations

6. 流式输出 - 实时交互的体验优化 / Streaming Output for Responsive Interaction

7. Prompt 工程基础 - 与 LLM 高效对话的技巧 / Prompt Engineering Fundamentals for Effective LLM Interaction

8. LLM 进化史 - 从词向量到 Transformer / The Evolution of LLMs from Word Embeddings to Transformers

9. Transformer 手动计算:从 Attention 到 Encoder-Decoder 完整数据流

10. Transformer 核心原理 - 现代 LLM 的基石 / Transformer Fundamentals Behind Modern LLMs

11. Decoder-Only LLM 深度解析:为什么扔掉 Encoder,以及 KV Cache 如何工作

12. 训练 vs 推理:同一个 Transformer,两条完全不同的执行路径

13. Transformer 训练阶段计算详解 - 手算每一行矩阵 / Transformer Training Computation Matrix by Matrix

14. Transformer 推理阶段详解 — 模型如何"思考"并生成回答 / Transformer Inference and Autoregressive Generation

15. 训练基础扫盲 - 理解 Fine-tune 在做什么 / A Training Primer for Understanding Fine-Tuning

16. LLM 预训练全景:数据管道、Scaling Laws 与训练稳定性

17. 训练基础设施 - 从单卡到千卡集群 / Training Infrastructure from One GPU to Thousand-GPU Clusters

18. Post-Training Pipeline - 从 Base Model 到可用助手 / The Post-Training Pipeline from Base Model to Assistant

19. SFT 深度解析:从 Base Model 到指令跟随——后训练第一步 / SFT Deep Dive: Teaching Base Models to Follow Instructions

20. RLHF 深度解析:从 Reward Model 到 PPO 的完整对齐流程

21. DPO 与对齐方法:从 RLHF 复杂度到直接偏好优化

22. 研究视角:DL/RL 理论到 LLM 训练的完整映射

本页目录

Transformer 核心原理 - 现代 LLM 的基石 / Transformer Fundamentals Behind Modern LLMs ​

📅 创建时间:2026-04-28 🏷️ 标签:#Transformer #Self-Attention #Multi-Head #位置编码 📚 前置知识:[[07 - LLM 进化史]]


📋 本章目标 ​

  • 深入理解 Self-Attention 的计算过程
  • 掌握 Multi-Head Attention 的原理
  • 理解位置编码的设计思路
  • 了解 FFN(Feed-Forward Network)的作用
  • 理解残差连接和层归一化
  • 掌握 Transformer 的完整数据流

第1部分:Self-Attention 详解 ​

1.1 从向量表示说起 ​

词嵌入:将词转换为向量

输入句子:"猫 追 老鼠"

每个词被表示为一个向量(假设维度 d_model = 4):
词 → 向量
────────────────────
猫   → [0.5, 0.2, 0.8, 0.1]
追   → [0.3, 0.7, 0.2, 0.6]
老鼠 → [0.6, 0.1, 0.3, 0.9]

这些向量包含了词的"语义信息"
通过 Word2Vec 或模型学习得到
1
2
3
4
5
6
7
8
9
10
11

1.2 Q/K/V 向量 ​

Query(查询)、Key(键)、Value(值)

核心思想:

Query:我想要什么信息?
Key:每个位置能提供什么信息?
Value:每个位置的实际信息内容

类比图书馆:
Query:你想要找什么书(主题)
Key:每本书的索引标签
Value:书的实际内容

Attention = 根据 Query 在 Key 中查找,提取对应的 Value
1
2
3
4
5
6
7
8
9
10

数学表示:

对于每个词向量 x,通过线性变换得到 Q/K/V:

Q = x · W_q  (Query 矩阵)
K = x · W_k  (Key 矩阵)
V = x · W_v  (Value 矩阵)

W_q, W_k, W_v 是可学习的参数
1
2
3
4
5
6
7

具体数值示例:

假设:
词向量 x_猫 = [0.5, 0.2, 0.8, 0.1]  (4维)
权重矩阵 W_q = [[0.1, 0.2],      (4×2矩阵)
                [0.3, 0.4],
                [0.5, 0.6],
                [0.7, 0.8]]

计算 Q_猫 = x_猫 · W_q:
Q_猫[0] = 0.5×0.1 + 0.2×0.3 + 0.8×0.5 + 0.1×0.7
        = 0.05 + 0.06 + 0.40 + 0.07
        = 0.58

Q_猫[1] = 0.5×0.2 + 0.2×0.4 + 0.8×0.6 + 0.1×0.8
        = 0.10 + 0.08 + 0.48 + 0.08
        = 0.74

Q_猫 = [0.58, 0.74]  (2维 Query)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

1.3 注意力分数计算 ​

步骤1:计算 Q 和 K 的点积

对于句子 "猫 追 老鼠",假设 d_k = 2:

Q 矩阵(每个词的 Query):
Q_猫   = [0.58, 0.74]
Q_追   = [0.62, 0.81]
Q_老鼠 = [0.45, 0.67]

K 矩阵(每个词的 Key):
K_猫   = [0.71, 0.52]
K_追   = [0.83, 0.69]
K_老鼠 = [0.55, 0.78]

计算注意力分数:score = Q · K^T

score(猫, 猫) = Q_猫 · K_猫 = 0.58×0.71 + 0.74×0.52 = 0.78
score(猫, 追) = Q_猫 · K_追 = 0.58×0.83 + 0.74×0.69 = 0.97
score(猫, 老鼠) = Q_猫 · K_老鼠 = 0.58×0.55 + 0.74×0.78 = 0.96
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

步骤2:除以 √d_k

为什么要除以 √d_k?

原因:防止点积值过大,导致 softmax 后梯度太小

d_k = 2
√d_k = 1.41

归一化后:
score(猫, 猫) = 0.78 / 1.41 = 0.55
score(猫, 追) = 0.97 / 1.41 = 0.69
score(猫, 老鼠) = 0.96 / 1.41 = 0.68
1
2
3
4
5
6
7
8
9
10
11

步骤3:Softmax 得到注意力权重

对每行进行 softmax:

猫 的注意力权重:
exp(0.55) = 1.73
exp(0.69) = 1.99
exp(0.68) = 1.97
总和 = 1.73 + 1.99 + 1.97 = 5.69

归一化:
attention(猫, 猫) = 1.73 / 5.69 = 0.30
attention(猫, 追) = 1.99 / 5.69 = 0.35
attention(猫, 老鼠) = 1.97 / 5.69 = 0.35

解释:对于"猫"这个词,它 30% 关注自己,35% 关注"追",35% 关注"老鼠"
1
2
3
4
5
6
7
8
9
10
11
12
13
14

1.4 最终输出计算 ​

步骤4:用注意力权重对 Value 加权求和

V 矩阵(每个词的 Value):
V_猫   = [0.52, 0.61]
V_追   = [0.78, 0.43]
V_老鼠 = [0.63, 0.72]

对于"猫"的输出:
output_猫 = 0.30 × V_猫 + 0.35 × V_追 + 0.35 × V_老鼠

output_猫[0] = 0.30×0.52 + 0.35×0.78 + 0.35×0.63
             = 0.156 + 0.273 + 0.221
             = 0.650

output_猫[1] = 0.30×0.61 + 0.35×0.43 + 0.35×0.72
             = 0.183 + 0.151 + 0.252
             = 0.586

output_猫 = [0.650, 0.586]

"猫"的表示现在包含了它与所有词的关系信息!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

1.5 Self-Attention 的完整矩阵形式 ​

┌─────────────────────────────────────────────────────────────┐
│                  Self-Attention 矩阵计算                     │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  输入:X(序列的词向量矩阵)                                  │
│                                                             │
│  1. X → Q = X · W_q                                       │
│  2. X → K = X · W_k                                       │
│  3. X → V = X · W_v                                       │
│                                                             │
│  4. Attention = softmax(Q · K^T / √d_k) · V               │
│                                                             │
│  其中:                                                     │
│  • Q, K, V 都是矩阵(一次计算所有词)                        │
│  • Q · K^T 是所有位置对的点积                                │
│  • softmax 按行进行                                          │
│  • 最后乘以 V 得到加权求和结果                               │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

第2部分:Multi-Head Attention ​

2.1 为什么需要多头? ​

单头 Attention 的局限:

单头只能学习一种类型的注意力模式

例如:只能学习"主语-动词"关系

但实际上,句子中有很多种关系:
• 主语-动词(谁做了什么)
• 形容词-名词(什么样的)
• 代词-指代(代词指谁)
• 全局语义相似性
1
2
3
4
5
6
7
8
9

多头 Attention:

多个注意力头并行
每个头学习不同类型的关系

head_1 = 关注 主语-动词
head_2 = 关注 形容词-名词
head_3 = 关注 代词指代
...

最终输出 = concat(head_1, head_2, ...) · W_o
1
2
3
4
5
6
7
8
9

2.2 多头的数值示例 ​

假设:
- d_model = 4(词向量维度)
- num_heads = 2(2个头)
- d_k = d_v = 2(每个头的维度)

每个头独立计算 Attention:

Head_1(关注语义相似):
Q₁ = X · W_q1
K₁ = X · W_k1
V₁ = X · W_v1
Attention₁ = softmax(Q₁ · K₁^T / √2) · V₁

Head_2(关注位置关系):
Q₂ = X · W_q2
K₂ = X · W_k2
V₂ = X · W_v2
Attention₂ = softmax(Q₂ · K₂^T / √2) · V₂

最终输出:
MultiHead = concat(Attention₁, Attention₂) · W_o
          = [head_1; head_2] · W_o
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

2.3 多头注意力图示 ​

┌─────────────────────────────────────────────────────────────┐
│                  Multi-Head Attention                         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│                    输入 X (d_model)                          │
│                         ↓                                   │
│     ┌─────────────────────────────────────────────┐        │
│     │        并行计算 h 个 Attention              │        │
│     │                                            │        │
│     │   Head_1 ──→ Attention₁ ──┐                │        │
│     │   Head_2 ──→ Attention₂ ──┼──→ concat ──→ W_o      │
│     │   ...   ──→ ...        ──┤                │        │
│     │   Head_h ──→ Attention_h ──┘                │        │
│     │                                            │        │
│     │  (每个头有独立的 W_q, W_k, W_v)              │        │
│     └─────────────────────────────────────────────┘        │
│                         ↓                                   │
│                  输出 (d_model)                             │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

2.4 为什么多头有效? ​

类比理解:

单头 = 只戴一副眼镜(只能看一种颜色)
多头 = 戴多副不同颜色的眼镜(同时看到多种信息)

技术原因:
1. 每个头学习不同的注意力模式
2. 不同的头关注句子的不同方面
3. 多个头的组合提供更丰富的表示
4. 某些头可以冗余备份,提高鲁棒性

实验观察:
• 不同的头确实学习了不同的语义关系
• 某些头在训练中被"淘汰"
• 某些头专门处理特定类型的依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

第3部分:位置编码 ​

3.1 为什么需要位置编码? ​

Attention 本身是"位置无关"的

Self-Attention 的计算:
output = softmax(Q · K^T / √d) · V

这里 Q·K^T 只考虑语义相似性
不包含位置信息!

结果:
"猫 追 老鼠" 和 "老鼠 追 猫" 的 Attention 结果相同!
(因为只是交换了位置)
1
2
3
4
5
6
7
8
9

位置编码的解决方案:

为每个位置添加一个独特的"位置向量"

位置向量 + 词向量 = 带位置信息的完整表示

"猫" 在位置 0:word_vec[猫] + pos_vec[0]
"追" 在位置 1:word_vec[追] + pos_vec[1]
"老鼠" 在位置 2:word_vec[老鼠] + pos_vec[2]
1
2
3
4
5
6
7

3.2 Sinusoidal 位置编码 ​

论文原文中使用的编码方式:

PE(pos, 2i)   = sin(pos / 10000^(2i/d_model))
PE(pos, 2i+1) = cos(pos / 10000^(2i/d_model))

其中:
- pos = 位置(0, 1, 2, ...)
- i = 维度索引(0, 1, 2, ..., d_model/2)
- d_model = 位置编码的总维度
1
2
3
4
5
6
7

具体数值示例:

假设 d_model = 4,则 i = 0, 1

位置 0(pos = 0):
PE(0, 0) = sin(0 / 10000^0) = sin(0) = 0
PE(0, 1) = cos(0 / 10000^0) = cos(0) = 1
PE(0, 2) = sin(0 / 10000^1) = sin(0) = 0
PE(0, 3) = cos(0 / 10000^1) = cos(0) = 1

位置向量 PE(0) = [0, 1, 0, 1]

位置 1(pos = 1):
PE(1, 0) = sin(1 / 10000^0) = sin(1) ≈ 0.84
PE(1, 1) = cos(1 / 10000^0) = cos(1) ≈ 0.54
PE(1, 2) = sin(1 / 10000^1) = sin(0.0001) ≈ 0.0001
PE(1, 3) = cos(1 / 10000^1) = cos(0.0001) ≈ 1.0

位置向量 PE(1) = [0.84, 0.54, 0.0001, 1.0]

位置 2(pos = 2):
PE(2, 0) = sin(2) ≈ 0.91
PE(2, 1) = cos(2) ≈ -0.42
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

3.3 位置编码的特性 ​

特性1:每个位置有独特编码

PE(0) = [0, 1, 0, 1]
PE(1) = [0.84, 0.54, 0.0001, 1.0]
PE(2) = [0.91, -0.42, 0.0002, 1.0]

任意两个位置都不相同!
1
2
3
4
5

特性2:相对位置可以通过线性变换得到

PE(pos + k) 可以表示为 PE(pos) 的线性组合

这意味着:
模型可以从绝对位置推断相对位置
这对学习位置关系很重要!
1
2
3
4
5

特性3:可以推广到任意长度

Sinusoidal 函数是周期函数
可以处理比训练时更长的序列

对于长位置,函数值仍然有定义
虽然可能不那么精确
1
2
3
4
5

3.4 位置编码图示 ​

┌─────────────────────────────────────────────────────────────┐
│                  位置编码示意图                               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  位置 0:    ▓░▓░▓░▓░  波形                                    │
│  位置 1:  ▓░▓░▓░▓░▓░                                              │
│  位置 2:░▓░▓░▓░▓░▓                                                │
│  ...                                                          │
│                                                             │
│  竖直看下去,每个位置有独特的"指纹"                              │
│                                                             │
│  ┌──────┬──────┬──────┬──────┐                               │
│  │ pos=0│ pos=1│ pos=2│ pos=3│                               │
│  ├──────┼──────┼──────┼──────┤                               │
│  │ [0,1,│[0.84,│[0.91,│[-0.76│                               │
│  │  0,1]│0.54, │-0.42,│ 0.65,│                               │
│  │      │0.0001│0.0002│0.0003│                               │
│  │      │  1.0]│  1.0]│  1.0]│                               │
│  └──────┴──────┴──────┴──────┘                               │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

第4部分:前馈神经网络(FFN) ​

4.1 FFN 在 Transformer 中的位置 ​

┌─────────────────────────────────────────────────────────────┐
│              Transformer Block 结构                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  输入                                                       │
│    ↓                                                        │
│  Multi-Head Self-Attention ← 捕捉序列内关系                  │
│    ↓                                                        │
│  Add & LayerNorm                                            │
│    ↓                                                        │
│  Feed-Forward Network ← 处理每个位置的"思考"                 │
│    ↓                                                        │
│  Add & LayerNorm                                            │
│    ↓                                                        │
│  输出                                                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

4.2 FFN 的结构 ​

FFN = 两层全连接网络 + 激活函数

FFN(x) = max(0, x · W₁ + b₁) · W₂ + b₂

或者使用 GELU:
FFN(x) = GELU(x · W₁ + b₁) · W₂ + b₂

结构:
输入(d_model) → 线性变换(W₁) → 隐藏层(d_ff = 4×d_model) → 激活 → 线性变换(W₂) → 输出(d_model)
1
2
3
4
5
6
7

具体数值示例:

假设:
- d_model = 4
- d_ff = 16(4倍扩展)

输入 x = [0.5, 0.2, 0.8, 0.1]

W₁ 是 4×16 的矩阵,b₁ 是 16 维向量
W₂ 是 16×4 的矩阵,b₂ 是 4 维向量

hidden_pre = x · W₁ + b₁
           = [0.5, 0.2, 0.8, 0.1] · W₁ + b₁
           = [0.65, -0.3, 0.45, ...16个值...]

hidden = GELU(hidden_pre)  # 非线性激活

output = hidden · W₂ + b₂
       = [0.65, 0, 0.45, ...] · W₂ + b₂
       = [0.7, 0.1, 0.6, 0.2]  # 回到 d_model 维度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

4.3 FFN 的作用 ​

Attention 之后为什么要加 FFN?

Attention 的作用:
- 整合其他位置的信息
- 每个位置都"看到"了整个序列

FFN 的作用:
- 对每个位置进行独立的非线性变换
- 增加模型的表达能力
- 可以看作是对"聚合后信息"的进一步处理

类比:
Attention = 开会讨论,收集大家意见
FFN = 会后独立思考,把讨论结果内化为自己的理解
1
2
3
4
5
6
7
8
9
10
11
12

为什么隐藏层要扩大 4 倍?

Transformer 原始论文建议 d_ff = 4 × d_model

经验公式,经大量实验验证

作用:
- 提供足够的"思考空间"
- 太小:表达能力不足
- 太大:计算成本高,容易过拟合

例如 BERT-base:
d_model = 768
d_ff = 3072 = 768 × 4
1
2
3
4
5
6
7
8
9
10
11
12

第5部分:残差连接与层归一化 ​

5.1 残差连接(Skip Connection) ​

问题:深层网络训练困难

网络太深时:
- 梯度消失/爆炸
- 训练困难
- 退化问题(层数增加,准确率反而下降)

解决方案:残差连接
1
2
3
4
5
6

残差连接的原理:

普通连接:
  输入 x → [网络层] → 输出 F(x)

残差连接:
  输入 x → → → → → → → ↓
                [网络层]
                     ↓
              输出 F(x) + x

输出 = 主路径输出 + 跳接输入
1
2
3
4
5
6
7
8
9
10

具体计算:

假设:
- 输入 x = [0.5, 0.2, 0.8, 0.1]
- 主路径变换 F(x) = [0.7, 0.3, 0.6, 0.2]

残差输出 = F(x) + x
         = [0.7, 0.3, 0.6, 0.2] + [0.5, 0.2, 0.8, 0.1]
         = [1.2, 0.5, 1.4, 0.3]

好处:
- 即使 F(x) = 0(主路径失效),输出也是 x(至少不会变差)
- 梯度可以直接传回输入端
- 训练更稳定
1
2
3
4
5
6
7
8
9
10
11
12

5.2 层归一化(Layer Normalization) ​

问题:每层输出的数值范围可能差异很大

不同层的输出:
Layer 1: [0.1, 0.2, 0.3]  小范围
Layer 2: [50, 60, 70]      大范围
Layer 3: [0.01, 0.02, 0.03]  又小了

这种不一致会影响训练稳定性
1
2
3
4
5
6

层归一化的公式:

给定输入 x = [x₁, x₂, ..., x_d]

计算:
mean = (x₁ + x₂ + ... + x_d) / d
variance = ((x₁-mean)² + ... + (x_d-mean)²) / d
std = √variance

归一化:
y_i = (x_i - mean) / (std + ε)

可学习的缩放和偏移:
output = γ * y + β

ε 是极小值,防止除零
γ 和 β 是可学习参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

具体数值示例:

输入 x = [2.0, 4.0, 6.0, 8.0]

mean = (2 + 4 + 6 + 8) / 4 = 5.0
variance = ((2-5)² + (4-5)² + (6-5)² + (8-5)²) / 4
          = (9 + 1 + 1 + 9) / 4 = 20 / 4 = 5.0
std = √5.0 ≈ 2.24

归一化:
y = [(2-5)/2.24, (4-5)/2.24, (6-5)/2.24, (8-5)/2.24]
  = [-1.34, -0.45, 0.45, 1.34]

输出范围被标准化了!
1
2
3
4
5
6
7
8
9
10
11
12

5.3 Add & LayerNorm 组合 ​

┌─────────────────────────────────────────────────────────────┐
│                  Add & LayerNorm                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  输入 x                                                     │
│    ↓                                                        │
│  ┌───────────────────────┐                                  │
│  │ 残差连接:            │                                  │
│  │ x ──→ [子层] ──→ F(x)│                                  │
│  │  ↓                   │                                  │
│  │  +                   │                                  │
│  │  ↓                   │                                  │
│  │  F(x) + x ──────────→│                                  │
│  └───────────────────────┘                                  │
│    ↓                                                        │
│  ┌───────────────────────┐                                  │
│  │ LayerNorm:           │                                  │
│  │ (F(x) + x - mean)/std│                                  │
│  └───────────────────────┘                                  │
│    ↓                                                        │
│  输出                                                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

第6部分:Transformer 完整架构 ​

6.1 编码器结构 ​

┌─────────────────────────────────────────────────────────────┐
│                    单个编码器层                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  输入 (词向量 + 位置编码)                                    │
│    ↓                                                        │
│  Multi-Head Self-Attention                                  │
│    ↓                                                        │
│  Add & LayerNorm                                            │
│    ↓                                                        │
│  Feed-Forward Network                                       │
│    ↓                                                        │
│  Add & LayerNorm                                            │
│    ↓                                                        │
│  输出                                                       │
│                                                             │
│  特点:每个位置可以看到所有其他位置                            │
│                                                             │
└─────────────────────────────────────────────────────────────┘

编码器堆叠 N 层(原始论文 N=6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

6.2 解码器结构 ​

┌─────────────────────────────────────────────────────────────┐
│                    单个解码器层                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  输入(已生成的词 + 位置编码)                                │
│    ↓                                                        │
│  Masked Multi-Head Self-Attention ← 不能看到未来             │
│    ↓                                                        │
│  Add & LayerNorm                                            │
│    ↓                                                        │
│  Multi-Head Cross-Attention ← 关注编码器的输出              │
│    ↓                                                        │
│  Add & LayerNorm                                            │
│    ↓                                                        │
│  Feed-Forward Network                                        │
│    ↓                                                        │
│  Add & LayerNorm                                            │
│    ↓                                                        │
│  输出                                                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘

解码器堆叠 N 层(原始论文 N=6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

6.3 Masked Attention 的作用 ​

为什么需要 Mask?

问题:解码器不应该"看到"未来的词

例如生成 "我爱AI":
位置 1: "我"      → 只能看自己
位置 2: "爱"      → 只能看"我"和自己
位置 3: "A"       → 只能看"我爱"和自己
位置 4: "I"       → 只能看"我爱AI"和自己

不能提前知道答案!
1
2
3
4
5
6
7
8
9

Mask 的实现:

对于位置 i,把位置 i+1, i+2, ... 的注意力分数设为 -∞

softmax 后这些位置的影响变成 0

示例(4个位置的 Attention):

原始注意力分数:
        位置0   位置1   位置2   位置3
位置0   0.5    0.3    0.1    0.1
位置1   0.2    0.6    0.1    0.1
位置2   0.1    0.2    0.5    0.2
位置3   0.1    0.1    0.2    0.6

添加 Mask(位置2不能看位置3):
        位置0   位置1   位置2   位置3
位置0   0.5    0.3    0.1    0.1
位置1   0.2    0.6    0.1    0.1
位置2   0.1    0.2    0.5   -∞
位置3  -∞    -∞    -∞    -∞

softmax 后:
位置2: [0.25, 0.38, 0.37, 0]  ← 不包含位置3
位置3: [0, 0, 0, 1]            ← 只看自己
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

第7部分:完整数据流 ​

7.1 从输入到输出 ​

┌─────────────────────────────────────────────────────────────────────────────┐
│                        Transformer 完整数据流                                 │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  输入:"I love AI"                                                         │
│                                                                             │
│  ┌───────────────────────────────────────────────────────────────────────┐ │
│  │ 步骤1:词嵌入 + 位置编码                                               │ │
│  │                                                                       │ │
│  │   "I"     → Embedding + Pos Encoding → [e₁]                         │ │
│  │   "love"  → Embedding + Pos Encoding → [e₂]                         │ │
│  │   "AI"    → Embedding + Pos Encoding → [e₃]                         │ │
│  └───────────────────────────────────────────────────────────────────────┘ │
│                                    ↓                                        │
│  ┌───────────────────────────────────────────────────────────────────────┐ │
│  │ 步骤2:编码器层堆叠(×6)                                              │ │
│  │                                                                       │ │
│  │   编码器层1: [e₁,e₂,e₃] → MultiHead → FFN → [h₁,h₂,h₃]             │ │
│  │   编码器层2: [h₁,h₂,h₃] → MultiHead → FFN → [g₁,g₂,g₃]             │ │
│  │   ...                                                                 │ │
│  │   编码器层6: [x₁,x₂,x₃] → [z₁,z₂,z₃] ← 编码器最终输出                │ │
│  └───────────────────────────────────────────────────────────────────────┘ │
│                                    ↓                                        │
│  ┌───────────────────────────────────────────────────────────────────────┐ │
│  │ 步骤3:解码器自回归生成                                               │ │
│  │                                                                       │ │
│  │   生成"<start>"                                                      │ │
│  │       ↓                                                              │ │
│  │   生成"我爱" → 关注编码器输出 [z₁,z₂,z₃] + 解码器历史                │ │
│  │       ↓                                                              │ │
│  │   生成"<end>"                                                        │ │
│  └───────────────────────────────────────────────────────────────────────┘ │
│                                    ↓                                        │
│  输出:翻译结果                                                            │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

7.2 自回归生成过程 ​

┌─────────────────────────────────────────────────────────────┐
│                    自回归生成示例                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  目标:将 "I love AI" 翻译成 "我爱AI"                       │
│                                                             │
│  步骤1:输入 "<start>"                                     │
│  → 解码器输出 "我"                                         │
│                                                             │
│  步骤2:输入 "<start> 我"                                  │
│  → 解码器输出 "爱"                                         │
│                                                             │
│  步骤3:输入 "<start> 我 爱"                               │
│  → 解码器输出 "AI"                                         │
│                                                             │
│  步骤4:输入 "<start> 我 爱 AI"                            │
│  → 解码器输出 "<end>"                                      │
│                                                             │
│  完成!输出:"我爱AI"                                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

核心总结 ​

总结1:Self-Attention 的本质 ​

Attention(Q, K, V) = softmax(Q · K^T / √d_k) · V

本质:
- Query:我要找什么
- Key:我能提供什么
- Value:我的实际内容

计算:Query 和 Key 的相似度 → 权重 → 加权 Value
1
2
3
4
5
6
7
8

总结2:多头注意力的意义 ​

多头的价值:
- 每个头学习不同的注意力模式
- 有的关注语法,有的关注语义
- 组合提供更丰富的表示

公式:MultiHead = concat(head₁, ..., head_h) · W_o
1
2
3
4
5
6

总结3:位置编码的设计 ​

目的:注入位置信息(Attention 本身位置无关)

方法:Sinusoidal 编码
PE(pos, 2i) = sin(pos / 10000^(2i/d))
PE(pos, 2i+1) = cos(pos / 10000^(2i/d))

特点:
- 每个位置独特
- 可表示相对位置
- 可推广到更长序列
1
2
3
4
5
6
7
8
9
10

总结4:Transformer 组件作用 ​

组件作用
Self-Attention捕捉序列内长距离依赖
Multi-Head多角度理解
FFN非线性变换,增强表达
残差连接梯度流动,稳定训练
LayerNorm稳定数值范围
位置编码注入位置信息

章节测试 ​

测试1:Q/K/V 的作用 ​

在 Self-Attention 中,Query、Key、Value 各自的作用是什么?

测试2:为什么要除以 √d_k ​

在计算注意力分数时,为什么要除以 √d_k?

测试3:多头注意力 ​

Multi-Head Attention 比单头 Attention 有什么优势?

测试4:位置编码 ​

为什么 Transformer 需要位置编码,而 RNN 不需要?

测试5:Mask 的作用 ​

在解码器的 Masked Attention 中,Mask 的作用是什么?


参考答案 ​

测试1答案 ​

答案:

  • Query(Q):当前位置的"查询",表示当前位置想要获取什么信息
  • Key(K):每个位置的"索引",表示该位置能提供什么信息
  • Value(V):每个位置的"内容",表示该位置的实际信息

解析:

类比图书馆系统:
- Query:你想搜索的主题
- Key:每本书的索引标签
- Value:书的实际内容

Attention = 用 Query 在 Key 中搜索,找到匹配的内容(Value)
1
2
3
4
5
6

测试2答案 ​

答案:防止点积值过大,导致 softmax 后梯度太小

解析:

问题来源:
- Q 和 K 的维度是 d_k
- 点积 Q·K^T 的值范围与 √d_k 成正比
- 当 d_k 很大时,点积值会很大

具体影响:
假设 Q, K 是均值为0、方差为1的随机向量:
E[Q·K^T] = d_k
std(Q·K^T) ≈ √(2d_k)

当 d_k = 64 时,点积最大值可达 ~30

经过 softmax:
softmax([30, 0, 0, ...]) ≈ [1, 0, 0, ...]
梯度接近 0,无法学习!

解决方案:除以 √d_k
softmax([30/8, 0, 0, ...]) = softmax([3.75, 0, 0, ...])
仍然很大但更可控

或者除以 √(2d_k),方差归一化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

测试3答案 ​

答案:

  1. 每个头可以学习不同类型的注意力模式
  2. 提供更丰富的语义表示
  3. 增加模型的鲁棒性(某些头可以备份)

解析:

单头的问题:
- 只能学习一种类型的注意力关系
- 表达能力有限

多头的优势:
- Head 1:学习主语-动词关系
- Head 2:学习形容词-名词关系
- Head 3:学习语义相似性
- Head 4:学习位置邻近性
- ...

最终输出 = concat(所有head) · W_o
- 维度不变,但信息更丰富
- 每个头互补,提供多角度理解
1
2
3
4
5
6
7
8
9
10
11
12
13
14

测试4答案 ​

答案:因为 Attention 机制本身是位置无关的

解析:

Transformer 的 Self-Attention:
output = softmax(Q · K^T / √d) · V

这里的计算:
- Q·K^T 只考虑语义相似性
- 不包含任何位置信息
- "猫 追 老鼠" 和 "老鼠 追 猫" 结果相同!

RNN 的特点:
- 顺序处理,每个位置依次计算
- 时间步天然包含位置信息
- "词1 → 词2 → 词3" 本身就代表了顺序

Transformer 需要位置编码:
- Attention 是"全连接"的,不包含顺序
- 必须显式添加位置信息
- 位置编码让模型知道词的相对/绝对位置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

测试5答案 ​

答案:防止解码器在生成当前位置时"看到"未来的词

解析:

自回归生成的问题:
- 生成第3个词时,不应该知道第4、5个词是什么
- 否则模型可能"偷看答案"

Mask 的作用:
- 把位置 i+1, i+2, ... 的注意力分数设为 -∞
- softmax 后这些位置的权重变成 0
- 当前位置只能关注自己和之前的词

示例(生成第3个词):
- 应该看:位置0, 位置1, 位置2
- 不应该看:位置3, 位置4, ...

没有 Mask:泄漏未来信息
有 Mask:严格自回归,训练目标正确
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

相关笔记 ​

  • [[01 - 神经网络基础]] - MLP、激活函数的理解
  • [[07 - LLM 进化史]] - Transformer 的历史背景
  • [[03 - 解码策略]] - Transformer 的解码过程

下一步学习 ​

  • [ ] 完成 LLM 前置知识模块
  • [ ] 前往 Agent 基础 开始学习

学习状态:✅ 已完成

恭喜你完成了 LLM 前置知识模块的学习!

最后更新于:

Pager
上一篇9. Transformer 手动计算:从 Attention 到 Encoder-Decoder 完整数据流
下一篇11. Decoder-Only LLM 深度解析:为什么扔掉 Encoder,以及 KV Cache 如何工作

持续记录,持续成长

Copyright © Tidenflow