手撕Transformer:一个完整的机器翻译实例详解

引言:当注意力成为唯一需要的东西

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 层,每层结构完全相同,包含两个子层:

  1. 多头自注意力子层(Multi-Head Self-Attention)
  2. 前馈网络子层(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 层,每层包含三个子层:

  1. 掩码多头自注意力(Masked Multi-Head Self-Attention)
  2. 编码器-解码器多头注意力(Cross-Attention)
  3. 前馈网络

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 来自解码器的上一子层,KeyValue 来自编码器输出。

对于每个头:

  • 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^=arg⁡max⁡Probabilities \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,未来位置被掩码
推理时编码器 完全并行 输入已知
推理时解码器 自回归(顺序) 每个词依赖之前生成的词

信息流动

  1. 编码器 :将源序列编码为上下文向量 EncoderOutput∈R3×512\text{EncoderOutput} \in \mathbb{R}^{3 \times 512}EncoderOutput∈R3×512
  2. 解码器:通过交叉注意力动态地从这些向量中检索信息,结合自身的自注意力,生成目标序列

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成功的几个关键因素:

三大核心创新

  1. 多头自注意力:让每个词都能直接与序列中所有其他词交互,完美捕捉长距离依赖
  2. 位置编码:弥补纯注意力架构对位置信息的缺失
  3. 残差连接 + 层归一化:使得深度网络的训练成为可能

维度设计的智慧

参数 设计理由
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》能成为深度学习领域的里程碑论文------它不仅改变了机器翻译,更开启了大语言模型的新时代。

参考文献

  1. Vaswani, A., et al. "Attention Is All You Need." NeurIPS 2017.
  2. The Illustrated Transformer. Jay Alammar.
  3. 从矩阵维度理解Transformer. CSDN博客.

本文首发于CSDN博客,欢迎转发讨论。如果觉得有帮助,请点赞支持!

相关推荐
高洁0143 分钟前
智能体的“记忆”难题
python·深度学习·机器学习·transformer
十三画者12 小时前
【文献分享】ConfRetro:融合3D构象信息的逆合成预测Transformer框架
人工智能·深度学习·数据挖掘·数据分析·transformer·数据可视化
雷帝木木14 小时前
数据湖与数据仓库:从理论到实践
人工智能·python·深度学习·机器学习
yanghuashuiyue15 小时前
RNN结构记录
人工智能·rnn·深度学习
%4718 小时前
DAY 38
人工智能·pytorch·深度学习
June bug18 小时前
【HCIA- AI(正课)】2.1 深度学习基础
人工智能·深度学习
黑马水牛19 小时前
Carla仿真系列:9_Carla 单目障碍物测距,四种方法原理与实测
经验分享·python·深度学习·计算机视觉·ros·传感器·carla仿真
船厂电气自动化ai大模型20 小时前
AI大模型与数学第42课:泰勒级数完整展开(神经网络近似核心)
人工智能·python·深度学习·算法·机器学习
就是一顿骚操作1 天前
GRU:用重置门与更新门简化序列记忆的经典解读
人工智能·深度学习·gru·论文解读
EachYoungX1 天前
Sleep-EDF 睡眠信号数据集深度解析:从 EDF 文件到可复现睡眠分期样本
深度学习·数据分析