目录
- 一、先从一张经典结构图开始
- 二、Transformer 不是一个模块,而是一组模块的组合
- 三、什么是 Encoder?
- 四、Encoder Block:Transformer 的基本积木
- 五、第一部分:Multi-Head Self-Attention
- 六、第二部分:为什么 Attention 后面还需要 Add?
- 七、第三部分:Norm 又是什么?
- 八、第四部分:Attention 之后,为什么还需要 FFN?
- 九、现在,我们终于可以看懂 Encoder Block 了
- 十、Encoder 到底输出了什么?
- 十一、接下来轮到 Decoder
- 十二、Decoder Block 为什么有两个 Attention?
- 十三、Encoder 和 Decoder 到底有什么区别?
- 十四、Transformer 到底是如何完成一次机器翻译的?
- 十五、等等,还有一个重要问题:Transformer 怎么知道顺序?
- 十六、Transformer 的完整数据流
- 十七、一个容易产生的误解:现在的 GPT 还是完整 Transformer 吗?
- 十八、现在,我们对 Transformer 应该有什么整体认识?
- 十九、小结
- 下一篇:Self-Attention 到底是什么?
《深入理解 Transformer:Transformer 究竟是什么?》
前言
在上一篇文章中,我们暂时没有急着讨论 Q、K、V,也没有直接推导 Attention 的计算公式。
我们先回答了一个更基础的问题:
为什么需要 Transformer?
在 Transformer 出现之前,处理文本等序列数据的主流方案是 RNN、LSTM 和 GRU。
它们都有一个非常明显的共同特点:
1x₁ → x₂ → x₃ → x₄ → ··· 2
也就是说,模型通常需要按照序列的顺序,一步一步地处理数据。
这种方式虽然符合人类阅读文本的直觉,但也带来了两个非常关键的问题:
- 计算过程存在顺序依赖,难以充分利用并行计算能力;
- 距离较远的信息需要经过多次传递,长距离依赖难以处理。
随后,Attention 的出现改变了这种思路。
我们不再要求信息必须:
1Token 1 2 ↓ 3Token 2 4 ↓ 5Token 3 6 ↓ 7Token 4 8
一级一级地传递。
而是可以让当前信息直接去关注序列中的其他信息:
1Token 1 ─────────────┐ 2Token 2 ─────────────┤ 3Token 3 ─────────────┼──→ 当前 Token 4Token 4 ─────────────┤ 5Token 5 ─────────────┘ 6
于是,一个新的问题出现了:
既然 Attention 已经这么强大,那么 Transformer 到底是什么?
很多刚开始学习 Transformer 的人都会有一种错觉:
Transformer 不就是 Attention 吗?
这个理解不能说完全错误,但显然还不够完整。
Attention 是 Transformer 最核心的思想之一,但一个完整的 Transformer 并不是只有 Attention。
在原始的 Transformer 中,我们还会看到:
1Encoder 2Decoder 3Multi-Head Attention 4Feed Forward Network 5Residual Connection 6Layer Normalization 7Positional Encoding 8
这些模块共同组成了 Transformer。
因此,这一篇文章我们的目标并不是立刻钻进某一个公式,而是先完成一件更加重要的事情:
先把 Transformer 的整体结构看明白。
只有先知道:
1Transformer 由哪些部分组成? 2每一部分负责什么? 3数据在模型中如何流动? 4
后面学习 Self-Attention、Multi-Head Attention 等内容时,才不会只看到一堆零散的公式。
一、先从一张经典结构图开始
Transformer 最早由论文《Attention Is All You Need》提出。
原始 Transformer 是一个典型的:
Encoder-Decoder 架构。
我们可以先把它最外层的结构理解成:
1输入序列 2 ↓ 3 Encoder 4 ↓ 5中间表示 6 ↓ 7 Decoder 8 ↓ 9输出序列 10
例如机器翻译:
1I love artificial intelligence. 2 ↓ 3 Encoder 4 ↓ 5 理解输入信息 6 ↓ 7 Decoder 8 ↓ 9我喜欢人工智能。 10
这里需要注意:
Encoder 和 Decoder 并不是 Transformer 随便划分出来的两个部分,它们承担着不同的职责。
简单来说:
- Encoder:负责理解输入;
- Decoder:负责根据已有信息生成输出。
我们可以先把它们理解成:
1 Transformer 2 3 ┌────────────┴────────────┐ 4 │ │ 5 ↓ ↓ 6 Encoder Decoder 7 │ │ 8 理解输入 生成输出 9
但是,真实的 Transformer 并不是只有一个 Encoder 和一个 Decoder。
它们内部实际上都由多个相同的 Block 堆叠而成。
下面是 Transformer 最外层的整体架构图:
输入序列
Encoder
中间表示
Decoder
输出序列
二、Transformer 不是一个模块,而是一组模块的组合
假设我们把 Transformer 看成一栋建筑。
那么:
1Encoder 2
和:
1Decoder 2
更像是两栋主要建筑。
而真正组成这两栋建筑的,是一个个重复出现的模块。
原始 Transformer 的结构可以简单表示为:
1Input 2 ↓ 3Embedding 4 ↓ 5Positional Encoding 6 ↓ 7┌─────────────────┐ 8│ Encoder Block │ 9└─────────────────┘ 10 ↓ 11┌─────────────────┐ 12│ Encoder Block │ 13└─────────────────┘ 14 ↓ 15 ··· 16 ↓ 17Encoder Output 18
Decoder 也是类似的结构:
1Output 2 ↓ 3Embedding 4 ↓ 5Positional Encoding 6 ↓ 7┌─────────────────┐ 8│ Decoder Block │ 9└─────────────────┘ 10 ↓ 11┌─────────────────┐ 12│ Decoder Block │ 13└─────────────────┘ 14 ↓ 15 ··· 16 ↓ 17Linear 18 ↓ 19Softmax 20 ↓ 21预测下一个 Token 22
所以理解 Transformer 时,实际上可以分成三个层次:
1第一层:整体架构 2 ↓ 3Encoder + Decoder 4 5第二层:Block 6 ↓ 7多个相同模块重复堆叠 8 9第三层:具体组件 10 ↓ 11Attention 12FFN 13Residual 14LayerNorm 15... 16
我们这一篇主要解决前两个层次的问题。
至于最底层的 Attention 是怎么计算的,会在后面的文章中逐步展开。
下面是 Transformer 三个理解层次的 Mermaid 图:
第三层:具体组件
Attention
FFN
Residual
LayerNorm
第二层:Block
多个相同模块重复堆叠
第一层:整体架构
Encoder + Decoder
三、什么是 Encoder?
先来看 Transformer 左边的 Encoder。
假设输入一句英文:
1I love artificial intelligence. 2
计算机首先并不能直接理解:
1I 2love 3artificial 4intelligence 5
这些单词。
因为对于神经网络来说,真正能够参与计算的是数字。
所以,输入首先需要经过一个过程:
1文本 2 ↓ 3Tokenization 4 ↓ 5Token 6 ↓ 7Token ID 8 ↓ 9Embedding 10 ↓ 11向量 12
例如:
1"I" → [0.12, -0.35, 0.71, ...] 2"love" → [0.43, 0.18, -0.22, ...] 3"artificial" → [-0.61, 0.29, 0.44, ...] 4"intelligence" → [0.07, -0.82, 0.15, ...] 5
这里得到的向量,就是后续 Transformer 真正处理的数据。
Encoder 的任务,就是不断处理这些 Token 对应的表示,并让模型逐渐理解:
这些 Token 分别是什么,以及它们之间存在什么关系。
例如:
1I love artificial intelligence. 2
经过 Encoder 之后,我们希望模型不再只是孤立地看:
1I 2love 3artificial 4intelligence 5
而是能够建立这样的联系:
1I ───────→ love 2 │ 3 ↓ 4 artificial intelligence 5
也就是说:
Encoder 的核心任务,是让每一个 Token 都获得“结合上下文之后”的表示。
这句话非常重要。
在输入 Transformer 之前:
1love 2
可能只是“love”这个词本身的向量。
但是经过 Encoder 的多层处理之后:
1love 2
所对应的向量,已经不再只包含“love”自身的信息。
它还会结合:
1谁在 love? 2love 什么? 3周围还有哪些词? 4这些词之间是什么关系? 5
于是,Token 的表示就从:
孤立的词表示
逐渐变成:
包含上下文信息的表示。
这就是 Encoder 的核心价值。
四、Encoder Block:Transformer 的基本积木
一个完整的 Encoder 并不是一次计算就结束。
它由多个 Encoder Block 叠加而成。
原始 Transformer 论文中使用了:
1N × Encoder Block 2
也就是说:
1Input 2 ↓ 3Encoder Block 1 4 ↓ 5Encoder Block 2 6 ↓ 7Encoder Block 3 8 ↓ 9 ··· 10 ↓ 11Encoder Block N 12
为什么需要多层?
我们可以把它理解成:
第一层建立比较基础的关系,后面的层继续在前一层结果的基础上进行更加复杂的特征提取。
例如:
1第一层: 2可能关注相邻 Token 之间的关系 3 4第二层: 5开始建立更复杂的语义关系 6 7第三层: 8进一步组合这些信息 9 10…… 11 12最后: 13形成更加丰富的上下文表示 14
当然,真实模型内部究竟学到了什么关系,并不是人为提前规定好的。
这里的“第一层学语法、第二层学语义”只能帮助我们建立直觉。
真正的情况是:
模型通过训练自己学习应该如何利用每一层的参数。
那么,一个 Encoder Block 内部到底有什么?
我们先看一个简化结构:
1Input 2 ↓ 3Multi-Head Self-Attention 4 ↓ 5Add & Norm 6 ↓ 7Feed Forward Network 8 ↓ 9Add & Norm 10 ↓ 11Output 12
这里出现了几个重要模块:
- Multi-Head Self-Attention;
- Residual Connection;
- Layer Normalization;
- Feed Forward Network。
接下来,我们先从整体职责理解它们。
下面是 Encoder Block 内部结构的 Mermaid 图:
Input
Multi-Head Self-Attention
Add & Norm
Feed Forward Network
Add & Norm
Output
五、第一部分:Multi-Head Self-Attention
这是 Transformer 中最核心的模块之一。
虽然具体计算过程会在后面的文章中详细展开,但现在我们先理解:
它在整个 Transformer 中负责什么?
答案是:
让 Token 之间进行信息交互。
假设有一句话:
1我 喜欢 学习 人工智能 2
如果每个 Token 都只是独立存在:
1我 2喜欢 3学习 4人工智能 5
那么模型并不知道:
1谁喜欢? 2喜欢什么? 3学习什么? 4
于是 Self-Attention 会让每个 Token 都有机会去关注其他 Token。
例如:
1 我 2 ↑ 3 │ 4喜欢 ← 学习 → 人工智能 5
更准确地说:
对于当前 Token,模型会计算序列中其他 Token 对它的重要程度。
因此:
1Self-Attention 2
解决的是:
Token 与 Token 之间如何交换信息。
这里的:
1Self 2
也非常关键。
它表示:
Attention 的信息来源和查询对象来自同一个序列。
例如:
1我 喜欢 学习 人工智能 2
序列中的每一个 Token 都可以关注:
1我 2喜欢 3学习 4人工智能 5
包括自己。
因此:
1Self-Attention 2
可以简单理解成:
序列内部自己关注自己。
至于为什么还要:
1Multi-Head 2
也就是“多头”,我们暂时先留一个问题:
如果一个 Attention 能够建立关系,为什么还需要多个 Attention Head?
这个问题会在后面的文章中专门展开。
六、第二部分:为什么 Attention 后面还需要 Add?
在 Transformer 的结构图中,你会经常看到:
1Add & Norm 2
其中:
1Add 2
指的就是:
Residual Connection,残差连接。
它的结构可以简单理解为:
1x 2├───────────────┐ 3│ │ 4↓ │ 5Sublayer(x) │ 6│ │ 7└─────── + ─────┘ 8 ↓ 9 Output 10
数学上可以写成:
y = x + F ( x ) y = x + F(x) y=x+F(x)
其中:
- x xx 是原始输入;
- F ( x ) F(x)F(x) 是某个子层处理之后的结果;
- y yy 是最终输出。
例如:
1Input 2 ↓ 3Attention 4 ↓ 5处理结果 6 7同时: 8 9Input ────────────────┐ 10 ↓ 11Attention Output + Input 12 ↓ 13 新输出 14
那么问题来了:
为什么不直接使用 Attention 的输出,而要把原始输入再加回来?
最直观的理解是:
让网络在学习新信息的同时,不轻易丢失原始信息。
假设某个模块处理之后产生:
F ( x ) F(x) F(x)
如果我们直接输出:
y = F ( x ) y = F(x) y=F(x)
那么下一层看到的只有:
1处理之后的信息 2
而加入残差连接之后:
y = x + F ( x ) y = x + F(x) y=x+F(x)
下一层同时保留:
1原始信息 + 新学习的信息 2
从深度网络训练的角度来看,Residual Connection 还有一个非常重要的作用:
帮助信息和梯度在深层网络中传播。
Transformer 往往会堆叠很多层。
如果信息必须经过:
1Layer 1 2 ↓ 3Layer 2 4 ↓ 5Layer 3 6 ↓ 7…… 8 ↓ 9Layer N 10
每一层都进行复杂变换,那么网络越深,训练就可能越困难。
Residual Connection 相当于提供了一条更加直接的信息通道。
所以:
1Add 2
并不是一个可有可无的小操作。
它是深层 Transformer 能够稳定训练的重要设计之一。
下面是残差连接(Residual Connection)的 Mermaid 图:
x
Sublayer(x)
y = x + F(x)
七、第三部分:Norm 又是什么?
Add 后面紧接着:
1Norm 2
也就是:
Normalization,归一化。
在 Transformer 中,经典设计使用的是:
Layer Normalization,LayerNorm。
我们先不急着推导它的全部细节,只理解它的作用。
假设某一层输出的数据分布非常不稳定:
1某些数值非常大 2某些数值非常小 3某些数据分布变化很明显 4
那么后面的网络就需要不断适应这些变化。
这会增加训练难度。
于是,我们希望对数据进行一定程度的标准化处理,让后续网络能够在更加稳定的数据分布上进行训练。
LayerNorm 的基本思想是:
对单个样本的特征维度进行归一化。
对于一个输入向量:
x = [ x 1 , x 2 , … , x d ] x = [x_1, x_2, \dots, x_d] x=[x1,x2,…,xd]
首先计算均值:
μ = 1 d ∑ i = 1 d x i \mu = \frac{1}{d}\sum_{i=1}^{d}x_i μ=d1i=1∑dxi
然后计算方差:
σ 2 = 1 d ∑ i = 1 d ( x i − μ ) 2 \sigma^2 = \frac{1}{d}\sum_{i=1}^{d}(x_i-\mu)^2 σ2=d1i=1∑d(xi−μ)2
最后进行归一化:
x ^ i = x i − μ σ 2 + ϵ \hat{x}_i = \frac{x_i-\mu}{\sqrt{\sigma^2+\epsilon}} x^i=σ2+ϵ xi−μ
随后再通过可学习参数进行缩放和平移:
y i = γ x ^ i + β y_i = \gamma \hat{x}_i + \beta yi=γx^i+β
其中:
- γ \gammaγ:缩放参数;
- β \betaβ:平移参数;
- ϵ \epsilonϵ:防止分母为 0 00 的一个很小的常数。
现在不需要强行记住这些公式。
这一阶段更重要的是知道:
LayerNorm 的作用,是帮助网络保持更加稳定的数值分布,从而让深层网络训练得更加稳定。
因此:
1Attention 2 ↓ 3Add 4 ↓ 5LayerNorm 6
共同构成了 Transformer 中非常重要的一部分。
八、第四部分:Attention 之后,为什么还需要 FFN?
很多刚学习 Transformer 的人,会把注意力全部放在 Attention 上。
但实际上,一个完整的 Transformer Block 中还有一个非常重要的模块:
Feed Forward Network,前馈神经网络。
通常简称:
1FFN 2
它的结构其实并不复杂。
可以理解成:
1输入 2 ↓ 3Linear 4 ↓ 5Activation 6 ↓ 7Linear 8 ↓ 9输出 10
原始 Transformer 中可以写成:
$$
\operatorname{FFN}(x)
\max(0, xW_1+b_1)W_2+b_2
$$
其中:
- 第一层线性层通常将维度扩大;
- 中间经过非线性激活函数;
- 第二层再将维度映射回来。
例如:
1d_model 2 ↓ 3Linear 4 ↓ 5d_ff 6 ↓ 7Activation 8 ↓ 9Linear 10 ↓ 11d_model 12
那么问题来了:
Attention 不是已经处理完信息了吗?为什么还需要 FFN?
这里可以从职责上理解。
Attention 更擅长做:
Token 与 Token 之间的信息交互。
例如:
1Token A 2 ↔ 3Token B 4 ↔ 5Token C 6
而 FFN 则更像是在:
每个 Token 获得上下文信息之后,进一步对自己的表示进行非线性变换。
我们可以简单理解为:
1Attention: 2“我应该从其他 Token 获得哪些信息?” 3 4FFN: 5“获得这些信息之后,我应该如何进一步处理自己?” 6
因此,一个 Transformer Block 实际上包含两类重要计算:
1Attention 2 ↓ 3Token 之间交换信息 4 5FFN 6 ↓ 7每个 Token 自己进行进一步变换 8
两者缺一不可。
九、现在,我们终于可以看懂 Encoder Block 了
经过前面的拆解,一个 Encoder Block 可以重新画成:
1Input 2 │ 3 ├──────────────────────────────┐ 4 ↓ │ 5Multi-Head Self-Attention │ 6 ↓ │ 7 Add ◄────────────────────┘ 8 ↓ 9LayerNorm 10 │ 11 ├──────────────────────────────┐ 12 ↓ │ 13Feed Forward Network │ 14 ↓ │ 15 Add ◄────────────────────┘ 16 ↓ 17LayerNorm 18 ↓ 19Output 20
现在,我们可以给每个模块一句话的定位:
Multi-Head Self-Attention
让不同 Token 之间交换信息。
Residual Connection
保留原始信息,并帮助深层网络训练。
LayerNorm
稳定数据分布,帮助训练过程更加稳定。
Feed Forward Network
对每个 Token 的表示进一步进行非线性变换。
于是,一个 Encoder Block 的完整工作流程可以理解成:
1原始 Token 表示 2 ↓ 3先看看其他 Token 4 ↓ 5获得上下文信息 6 ↓ 7保留原始信息 8 ↓ 9稳定数据分布 10 ↓ 11进一步进行非线性处理 12 ↓ 13再次保留原始信息 14 ↓ 15输出新的 Token 表示 16
这就是 Encoder Block 的基本思想。
下面是 Encoder Block 完整工作流程的 Mermaid 图:
原始 Token 表示
先看看其他 Token
获得上下文信息
保留原始信息
稳定数据分布
进一步进行非线性处理
再次保留原始信息
输出新的 Token 表示
十、Encoder 到底输出了什么?
Encoder 处理完成之后,会输出什么?
答案不是:
1一个句子 2
也不是:
1最终分类结果 2
而是:
经过上下文编码之后的一组 Token 表示。
例如输入:
1I love artificial intelligence. 2
最开始:
1I 2love 3artificial 4intelligence 5
每个 Token 都有自己的初始 Embedding。
经过多个 Encoder Block 之后:
1I' ← 结合上下文之后的新表示 2love' ← 结合上下文之后的新表示 3artificial' ← 结合上下文之后的新表示 4intelligence' ← 结合上下文之后的新表示 5
这里的:
1I' 2love' 3... 4
并不是新的单词。
而是表示:
每个 Token 对应的向量已经发生了变化。
例如:
1love 2
经过 Encoder 之后,它所对应的向量不再只表示:
“love 这个词本身”。
它可能已经包含:
1谁在 love? 2love 的对象是什么? 3这句话整体表达什么? 4
这样的上下文信息。
所以 Encoder 的输出可以理解为:
一组上下文化(Contextualized)的 Token 表示。
十一、接下来轮到 Decoder
如果说 Encoder 负责:
理解输入。
那么 Decoder 负责的就是:
生成输出。
例如机器翻译:
1输入: 2 3I love artificial intelligence. 4 5输出: 6 7我喜欢人工智能。 8
Decoder 并不是一次性把整句话全部生成出来。
它通常按照自回归的方式:
1开始 2 ↓ 3我 4 ↓ 5我 喜欢 6 ↓ 7我 喜欢 人工智能 8 ↓ 9结束 10
也就是说:
生成当前 Token 时,需要参考之前已经生成的 Token。
因此 Decoder 面临两个任务:
- 关注自己之前生成的内容;
- 关注 Encoder 对输入序列的理解。
所以,Decoder 的结构会比 Encoder 更复杂一些。
十二、Decoder Block 为什么有两个 Attention?
一个典型的 Decoder Block 可以简化为:
1Input 2 ↓ 3Masked Multi-Head Self-Attention 4 ↓ 5Add & Norm 6 ↓ 7Encoder-Decoder Attention 8 ↓ 9Add & Norm 10 ↓ 11Feed Forward Network 12 ↓ 13Add & Norm 14 ↓ 15Output 16
你会发现:
Decoder 里面有两个 Attention。
为什么?
因为它需要解决两个不同的问题。
12.1 第一个 Attention:看自己已经生成的内容
假设 Decoder 正在生成:
1我 喜欢 人工智能 2
当它准备预测下一个 Token 时,它需要参考:
1我 2喜欢 3人工智能 4
这些已经出现的信息。
因此,第一个 Attention 负责:
让 Decoder 内部的 Token 彼此建立关系。
但是,这里有一个非常重要的限制。
假设我们正在预测:
1Token 3 2
那么模型不能提前偷看:
1Token 4 2Token 5 3Token 6 4
否则训练和实际生成时就会出现问题。
因此,Decoder 使用的是:
Masked Self-Attention。
所谓 Mask,可以简单理解成:
把未来的信息遮住。
例如:
1Token 1 可以看: 2Token 1 3 4Token 2 可以看: 5Token 1、Token 2 6 7Token 3 可以看: 8Token 1、Token 2、Token 3 9 10Token 4 可以看: 11Token 1、Token 2、Token 3、Token 4 12
但是:
1Token 2 2
不能偷看:
1Token 3、Token 4…… 2
所以注意力矩阵会形成一种类似:
1✓ × × × 2✓ ✓ × × 3✓ ✓ ✓ × 4✓ ✓ ✓ ✓ 5
的结构。
这就是所谓的:
Causal Mask,因果掩码。
它保证:
当前 Token 只能看到自己以及过去的信息,不能看到未来。
这也是后面理解 GPT 的一个非常重要的基础。
12.2 第二个 Attention:去看 Encoder
Decoder 只看自己还不够。
例如我们现在正在进行翻译:
1输入: 2 3I love artificial intelligence. 4
Decoder 正在生成:
1我 喜欢 … 2
那么当 Decoder 想继续生成时,它还需要知道:
输入的英文到底是什么?
所以,它需要去关注 Encoder 的输出。
于是出现第二个 Attention:
Encoder-Decoder Attention。
我们可以理解成:
1Decoder 当前状态 2 ↓ 3 “我现在需要什么信息?” 4 ↓ 5 Query 6 7Encoder 输出 8 ↓ 9 “输入中有哪些信息?” 10 ↓ 11 Key / Value 12
因此,这个 Attention 的核心作用是:
让 Decoder 在生成输出时,能够参考 Encoder 对输入序列的理解。
例如:
1Encoder: 2理解英文输入 3 4Decoder: 5生成中文输出 6 7Decoder ─────→ 需要时关注 Encoder 8
所以原始 Transformer 的 Decoder 实际上同时处理:
1过去生成的信息 2 + 3输入序列的信息 4
这也是为什么它需要两个不同的 Attention 模块。
十三、Encoder 和 Decoder 到底有什么区别?
现在我们可以把两者放在一起比较。
Encoder
1Input 2 ↓ 3Self-Attention 4 ↓ 5Add & Norm 6 ↓ 7FFN 8 ↓ 9Add & Norm 10
核心目标:
理解整个输入序列。
因为 Encoder 在处理输入时,通常可以同时看到整个输入:
1Token 1 2Token 2 3Token 3 4... 5Token N 6
因此 Encoder 的 Self-Attention 可以建立:
1任意 Token ↔ 任意 Token 2
之间的关系。
Decoder
1Output 2 ↓ 3Masked Self-Attention 4 ↓ 5Add & Norm 6 ↓ 7Encoder-Decoder Attention 8 ↓ 9Add & Norm 10 ↓ 11FFN 12 ↓ 13Add & Norm 14
核心目标:
根据已有信息逐步生成输出。
因此 Decoder:
- 需要关注已经生成的 Token;
- 不能偷看未来 Token;
- 还需要关注 Encoder 输出。
所以 Decoder 比 Encoder 多了:
1Masked Self-Attention 2
和:
1Encoder-Decoder Attention 2
这样的结构。
十四、Transformer 到底是如何完成一次机器翻译的?
现在我们把整个过程串起来。
假设:
1输入: 2 3I love artificial intelligence. 4
目标:
1我喜欢人工智能。 2
整个流程可以简单理解成:
1英文输入 2 ↓ 3Tokenization 4 ↓ 5Token Embedding 6 ↓ 7Positional Encoding 8 ↓ 9Encoder 10 ↓ 11Encoder Output 12 ↓ 13Decoder 14 ↓ 15预测“我” 16 ↓ 17Decoder 18 ↓ 19预测“喜欢” 20 ↓ 21Decoder 22 ↓ 23预测“人工智能” 24 ↓ 25Decoder 26 ↓ 27结束 28
展开一点:
1┌──────────────────────────────┐ 2│ Encoder │ 3│ │ 4│ I love artificial intelligence │ 5│ ↓ │ 6│ 上下文信息理解 │ 7└──────────────┬───────────────┘ 8 │ 9 │ Encoder Output 10 ↓ 11┌──────────────────────────────┐ 12│ Decoder │ 13│ │ 14│ <START> │ 15│ ↓ │ 16│ 我 │ 17│ ↓ │ 18│ 我 喜欢 │ 19│ ↓ │ 20│ 我 喜欢 人工智能 │ 21└──────────────────────────────┘ 22
这就是原始 Transformer Encoder-Decoder 架构的整体工作方式。
十五、等等,还有一个重要问题:Transformer 怎么知道顺序?
现在我们已经知道:
1Attention 2
可以让不同 Token 建立联系。
但这里还有一个问题。
假设输入:
1我 喜欢 你 2
和:
1你 喜欢 我 2
这两句话使用的 Token 完全一样:
1我 2喜欢 3你 4
但是顺序不同,含义也完全不同。
然而 Attention 本身只是在计算 Token 之间的关系。
那么:
Transformer 怎么知道哪个 Token 在前,哪个 Token 在后?
这就是:
Positional Encoding,位置编码。
Transformer 不像 RNN。
RNN 天然按照:
1第一个 2↓ 3第二个 4↓ 5第三个 6
的顺序进行计算。
因此:
顺序本身就包含在计算过程中。
但是 Transformer 可以并行处理:
1Token 1 2Token 2 3Token 3 4Token 4 5
这意味着:
模型本身并不知道这些 Token 的先后顺序。
所以必须额外把位置信息加入进去:
1Token Embedding 2 + 3Position Information 4 ↓ 5Transformer Input 6
原始 Transformer 使用的是:
Sinusoidal Positional Encoding,正弦余弦位置编码。
位置编码公式如下:
P E ( p o s , 2 i ) = sin ( p o s 10000 2 i d model ) PE(pos, 2i) = \sin\left(\frac{pos}{10000^{\frac{2i}{d_{\text{model}}}}}\right) PE(pos,2i)=sin(10000dmodel2ipos)
P E ( p o s , 2 i + 1 ) = cos ( p o s 10000 2 i d model ) PE(pos, 2i+1) = \cos\left(\frac{pos}{10000^{\frac{2i}{d_{\text{model}}}}}\right) PE(pos,2i+1)=cos(10000dmodel2ipos)
其中 p o s pospos 为位置索引, i ii 为维度索引, d model d_{\text{model}}dmodel 为模型维度。
现在不需要强行理解:
为什么是 10000?
为什么使用 sin?
为什么使用 cos?
这一篇只需要先建立一个概念:
Attention 本身不包含顺序信息,所以 Transformer 必须额外告诉模型每个 Token 的位置。
后面我们会专门讨论 Position Encoding。
十六、Transformer 的完整数据流
到这里,我们已经可以把原始 Transformer 的整体流程串起来了。
1 输入序列 2 ↓ 3 Token Embedding 4 ↓ 5 Positional Encoding 6 ↓ 7 ┌────────────────┐ 8 │ Encoder Block │ 9 └────────────────┘ 10 ↓ 11 ┌────────────────┐ 12 │ Encoder Block │ 13 └────────────────┘ 14 ↓ 15 ... 16 ↓ 17 Encoder Output 18 │ 19 │ 20 ↓ 21输出序列 → Token Embedding 22 ↓ 23 Positional Encoding 24 ↓ 25 Masked Self-Attention 26 ↓ 27 Add & Norm 28 ↓ 29 Encoder-Decoder Attention 30 ↓ 31 Add & Norm 32 ↓ 33 Feed Forward Network 34 ↓ 35 Add & Norm 36 ↓ 37 Linear 38 ↓ 39 Softmax 40 ↓ 41 下一个 Token 42
从职责上,我们也可以把 Transformer 简化成:
1Embedding 2 ↓ 3把 Token 转换成向量 4 5Positional Encoding 6 ↓ 7告诉模型 Token 的位置 8 9Attention 10 ↓ 11建立 Token 之间的关系 12 13FFN 14 ↓ 15进一步处理 Token 表示 16 17Residual + LayerNorm 18 ↓ 19帮助深层网络稳定训练 20 21Encoder 22 ↓ 23理解输入 24 25Decoder 26 ↓ 27生成输出 28
十七、一个容易产生的误解:现在的 GPT 还是完整 Transformer 吗?
看到这里,可能会有一个问题:
我们现在使用的大语言模型,例如 GPT,真的还是上面这种完整的 Encoder-Decoder Transformer 吗?
答案是:
不完全是。
Transformer 最初是一种完整的 Encoder-Decoder 架构。
但后来研究人员发现,不同任务可以使用 Transformer 的不同部分。
于是逐渐出现了三种非常重要的架构:
1Encoder-only 2Decoder-only 3Encoder-Decoder 4
例如:
Encoder-only
典型代表:
1BERT 2
主要使用 Transformer Encoder。
更擅长:
1文本理解 2文本分类 3命名实体识别 4
Decoder-only
典型代表:
1GPT 2
主要使用 Transformer Decoder 中适合自回归生成的结构。
更擅长:
1文本生成 2对话 3代码生成 4
今天的大语言模型,大量采用的就是这种:
Decoder-only Transformer。
Encoder-Decoder
典型代表:
1T5 2
更适合:
1机器翻译 2文本摘要 3输入序列 → 输出序列 4
所以:
Transformer 并不是只有一种固定形态。
它更像是一套非常成功的基础架构思想。
不同模型可以根据任务:
1只使用 Encoder 2 3只使用 Decoder 4 5或者同时使用 Encoder + Decoder 6
这也是 Transformer 后来能够广泛发展的一个重要原因。
十八、现在,我们对 Transformer 应该有什么整体认识?
经过这一篇文章,我们暂时还没有深入:
1Q、K、V 2
也没有真正计算:
1Attention Score 2
但现在,我们至少应该建立起这样一张地图:
1 Transformer 2 │ 3 ┌───────────────┴───────────────┐ 4 │ │ 5 ↓ ↓ 6 Encoder Decoder 7 │ │ 8 │ Masked Self-Attention 9 │ │ 10 Self-Attention ↓ 11 │ Encoder-Decoder Attention 12 ↓ │ 13 Add & Norm ↓ 14 ↓ FFN 15 FFN │ 16 ↓ ↓ 17 Add & Norm Add & Norm 18
并且知道每个模块的大致职责:
| 模块 | 核心作用 |
|---|---|
| Embedding | 将 Token 转换为向量 |
| Positional Encoding | 提供位置信息 |
| Self-Attention | 建立 Token 之间的关系 |
| Multi-Head Attention | 从多个角度建立关系 |
| FFN | 对 Token 表示进行非线性变换 |
| Residual Connection | 保留信息,帮助深层训练 |
| LayerNorm | 稳定数据分布 |
| Encoder | 理解输入 |
| Decoder | 逐步生成输出 |
如果能够建立起这张地图,那么后面学习 Transformer 的细节就会轻松很多。
十九、小结
这一篇,我们主要完成了一件事情:
从整体上认识 Transformer 到底是什么。
Transformer 最初采用的是:
Encoder-Decoder 架构。
其中:
1Encoder 2
负责:
理解输入序列,并生成包含上下文信息的表示。
而:
1Decoder 2
负责:
在参考已有输出和 Encoder 信息的基础上,逐步生成新的 Token。
一个典型的 Encoder Block 包含:
1Multi-Head Self-Attention 2 ↓ 3Add & Norm 4 ↓ 5Feed Forward Network 6 ↓ 7Add & Norm 8
而 Decoder Block 则比 Encoder 多出了:
1Masked Self-Attention 2
以及:
1Encoder-Decoder Attention 2
同时,因为 Transformer 不像 RNN 一样天然按照顺序处理数据,所以还需要:
Positional Encoding。
最终,整个 Transformer 可以理解成:
1Token 2 ↓ 3Embedding 4 ↓ 5加入位置信息 6 ↓ 7Attention 建立关系 8 ↓ 9FFN 进一步处理 10 ↓ 11多层 Block 不断提取信息 12 ↓ 13完成理解或生成任务 14
下一篇:Self-Attention 到底是什么?
现在,我们已经看清了 Transformer 的整体结构。
但是整套架构中最核心的问题仍然没有真正解决:
Attention 到底是怎么工作的?
为什么 Transformer 会把输入转换成:
1Q 2K 3V 4
为什么要计算:
Q K T QK^T QKT
为什么还要进行:
softmax ( Q K T d k ) \operatorname{softmax} \left( \frac{QK^T}{\sqrt{d_k}} \right) softmax(dk QKT)
这些操作究竟在做什么?
下一篇,我们将正式进入 Transformer 最核心的部分:
Self-Attention。
我们会从一个具体的句子开始,一步一步理解:
1Q 到底是什么? 2K 到底是什么? 3V 又是什么? 4
然后亲手走完整个 Attention 的计算过程。
只有真正理解了 Self-Attention,Transformer 的核心才算真正开始展开。