Transformer

Transformer 架构

Transformer 是现代自然语言处理(NLP)和多模态大模型的基石。它摒弃了传统的循环神经网络(RNN)和卷积神经网络(CNN),完全依赖 Attention 机制 来捕捉序列中的长距离依赖。

前置知识: 关于 Attention 机制的详细原理(Scaled Dot-Product, Multi-Head, KV Cache),请查阅 Attention 机制 笔记。

1. 宏观概览 (Overview)

Transformer 本质上是一个 Sequence-to-Sequence (Seq2Seq) 的映射机器。

🏗️ 整体架构:Encoder-Decoder

原始的 Transformer 包含两个主要部分:

  1. Encoder (编码器):负责 “理解”。它读取输入序列,通过层层抽象,将其转化为一个富含语义的连续表示(Context Vector)。
  2. Decoder (解码器):负责 “生成”。它利用 Encoder 提供的语义信息,并结合已经生成的历史词,逐个预测下一个词。

数据流向: Input (X) -> [Encoder] -> Context (K, V) -> [Decoder] -> Output (Y)

2. 输入层 (Input Layer)

在进入 Transformer 模块之前,原始文本需要经过预处理。

2.1 Embedding (词嵌入)

将离散的 Token ID 转换为稠密的向量(Dense Vector)。

$$ x*{embedding} \in \mathbb{R}^{d*{model}} $$

2.2 Positional Encoding (位置编码)

由于 Transformer 的 Attention 机制是并行处理的,本身不具备位置感(即打乱句子顺序,Attention 结果不变)。为了让模型理解词序(“Tom hits Jerry” vs “Jerry hits Tom”),必须显式注入位置信息。

  • 绝对位置编码 (Sinusoidal): 原始论文使用正弦/余弦函数叠加直接相加。 $$ PE(pos, 2i) = \sin(pos / 10000^{2i/d\_{model}}) $$
  • 相对位置编码 (RoPE/ALiBi): 现代 LLM(如 LLaMA)大多使用旋转位置编码(RoPE),效果更好,且具有外推性。

3. 编码器 (Encoder): 理解引擎

Encoder 由 $N$ 个相同的层(Block)堆叠而成。每一层包含两个子层:

  1. Multi-Head Self-Attention:
    • 机制: 详见 Attention.md
    • 作用: 让每个词都能"看"到句子中的其他词,建立上下文联系。
  2. Feed-Forward Network (FFN):
    • 也称为 MLP。对每个位置的向量独立进行非线性变换,增加模型的表达能力。
    • 现代变体常用 SwiGLU 激活函数。

Add & Norm: 每个子层后都有残差连接(Residual Connection)和层归一化(LayerNorm)。

$$ \text{Output} = \text{LayerNorm}(x + \text{SubLayer}(x)) $$

(注: 现代 LLM 多采用 Pre-Norm 结构,即先 Norm 再进子层,训练更稳定)

4. 解码器 (Decoder): 生成引擎

Decoder 同样由 $N$ 个层堆叠而成,但结构略有不同,包含三个子层:

  1. Masked Self-Attention:
    • 关键点: Mask (掩码)。在预测第 $t$ 个词时,绝不能看到 $t$ 之后的词。因此 Attention 矩阵的上三角部分被置为 $-\infty$。
  2. Cross-Attention (交叉注意力):
    • 机制: 详见 交叉注意力
    • 作用: 连接 Encoder 和 Decoder。Query 来自 Decoder(当前生成的搜索意图),Key/Value 来自 Encoder(源句子的语义信息)。
  3. Feed-Forward Network (FFN): 同 Encoder。

5. 训练 vs 推理 (Training vs Inference)

特性训练阶段 (Training)推理阶段 (Inference)
模式Teacher ForcingAutoregressive (自回归)
输入一次性输入完整的正确目标序列 (Ground Truth)。初始通过 BOS,之后每步输入上一步生成的词。
并行性高度并行。所有 Token 的 Loss 可以同时计算。串行。必须等 $t$ 生成完才能生成 $t+1$。
速度快 (得益于矩阵运算)。慢 (受限于解码步数)。需使用 KV Cache 加速。

6. 架构演变 (Architecture Variants)

随着发展,Transformer 分化出了三条主要路线:

  1. Encoder-Only (双向):
    • 代表: BERT, RoBERTa。
    • 特点: 能同时看到上下文,擅长理解任务(分类、NER)。
  2. Decoder-Only (自回归/GPT):
    • 代表: GPT 系列, LLaMA, Qwen。
    • 特点: 只能看到历史,擅长生成任务。这是目前 LLM 的绝对主流
  3. Encoder-Decoder (序列到序列):
    • 代表: T5, BART, Original Transformer。
    • 特点: 经典的翻译/摘要架构。

7. PyTorch 实现

以下是一个简化的 Decoder-Only Block 实现(GPT 风格),展示了最核心的组件。

import torch
import torch.nn as nn
import torch.nn.functional as F
import math

class CausalSelfAttention(nn.Module):
    def __init__(self, d_model, n_head, max_len=1024):
        super().__init__()
        self.d_k = d_model // n_head
        self.n_head = n_head
        # Q, K, V 映射层
        self.c_attn = nn.Linear(d_model, 3 * d_model)
        # 输出投影层
        self.c_proj = nn.Linear(d_model, d_model)
        # Causal Mask: 下三角矩阵,保证不能看到未来
        self.register_buffer("bias", torch.tril(torch.ones(max_len, max_len))
                                     .view(1, 1, max_len, max_len))

    def forward(self, x):
        B, T, C = x.size() # Batch, SeqLen, Dim

        # 1. 计算 Q, K, V
        qkv = self.c_attn(x)
        q, k, v = qkv.split(C, dim=2)

        # 2. Reshape 为多头: (B, n_head, T, d_k)
        q = q.view(B, T, self.n_head, self.d_k).transpose(1, 2)
        k = k.view(B, T, self.n_head, self.d_k).transpose(1, 2)
        v = v.view(B, T, self.n_head, self.d_k).transpose(1, 2)

        # 3. Scaled Dot-Product Attention
        att = (q @ k.transpose(-2, -1)) * (1.0 / math.sqrt(self.d_k))
        # 4. Apply Mask (关键步:将未来的位置设为负无穷)
        att = att.masked_fill(self.bias[:,:,:T,:T] == 0, float('-inf'))
        att = F.softmax(att, dim=-1)

        # 5. 加权求和
        y = att @ v
        y = y.transpose(1, 2).contiguous().view(B, T, C)
        return self.c_proj(y)

class MLP(nn.Module):
    def __init__(self, d_model):
        super().__init__()
        self.c_fc    = nn.Linear(d_model, 4 * d_model)
        self.act     = nn.GELU() # 现代模型常用 GeLU 或 SwiGLU
        self.c_proj  = nn.Linear(4 * d_model, d_model)

    def forward(self, x):
        return self.c_proj(self.act(self.c_fc(x)))

class TransformerBlock(nn.Module):
    def __init__(self, d_model, n_head):
        super().__init__()
        self.ln1 = nn.LayerNorm(d_model)
        self.attn = CausalSelfAttention(d_model, n_head)
        self.ln2 = nn.LayerNorm(d_model)
        self.mlp = MLP(d_model)

    def forward(self, x):
        # Pre-Norm 结构:Norm -> Layer -> Add
        x = x + self.attn(self.ln1(x))
        x = x + self.mlp(self.ln2(x))
        return x

8. 参考