Transformer模型深度游历:NLP领域的革新应用探索
本文将带你深入了解 Transformer 模型在自然语言处理(NLP)中的原理与应用,从最核心的自注意力机制到完整的编码器—解码器架构,并配以详尽的数学推导、代码示例与图解,帮助你快速掌握 Transformer 及其在机器翻译、文本分类等任务中的应用。
目录
- 引言
- 背景与发展历程
- Transformer 模型概览 
- 自注意力机制深度剖析 
- 完整 Transformer 架构解析 
- 代码示例:从零实现简化版 Transformer 
- 图解:Transformer 各模块示意 
- Transformer 在 NLP 中的经典应用 
- 优化与进阶:Transformers 家族演化 
- 总结与最佳实践
引言
在传统 RNN、LSTM 基础上,Transformer 模型以其“全注意力(All-Attention)”的架构彻底颠覆了序列建模的思路。自 Vaswani 等人在 2017 年提出《Attention Is All You Need》 以来,Transformer 不仅在机器翻译、文本分类、文本生成等众多 NLP 任务中取得了突破性成果,也逐渐催生了如 BERT、GPT、T5 等一系列预训练大模型,成为当下最热门的研究方向之一。
本文将从 Transformer 的核心构件——自注意力机制开始,逐步深入其编码器(Encoder)与解码器(Decoder)结构,并通过 PyTorch 代码示例带你手把手实现一个简化版 Transformer,最后介绍其在实际 NLP 任务中的典型应用及后续发展。
背景与发展历程
在 Transformer 出现之前,主流的序列建模方法主要依赖循环神经网络(RNN)及其变体 LSTM、GRU 等。尽管 LSTM 能通过门控机制在一定程度上缓解长程依赖消失(vanishing gradient)的问题,但在并行化计算、长距离依赖捕捉等方面依旧存在瓶颈:
- 计算瓶颈 - RNN 需要按时间步(time-step)序贯计算,训练与推理难以并行化。
 
- 长程依赖与梯度消失 - 随着序列长度增大,若信息需要跨越多个时间步传播,LSTM 依旧会出现注意力衰减,要么依赖于注意力机制(如 Seq2Seq+Attention 架构),要么被限制在较短上下文窗口内。
 
- 注意力架构的初步尝试 - Luong Attention、Bahdanau Attention 等 Seq2Seq+Attention 结构,虽然缓解了部分长程依赖问题,但注意力仅在编码器—解码器之间进行,并没有完全“摆脱” RNN 的序列瓶颈。
 
Transformer 的核心思想是:完全用注意力机制替代 RNN/卷积,使序列中任意两处都能直接交互,从而实现并行化、高效地捕捉长程依赖。它一经提出,便在机器翻译上瞬间刷新了多项基准,随后被广泛迁移到各类 NLP 任务中。
Transformer 模型概览
3.1 为何需要 Transformer?
- 并行化计算 - RNN 需要按时间顺序一步步地“读入”上一个词的隐藏状态,导致 GPU/TPU 并行能力无法充分利用。
- Transformer 利用“自注意力”在同一层就能把序列内的所有位置同时进行计算,大幅提升训练速度。
 
- 全局依赖捕捉 - 传统 RNN 的信息传递依赖于“逐步传递”,即使有注意力层,编码仍受前几层的限制。
- Transformer 中的注意力可以直接在任何两个位置之间建立关联,不受序列距离影响。
 
- 建模灵活性 - 不同层之间可以采用不同数量的注意力头(Multi-Head Attention),更细腻地捕捉子空间信息。
- 编码器—解码器之间可以灵活地进行交互注意力(encoder-decoder attention)。
 
3.2 核心创新:自注意力机制(Self-Attention)
“自注意力”是 Transformer 最核心的模块,其基本思想是:对于序列中任意一个位置的隐藏表示,将它与序列中所有位置的隐藏表示进行“打分”计算权重,然后根据这些权重对所有位置的信息做加权求和,得到该位置的新的表示。这样,每个位置都能动态地“看看”整个句子,更好地捕获长程依赖。
下文我们将从数学公式与代码层面深入剖析自注意力的工作原理。
自注意力机制深度剖析
4.1 打破序列顺序的限制
在 RNN 中,序列信息是通过隐藏状态 $h\_t = f(h\_{t-1}, x\_t)$ 逐步传递的,第 $t$ 步的输出依赖于第 $t-1$ 步。这样会导致:
- 序列越长,早期信息越难保留;
- 难以并行,因为第 $t$ 步要等第 $t-1$ 步完成。
自注意力(Self-Attention) 的关键在于:一次性把整个序列 $X = [x\_1, x\_2, \dots, x\_n]$ 同时“看一遍”,并基于所有位置的交互计算每个位置的表示。
具体地,给定输入序列的隐藏表示矩阵 $X \in \mathbb{R}^{n \times d}$,在自注意力中,我们首先将 $X$ 线性映射为三组向量:Query(查询)、Key(键)、Value(值),分别记为:
$$
Q = XW^Q,\quad K = XW^K,\quad V = XW^V,
$$
其中权重矩阵 $W^Q, W^K, W^V \in \mathbb{R}^{d \times d\_k}$。随后,对于序列中的每个位置 $i$,(即 $Q\_i$)与所有位置的 Key 向量 ${K\_j}{j=1}^n$ 做点积打分,再通过 Softmax 得到注意力权重 $\alpha{ij}$,最后用这些权重加权 Value 矩阵:
$$
\text{Attention}(Q, K, V)_i
= \sum_{j=1}^n \alpha_{ij}\, V_j,\quad
\alpha_{ij} = \frac{\exp(Q_i \cdot K_j / \sqrt{d_k})}{\sum_{l=1}^n \exp(Q_i \cdot K_l / \sqrt{d_k})}.
$$
这样,位置 $i$ 的新表示 $\text{Attention}(Q,K,V)\_i$ 包含了序列上所有位置按相关度加权的信息。
4.2 Scaled Dot-Product Attention 数学推导
- Query-Key 点积打分
 对于序列中位置 $i$ 的 Query 向量 $Q\_i \in \mathbb{R}^{d\_k}$,和位置 $j$ 的 Key 向量 $K\_j \in \mathbb{R}^{d\_k}$,它们的点积:
 - $$
  e_{ij} = Q_i \cdot K_j = \sum_{m=1}^{d_k} Q_i^{(m)}\, K_j^{(m)}.
$$ - $e\_{ij}$ 表征了位置 $i$ 与位置 $j$ 的相似度。 
- 缩放因子
 由于当 $d\_k$ 较大时,点积值的方差会随着 $d\_k$ 增大而增大,使得 Softmax 的梯度在极端值区可能变得非常小,进而导致梯度消失或训练不稳定。因此,引入缩放因子 $\sqrt{d\_k}$,将打分结果缩放到合适范围:
 - $$
  \tilde{e}_{ij} = \frac{Q_i \cdot K_j}{\sqrt{d_k}}.
$$ 
- Softmax 正则化
 将缩放后的分数映射为权重:
 - $$
  \alpha_{ij} = \frac{\exp(\tilde{e}_{ij})}{\sum_{l=1}^{n} \exp(\tilde{e}_{il})},\quad \sum_{j=1}^{n} \alpha_{ij} = 1.
$$ 
- 加权输出
 最终位置 $i$ 的输出为:
 - $$
  \text{Attention}(Q, K, V)_i = \sum_{j=1}^{n} \alpha_{ij}\, V_j,\quad V_j \in \mathbb{R}^{d_v}.
$$ 
整个过程可以用矩阵形式表示为:
$$
  \text{Attention}(Q,K,V)
  = \text{softmax}\Bigl(\frac{QK^\top}{\sqrt{d_k}}\Bigr)\, V,
$$
其中 $QK^\top \in \mathbb{R}^{n \times n}$,Softmax 是对行进行归一化。
4.3 Multi-Head Attention 详解
单一的自注意力有时只能关注序列中的某种相关性模式,但自然语言中往往存在多种“子空间”关系,比如语义相似度、词性匹配、命名实体关系等。Multi-Head Attention(多头注意力) 就是将多个“自注意力头”并行计算,再将它们的输出拼接在一起,以捕捉多种不同的表达子空间:
- 多头并行计算
 令模型设定头数为 $h$。对于第 $i$ 个头:
 - $$
  Q_i = X\, W_i^Q,\quad K_i = X\, W_i^K,\quad V_i = X\, W_i^V,
$$ - 其中 $W\_i^Q, W\_i^K, W\_i^V \in \mathbb{R}^{d \times d\_k}$,通常令 $d\_k = d / h$。
 然后第 $i$ 个头的注意力输出为:
 - $$
  \text{head}_i = \text{Attention}(Q_i, K_i, V_i) \in \mathbb{R}^{n \times d_k}.
$$ 
- 拼接与线性映射
 将所有头的输出在最后一个维度拼接:
 - $$
  \text{Head} = \bigl[\text{head}_1; \text{head}_2; \dots; \text{head}_h\bigr] \in \mathbb{R}^{n \times (h\,d_k)}.
$$ - 再通过一个线性映射矩阵 $W^O \in \mathbb{R}^{(h,d\_k) \times d}$ 变换回原始维度: - $$
  \text{MultiHead}(Q,K,V) = \text{Head}\, W^O \in \mathbb{R}^{n \times d}.
$$ 
- 注意力图示(简化)
      输入 X (n × d)
          │
   ┌──────▼──────┐   ┌──────▼──────┐   ...   ┌──────▼──────┐
   │  Linear Q₁  │   │  Linear Q₂  │         │  Linear Q_h  │
   │  (d → d_k)   │   │  (d → d_k)   │         │  (d → d_k)   │
   └──────┬──────┘   └──────┬──────┘         └──────┬──────┘
          │                 │                       │
   ┌──────▼──────┐   ┌──────▼──────┐         ┌──────▼──────┐
   │  Linear K₁  │   │  Linear K₂  │         │  Linear K_h  │
   │  (d → d_k)   │   │  (d → d_k)   │         │  (d → d_k)   │
   └──────┬──────┘   └──────┬──────┘         └──────┬──────┘
          │                 │                       │
   ┌──────▼──────┐   ┌──────▼──────┐         ┌──────▼──────┐
   │  Linear V₁  │   │  Linear V₂  │         │  Linear V_h  │
   │  (d → d_k)   │   │  (d → d_k)   │         │  (d → d_k)   │
   └──────┬──────┘   └──────┬──────┘         └──────┬──────┘
          │                 │                       │
   ┌──────▼──────┐   ┌──────▼──────┐         ┌──────▼──────┐
   │Attention₁(Q₁,K₁,V₁)│Attention₂(Q₂,K₂,V₂) ... Attention_h(Q_h,K_h,V_h)
   │   (n×d_k → n×d_k)  │   (n×d_k → n×d_k)          (n×d_k → n×d_k)
   └──────┬──────┘   └──────┬──────┘         └──────┬──────┘
          │                 │                       │
   ┌───────────────────────────────────────────────────────┐
   │         Concat(head₁, head₂, …, head_h)               │  (n × (h d_k))
   └───────────────────────────────────────────────────────┘
                         │
               ┌─────────▼─────────┐
               │   Linear W^O      │ ( (h d_k) → d )
               └─────────┬─────────┘
                         │
                    输出 (n × d)
- 每个 Attention 头在不同子空间上进行投影与打分;
- 拼接后通过线性层整合各头的信息,得到最终的多头注意力输出。
4.4 位置编码(Positional Encoding)
自注意力是对序列中任意位置都能“直接注意”到,但它本身不具备捕获单词顺序(时序)信息的能力。为了解决这一点,Transformer 为输入添加了 位置编码,使模型在做注意力计算时能感知单词的相对/绝对位置。
- 正弦/余弦位置编码(原论文做法)
 对于输入序列中第 $pos$ 个位置、第 $i$ 维维度,定义:
 - $$
  \begin{aligned}
    PE_{pos,\,2i} &= \sin\Bigl(\frac{pos}{10000^{2i/d_{\text{model}}}}\Bigr), \\
    PE_{pos,\,2i+1} &= \cos\Bigl(\frac{pos}{10000^{2i/d_{\text{model}}}}\Bigr).
  \end{aligned}
$$ 
- 可学习的位置编码 - 有些改进版本直接将位置编码当作可学习参数 $\mathrm{PE} \in \mathbb{R}^{n \times d\_{\text{model}}}$,在训练中共同优化。
- 其表达能力更强,但占用更多参数,对低资源场景可能不适。
 
- 位置编码可视化
import numpy as np
import matplotlib.pyplot as plt
def get_sinusoid_encoding_table(n_position, d_model):
    """生成 n_position×d_model 的正弦/余弦位置编码矩阵。"""
    def get_angle(pos, i):
        return pos / np.power(10000, 2 * (i//2) / d_model)
    PE = np.zeros((n_position, d_model))
    for pos in range(n_position):
        for i in range(d_model):
            angle = get_angle(pos, i)
            if i % 2 == 0:
                PE[pos, i] = np.sin(angle)
            else:
                PE[pos, i] = np.cos(angle)
    return PE
# 可视化前 50 个位置、64 维位置编码的热力图
n_pos, d_model = 50, 64
PE = get_sinusoid_encoding_table(n_pos, d_model)
plt.figure(figsize=(10, 6))
plt.imshow(PE, cmap='viridis', aspect='auto')
plt.colorbar()
plt.title("Sinusoidal Positional Encoding (first 50 positions)")
plt.xlabel("Dimension")
plt.ylabel("Position")
plt.show()
- 上图横轴为编码维度 $i \in [0,63]$,纵轴为位置 $pos \in [0,49]$。可以看到正弦/余弦曲线在不同维度上呈现不同频率,从而让模型区分不同位置。
完整 Transformer 架构解析
5.1 Encoder(编码器)结构
一个标准的 Transformer Encoder 一般包含 $N$ 层相同的子层堆叠,每个子层由两个主要模块组成:
- Multi-Head Self-Attention
- Position-wise Feed-Forward Network(前馈网络)
同时,每个模块之后均有残差连接(Residual Connection)与层归一化(LayerNorm)。
Single Encoder Layer 结构图示:
    输入 X (n × d)
        │
   ┌────▼────┐
   │  Multi- │
   │ HeadAtt │
   └────┬────┘
        │
   ┌────▼────┐
   │  Add &  │
   │ LayerNorm │
   └────┬────┘
        │
   ┌────▼────┐
   │ Position- │
   │ Feed-Forw │
   └────┬────┘
        │
   ┌────▼────┐
   │  Add &  │
   │ LayerNorm │
   └────┬────┘
        │
     输出 (n × d)
- 输入嵌入 + 位置编码 - 对原始单词序列进行嵌入(Embedding)操作得到 $X\_{\text{embed}} \in \mathbb{R}^{n \times d}$;
- 与对应位置的 $PE \in \mathbb{R}^{n \times d}$ 相加,得到最终输入 $X \in \mathbb{R}^{n \times d}$.
 
- Multi-Head Self-Attention - 将 $X$ 分别映射为 $Q, K, V$;
- 并行计算 $h$ 个头的注意力输出,拼接后线性映射回 $d$ 维;
- 输出记为 $\mathrm{MHA}(X) \in \mathbb{R}^{n \times d}$.
 
- 残差连接 + LayerNorm - 残差连接:$\mathrm{Z}\_1 = \mathrm{LayerNorm}\bigl(X + \mathrm{MHA}(X)\bigr)$.
 
- 前馈全连接网络 - 对 $\mathrm{Z}1$ 做两层线性变换,通常中间维度为 $d{\mathrm{ff}} = 4d$: - $$
  \mathrm{FFN}(\mathrm{Z}_1) = \max\Bigl(0,\, \mathrm{Z}_1 W_1 + b_1\Bigr)\, W_2 + b_2,
$$ - 其中 $W\_1 \in \mathbb{R}^{d \times d\_{\mathrm{ff}}}$,$W\_2 \in \mathbb{R}^{d\_{\mathrm{ff}} \times d}$; 
- 输出 $\mathrm{FFN}(\mathrm{Z}\_1) \in \mathbb{R}^{n \times d}$.
 
- 残差连接 + LayerNorm - 最终输出:$\mathrm{Z}\_2 = \mathrm{LayerNorm}\bigl(\mathrm{Z}\_1 + \mathrm{FFN}(\mathrm{Z}\_1)\bigr)$.
 
整个 Encoder 向后堆叠 $N$ 层后,将得到完整的编码表示 $\mathrm{EncOutput} \in \mathbb{R}^{n \times d}$.
5.2 Decoder(解码器)结构
Decoder 与 Encoder 类似,也包含 $N$ 个相同的子层,每个子层由三个模块组成:
- Masked Multi-Head Self-Attention
- Encoder-Decoder Multi-Head Attention
- Position-wise Feed-Forward Network
每个模块后同样有残差连接与层归一化。
Single Decoder Layer 结构图示:
    输入 Y (m × d)
        │
   ┌────▼─────┐
   │ Masked   │   ← Prev tokens 的 Masked Self-Attn
   │ Multi-Head│
   │ Attention │
   └────┬─────┘
        │
   ┌────▼─────┐
   │ Add &    │
   │ LayerNorm│
   └────┬─────┘
        │
   ┌────▼──────────┐
   │ Encoder-Decoder│  ← Query 来自上一步,Key&Value 来自 Encoder Output
   │  Multi-Head   │
   │  Attention    │
   └────┬──────────┘
        │
   ┌────▼─────┐
   │ Add &    │
   │ LayerNorm│
   └────┬─────┘
        │
   ┌────▼──────────┐
   │ Position-wise │
   │ Feed-Forward  │
   └────┬──────────┘
        │
   ┌────▼─────┐
   │ Add &    │
   │ LayerNorm│
   └────┬─────┘
        │
     输出 (m × d)
- Masked Multi-Head Self-Attention - 为保证解码时只能看到当前位置及之前的位置,使用掩码机制(Masking)将当前位置之后的注意力分数置为 $-\infty$,再做 Softmax。
- 这样,在生成时每个位置只能关注到当前位置及其之前,避免“作弊”。
 
- Encoder-Decoder Multi-Head Attention - Query 来自上一步的 Masked Self-Attn 输出;
- Key 和 Value 来自 Encoder 最后一层的输出 $\mathrm{EncOutput} \in \mathbb{R}^{n \times d}$;
- 作用是让 Decoder 在生成时能“查看”整个源序列的表示。
 
- 前馈网络(Feed-Forward) - 与 Encoder 相同,先线性映射升维、ReLU 激活,再线性映射回原始维度;
- 残差连接与归一化后得到该层输出。
 
5.3 残差连接与层归一化(LayerNorm)
Transformer 在每个子层后使用 残差连接(Residual Connection),结合 Layer Normalization 保持梯度稳定,并加速收敛。
5.4 前馈全连接网络(Feed-Forward Network)
在每个 Encoder/Decoder 子层中,注意力模块之后都会紧跟一个两层前馈全连接网络(Position-wise FFN),其作用是对每个序列位置的表示进行更高维的非线性变换:
$$
  \mathrm{FFN}(x) = \mathrm{ReLU}(x\, W_1 + b_1)\, W_2 + b_2,
$$
- 第一层将维度由 $d$ 提升到 $d\_{\mathrm{ff}}$(常取 $4d$);
- ReLU 激活后再线性映射回 $d$ 维;
- 每个位置独立计算,故称为“Position-wise”。
代码示例:从零实现简化版 Transformer
下面我们用 PyTorch 手把手实现一个简化版 Transformer,帮助你理解各模块的实现细节。
6.1 环境与依赖
# 建议 Python 版本 >= 3.7
pip install torch torchvision numpy matplotlib
import torch
import torch.nn as nn
import torch.nn.functional as F
import math
6.2 Scaled Dot-Product Attention 实现
class ScaledDotProductAttention(nn.Module):
    def __init__(self, d_k):
        super(ScaledDotProductAttention, self).__init__()
        self.scale = math.sqrt(d_k)
    def forward(self, Q, K, V, mask=None):
        """
        Q, K, V: (batch_size, num_heads, seq_len, d_k)
        mask: (batch_size, 1, seq_len, seq_len) 或 None
        """
        # Q @ K^T  → (batch, heads, seq_q, seq_k)
        scores = torch.matmul(Q, K.transpose(-2, -1)) / self.scale
        # 如果有 mask,则将被 mask 的位置设为 -inf
        if mask is not None:
            scores = scores.masked_fill(mask == 0, float('-inf'))
        # Softmax 获得 attention 权重 (batch, heads, seq_q, seq_k)
        attn = F.softmax(scores, dim=-1)
        # 加权 V 得到输出 (batch, heads, seq_q, d_k)
        output = torch.matmul(attn, V)
        return output, attn
- d_k是每个头的维度。
- mask可用于解码器中的自注意力屏蔽未来位置,也可用于 padding mask。
6.3 Multi-Head Attention 实现
class MultiHeadAttention(nn.Module):
    def __init__(self, d_model, num_heads):
        """
        d_model: 模型隐藏尺寸
        num_heads: 注意力头数
        """
        super(MultiHeadAttention, self).__init__()
        assert d_model % num_heads == 0
        self.d_model = d_model
        self.num_heads = num_heads
        self.d_k = d_model // num_heads
        # Q, K, V 的线性层:将输入映射到 num_heads × d_k
        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)
        self.attention = ScaledDotProductAttention(self.d_k)
    def split_heads(self, x):
        """
        将 x 从 (batch, seq_len, d_model) → (batch, num_heads, seq_len, d_k)
        """
        batch_size, seq_len, _ = x.size()
        # 先 reshape,再 transpose
        x = x.view(batch_size, seq_len, self.num_heads, self.d_k)
        x = x.transpose(1, 2)  # (batch, num_heads, seq_len, d_k)
        return x
    def combine_heads(self, x):
        """
        将 x 从 (batch, num_heads, seq_len, d_k) → (batch, seq_len, d_model)
        """
        batch_size, num_heads, seq_len, d_k = x.size()
        x = x.transpose(1, 2).contiguous()  # (batch, seq_len, num_heads, d_k)
        x = x.view(batch_size, seq_len, num_heads * d_k)  # (batch, seq_len, d_model)
        return x
    def forward(self, Q, K, V, mask=None):
        """
        Q, K, V: (batch, seq_len, d_model)
        mask: (batch, 1, seq_len, seq_len) 或 None
        """
        # 1. 线性映射
        q = self.W_Q(Q)  # (batch, seq_len, d_model)
        k = self.W_K(K)
        v = self.W_V(V)
        # 2. 划分 heads
        q = self.split_heads(q)  # (batch, heads, seq_len, d_k)
        k = self.split_heads(k)
        v = self.split_heads(v)
        # 3. Scaled Dot-Product Attention
        scaled_attention, attn_weights = self.attention(q, k, v, mask)
        # scaled_attention: (batch, heads, seq_len, d_k)
        # 4. 拼接 heads
        concat_attention = self.combine_heads(scaled_attention)  # (batch, seq_len, d_model)
        # 5. 最后输出映射
        output = self.W_O(concat_attention)  # (batch, seq_len, d_model)
        return output, attn_weights
- split_heads:将映射后的张量切分为多个头;
- combine_heads:将多个头的输出拼接回原始维度;
- mask可用于自注意力中屏蔽未来位置或填充区域。
6.4 位置编码实现
class PositionalEncoding(nn.Module):
    def __init__(self, d_model, max_len=5000):
        """
        d_model: 模型隐藏尺寸,max_len: 序列最大长度
        """
        super(PositionalEncoding, self).__init__()
        # 创建位置编码矩阵 PE (max_len, d_model)
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)  # (max_len, 1)
        div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
        # pos * 1/(10000^{2i/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)
        # 将 pe 注册为 buffer,不参与反向传播
        self.register_buffer('pe', pe)
    def forward(self, x):
        """
        x: (batch, seq_len, d_model)
        """
        seq_len = x.size(1)
        # 将位置编码加到输入嵌入上
        x = x + self.pe[:, :seq_len, :]
        return x
- pe在初始化时根据正弦/余弦函数预先计算好,并注册为 buffer,不参与梯度更新;
- 在 forward中,将前seq_len行位置编码与输入相加。
6.5 简化版 Encoder Layer
class EncoderLayer(nn.Module):
    def __init__(self, d_model, num_heads, d_ff, dropout=0.1):
        super(EncoderLayer, self).__init__()
        self.mha = MultiHeadAttention(d_model, num_heads)
        self.ffn = nn.Sequential(
            nn.Linear(d_model, d_ff),
            nn.ReLU(),
            nn.Linear(d_ff, d_model)
        )
        self.layernorm1 = nn.LayerNorm(d_model, eps=1e-6)
        self.layernorm2 = nn.LayerNorm(d_model, eps=1e-6)
        self.dropout1 = nn.Dropout(dropout)
        self.dropout2 = nn.Dropout(dropout)
    def forward(self, x, mask=None):
        # Multi-Head Self-Attention
        attn_output, _ = self.mha(x, x, x, mask)  # (batch, seq_len, d_model)
        attn_output = self.dropout1(attn_output)
        out1 = self.layernorm1(x + attn_output)   # 残差 + LayerNorm
        # 前馈网络
        ffn_output = self.ffn(out1)               # (batch, seq_len, d_model)
        ffn_output = self.dropout2(ffn_output)
        out2 = self.layernorm2(out1 + ffn_output) # 残差 + LayerNorm
        return out2
- d_ff通常取 $4 \times d\_{\text{model}}$;
- Dropout 用于正则化;
- 两次 LayerNorm 分别位于 Attention 和 FFN 之后。
6.6 简化版 Decoder Layer
class DecoderLayer(nn.Module):
    def __init__(self, d_model, num_heads, d_ff, dropout=0.1):
        super(DecoderLayer, self).__init__()
        self.mha1 = MultiHeadAttention(d_model, num_heads)  # Masked Self-Attn
        self.mha2 = MultiHeadAttention(d_model, num_heads)  # Enc-Dec Attn
        self.ffn = nn.Sequential(
            nn.Linear(d_model, d_ff),
            nn.ReLU(),
            nn.Linear(d_ff, d_model)
        )
        self.layernorm1 = nn.LayerNorm(d_model, eps=1e-6)
        self.layernorm2 = nn.LayerNorm(d_model, eps=1e-6)
        self.layernorm3 = nn.LayerNorm(d_model, eps=1e-6)
        self.dropout1 = nn.Dropout(dropout)
        self.dropout2 = nn.Dropout(dropout)
        self.dropout3 = nn.Dropout(dropout)
    def forward(self, x, enc_output, look_ahead_mask=None, padding_mask=None):
        """
        x: (batch, target_seq_len, d_model)
        enc_output: (batch, input_seq_len, d_model)
        look_ahead_mask: 用于 Masked Self-Attn
        padding_mask: 用于 Encoder-Decoder Attn 针对输入序列的填充
        """
        # 1. Masked Multi-Head Self-Attention
        attn1, attn_weights1 = self.mha1(x, x, x, look_ahead_mask)
        attn1 = self.dropout1(attn1)
        out1 = self.layernorm1(x + attn1)
        # 2. Encoder-Decoder Multi-Head Attention
        attn2, attn_weights2 = self.mha2(out1, enc_output, enc_output, padding_mask)
        attn2 = self.dropout2(attn2)
        out2 = self.layernorm2(out1 + attn2)
        # 3. 前馈网络
        ffn_output = self.ffn(out2)
        ffn_output = self.dropout3(ffn_output)
        out3 = self.layernorm3(out2 + ffn_output)
        return out3, attn_weights1, attn_weights2
- look_ahead_mask用于遮蔽未来位置;
- padding_mask用于遮蔽输入序列中的 padding 部分(在 Encoder-Decoder Attention 中);
- Decoder Layer 有三个 LayerNorm 分别对应三个子层的残差连接。
6.7 完整 Transformer 模型组装
class SimpleTransformer(nn.Module):
    def __init__(self,
                 input_vocab_size,
                 target_vocab_size,
                 d_model=512,
                 num_heads=8,
                 d_ff=2048,
                 num_encoder_layers=6,
                 num_decoder_layers=6,
                 max_len=5000,
                 dropout=0.1):
        super(SimpleTransformer, self).__init__()
        self.d_model = d_model
        # 输入与输出的嵌入层
        self.encoder_embedding = nn.Embedding(input_vocab_size, d_model)
        self.decoder_embedding = nn.Embedding(target_vocab_size, d_model)
        # 位置编码
        self.pos_encoding = PositionalEncoding(d_model, max_len)
        # Encoder 堆叠
        self.encoder_layers = nn.ModuleList([
            EncoderLayer(d_model, num_heads, d_ff, dropout)
            for _ in range(num_encoder_layers)
        ])
        # Decoder 堆叠
        self.decoder_layers = nn.ModuleList([
            DecoderLayer(d_model, num_heads, d_ff, dropout)
            for _ in range(num_decoder_layers)
        ])
        # 最后线性层映射到词表大小,用于计算预测分布
        self.final_linear = nn.Linear(d_model, target_vocab_size)
    def make_padding_mask(self, seq):
        """
        seq: (batch, seq_len)
        return mask: (batch, 1, 1, seq_len)
        """
        mask = (seq == 0).unsqueeze(1).unsqueeze(2)  # 假设 PAD token 索引为 0
        # mask 的位置为 True 则表示要遮蔽
        return mask  # bool tensor
    def make_look_ahead_mask(self, size):
        """
        生成 (1, 1, size, size) 的上三角 mask,用于遮蔽未来时刻
        """
        mask = torch.triu(torch.ones((size, size)), diagonal=1).bool()
        return mask.unsqueeze(0).unsqueeze(0)  # (1,1, size, size)
    def forward(self, enc_input, dec_input):
        """
        enc_input: (batch, enc_seq_len)
        dec_input: (batch, dec_seq_len)
        """
        batch_size, enc_len = enc_input.size()
        _, dec_len = dec_input.size()
        # 1. Encoder embedding + positional encoding
        enc_embed = self.encoder_embedding(enc_input) * math.sqrt(self.d_model)
        enc_embed = self.pos_encoding(enc_embed)
        # 2. 生成 Encoder padding mask
        enc_padding_mask = self.make_padding_mask(enc_input)
        # 3. 通过所有 Encoder 层
        enc_output = enc_embed
        for layer in self.encoder_layers:
            enc_output = layer(enc_output, enc_padding_mask)
        # 4. Decoder embedding + positional encoding
        dec_embed = self.decoder_embedding(dec_input) * math.sqrt(self.d_model)
        dec_embed = self.pos_encoding(dec_embed)
        # 5. 生成 Decoder masks
        look_ahead_mask = self.make_look_ahead_mask(dec_len).to(enc_input.device)
        dec_padding_mask = self.make_padding_mask(enc_input)
        # 6. 通过所有 Decoder 层
        dec_output = dec_embed
        for layer in self.decoder_layers:
            dec_output, attn1, attn2 = layer(dec_output, enc_output, look_ahead_mask, dec_padding_mask)
        # 7. 最终线性映射
        logits = self.final_linear(dec_output)  # (batch, dec_seq_len, target_vocab_size)
        return logits, attn1, attn2
- 输入与输出都先经过 Embedding + Positional Encoding;
- Encoder-Decoder 层中使用前文定义的 EncoderLayer与DecoderLayer;
- Mask 分为两部分:Decoder 的 look-ahead mask 和 Encoder-Decoder 的 padding mask;
- 最后输出词向量维度大小的 logits,用于交叉熵损失计算。
6.8 训练示例:机器翻译任务
下面以一个简单的“英法翻译”示例演示如何训练该简化 Transformer。由于数据集加载与预处理相对繁琐,以下示例仅演示关键训练逻辑,具体数据加载可使用类似 torchtext 或自定义方式。
import torch.optim as optim
# 超参数示例
INPUT_VOCAB_SIZE = 10000   # 英语词表大小
TARGET_VOCAB_SIZE = 12000  # 法语词表大小
D_MODEL = 512
NUM_HEADS = 8
D_FF = 2048
NUM_LAYERS = 4
MAX_LEN = 100
DROPOUT = 0.1
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# 初始化模型
model = SimpleTransformer(
    INPUT_VOCAB_SIZE,
    TARGET_VOCAB_SIZE,
    D_MODEL,
    NUM_HEADS,
    D_FF,
    num_encoder_layers=NUM_LAYERS,
    num_decoder_layers=NUM_LAYERS,
    max_len=MAX_LEN,
    dropout=DROPOUT
).to(device)
# 损失与优化器
criterion = nn.CrossEntropyLoss(ignore_index=0)  # 假设 PAD token 索引为 0
optimizer = optim.Adam(model.parameters(), lr=1e-4)
def train_step(enc_batch, dec_batch, dec_target):
    """
    enc_batch: (batch, enc_seq_len)
    dec_batch: (batch, dec_seq_len) 输入给 Decoder,包括 <sos> 开头
    dec_target: (batch, dec_seq_len) 真实目标,包括 <eos> 结尾
    """
    model.train()
    optimizer.zero_grad()
    logits, _, _ = model(enc_batch, dec_batch)  # (batch, dec_seq_len, target_vocab_size)
    # 将 logits 与目标调整形状
    loss = criterion(
        logits.reshape(-1, logits.size(-1)), 
        dec_target.reshape(-1)
    )
    loss.backward()
    optimizer.step()
    return loss.item()
# 伪代码示例:训练循环
for epoch in range(1, 11):
    total_loss = 0
    for batch in train_loader:  # 假设 train_loader 迭代器返回 (enc_batch, dec_batch, dec_target)
        enc_batch, dec_batch, dec_target = [x.to(device) for x in batch]
        loss = train_step(enc_batch, dec_batch, dec_target)
        total_loss += loss
    print(f"Epoch {epoch}, Loss: {total_loss/len(train_loader):.4f}")
- train_loader应返回三个张量:- enc_batch(源语言输入)、- dec_batch(目标语言输入,含- <sos>)、- dec_target(目标语言标签,含- <eos>);
- 每轮迭代根据模型输出计算交叉熵损失并更新参数;
- 实际应用中,还需要学习率衰减、梯度裁剪等技巧以稳定训练。
图解:Transformer 各模块示意
7.1 自注意力机制示意图
  输入序列(长度=4):              Embedding+Positional Encoding
  ["I", "love", "NLP", "."]         ↓  (4×d)
   ┌─────────────────────────────────────────────────────────────────┐
   │                        输入矩阵 X (4×d)                           │
   └─────────────────────────────────────────────────────────────────┘
              │                 │                  │
       ┌──────▼──────┐   ┌──────▼──────┐    ┌──────▼──────┐
       │   Linear    │   │   Linear    │    │   Linear    │
       │   Q = XW^Q  │   │   K = XW^K  │    │   V = XW^V  │
       │  (4×d → 4×d_k) │ │  (4×d → 4×d_k) │ │  (4×d → 4×d_k) │
       └──────┬──────┘   └──────┬──────┘    └──────┬──────┘
              │                 │                  │
       ┌──────▼──────┐   ┌──────▼──────┐    ┌──────▼──────┐
       │   Split     │   │   Split     │    │   Split     │
       │  Heads:     │   │  Heads:     │    │  Heads:     │
       │ (4×d_k → num_heads × (4×d/h)) │  num_heads × (4×d/h)  │
       └──────┬──────┘   └──────┬──────┘    └──────┬──────┘
              │                 │                  │
 ┌─────────────────────────────────────────────────────────────────┐
 │       Scaled Dot-Product Attention for each head               │
 │    Attention(Q_i, K_i, V_i):                                    │
 │      scores = Q_i × K_i^T / √d_k; Softmax; output = scores×V_i  │
 └─────────────────────────────────────────────────────────────────┘
              │                 │                  │
       ┌──────▼──────┐   ┌──────▼──────┐    ┌──────▼──────┐
       │  head₁: (4×d/h) │  head₂: (4×d/h) │ …  head_h: (4×d/h) │
       └──────┬──────┘   └──────┬──────┘    └──────┬──────┘
              │                 │                  │
       ┌────────────────────────────────────────────────────┐
       │       Concat(head₁, …, head_h) → (4×d_k × h = 4×d)   │
       └────────────────────────────────────────────────────┘
              │
       ┌──────▼──────┐
       │  Linear W^O  │  (4×d → 4×d)
       └──────┬──────┘
              │
   输出矩阵 (4×d)
- 上图以序列长度 4 为例,将 d 维表示映射到 $d\_k = d/h$ 后并行计算多头注意力,最后拼接再线性映射回 $d$ 维。
7.2 编码器—解码器整体流程图
源序列(英语):     "I love NLP ."
  ↓ Tokenize + Embedding
  ↓ Positional Encoding
┌───────────────────────────────────────┐
│         Encoder Layer × N             │
│   (Self-Attn → Add+Norm → FFN → Add+Norm)  │
└───────────────────────────────────────┘
  ↓
Encoder 输出 (EncOutput)   (n × d)
目标序列(法语):    "J'aime le NLP ."
  ↓ Tokenize + Embedding
  ↓ Positional Encoding
┌───────────────────────────────────────┐
│    Decoder Layer × N  (每层三步)      │
│  1. Masked Self-Attn  → Add+Norm       │
│  2. Enc-Dec Attn     → Add+Norm       │
│  3. FFN              → Add+Norm       │
└───────────────────────────────────────┘
  ↓
Decoder 输出 (DecOutput)  (m × d)
  ↓ 线性层 + Softmax (target_vocab_size)
预测下一个单词概率分布
- 源序列进入 Encoder,多层自注意力捕获句内关系;
- Decoder 第一层做 Masked Self-Attention,只能关注目标序列已生成部分;
- 第二步做 Encoder-Decoder Attention,让 Decoder 查看 Encoder 提供的上下文;
- 最终经过前馈网络输出下一个词的概率。
7.3 位置编码可视化
在 4.4 节中,我们已经用代码示例展示了正弦/余弦位置编码的热力图。为了直观理解,回顾一下:
 Sinusoidal Positional Encoding Heatmap
Sinusoidal Positional Encoding Heatmap- 纵轴:序列中的每个位置(从 0 开始);
- 横轴:隐藏表示的维度 $i$;
- 不同维度采用不同频率的正弦/余弦函数,确保位置信息在各个维度上交错分布。
Transformer 在 NLP 中的经典应用
8.1 机器翻译(Machine Translation)
Transformer 最初即为机器翻译设计,实验主要在 WMT 2014 英德、英法翻译数据集上进行:
- 性能:在 2017 年,该模型在 BLEU 分数上均超越当时最先进的 RNN+Attention 模型。
- 特点: - 并行训练速度极快;
- 由于长程依赖捕捉能力突出,翻译长句表现尤为优异;
- 支持大规模预训练模型(如 mBART、mT5 等多语种翻译模型)。
 
示例:Hugging Face Transformers 应用机器翻译
from transformers import MarianMTModel, MarianTokenizer
# 以“英语→德语”为例,加载预训练翻译模型
model_name = 'Helsinki-NLP/opus-mt-en-de'
tokenizer = MarianTokenizer.from_pretrained(model_name)
model = MarianMTModel.from_pretrained(model_name)
def translate_en_to_de(sentence):
    # 1. Tokenize
    inputs = tokenizer.prepare_seq2seq_batch([sentence], return_tensors='pt')
    # 2. 生成
    translated = model.generate(**inputs, max_length=40)
    # 3. 解码
    tgt = [tokenizer.decode(t, skip_special_tokens=True) for t in translated]
    return tgt[0]
src_sent = "Transformer models have revolutionized machine translation."
print("EN:", src_sent)
print("DE:", translate_en_to_de(src_sent))
- 上述示例展示了如何用预训练 Marian 翻译模型进行英语到德语翻译,感受 Transformer 在实际任务上的便捷应用。
8.2 文本分类与情感分析(Text Classification & Sentiment Analysis)
通过在 Transformer 编码器后接一个简单的线性分类头,可实现情感分类、主题分类等任务:
- 加载预训练 BERT(其实是 Transformer 编码器) - from transformers import BertTokenizer, BertForSequenceClassification
model_name = "bert-base-uncased"
tokenizer = BertTokenizer.from_pretrained(model_name)
model = BertForSequenceClassification.from_pretrained(model_name, num_labels=2)
 
- 微调示例 - import torch
from torch.optim import AdamW
from torch.utils.data import DataLoader, Dataset
class TextDataset(Dataset):
    def __init__(self, texts, labels, tokenizer, max_len):
        self.texts = texts
        self.labels = labels
        self.tokenizer = tokenizer
        self.max_len = max_len
    def __len__(self):
        return len(self.texts)
    def __getitem__(self, idx):
        text = self.texts[idx]
        label = self.labels[idx]
        encoding = self.tokenizer.encode_plus(
            text,
            add_special_tokens=True,
            max_length=self.max_len,
            padding='max_length',
            truncation=True,
            return_tensors='pt'
        )
        return {
            'input_ids': encoding['input_ids'].squeeze(0),
            'attention_mask': encoding['attention_mask'].squeeze(0),
            'labels': torch.tensor(label, dtype=torch.long)
        }
# 假设 texts_train、labels_train 已准备好
train_dataset = TextDataset(texts_train, labels_train, tokenizer, max_len=128)
train_loader = DataLoader(train_dataset, batch_size=16, shuffle=True)
optimizer = AdamW(model.parameters(), lr=2e-5)
model.train()
for epoch in range(3):
    total_loss = 0
    for batch in train_loader:
        input_ids = batch['input_ids'].to(model.device)
        attention_mask = batch['attention_mask'].to(model.device)
        labels = batch['labels'].to(model.device)
        outputs = model(input_ids=input_ids, attention_mask=attention_mask, labels=labels)
        loss = outputs.loss
        loss.backward()
        optimizer.step()
        optimizer.zero_grad()
        total_loss += loss.item()
    print(f"Epoch {epoch+1}, Loss: {total_loss/len(train_loader):.4f}")
 
- 以上示例展示了如何在情感分类(IMDb 数据集等)上微调 BERT,BERT 本质上是 Transformer 的编码器部分,通过在顶端加分类头即可完成分类任务。
8.3 文本生成与摘要(Text Generation & Summarization)
Decoder 个性化的 Transformer(如 GPT、T5、BART)在文本生成、摘要任务中表现尤为突出:
示例:使用 Hugging Face 预训练 BART 做摘要任务
from transformers import BartTokenizer, BartForConditionalGeneration
# 加载预训练 BART 模型与分词器
model_name = "facebook/bart-large-cnn"
tokenizer = BartTokenizer.from_pretrained(model_name)
model = BartForConditionalGeneration.from_pretrained(model_name)
article = """
The COVID-19 pandemic has fundamentally altered the landscape of remote work, 
with many companies adopting flexible work-from-home policies. 
As organizations continue to navigate the challenges of maintaining productivity 
and employee engagement, new technologies and management strategies are emerging 
to support this transition.
"""
# 1. Encode 输入文章
inputs = tokenizer(article, max_length=512, return_tensors="pt", truncation=True)
# 2. 生成摘要(可调节 beam search 大小和摘要最大长度)
summary_ids = model.generate(
    inputs["input_ids"], 
    num_beams=4, 
    max_length=80, 
    early_stopping=True
)
# 3. 解码输出
summary = tokenizer.decode(summary_ids[0], skip_special_tokens=True)
print("摘要:", summary)
- 运行后,BART 会输出一段简洁的文章摘要,展示 Transformer 在文本摘要领域的强大能力。
8.4 问答系统与对话生成(QA & Dialogue)
基于 Transformer 的预训练模型(如 BERT、RoBERTa、ALBERT、T5、GPT)已在问答与对话任务中被广泛应用:
- 检索式问答(Retrieval-based QA) - 利用 BERT 对查询与一段文本进行编码,计算相似度以定位答案所在位置;
- 例如 SQuAD 数据集上,BERT Large 模型达到超过 90% 的 F1 分数。
 
- 生成式对话(Generative Dialogue) - GPT 类模型通过自回归方式逐 token 生成回复;
- 使用对话上下文作为输入,模型自动学习上下文关联与回复策略;
- OpenAI ChatGPT、Google LaMDA 等都是这一范式的典型代表。
 
- 多任务联合训练 - 如 T5 可以将 QA、对话、翻译等任务都转化为文本—文本格式,通过一个统一框架处理多种任务。
 
优化与进阶:Transformers 家族演化
9.1 改进结构与高效注意力(Efficient Attention)
Transformer 原始自注意力计算为 $O(n^2)$,当序列长度 $n$ 非常大时会出现内存与算力瓶颈。为了解决这一问题,出现了多种高效注意力机制:
- Sparse Attention - 通过限制注意力矩阵为稀疏结构,只计算与相邻位置或特定模式有关的注意力分数;
- 例如 Longformer 的滑动窗口注意力(sliding-window attention)、BigBird 的随机+局部+全局混合稀疏模式。
 
- Linformer - 假设注意力矩阵存在低秩结构,将 Key、Value 做投影降维,使注意力计算复杂度从 $O(n^2)$ 降到 $O(n)$.
 
- Performer - 基于随机特征映射(Random Feature Mapping),将 Softmax Attention 近似为线性运算,时间复杂度降为 $O(n)$.
 
- Reformer - 通过局部敏感哈希(LSH)构建近似注意力,实现 $O(n \log n)$ 时间复杂度。
 
这些方法极大地拓宽了 Transformer 在超长序列(如文档级理解、多模态序列)上的应用场景。
9.2 预训练模型与微调范式(BERT、GPT、T5 等)
- BERT(Bidirectional Encoder Representations from Transformers) - 只采用编码器结构,利用Masked Language Modeling(MLM) 和 Next Sentence Prediction(NSP) 进行预训练;
- 其双向(Bidirectional)编码使得上下文理解更全面;
- 在 GLUE、SQuAD 等多项基准任务上刷新记录;
- 微调步骤:在下游任务(分类、问答、NER)上插入一个简单的线性层,联合训练整个模型。
 
- GPT(Generative Pre-trained Transformer) - 采用 Decoder-only 架构,进行自回归语言建模预训练;
- GPT-2、GPT-3 扩展到数十亿乃至数千亿参数,展现了强大的零/少样本学习能力;
- 在对话生成、文本续写、开放领域 QA、程序生成等任务中表现出众。
 
- T5(Text-to-Text Transfer Transformer) - 采用 Encoder-Decoder 架构,将所有下游任务都转化为文本—文本映射;
- 预训练任务为填空式(text infilling)和随机下采样(sentence permutation)、前向/后向预测等;
- 在多种任务上(如翻译、摘要、QA、分类)实现统一框架与端到端微调。
 
- BART(Bidirectional and Auto-Regressive Transformers) - 结合编码器—解码器与掩码生成,预训练目标包括文本破坏(text infilling)、删除随机句子、token 重排;
- 在文本摘要、生成式问答等任务中性能出色。
 
这些预训练范式为各类 NLP 任务提供了强大的“通用语言理解与生成”能力,使得构造少样本学习、跨领域迁移成为可能。
9.3 多模态 Transformer(Vision Transformer、Speech Transformer)
- Vision Transformer(ViT) - 将图像划分为若干固定大小的补丁(patch),将每个补丁视作一个“token”,然后用 Transformer 编码器对补丁序列建模;
- 预训练后在图像分类、目标检测、分割等任务上表现与卷积网络(CNN)相当,甚至更优。
 
- Speech Transformer - 用于语音识别(ASR)与语音合成(TTS)任务,直接对声谱图(spectrogram)等时频特征序列做自注意力建模;
- 相比传统的 RNN+Seq2Seq 结构,Transformer 在并行化与长程依赖捕捉方面具有显著优势;
 
- Multimodal Transformer - 将文本、图像、音频、视频等不同模态的信息联合建模,常见架构包括 CLIP(文本—图像对齐)、Flamingo(少样本多模态生成)、VideoBERT(视频+字幕联合模型)等;
- 在视觉问答(VQA)、图文检索、多模态对话系统等场景中取得突破性效果。
 
总结与最佳实践
- 掌握核心模块 - 理解并能实现 Scaled Dot-Product Attention 和 Multi-Head Attention;
- 熟练构造 Encoder Layer 和 Decoder Layer,掌握残差连接与 LayerNorm 细节;
- 了解位置编码的原理及其对捕捉序列顺序信息的重要性。
 
- 代码实现与调试技巧 - 在实现自注意力时,注意 mask的维度与布尔值含义,避免注意力泄露;
- 训练过程中常需要进行梯度裁剪(torch.nn.utils.clip_grad_norm_)、学习率预热与衰减、混合精度训练(torch.cuda.amp)等操作;
- 对于较大模型可使用分布式训练(torch.nn.parallel.DistributedDataParallel)或深度学习框架自带的高效实现,如torch.nn.Transformer、transformers库等。
 
- 预训练与微调技巧 - 明确下游任务需求后,选择合适的预训练模型体系(Encoder-only、Decoder-only 或 Encoder-Decoder);
- 对任务数据进行合理预处理与增广;
- 微调时可冻结部分层,只训练顶层或新增层,尽量避免过拟合;
- 监控训练曲线,及时进行早停(Early Stopping)或调整学习率。
 
- 未来探索方向 - 高效注意力:研究如何在处理长文本、长音频、长视频时降低计算复杂度;
- 多模态融合:将 Transformer 从单一文本扩展到联合图像、音频、视频、多源文本等多模态场景;
- 边缘端与移动端部署:在资源受限环境中优化 Transformer 模型,如量化、剪枝、蒸馏等技术;
- 自监督与少样本学习:探索更高效的预训练目标与少样本学习范式,以降低对大规模标注数据的依赖。