Skip to content

完整架构

这一页把前面所有零件组装成一台完整机器——2017 年原论文里那个用于翻译的 Transformer。建议对照下面这张全景图,从上到下、从左到右走一遍。

1. 全景图

 ┌─────────────── Encoder (左) ───────────────┐        ┌──────────── Decoder (右) ────────────┐
 │                                            │        │                                        │
 输入 "I love you"                        目标(右移) "<bos> 我 爱"
 │                                            │        │                                        │
 ▼                                            │        ▼                                        │
[Input Embedding + PE]                        │   [Output Embedding + PE]                        │
 │                                            │        │                                        │
 ▼                                            │        ▼                                        │
┌──────────────────────┐                     │   ┌──────────────────────┐                      │
│  Masked Self-Attn    │  ← 编码器无掩码(可见全句)│   │  Masked Self-Attn    │  ← 因果掩码,只看过去 │
│  Add & Norm          │                     │   │  Add & Norm          │                      │
│  Cross-Attention ────┼────── K,V 来自编码器 ─┼──►│  Cross-Attention     │  ← Q来自解码器        │
│  Add & Norm          │                     │   │  Add & Norm          │                      │
│  FFN + Add & Norm    │                     │   │  FFN + Add & Norm    │                      │
└──────────┬───────────┘                     │   └──────────┬───────────┘                      │
     × N 层 (堆叠)                            │        × N 层 (堆叠)                             │
           │                                  │             │                                   │
      最终输出(记忆K,V)                        │             ▼                                   │
           └─────────────►(供解码器 Cross-Attn)│        [Linear → Softmax]                       │
                                              │             │                                   │
                                              │             ▼                                   │
                                              │        预测下一个词 "爱 / 你 / <eos>"              │
 └────────────────────────────────────────────┘        └────────────────────────────────────────┘

一句话读图:编码器把源句压缩成一份富含语义的表示(K/V),解码器一边「回看」这个表示、一边因果地逐词生成目标句。

2. 数据如何流动(一步步)

以「I love you → 我爱你」为例:

  1. 编码器输入I love you 分词 → 查词嵌入 → 加位置编码 → [3, d_model]
  2. 编码器 N 层:每层「自注意力 + FFN」,让三个词充分交换信息,得到富含上下文的表示。
  3. 解码器输入(训练时用「右移」)<bos> 我 爱(即目标序列右移一位,末尾砍掉),让模型在已知前文时预测下一个词。
  4. 解码器每层三件事
    • 带因果掩码的自注意力(看已生成的目标词)
    • 交叉注意力(用目标当前状态去「查询」编码器的源句表示)
    • FFN 加工
  5. 输出层:最后一层解码器输出 [T, d_model] → Linear 映射到词表大小 → Softmax 得到每个位置「下一个词」的概率分布。

3. 训练时并行、生成时串行

这是最容易混淆、也最重要的一点:

训练:  目标句已知 → 整句一次性喂进解码器(靠因果掩码保证不偷看) → 并行算所有位置损失 ✅快
生成:  目标句未知 → 只能一次产一个词,把新词再接回去产下一个 → 自回归,串行 🔁
       <bos> → 我 → 爱 → 你 → <eos>
  • 训练时「右移 + 因果掩码」让所有位置的损失能并行计算,这是 Transformer 训练飞快的关键。
  • 推理生成时无法并行,只能一个词一个词地蹦(kv cache 就是为加速这个过程,见进阶页)。

4. 关键超参数(原始 base 模型)

python
config = dict(
    N = 6,            # 编码器/解码器各堆 6 层
    d_model = 512,    # 主干宽度
    d_ff = 2048,      # FFN 中间层 = 4×d_model
    h = 8,            # 注意力头数, 每头 512/8=64 维
    dropout = 0.1,    # 子层与嵌入上的 dropout
)
# 参数量约 65M(base); big 模型 d_model=1024,h=16,约 213M

5. 训练细节速览

  • 损失:词表上的交叉熵(对每个目标位置)。
  • 优化器:Adam,配合 warmup + 衰减 的学习率调度(Post-Norm 尤其需要 warmup)。
  • Label Smoothing:轻微平滑标签,缓解过拟合、提升 BLEU。
  • 正则:dropout + 残差,让 6~N 层稳定训练。

6. 用 PyTorch 把整台机器串起来

python
import torch, torch.nn as nn

class EncoderLayer(nn.Module):
    def __init__(self, d_model, h, d_ff, p=0.1):
        super().__init__()
        self.attn = nn.MultiheadAttention(d_model, h, dropout=p, batch_first=True)
        self.ffn = nn.Sequential(nn.Linear(d_model, d_ff), nn.GELU(), nn.Linear(d_ff, d_model))
        self.n1, self.n2 = nn.LayerNorm(d_model), nn.LayerNorm(d_model)
        self.drop = nn.Dropout(p)
    def forward(self, x, mask=None):
        a, _ = self.attn(x, x, x, attn_mask=mask, need_weights=False)
        x = self.n1(x + self.drop(a))
        x = self.n2(x + self.drop(self.ffn(x)))
        return x

class DecoderLayer(nn.Module):
    def __init__(self, d_model, h, d_ff, p=0.1):
        super().__init__()
        self.self_attn = nn.MultiheadAttention(d_model, h, dropout=p, batch_first=True)
        self.cross_attn = nn.MultiheadAttention(d_model, h, dropout=p, batch_first=True)
        self.ffn = nn.Sequential(nn.Linear(d_model, d_ff), nn.GELU(), nn.Linear(d_ff, d_model))
        self.n1, self.n2, self.n3 = (nn.LayerNorm(d_model) for _ in range(3))
        self.drop = nn.Dropout(p)
    def forward(self, x, memory, src_mask=None, tgt_mask=None):
        a, _ = self.self_attn(x, x, x, attn_mask=tgt_mask, need_weights=False)
        x = self.n1(x + self.drop(a))
        c, _ = self.cross_attn(x, memory, memory, need_weights=False)  # Q=目标, K/V=源
        x = self.n2(x + self.drop(c))
        x = self.n3(x + self.drop(self.ffn(x)))
        return x

# 各堆 N 层,再接 embedding / 输出 Linear,即构成完整 Transformer(下节实战会给出可训练版本)

7. 三处掩码别搞混

掩码出现位置作用
padding mask编/解码输入屏蔽补零的空位(<pad>
causal mask解码器自注意力禁止看未来词
cross 无需因果掩码解码器交叉注意力源句是完整的,可全部看

小结

  • 完整 Transformer = 编码器(理解源句)+ 解码器(回看源句、逐词生成目标)。
  • 解码器每层三件套:因果自注意力 + 交叉注意力 + FFN。
  • 训练并行、生成串行 是其行为模式的核心区别。
  • 掩码分三类,别在交叉注意力上错加因果掩码。

下一步

想更细地看清编码器与解码器各自的职责分工 → Encoder与Decoder