跳到主要内容

第3章:序列建模——语言比图像难在哪里

上一章我们看到,CNN 用局部感受野和权重共享征服了图像识别。图像有一个让人省心的性质:一张 224×224 的图,输入维度永远是固定的。但语言不是这样。"猫跑了"是 3 个字,"这只住在我家楼道里、浑身雪白的猫昨天突然跑了"是 19 个字——两句话的意思有关联,但长度完全不同。这只是语言难题的冰山一角。


3.1 语言的本质难点

3.1.1 不定长输入

图像可以统一 resize,文本不行。强行截断或补零会破坏语义。神经网络的标准设计假设输入维度固定,语言天然违反这个假设。

3.1.2 长程依赖(Long-range Dependency)

考虑这个句子:

"The keys to the cabinet are on the table."

动词 are 的数(复数)由主语 keys 决定,而不是紧邻的 cabinet(单数)。模型必须"记住"几个词之前的信息来做出正确预测。更极端的例子:

"The man who said that the woman who studied linguistics at MIT had published a paper was wrong."

主语 man 和谓语 was 之间隔了整整一个从句。

3.1.3 顺序敏感

"狗咬人"和"人咬狗",词相同但顺序不同,意义截然相反。语言中词序携带了核心语义信息,这与图像中像素的空间位置有本质不同——你很少会在意两个像素的相对顺序,但单词的顺序至关重要。

3.1.4 CNN 为什么不适合语言

CNN 的卷积核大小固定(比如 3×3),感受野有限。虽然可以堆叠多层来扩大感受野,但:

  1. 捕捉距离为 kk 的依赖需要 O(k/kernel_size)O(k/\text{kernel\_size}) 层,对长距离依赖代价高昂。
  2. CNN 假设特征局部平移不变,但"不是好"和"是好"这两个短语,"不"的位置不同会导致截然相反的语义,局部平移不变性在语言中往往不成立。

:::warning 直觉小结 图像的核心挑战是空间不变性(同一个猫在图片哪个角落都算猫)。语言的核心挑战是时序依赖(词的顺序和上下文决定意义)。这两个问题需要完全不同的工具。 :::


3.2 RNN(循环神经网络)

面对不定长输入和时序依赖,研究者的第一个解法是:让网络有记忆

3.2.1 核心思想:隐状态传递记忆

RNN(Recurrent Neural Network,循环神经网络)在每个时间步 tt 处理一个词,同时维护一个隐状态(hidden state)hth_t,它扮演"工作记忆"的角色:

ht=tanh(Whht1+Wxxt+b)h_t = \tanh(W_h h_{t-1} + W_x x_t + b) yt=Wyhty_t = W_y h_t

其中 xtx_t 是当前输入词的向量,ht1h_{t-1} 是上一步的隐状态,WhW_hWxW_xWyW_y 是共享的权重矩阵。

x₁ x₂ x₃ x₄
↓ ↓ ↓ ↓
□ → □ → □ → □ ← 每个方块是同一个 RNN cell,共享权重
h₀ h₁ h₂ h₃

这个设计解决了两个问题:

  • 不定长输入:逐词处理,序列多长都行。
  • 记忆传递hth_t 理论上包含了 x1,x2,,xtx_1, x_2, \ldots, x_t 的信息。

3.2.2 致命缺陷:梯度消失

RNN 的训练使用 BPTT(Backpropagation Through Time,时序反向传播)。计算第 tt 步损失对第 11 步参数的梯度时,需要把梯度从 tt 一路乘回到 11

Lh1=Lhtk=2thkhk1\frac{\partial L}{\partial h_1} = \frac{\partial L}{\partial h_t} \cdot \prod_{k=2}^{t} \frac{\partial h_k}{\partial h_{k-1}}

每一步的 hkhk1=diag(tanh())Wh\frac{\partial h_k}{\partial h_{k-1}} = \text{diag}(\tanh'(\cdot)) \cdot W_h。如果 Wh<1\|W_h\| < 1,这个乘积随 tt 指数衰减趋向 0——梯度消失(vanishing gradient);如果 Wh>1\|W_h\| > 1,则指数爆炸。

具体后果:在实践中,RNN 基本只能"记住"最近 10-20 步的信息。句子一长,早期词的梯度信号就消失了,模型学不到长程依赖。

另一个问题是无法并行hth_t 依赖 ht1h_{t-1},必须串行计算,无法利用 GPU 的并行能力。训练一段长文本极其耗时。

:::info 直觉类比 RNN 像一个只有短期记忆的人,看书时每读一个词就把前面的内容稍微淡忘一点。读到第 50 个词时,第 1 个词几乎已经被彻底遗忘。 :::


3.3 LSTM(1997)

1997 年,Hochreiter 和 Schmidhuber 提出了 LSTM(Long Short-Term Memory,长短期记忆网络),专门解决梯度消失问题。

3.3.1 核心思想:门控机制 + 细胞状态高速公路

LSTM 在隐状态 hth_t 之外,引入了第二条信息流:细胞状态(cell state)CtC_t。它像一条"高速公路",信息可以不经过复杂变换而直接流过多个时间步,梯度也因此不会指数衰减。

LSTM 用三个(gate)来控制信息的流入和流出:

公式作用
遗忘门(forget gate)ft=σ(Wf[ht1,xt]+bf)f_t = \sigma(W_f [h_{t-1}, x_t] + b_f)决定忘掉 Ct1C_{t-1} 的哪些部分
输入门(input gate)it=σ(Wi[ht1,xt]+bi)i_t = \sigma(W_i [h_{t-1}, x_t] + b_i)决定写入多少新信息
输出门(output gate)ot=σ(Wo[ht1,xt]+bo)o_t = \sigma(W_o [h_{t-1}, x_t] + b_o)决定 CtC_t 有多少输出给 hth_t

候选细胞状态:

C~t=tanh(WC[ht1,xt]+bC)\tilde{C}_t = \tanh(W_C [h_{t-1}, x_t] + b_C)

细胞状态更新——关键所在:

Ct=ftCt1+itC~tC_t = f_t \odot C_{t-1} + i_t \odot \tilde{C}_t

最终输出:

ht=ottanh(Ct)h_t = o_t \odot \tanh(C_t)

其中 σ\sigma 是 sigmoid 函数(输出 0~1,充当"阀门"),\odot 是逐元素乘法。

3.3.2 为什么能解决梯度消失

注意细胞状态的更新公式 Ct=ftCt1+itC~tC_t = f_t \odot C_{t-1} + i_t \odot \tilde{C}_t——梯度从 CtC_t 反传到 Ct1C_{t-1} 时,只需乘以 ftf_t(而非 WhW_h 的矩阵乘法)。如果遗忘门 ft1f_t \approx 1,梯度几乎原样流过,不会衰减。这条"细胞状态高速公路"使得 LSTM 能维持数百步的梯度传播。

:::tip 门控的直觉 把 LSTM 想象成一个有选择能力的秘书:遗忘门决定"哪些旧记录可以扔掉",输入门决定"今天新来的信息哪些值得记录",输出门决定"汇报时展示记录的哪个部分"。RNN 的秘书只会机械地把所有东西混在一起,而 LSTM 的秘书会主动管理记忆。 :::

3.3.3 仍然存在的问题

LSTM 虽然解决了梯度消失,但两个根本局限依然存在:

  1. 顺序计算,无法并行CtC_thth_t 都依赖前一步,序列必须串行处理。在 2014 年以后,随着训练数据规模爆炸式增长,这成为严重瓶颈。
  2. 长序列仍然力不从心:虽然比 RNN 好很多,但当序列长度达到数百甚至数千时,早期信息仍然难以被准确保留。信息的"压缩损耗"不可避免。

3.4 Seq2Seq 与注意力机制的萌芽(2014–2015)

3.4.1 Seq2Seq:Encoder 压缩成向量,Decoder 还原

2014 年,Google 的 Sutskever 等人提出 Seq2Seq(Sequence-to-Sequence)架构,用于机器翻译:

输入: "我 爱 北京"
↓ Encoder (LSTM)
[context vector c] ← 整个句子压缩进这一个向量
↓ Decoder (LSTM)
输出: "I love Beijing"

Encoder 逐词读入源语言句子,最终的隐状态 c=hTencc = h_T^{enc} 被称为上下文向量(context vector),代表整个句子的语义。Decoder 以 cc 为初始状态,逐词生成目标语言。

这个架构思路简洁,但有一个致命弱点。

3.4.2 信息瓶颈(Information Bottleneck)

无论源句子有多长,都必须被压缩进固定维度(比如 512 维)的向量 cc。翻译"猫跑了"(3 词)和翻译一段 100 词的段落,Decoder 能用的信息载体大小完全一样。

实验结果清晰地显示:Seq2Seq 在短句(≤20 词)上表现优秀,但句子越长,翻译质量下降越明显。直觉上也很显然——让一个人记住一首诗的全部细节,再用一张便利贴把整首诗的意思写下来,本来就是不可能完成的任务。

:::warning 信息瓶颈的量化直觉 假设每个词需要约 10 bits 的信息量,一个 512 维的 float32 向量有约 16000 bits 的容量。听起来够用,但实际上向量空间的"有效维度"远小于理论上限,而且 Decoder 在解码时对向量的访问是固定的,无法"查询"特定位置。 :::

3.4.3 Bahdanau Attention:解码时回头看原句每个位置

2015 年,Bahdanau 等人(蒙特利尔大学)发表了《Neural Machine Translation by Jointly Learning to Align and Translate》,提出了一个绕过信息瓶颈的方案:让 Decoder 在每一步解码时,直接访问所有 Encoder 隐状态的加权组合。

具体机制如下:

设 Encoder 的所有隐状态为 h1enc,h2enc,,hTench_1^{enc}, h_2^{enc}, \ldots, h_T^{enc},Decoder 在第 tt 步的隐状态为 st1s_{t-1}

第一步:计算对齐分数(alignment score),衡量"解码第 tt 个词时,应该关注源句第 ii 个词多少":

et,i=a(st1,hienc)e_{t,i} = a(s_{t-1}, h_i^{enc})

其中 aa 是一个小型神经网络(原文用单隐层 MLP):

et,i=vatanh(Wast1+Uahienc)e_{t,i} = v_a^\top \tanh(W_a s_{t-1} + U_a h_i^{enc})

第二步:用 softmax 归一化得到注意力权重(attention weights):

αt,i=exp(et,i)j=1Texp(et,j)\alpha_{t,i} = \frac{\exp(e_{t,i})}{\sum_{j=1}^T \exp(e_{t,j})}

第三步:加权求和,得到当前步的上下文向量:

ct=i=1Tαt,ihiencc_t = \sum_{i=1}^T \alpha_{t,i} \cdot h_i^{enc}

第四步:用 ctc_tst1s_{t-1} 更新 Decoder 隐状态并生成输出词。

步骤Seq2Seq(无注意力)Bahdanau Attention
Decoder 能看到什么固定的 cc(全句压缩)动态的 ctc_t(加权全句)
信息访问方式一次性,静态每步重新计算,动态
长句翻译质量显著下降大幅提升

3.4.4 注意力机制的起源:一个对齐工具

Bahdanau 注意力的可视化非常直观——对于翻译"European Economic Area"→"zone économique européenne",注意力权重矩阵清楚地显示出"économique"在生成时主要关注"Economic",尽管法语词序与英语不同。

但在 2015 年,注意力机制只是 RNN 的一个附加模块(add-on),核心的序列处理仍然依赖 LSTM。每步的 αt,i\alpha_{t,i} 计算需要 Encoder 已经跑完,Decoder 仍然是串行的。并行化问题没有解决,只是翻译质量提升了。

:::info 2015 年的认知边界 当时学界的共识是:RNN/LSTM 处理序列,注意力帮助 RNN 记得更好。没有人认真设想过——注意力本身能不能成为序列建模的主角,完全替代 RNN? :::


本章小结

模型解决的问题引入的新问题
RNN不定长输入、时序记忆梯度消失、无法并行、长依赖学不好
LSTMRNN 的梯度消失仍然顺序计算、超长序列仍力不从心
Seq2Seq端到端序列转换固定向量的信息瓶颈
Bahdanau Attention打破信息瓶颈,动态访问编码器仍依附于 RNN,无法并行

每一代技术都是被上一代的具体失败场景逼出来的。RNN 无法记住 50 词前的内容,于是有了 LSTM 的门控机制;LSTM 把整句话压进一个向量,于是有了注意力机制让 Decoder 回头查看每个位置。

到 2015 年,注意力机制已经证明了自己的价值——但它还被当作 RNN 的"辅助工具"。一个自然而大胆的问题浮现出来:既然注意力机制如此强大,能不能把 RNN 完全去掉,让注意力机制独立担当序列建模的全部工作? 这个问题的答案,将在 2017 年彻底改变深度学习的格局。