一、什么是 Transformer?

Transformer 是一种基于**自注意力机制(Self-Attention)**的深度学习模型架构,彻底改变了自然语言处理(NLP)乃至计算机视觉(CV)、语音识别等多个领域。

在 Transformer 出现之前,序列建模的主流是 RNN(循环神经网络)LSTM/GRU。这些模型存在根本性缺陷:

  • 串行计算:必须按时间步顺序处理,无法并行
  • 长距离依赖:信息随时间步传播会衰减,难以捕捉远距离 token 之间的关系
  • 梯度消失/爆炸:长序列训练困难

Transformer 的核心主张是:完全抛弃循环和卷积结构,仅依靠注意力机制来建模序列中任意两个位置之间的依赖关系


二、核心创新点

1. 自注意力机制(Self-Attention)⭐

这是 Transformer 的灵魂。它允许模型在处理每个 token 时,同时关注输入序列中的所有位置,并自动学习不同位置之间的关联权重。

关键突破

  • 任意两个 token 的距离都变为 O(1)(直接计算注意力权重)
  • 彻底解决了 RNN 的长距离依赖问题
  • 全局视野,每个位置都能"看到"整个序列

2. 完全并行化(Parallelization)⭐

RNN 必须按顺序计算:h_t = f(h_{t-1}, x_t)
Transformer 的 Self-Attention 可以同时计算所有位置的表示,训练速度大幅提升,且易于在 GPU/TPU 上扩展。

3. 多头注意力(Multi-Head Attention)

将注意力机制复制多份(heads),每份学习不同的"关注点"(子空间):

  • 有的 head 关注语法关系
  • 有的 head 关注语义关系
  • 有的 head 关注指代消解

最终拼接所有 head 的结果,获得更丰富的表示。

4. 位置编码(Positional Encoding)

由于 Self-Attention 本身没有位置概念(对输入顺序不敏感),Transformer 通过正弦/余弦函数将位置信息注入模型:

PE(pos, 2i)   = sin(pos / 10000^(2i/d_model))
PE(pos, 2i+1) = cos(pos / 10000^(2i/d_model))

这种编码方式允许模型学习相对位置关系,且能外推到训练时未见过的更长序列。

5. 残差连接与层归一化(Residual Connection & Layer Normalization)

  • 残差连接Output = LayerNorm(x + Sublayer(x)),缓解梯度消失,支持深层网络
  • 层归一化:对每个样本的所有特征做归一化,稳定训练

6. Encoder-Decoder 架构的解耦

  • Encoder:通过 Self-Attention 编码输入序列的上下文表示
  • Decoder:通过 Masked Self-Attention + Cross-Attention 自回归生成输出

三、Transformer 如何工作?(架构详解)

3.1 整体架构

┌─────────────────────────────────────────────────────────────┐
│                        Transformer                           │
├─────────────────────────────┬───────────────────────────────┤
│         Encoder Stack        │         Decoder Stack          │
│  ┌───────────────────────┐  │  ┌─────────────────────────┐  │
│  │  Input Embedding      │  │  │  Output Embedding       │  │
│  │  + Positional Encoding│  │  │  + Positional Encoding  │  │
│  └───────────┬───────────┘  │  └───────────┬─────────────┘  │
│              ▼               │              ▼                │
│  ┌───────────────────────┐  │  ┌─────────────────────────┐  │
│  │  Multi-Head Attention │  │  │  Masked Multi-Head Attn │  │
│  │  + Add & Norm         │  │  │  + Add & Norm           │  │
│  └───────────┬───────────┘  │  └───────────┬─────────────┘  │
│              ▼               │              ▼                │
│  ┌───────────────────────┐  │  ┌─────────────────────────┐  │
│  │  Feed Forward Network │  │  │  Multi-Head Cross-Attn  │  │
│  │  + Add & Norm         │  │  │  + Add & Norm           │  │
│  └───────────┬───────────┘  │  └───────────┬─────────────┘  │
│              ▼               │              ▼                │
│  ┌───────────────────────┐  │  ┌─────────────────────────┐  │
│  │  ... (N layers)       │  │  │  Feed Forward Network   │  │
│  └───────────┬───────────┘  │  │  + Add & Norm           │  │
│              ▼               │  └───────────┬─────────────┘  │
│  ┌───────────────────────┐  │              ▼                │
│  │  Output to Decoder    │──┼──▶│  ... (N layers)         │  │
│  └───────────────────────┘  │  └───────────┬─────────────┘  │
│                             │              ▼                │
│                             │  ┌─────────────────────────┐  │
│                             │  │  Linear + Softmax       │  │
│                             │  │  → Probability Dist.    │  │
│                             │  └─────────────────────────┘  │
└─────────────────────────────┴───────────────────────────────┘

3.2 Self-Attention 的数学原理

Step 1: 生成 Q, K, V

对每个输入 token 的嵌入向量 x,通过三个不同的权重矩阵映射为:

  • Query (Q): 当前 token "想要查询什么"
  • Key (K): 当前 token "包含什么信息"
  • Value (V): 当前 token "实际传递什么内容"
Q = X · W_Q
K = X · W_K
V = X · W_V

其中 W_Q, W_K, W_V ∈ R^(d_model × d_k) 是可学习的参数矩阵。

Step 2: 计算注意力分数

Attention(Q, K, V) = softmax(QK^T / √d_k) · V

分步拆解

  1. QK^T: 计算每对 token 之间的相似度(点积),得到注意力分数矩阵

    • 形状: (seq_len, seq_len) —— 每个位置关注所有位置的分数
  2. / √d_k缩放因子(Scaling)

    • 当 d_k 很大时,点积的数值会非常大,导致 softmax 进入梯度极小的饱和区
    • 除以 √d_k 将方差控制在合理范围,保证梯度稳定
  3. softmax: 将分数归一化为概率分布(每行之和为 1)

  4. · V: 用注意力权重对 Value 做加权求和,得到输出表示

Step 3: 多头拼接

MultiHead(Q, K, V) = Concat(head_1, ..., head_h) · W_O
where head_i = Attention(QW_i^Q, KW_i^K, VW_i^V)
  • 原始论文: h = 8 个头, d_k = d_v = d_model / h = 64
  • 每个 head 独立学习不同的注意力模式
  • 最终通过 W_O 投影回 d_model 维度

3.3 Masked Self-Attention(Decoder 专用)

Decoder 在训练时需要防止看到未来的 token(保持自回归特性)。

实现方式:在 softmax 之前,将未来位置的注意力分数设为 -∞

Mask = [[0, -∞, -∞, ...],
        [0,  0, -∞, ...],
        [0,  0,  0, ...],
        ...]

Attention_scores = QK^T / √d_k + Mask

这样每个位置只能关注到它及之前的位置。

3.4 Cross-Attention(Encoder-Decoder Attention)

Decoder 中的第二层注意力:

  • Q 来自 Decoder 上一层的输出(当前已生成的序列)
  • K, V 来自 Encoder 的最终输出(源序列的编码表示)

这实现了源语言 → 目标语言的信息传递,是机器翻译等任务的核心。

3.5 前馈神经网络(Feed-Forward Network, FFN)

每个 Encoder/Decoder 层都包含一个全连接前馈网络:

FFN(x) = max(0, xW_1 + b_1)W_2 + b_2

即:Linear → ReLU → Linear

  • 中间维度: d_ff = 2048(原始论文)
  • 每个位置独立应用(不共享信息,信息交互由 Attention 完成)
  • 增加模型的非线性表达能力

3.6 层归一化(Layer Normalization)

LayerNorm(x) = γ ⊙ (x - μ) / √(σ² + ε) + β
  • 单个样本的所有特征做归一化(区别于 BatchNorm)
  • 适用于序列长度变化的场景
  • Pre-Norm vs Post-Norm:原始论文用 Post-Norm,现代变体多用 Pre-Norm(更稳定)

四、训练细节

4.1 输入嵌入(Input Embedding)

  • 使用可学习的词嵌入矩阵将 token ID 映射为 d_model 维向量
  • 原始论文: d_model = 512
  • 嵌入权重与输出层 softmax 前的线性层共享权重(减少参数量,提升性能)

4.2 输出层

Decoder 最终输出经过:

  1. Linear 层: 将 d_model 映射到词汇表大小 vocab_size
  2. Softmax: 生成下一个 token 的概率分布

4.3 损失函数

标准交叉熵损失(Cross-Entropy Loss):

L = -Σ log P(y_t | y_<t, x)

4.4 优化器与正则化

  • Adam 优化器β1=0.9, β2=0.98, ε=10⁻⁹
  • 学习率调度(Warmup + 衰减):
    lrate = d_model^(-0.5) · min(step^(-0.5), step · warmup_steps^(-1.5))
    
    • Warmup: 前 4000 步线性增长
    • 之后按 step^(-0.5) 衰减
  • DropoutP_drop = 0.1(嵌入、注意力、FFN、残差连接后)
  • Label Smoothingε_ls = 0.1(防止模型过度自信)

五、为什么 Transformer 如此强大?

特性RNN/LSTMTransformer
并行性❌ 串行✅ 完全并行
长距离依赖❌ 随距离衰减✅ 直接连接
计算复杂度(每步)O(1)O(1)(但总体 O(n²))
训练速度快(可大规模并行)
位置感知天然有序需位置编码
可解释性高(注意力权重可视化)

5.1 注意力可视化

通过观察注意力权重矩阵,可以直观理解模型在关注什么:

  • 句法关系: 代词指向其指代的名词
  • 语义关系: 同义词/反义词之间的关联
  • 跨语言对齐: 翻译任务中源语言和目标语言的词对齐

5.2 从 Transformer 到现代大模型

Transformer 架构是以下所有模型的基础:

模型架构特点
BERTEncoder-only双向编码,预训练 + 微调范式
GPT 系列Decoder-only自回归生成,Scaling Law
T5Encoder-DecoderText-to-Text 统一框架
Vision Transformer (ViT)Encoder将图像分块作为序列处理
CLIPDual Encoder图文对齐,多模态理解
LLaMA, ChatGPT, ClaudeDecoder-only大规模预训练 + RLHF

六、PyTorch 核心实现

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

class MultiHeadAttention(nn.Module):
    """多头自注意力机制"""
    def __init__(self, d_model=512, num_heads=8):
        super().__init__()
        assert d_model % num_heads == 0

        self.d_model = d_model
        self.num_heads = num_heads
        self.d_k = d_model // num_heads  # 每个头的维度

        # 线性投影层
        self.W_q = nn.Linear(d_model, d_model)
        self.W_k = nn.Linear(d_model, d_model)
        self.W_v = nn.Linear(d_model, d_model)
        self.W_o = nn.Linear(d_model, d_model)

    def scaled_dot_product_attention(self, Q, K, V, mask=None):
        """计算缩放点积注意力"""
        scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)

        if mask is not None:
            scores = scores.masked_fill(mask == 0, -1e9)

        attn_weights = F.softmax(scores, dim=-1)
        output = torch.matmul(attn_weights, V)
        return output, attn_weights

    def forward(self, query, key, value, mask=None):
        batch_size = query.size(0)

        # 1. 线性投影并分头
        # (batch, seq, d_model) -> (batch, seq, num_heads, d_k) -> (batch, num_heads, seq, d_k)
        Q = self.W_q(query).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
        K = self.W_k(key).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
        V = self.W_v(value).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)

        # 2. 计算注意力
        attn_output, attn_weights = self.scaled_dot_product_attention(Q, K, V, mask)

        # 3. 拼接多头并输出投影
        # (batch, num_heads, seq, d_k) -> (batch, seq, d_model)
        attn_output = attn_output.transpose(1, 2).contiguous().view(
            batch_size, -1, self.d_model
        )

        return self.W_o(attn_output)


class PositionwiseFeedForward(nn.Module):
    """前馈神经网络"""
    def __init__(self, d_model=512, d_ff=2048, dropout=0.1):
        super().__init__()
        self.linear1 = nn.Linear(d_model, d_ff)
        self.linear2 = nn.Linear(d_ff, d_model)
        self.dropout = nn.Dropout(dropout)

    def forward(self, x):
        return self.linear2(self.dropout(F.relu(self.linear1(x))))


class PositionalEncoding(nn.Module):
    """正弦位置编码"""
    def __init__(self, d_model=512, max_len=5000, dropout=0.1):
        super().__init__()
        self.dropout = nn.Dropout(dropout)

        # 预计算位置编码矩阵
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)

        div_term = torch.exp(
            torch.arange(0, d_model, 2).float() * 
            (-math.log(10000.0) / d_model)
        )

        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        pe = pe.unsqueeze(0)  # (1, max_len, d_model)

        self.register_buffer('pe', pe)

    def forward(self, x):
        x = x + self.pe[:, :x.size(1), :]
        return self.dropout(x)


class EncoderLayer(nn.Module):
    """单个 Encoder 层"""
    def __init__(self, d_model=512, num_heads=8, d_ff=2048, dropout=0.1):
        super().__init__()
        self.self_attn = MultiHeadAttention(d_model, num_heads)
        self.feed_forward = PositionwiseFeedForward(d_model, d_ff, dropout)
        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)
        self.dropout = nn.Dropout(dropout)

    def forward(self, x, mask=None):
        # 子层1: Multi-Head Self-Attention + Add & Norm
        attn_output = self.self_attn(x, x, x, mask)
        x = self.norm1(x + self.dropout(attn_output))

        # 子层2: FFN + Add & Norm
        ff_output = self.feed_forward(x)
        x = self.norm2(x + self.dropout(ff_output))

        return x


class TransformerEncoder(nn.Module):
    """Transformer Encoder 堆叠"""
    def __init__(self, vocab_size, d_model=512, num_heads=8, 
                 num_layers=6, d_ff=2048, dropout=0.1, max_len=5000):
        super().__init__()
        self.embedding = nn.Embedding(vocab_size, d_model)
        self.pos_encoding = PositionalEncoding(d_model, max_len, dropout)
        self.layers = nn.ModuleList([
            EncoderLayer(d_model, num_heads, d_ff, dropout)
            for _ in range(num_layers)
        ])
        self.dropout = nn.Dropout(dropout)
        self.scale = math.sqrt(d_model)

    def forward(self, x, mask=None):
        x = self.embedding(x) * self.scale
        x = self.pos_encoding(x)

        for layer in self.layers:
            x = layer(x, mask)

        return x

七、总结

核心公式回顾

组件公式
Scaled Dot-Product Attentionsoftmax(QK^T / √d_k)V
Multi-Head AttentionConcat(head₁,...,headₕ)W^O
FFNmax(0, xW₁+b₁)W₂+b₂
Positional Encodingsin/cos(pos/10000^(2i/d_model))
Layer Normalizationγ(x-μ)/√(σ²+ε) + β

设计哲学

  1. Attention Is All You Need: 用注意力替代循环/卷积,简化架构
  2. 并行优于串行: 牺牲 O(n²) 的注意力计算,换取完全并行的训练
  3. 深度 + 残差: 通过残差连接和层归一化堆叠深层网络
  4. 表示学习: 通过多头机制学习丰富的多视角表示

历史意义

Transformer 不仅是 NLP 的里程碑,更是现代人工智能的基石。从 BERT 到 GPT-4,从 ChatGPT 到 Sora,几乎所有当前最先进的 AI 系统都建立在 Transformer 或其变体之上。它证明了:一个简洁而优雅的架构设计,可以引发整个领域的范式革命

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐