引言:当注意力成为唯一需要的东西
2017年,Google Brain团队发表了题为《Attention Is All You Need》的论文,提出了Transformer架构。这篇论文彻底改变了自然语言处理领域,成为后续BERT、GPT等大模型的基石。
与传统的RNN和LSTM不同,Transformer完全抛弃了循环结构,仅依赖注意力机制来捕捉序列中的依赖关系。这使得模型可以并行处理整个序列,大大提高了训练效率。
本文将通过一个具体的机器翻译实例------将英文句子"I love you"翻译为中文"我爱你"------来详细讲解Transformer的完整前向传播过程,并突出每一步的张量维度变化。
实例设定
| 项目 | 内容 |
|---|---|
| 输入序列(源语言) | ["I", "love", "you"],长度 n=3n = 3n=3 |
| 输出序列(目标语言) | ["我", "爱", "你"],长度 m=3m = 3m=3 |
| 模型维度 | dmodel=512d_{\text{model}} = 512dmodel=512 |
| 注意力头数 | h=8h = 8h=8 |
| 每个头的维度 | dk=dv=dmodel/h=64d_k = d_v = d_{\text{model}} / h = 64dk=dv=dmodel/h=64 |
| 前馈网络内层维度 | dff=2048d_{ff} = 2048dff=2048 |
| 词汇表大小 | V=37000V = 37000V=37000(参考论文WMT英德任务) |
第一阶段:输入表示(编码器端)
1. 词嵌入(Word Embedding)
每个输入词元通过一个可学习的嵌入矩阵 E∈RV×dmodelE \in \mathbb{R}^{V \times d_{\text{model}}}E∈RV×dmodel 转换为稠密向量。
Xembed=Lookup(E,["I","love","you"]) X_{\text{embed}} = \text{Lookup}(E, [\text{"I"}, \text{"love"}, \text{"you"}]) Xembed=Lookup(E,["I","love","you"])
维度变化:
- 输入:3个词元ID
- 输出:Xembed∈R3×512X_{\text{embed}} \in \mathbb{R}^{3 \times 512}Xembed∈R3×512
每个词元被映射为一个512维的连续向量,这些向量将在训练过程中学习到语义信息。
2. 位置编码(Positional Encoding)
由于Transformer没有循环或卷积结构,它无法感知词元的顺序信息。因此,需要显式地注入位置信息。
位置编码使用正弦和余弦函数:
PE(pos,2i)=sin(pos100002i/dmodel) PE_{(pos, 2i)} = \sin\left(\frac{pos}{10000^{2i/d_{\text{model}}}}\right) PE(pos,2i)=sin(100002i/dmodelpos)
PE(pos,2i+1)=cos(pos100002i/dmodel) PE_{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{2i/d_{\text{model}}}}\right) PE(pos,2i+1)=cos(100002i/dmodelpos)
其中 pospospos 是位置索引(0, 1, 2),iii 是维度索引(0 到 255)。
操作:
X=Xembed+PE X = X_{\text{embed}} + PE X=Xembed+PE
维度变化:
- Xembed∈R3×512X_{\text{embed}} \in \mathbb{R}^{3 \times 512}Xembed∈R3×512
- PE∈R3×512PE \in \mathbb{R}^{3 \times 512}PE∈R3×512
- 输出:X∈R3×512X \in \mathbb{R}^{3 \times 512}X∈R3×512(维度不变)
位置编码与词嵌入相加,使得每个位置的表示既包含词的语义信息,又包含其位置信息。
第二阶段:编码器处理(以第一层为例)
编码器共有 N=6N = 6N=6 层,每层结构完全相同,包含两个子层:
- 多头自注意力子层(Multi-Head Self-Attention)
- 前馈网络子层(Feed-Forward Network)
每个子层后都跟着残差连接 和层归一化。
1. 多头自注意力子层
步骤1:线性投影生成 Q、K、V
对于输入 X∈R3×512X \in \mathbb{R}^{3 \times 512}X∈R3×512,对于每个注意力头 iii(共 h=8h = 8h=8 个),有独立的投影矩阵:
WiQ∈R512×64,WiK∈R512×64,WiV∈R512×64 W_i^Q \in \mathbb{R}^{512 \times 64}, \quad W_i^K \in \mathbb{R}^{512 \times 64}, \quad W_i^V \in \mathbb{R}^{512 \times 64} WiQ∈R512×64,WiK∈R512×64,WiV∈R512×64
计算每个头的查询、键、值矩阵:
Qi=X⋅WiQ∈R3×64 Q_i = X \cdot W_i^Q \in \mathbb{R}^{3 \times 64} Qi=X⋅WiQ∈R3×64
Ki=X⋅WiK∈R3×64 K_i = X \cdot W_i^K \in \mathbb{R}^{3 \times 64} Ki=X⋅WiK∈R3×64
Vi=X⋅WiV∈R3×64 V_i = X \cdot W_i^V \in \mathbb{R}^{3 \times 64} Vi=X⋅WiV∈R3×64
步骤2:缩放点积注意力(每个头并行计算)
注意力计算公式为:
Attention(Qi,Ki,Vi)=softmax(QiKiTdk)Vi \text{Attention}(Q_i, K_i, V_i) = \text{softmax}\left(\frac{Q_i K_i^T}{\sqrt{d_k}}\right) V_i Attention(Qi,Ki,Vi)=softmax(dk QiKiT)Vi
关键维度变化:
- Qi∈R3×64Q_i \in \mathbb{R}^{3 \times 64}Qi∈R3×64,KiT∈R64×3K_i^T \in \mathbb{R}^{64 \times 3}KiT∈R64×3
- QiKiT∈R3×3Q_i K_i^T \in \mathbb{R}^{3 \times 3}QiKiT∈R3×3(注意力分数矩阵,表示每个词关注其他所有词的强度)
- dk=64=8\sqrt{d_k} = \sqrt{64} = 8dk =64 =8(缩放因子,防止点积过大)
- softmax\text{softmax}softmax 后:R3×3\mathbb{R}^{3 \times 3}R3×3(注意力权重矩阵,每行和为1)
- 乘以 Vi∈R3×64V_i \in \mathbb{R}^{3 \times 64}Vi∈R3×64 后:headi∈R3×64\text{head}_i \in \mathbb{R}^{3 \times 64}headi∈R3×64
注意力权重矩阵的含义:
I love you
I [0.85, 0.10, 0.05]
love [0.20, 0.65, 0.15]
you [0.08, 0.12, 0.80]
第 iii 行第 jjj 列的值表示位置 iii 对位置 jjj 的关注程度。
步骤3:多头拼接与投影
将所有 h=8h=8h=8 个头的输出在特征维度上拼接:
Concat(head1,...,head8)∈R3×512 \text{Concat}(\text{head}_1, \dots, \text{head}_8) \in \mathbb{R}^{3 \times 512} Concat(head1,...,head8)∈R3×512
通过输出投影矩阵 WO∈R512×512W^O \in \mathbb{R}^{512 \times 512}WO∈R512×512 进行线性变换:
MultiHead(X)=Concat(head1,...,head8)⋅WO∈R3×512 \text{MultiHead}(X) = \text{Concat}(\text{head}_1, \dots, \text{head}_8) \cdot W^O \in \mathbb{R}^{3 \times 512} MultiHead(X)=Concat(head1,...,head8)⋅WO∈R3×512
步骤4:残差连接与层归一化
Z1=LayerNorm(X+MultiHead(X))∈R3×512 Z_1 = \text{LayerNorm}(X + \text{MultiHead}(X)) \in \mathbb{R}^{3 \times 512} Z1=LayerNorm(X+MultiHead(X))∈R3×512
残差连接让梯度能够直接流过,缓解深层网络的梯度消失问题;层归一化则稳定训练过程。
2. 前馈网络子层
前馈网络由两个线性变换和一个ReLU激活函数组成:
FFN(x)=max(0,xW1+b1)W2+b2 \text{FFN}(x) = \max(0, xW_1 + b_1)W_2 + b_2 FFN(x)=max(0,xW1+b1)W2+b2
其中:
- W1∈R512×2048W_1 \in \mathbb{R}^{512 \times 2048}W1∈R512×2048,b1∈R2048b_1 \in \mathbb{R}^{2048}b1∈R2048
- W2∈R2048×512W_2 \in \mathbb{R}^{2048 \times 512}W2∈R2048×512,b2∈R512b_2 \in \mathbb{R}^{512}b2∈R512
维度变化:
- 输入 Z1∈R3×512Z_1 \in \mathbb{R}^{3 \times 512}Z1∈R3×512
- Z1⋅W1∈R3×2048Z_1 \cdot W_1 \in \mathbb{R}^{3 \times 2048}Z1⋅W1∈R3×2048(升维到2048)
- ReLU激活后:R3×2048\mathbb{R}^{3 \times 2048}R3×2048(维度不变)
- ⋅W2∈R3×512\cdot W_2 \in \mathbb{R}^{3 \times 512}⋅W2∈R3×512(降维回512)
残差连接与层归一化:
EncoderOutput1=LayerNorm(Z1+FFN(Z1))∈R3×512 \text{EncoderOutput}_1 = \text{LayerNorm}(Z_1 + \text{FFN}(Z_1)) \in \mathbb{R}^{3 \times 512} EncoderOutput1=LayerNorm(Z1+FFN(Z1))∈R3×512
3. 堆叠编码器层
将 EncoderOutput1\text{EncoderOutput}_1EncoderOutput1 作为第二层的输入,重复上述过程 N=6N=6N=6 次。
最终编码器输出:
EncoderOutput∈R3×512 \text{EncoderOutput} \in \mathbb{R}^{3 \times 512} EncoderOutput∈R3×512
每个输入词元被编码为一个包含整个序列上下文信息的512维向量。
第三阶段:解码器处理(自回归生成)
解码器在训练时和推理时的流程不同。此处以**推理时生成第一个词"我"**为例。
解码器同样有 N=6N=6N=6 层,每层包含三个子层:
- 掩码多头自注意力(Masked Multi-Head Self-Attention)
- 编码器-解码器多头注意力(Cross-Attention)
- 前馈网络
1. 初始输入
解码器输入以起始符 <s> 开始,当前输出序列为 ["<s>"],长度 mcurrent=1m_{\text{current}} = 1mcurrent=1。
经过输出嵌入和位置编码后:
Y∈R1×512 Y \in \mathbb{R}^{1 \times 512} Y∈R1×512
2. 解码器第一层(以生成第一个词为例)
子层1:掩码多头自注意力
与编码器自注意力类似,但使用**因果掩码(Causal Mask)**防止看到未来位置。
对于输入 Y∈R1×512Y \in \mathbb{R}^{1 \times 512}Y∈R1×512,每个头生成:
Qi,Ki,Vi∈R1×64 Q_i, K_i, V_i \in \mathbb{R}^{1 \times 64} Qi,Ki,Vi∈R1×64
计算注意力分数:
Scores=QiKiTdk∈R1×1 \text{Scores} = \frac{Q_i K_i^T}{\sqrt{d_k}} \in \mathbb{R}^{1 \times 1} Scores=dk QiKiT∈R1×1
由于只有一个词,它只能关注自身(因果掩码在此处无影响)。
残差连接与层归一化:
D1=LayerNorm(Y+MaskedMultiHead(Y))∈R1×512 D_1 = \text{LayerNorm}(Y + \text{MaskedMultiHead}(Y)) \in \mathbb{R}^{1 \times 512} D1=LayerNorm(Y+MaskedMultiHead(Y))∈R1×512
子层2:编码器-解码器注意力(交叉注意力)
这是解码器的核心组件,它让解码器能够"查看"编码器的输出。
Query 来自解码器的上一子层,Key 和 Value 来自编码器输出。
对于每个头:
- Qi=D1⋅WiQ∈R1×64Q_i = D_1 \cdot W_i^Q \in \mathbb{R}^{1 \times 64}Qi=D1⋅WiQ∈R1×64
- Ki=EncoderOutput⋅WiK∈R3×64K_i = \text{EncoderOutput} \cdot W_i^K \in \mathbb{R}^{3 \times 64}Ki=EncoderOutput⋅WiK∈R3×64
- Vi=EncoderOutput⋅WiV∈R3×64V_i = \text{EncoderOutput} \cdot W_i^V \in \mathbb{R}^{3 \times 64}Vi=EncoderOutput⋅WiV∈R3×64
注意力计算:
Scores=QiKiTdk∈R1×3 \text{Scores} = \frac{Q_i K_i^T}{\sqrt{d_k}} \in \mathbb{R}^{1 \times 3} Scores=dk QiKiT∈R1×3
这个 1×31 \times 31×3 的向量表示当前解码器位置对编码器3个位置的关注程度。
Attentioni=softmax(Scores)⋅Vi∈R1×64 \text{Attention}_i = \text{softmax}(\text{Scores}) \cdot V_i \in \mathbb{R}^{1 \times 64} Attentioni=softmax(Scores)⋅Vi∈R1×64
多头拼接与投影:
CrossAttention=Concat(Attention1,...,Attention8)⋅WO∈R1×512 \text{CrossAttention} = \text{Concat}(\text{Attention}_1, \dots, \text{Attention}_8) \cdot W^O \in \mathbb{R}^{1 \times 512} CrossAttention=Concat(Attention1,...,Attention8)⋅WO∈R1×512
残差连接与层归一化:
D2=LayerNorm(D1+CrossAttention)∈R1×512 D_2 = \text{LayerNorm}(D_1 + \text{CrossAttention}) \in \mathbb{R}^{1 \times 512} D2=LayerNorm(D1+CrossAttention)∈R1×512
子层3:前馈网络
与编码器相同:
FFN(D2)∈R1×512 \text{FFN}(D_2) \in \mathbb{R}^{1 \times 512} FFN(D2)∈R1×512
DecoderOutput1=LayerNorm(D2+FFN(D2))∈R1×512 \text{DecoderOutput}_1 = \text{LayerNorm}(D_2 + \text{FFN}(D_2)) \in \mathbb{R}^{1 \times 512} DecoderOutput1=LayerNorm(D2+FFN(D2))∈R1×512
3. 堆叠解码器层
经过 N=6N=6N=6 层解码器后,得到当前解码器输出:
DecoderOutput∈R1×512 \text{DecoderOutput} \in \mathbb{R}^{1 \times 512} DecoderOutput∈R1×512
第四阶段:输出生成
1. 线性投影与Softmax
通过一个可学习的线性层 Wlinear∈R512×VW_{\text{linear}} \in \mathbb{R}^{512 \times V}Wlinear∈R512×V 将解码器输出映射到词汇表空间:
Logits=DecoderOutput⋅Wlinear∈R1×37000 \text{Logits} = \text{DecoderOutput} \cdot W_{\text{linear}} \in \mathbb{R}^{1 \times 37000} Logits=DecoderOutput⋅Wlinear∈R1×37000
应用Softmax得到概率分布:
Probabilities=softmax(Logits)∈R1×37000 \text{Probabilities} = \text{softmax}(\text{Logits}) \in \mathbb{R}^{1 \times 37000} Probabilities=softmax(Logits)∈R1×37000
选择概率最高的词元作为输出:
y^=argmaxProbabilities \hat{y} = \arg\max \text{Probabilities} y^=argmaxProbabilities
假设输出为"我"。
2. 迭代生成
将生成的"我"追加到输出序列,现在序列为 ["<s>", "我"],mcurrent=2m_{\text{current}} = 2mcurrent=2。
重复整个第三阶段和第四阶段:
- 解码器输入为两个词元的嵌入 Y∈R2×512Y \in \mathbb{R}^{2 \times 512}Y∈R2×512
- 在掩码自注意力中,QKTQK^TQKT 是一个 R2×2\mathbb{R}^{2 \times 2}R2×2 的矩阵
因果掩码示例 (m=2m=2m=2):
M=[0−∞00] M = \begin{bmatrix} 0 & -\infty \\ 0 & 0 \end{bmatrix} M=[00−∞0]
- 第一行(对应
<s>):只能关注自己 - 第二行(对应"我"):可以关注
<s>和自己,不能关注未来位置
最终生成第二个词"爱",以此类推,直到生成结束符 <eos>。
核心维度总结表
| 步骤 | 关键输入 | 关键操作/矩阵 | 输出维度 | 说明 |
|---|---|---|---|---|
| 输入嵌入 | 词元ID (n=3) | 嵌入矩阵 E∈RV×512E \in \mathbb{R}^{V \times 512}E∈RV×512 | R3×512\mathbb{R}^{3 \times 512}R3×512 | 将词转换为向量 |
| 位置编码 | Xembed∈R3×512X_{\text{embed}} \in \mathbb{R}^{3 \times 512}Xembed∈R3×512 | 正弦函数 PE(pos)PE(pos)PE(pos) | R3×512\mathbb{R}^{3 \times 512}R3×512 | 加入顺序信息 |
| Q/K/V投影 | X∈R3×512X \in \mathbb{R}^{3 \times 512}X∈R3×512 | WiQ,WiK,WiV∈R512×64W_i^Q, W_i^K, W_i^V \in \mathbb{R}^{512 \times 64}WiQ,WiK,WiV∈R512×64 | Qi,Ki,Vi∈R3×64Q_i, K_i, V_i \in \mathbb{R}^{3 \times 64}Qi,Ki,Vi∈R3×64 | 每个注意力头 |
| 注意力权重 | Qi∈R3×64Q_i \in \mathbb{R}^{3 \times 64}Qi∈R3×64, KiT∈R64×3K_i^T \in \mathbb{R}^{64 \times 3}KiT∈R64×3 | QiKiTQ_i K_i^TQiKiT | R3×3\mathbb{R}^{3 \times 3}R3×3 | 词与词之间的相关性矩阵 |
| 注意力输出 | 权重 R3×3\mathbb{R}^{3 \times 3}R3×3, Vi∈R3×64V_i \in \mathbb{R}^{3 \times 64}Vi∈R3×64 | softmax(...)⋅Vi\text{softmax}(...) \cdot V_isoftmax(...)⋅Vi | headi∈R3×64\text{head}_i \in \mathbb{R}^{3 \times 64}headi∈R3×64 | 加权求和的值 |
| 多头拼接 | 8个 headi∈R3×64\text{head}_i \in \mathbb{R}^{3 \times 64}headi∈R3×64 | 拼接 Concat | R3×512\mathbb{R}^{3 \times 512}R3×512 | 合并所有头的信息 |
| 前馈网络 | Z∈R3×512Z \in \mathbb{R}^{3 \times 512}Z∈R3×512 | W1∈R512×2048W_1 \in \mathbb{R}^{512 \times 2048}W1∈R512×2048, W2∈R2048×512W_2 \in \mathbb{R}^{2048 \times 512}W2∈R2048×512 | R3×512\mathbb{R}^{3 \times 512}R3×512 | 逐位置非线性变换 |
| 交叉注意力Q | D∈Rm×512D \in \mathbb{R}^{m \times 512}D∈Rm×512 (m=1) | WiQ∈R512×64W_i^Q \in \mathbb{R}^{512 \times 64}WiQ∈R512×64 | Q∈R1×64Q \in \mathbb{R}^{1 \times 64}Q∈R1×64 | 来自解码器 |
| 交叉注意力K/V | EncoderOutput∈R3×512\text{EncoderOutput} \in \mathbb{R}^{3 \times 512}EncoderOutput∈R3×512 | WiK,WiV∈R512×64W_i^K, W_i^V \in \mathbb{R}^{512 \times 64}WiK,WiV∈R512×64 | K,V∈R3×64K, V \in \mathbb{R}^{3 \times 64}K,V∈R3×64 | 来自编码器 |
| 交叉注意力权重 | Q∈R1×64Q \in \mathbb{R}^{1 \times 64}Q∈R1×64, KT∈R64×3K^T \in \mathbb{R}^{64 \times 3}KT∈R64×3 | QKTQ K^TQKT | R1×3\mathbb{R}^{1 \times 3}R1×3 | 解码器词关注所有编码器词 |
| 输出投影 | DecoderOutput∈Rm×512\text{DecoderOutput} \in \mathbb{R}^{m \times 512}DecoderOutput∈Rm×512 | Wlinear∈R512×VW_{\text{linear}} \in \mathbb{R}^{512 \times V}Wlinear∈R512×V | Rm×V\mathbb{R}^{m \times V}Rm×V | 映射到词汇表概率 |
流程核心要点
维度主线
dmodel=512d_{\text{model}} = 512dmodel=512 是贯穿始终的主维度;nnn(源序列长度)和 mmm(目标序列长度)是动态变化的序列长度维度。
注意力本质
通过 QKTQK^TQKT 计算出一个 序列长度 × 序列长度 的权重矩阵,实现词与词之间的全局交互。这个矩阵是Transformer能够捕捉长距离依赖的关键。
并行与顺序的区别
| 阶段 | 并行性 | 原因 |
|---|---|---|
| 训练时编码器 | 完全并行 | 无依赖关系 |
| 训练时解码器 | 并行(带掩码) | 使用Teacher Forcing,未来位置被掩码 |
| 推理时编码器 | 完全并行 | 输入已知 |
| 推理时解码器 | 自回归(顺序) | 每个词依赖之前生成的词 |
信息流动
- 编码器 :将源序列编码为上下文向量 EncoderOutput∈R3×512\text{EncoderOutput} \in \mathbb{R}^{3 \times 512}EncoderOutput∈R3×512
- 解码器:通过交叉注意力动态地从这些向量中检索信息,结合自身的自注意力,生成目标序列
CrossAttention(Qdec,Kenc,Venc)=softmax(QdecKencTdk)Venc \text{CrossAttention}(Q_{\text{dec}}, K_{\text{enc}}, V_{\text{enc}}) = \text{softmax}\left(\frac{Q_{\text{dec}} K_{\text{enc}}^T}{\sqrt{d_k}}\right) V_{\text{enc}} CrossAttention(Qdec,Kenc,Venc)=softmax(dk QdecKencT)Venc
总结:Transformer的成功秘诀
通过这个完整的矩阵演算,我们可以总结出Transformer成功的几个关键因素:
三大核心创新
- 多头自注意力:让每个词都能直接与序列中所有其他词交互,完美捕捉长距离依赖
- 位置编码:弥补纯注意力架构对位置信息的缺失
- 残差连接 + 层归一化:使得深度网络的训练成为可能
维度设计的智慧
| 参数 | 值 | 设计理由 |
|---|---|---|
| dmodel=512d_{\text{model}} = 512dmodel=512 | 512 | 足够大的表示容量 |
| dff=2048d_{ff} = 2048dff=2048 | 2048 | 4倍的扩展,提供充分的非线性变换能力 |
| h=8h = 8h=8, dk=64d_k = 64dk=64 | 8头,64维 | 多头并行,每个头关注不同的特征子空间 |
最终结论
Transformer的成功在于它用统一的注意力机制替代了复杂的循环结构,使得模型能够:
- 并行处理整个序列,训练速度快
- 捕捉任意距离的依赖关系
- 自动学习词对齐,无需显式标注
- 易于扩展为大规模预训练模型
这就是为什么《Attention Is All You Need》能成为深度学习领域的里程碑论文------它不仅改变了机器翻译,更开启了大语言模型的新时代。
参考文献
- Vaswani, A., et al. "Attention Is All You Need." NeurIPS 2017.
- The Illustrated Transformer. Jay Alammar.
- 从矩阵维度理解Transformer. CSDN博客.
本文首发于CSDN博客,欢迎转发讨论。如果觉得有帮助,请点赞支持!