外观
2.2 序列模型:从循环神经网络到 Transformer
许多数据带有明确的时间顺序,例如语音、文本和智能体的状态轨迹。此时,当前观测可能依赖过去一段时间内的信息,不能简单地把各时间步当作相互独立的样本。序列模型要解决的核心问题,就是在有限的表示与计算预算下保留对当前预测真正有用的历史。

图 2.2-1:早期神经注意力在机器翻译中学出的词语对齐热图,把不同长度序列之间的依赖直接变成可观察权重。 出处:Dzmitry Bahdanau; Kyunghyun Cho; Yoshua Bengio,Neural Machine Translation by Jointly Learning to Align and Translate(2015),Figure 3。
在本节中,我们将首先追溯序列建模的统计学起源,从基础的高中概率论出发,推导出处理序列数据的核心数学框架。接着,我们将回顾循环神经网络(Recurrent Neural Networks, RNN)[Elman, 1990] 的设计哲学,剖析其如何维持“隐状态”以记忆历史信息。然而,RNN 由于其时序展开特性,在训练效率和长程梯度传播上面临挑战 [Hochreiter & Schmidhuber, 1997]。由此,我们将过渡到 Transformer [Vaswani et al., 2017],讨论自注意力机制(Self-Attention)如何通过投影与加权聚合来建模序列。
2.2.1 序列数据的统计学视角
联合概率与条件概率的链式法则
为了建立对序列数据的数学描述,让我们先回到高中数学中的概率论基础。假设我们有一枚硬币,连续抛掷
对于任意长度为
这个分解说明,序列的联合分布可以通过一组“给定历史预测下一步”的条件分布来表示。这是自回归(Autoregressive)生成模型的概率基础。
马尔可夫假设与自回归模型
直接把完整历史作为离散条件表会迅速遇到组合数量过大的问题;即使使用神经网络,历史长度增加也会带来更高的计算和存储开销。一种早期而直接的简化是限制模型只查看有限窗口。
最经典的妥协方案是引入马尔可夫假设(Markov Assumption):假设当前时刻的状态仅仅依赖于过去有限的
尽管马尔可夫假设使得模型变得可计算,但它的缺陷同样明显:它人为地切断了序列的长程依赖(Long-range Dependency)。例如,在句子“他来自法国,精通各种文学和艺术,并且能说一口流利的[填空]”中,要填出“法语”,模型必须回忆起远在句子开头的“法国”。固定的截断窗口
2.2.2 循环神经网络(RNN)的数学推导
为了摆脱固定窗口,循环神经网络引入了隐状态(Hidden State)。
从标量到张量:隐状态的诞生
让我们先用高中物理中的运动学来建立直觉。假设我们要追踪一个正在做复杂曲线运动的粒子。在任意时刻
在深度学习中,隐状态
现在,我们通过严谨的矩阵运算来具体实例化这个非线性函数
其中:
是输入到隐状态的权重矩阵; 是隐状态到隐状态(即时间步之间传递记忆)的权重矩阵; 是偏置参数; 是非线性激活函数,在传统 RNN 中通常采用 函数,以保证隐状态的数值范围被稳定限制在 之间。
有了当前的隐状态
这里
沿时间反向传播(BPTT)与梯度消失
尽管 RNN 的前向传播公式看起来简洁优雅,但其在优化时却面临严重的数学困难。在 RNN 中,我们通常使用“沿时间反向传播”(Backpropagation Through Time, BPTT)来计算梯度。本质上,BPTT 就是将该公式在时间轴上展开,然后应用微积分中的链式法则。
假设我们要计算最终输出关于初始隐状态

图 2.2-2:跨时间传播的梯度由每一步局部 Jacobian 依次相乘;其典型尺度持续小于 1 时衰减,持续大于 1 时增长。
每一项偏导数都包含循环权重与当前激活函数导数,因此实际传播的是一串随时间变化的 Jacobian。若这些 Jacobian 的典型奇异值持续小于
下面用 PyTorch 从零实现一个单步 RNN。
python
import torch
from torch import nn
from torch.nn import functional as F
class RNNStep(nn.Module):
def __init__(self, input_size, hidden_size):
super().__init__()
self.hidden_size = hidden_size
# 严谨对应公式 eqref:eq_rnn_step 的参数定义
self.W_xh = nn.Parameter(torch.randn(input_size, hidden_size) * 0.01)
self.W_hh = nn.Parameter(torch.randn(hidden_size, hidden_size) * 0.01)
self.b_h = nn.Parameter(torch.zeros(hidden_size))
def forward(self, X, H_prev):
# X: (batch_size, input_size)
# H_prev: (batch_size, hidden_size)
# 矩阵乘法并相加:计算当前步的预激活值
pre_activation = torch.matmul(X, self.W_xh) + torch.matmul(H_prev, self.W_hh) + self.b_h
# 使用 tanh 作为非线性激活函数,保持数值稳定
H_curr = torch.tanh(pre_activation)
return H_curr
# 测试一个简单的小批量数据
batch_size, input_size, hidden_size = 32, 128, 256
rnn_step = RNNStep(input_size, hidden_size)
X_t = torch.randn(batch_size, input_size)
H_prev = torch.zeros(batch_size, hidden_size)
# 执行单步前向传播
H_t = rnn_step(X_t, H_prev)
print(f"H_t shape: {H_t.shape}") # 预期输出: torch.Size([32, 256])2.2.3 注意力机制与Transformer架构
为缓解传统 RNN 的长程依赖与梯度传播问题,研究者提出了长短期记忆网络(LSTM, [Hochreiter & Schmidhuber, 1997])和门控循环单元(GRU, [Cho et al., 2014])。它们用门控机制控制信息流。不过,在标准 RNN 中,当前状态

图 2.2-3:GRU 原论文的隐藏单元图显示重置门 r 与更新门 z 如何控制旧状态和候选状态的合成。 出处:Kyunghyun Cho et al.,Learning Phrase Representations using RNN Encoder–Decoder for Statistical Machine Translation(2014),Figure 2。
2017 年,Vaswani 等人发表了 Attention Is All You Need [Vaswani et al., 2017],提出不使用循环结构、主要依赖注意力与前馈网络的 Transformer。训练时,给定完整输入序列后,各位置的注意力计算可以并行;自回归解码时仍需按词元逐步生成,不能概括为消除了所有时序依赖。

图 2.2-4:Transformer 原始架构把编码器和解码器组织为多头注意力、前馈层、残差连接与位置编码的堆栈。 出处:Ashish Vaswani et al.,Attention Is All You Need(2017),Figure 1。
自注意力(Self-Attention)的几何直觉与推导
先从向量内积看注意力分数的含义。
对于两个向量
在自注意力机制中,我们将序列中的每一个元素(如词元)投影到三个不同的向量空间,分别赋予它们三种不同的身份角色:
- 查询向量(Query,
):代表该元素正在寻找什么样的信息。 - 键向量(Key,
):代表该元素包含了什么样的信息特征。 - 值向量(Value,
):代表该元素实际提供的内容实质。
对位置
让我们严格写出这个过程的数学公式。对于序列中第
为了将这些原始打分转化为概率分布(权重之和为1),我们对其施加 Softmax 函数。同时,当向量维度
最后,元素
从向量到矩阵
将长度为
训练时,这种矩阵形式能并行处理所有位置,不再像标准 RNN 那样沿时间步串行展开。但注意力矩阵大小为
多头注意力(Multi-Head Attention)与位置编码
单一的自注意力机制往往只能捕捉序列中某一种维度的关联(例如仅仅关注语法结构或者仅仅关注情感倾向)。为了让模型拥有从多个独立子空间提取特征的能力,Transformer 引入了多头注意力(Multi-Head Attention)。它将原始的
单独的自注意力不包含绝对或相对位置信息。若按同一种置换重排输入,输出也会相应重排,因此模型需要额外的位置表示来区分顺序。
原始 Transformer 使用正弦和余弦函数构造位置编码(Positional Encoding);其他模型也可使用可学习位置嵌入或相对位置编码。对于位置
在模型实际使用的有限位置范围内,多组频率共同提供可区分的位置模式。利用三角函数的和差公式,固定偏移
下面用 PyTorch 实现缩放点积注意力。
python
import math
import torch
from torch import nn
def masked_softmax(X, valid_lens):
"""通过在掩码位置填充极小值来执行掩蔽 softmax 操作,常用于处理变长序列"""
if valid_lens is None:
return nn.functional.softmax(X, dim=-1)
else:
shape = X.shape
if valid_lens.dim() == 1:
valid_lens = torch.repeat_interleave(valid_lens, shape[1])
else:
valid_lens = valid_lens.reshape(-1)
# 展平以便于掩蔽
X = X.reshape(-1, shape[-1])
mask = torch.arange((shape[-1]), dtype=torch.float32,
device=X.device)[None, :] < valid_lens[:, None]
# 将无效位置填充为非常小的值(接近负无穷),使得 softmax 后的概率趋近于0
X[~mask] = -1e6
return nn.functional.softmax(X.reshape(shape), dim=-1)
class DotProductAttention(nn.Module):
"""严谨实现的缩放点积注意力"""
def __init__(self, dropout, **kwargs):
super(DotProductAttention, self).__init__(**kwargs)
self.dropout = nn.Dropout(dropout)
def forward(self, queries, keys, values, valid_lens=None):
# queries 的形状:(batch_size, num_queries, d)
# keys 的形状:(batch_size, num_kv_pairs, d)
# values 的形状:(batch_size, num_kv_pairs, value_dimension)
d = queries.shape[-1]
# 执行矩阵乘法 QK^T,并除以 sqrt(d) 进行稳定缩放
# transpose(1, 2) 实现了矩阵转置,形状变为 (batch_size, num_queries, num_kv_pairs)
scores = torch.bmm(queries, keys.transpose(1, 2)) / math.sqrt(d)
# 应用 softmax 获取概率分布权重
self.attention_weights = masked_softmax(scores, valid_lens)
# 将概率权重与 values 矩阵相乘
return torch.bmm(self.dropout(self.attention_weights), values)
# 创建小批量测试张量
queries = torch.normal(0, 1, (2, 1, 64))
keys = torch.normal(0, 1, (2, 10, 64))
values = torch.normal(0, 1, (2, 10, 128))
valid_lens = torch.tensor([2, 6])
attention = DotProductAttention(dropout=0.5)
attention.eval() # 评估模式,关闭 dropout
context = attention(queries, keys, values, valid_lens)
print(f"注意力输出形状: {context.shape}") # 预期输出: torch.Size([2, 1, 128])2.2.4 小结
本节从条件概率链式法则出发,说明了序列建模为何需要压缩和利用历史。**循环神经网络(RNN)**用隐状态递归地维护历史摘要,但标准 RNN 的时间串行计算和长链 Jacobian 会带来并行效率与梯度传播问题。
Transformer用缩放点积自注意力让任意两个位置在一层内直接交互,并允许训练阶段并行处理整段序列。它缩短了远距离信息的交互路径,却没有“彻底解决”长程依赖:有限上下文、二次复杂度和优化难度仍然存在。理解这组收益与代价,比把 Transformer 看成 RNN 的简单替代更重要。
2.2.5 练习
- 回顾该公式,假设
是一个对角矩阵,且对角线元素全部为 。经过 个时间步的沿时间反向传播,最初一步的梯度将衰减到原始大小的多少?这说明了 RNN 训练的什么问题? - 提示:计算
,并结合深度学习中数值下溢的概念进行思考。
- 提示:计算
- 在 Transformer 的缩放点积注意力该公式中,为什么我们必须除以
? - 提示:假设
和 的元素都是均值为 、方差为 的独立随机变量。利用高中统计学中独立变量乘积与求和的期望与方差公式,推导 的方差变化,思考如果不除以 ,随着维度增加,Softmax 函数的输入分布会发生怎样的严重偏移。
- 提示:假设
- 位置编码该公式采用了三角函数。请尝试用高中数学的三角函数和差公式推导:对于任意固定的偏移量
, 能否表示为 的线性函数? - 提示:展开
和 ,寻找它们与 和 的线性关系。
- 提示:展开

