2. 序列到序列模型基础:RNN、LSTM、GRU的原理与局限

说到Transformer,得先聊聊它的「前任」们。

序列到序列(Seq2Seq)这个任务,说白了就是「一段进去,一段出来」。翻译、语音识别、文本摘要,全是这类问题。Transformer之前,大家靠的是循环神经网络(RNN)家族。我今天带你过一遍这三个核心成员:原始RNN、LSTM、GRU。你得理解它们为什么被设计成这样,又为什么最终被Transformer取代。

2.1 原始RNN:最朴素的记忆体

RNN的想法很直觉:让网络有「记忆」。处理当前词时,看一眼前一个词留下的状态。

结构长这样:

  • 输入:当前时刻的词向量 xₜ
  • 隐藏状态:hₜ = tanh(Wₓ xₜ + Wₕ hₜ₋₁ + b)
  • 输出:yₜ = softmax(Wₕ hₜ + bₒ)

简单吧?但简单背后藏着大问题。

核心公式(你记一下):

hₜ = tanh(Wₓ * xₜ + Wₕ * hₕ₋₁ + b)
yₜ = softmax(Wₕ * hₜ + bₒ)

举个例子。假设我们要翻译:

"I am from China, and I love eating dumplings."

当你生成"我来自中国"时,需要记住"China"在句首。RNN靠hₜ一路传递这个信息。如果句子短,够用。但句子一长——比如说100个词——早期信息早就被tanh压碎了。

2.2 梯度消失与梯度爆炸:RNN的致命伤

为什么会这样?

你想想看,RNN在时间步上展开后,就是一个超深的网络。反向传播时,梯度要一路往回传。链式法则一乘,如果激活函数是tanh或sigmoid,导数小于1,连乘几次就趋近于0。这就是梯度消失。

反过来,如果Wₕ的范数大于1,梯度会指数级增长,变成梯度爆炸。

避坑指南:

我在项目里遇到过,模型训练到一半loss突然变成NaN,十有八九是梯度爆炸。解决方案倒是简单——梯度裁剪(gradient clipping),设定一个阈值,超过就直接截断。但我曾经因为忘记加这个,白跑了两天实验。

梯度消失更隐蔽。模型能训练,loss也在降,但长距离依赖就是学不会。我做个机器翻译,50个词以内的还能看,超过100个词直接崩了——前面主语的信息根本传不到后面。

2.3 LSTM:加了三个「门」的升级版

长短期记忆网络(LSTM)是1997年提出的,但直到2014年左右才大规模用起来。它比RNN多了三个门控机制:

  1. 遗忘门:决定丢掉哪些旧信息。fₜ = σ(W[ xₜ, hₜ₋₁ ] + b)
  2. 输入门:决定写入哪些新信息。iₜ = σ(W[ xₜ, hₜ₋₁ ] + b)
  3. 输出门:决定输出哪些给下一时刻。oₜ = σ(W[ xₜ, hₜ₋₁ ] + b)

还有一个细胞状态(cell state)Cₜ,这是LSTM的核心。它像一条传送带,信息可以在上面直通,不受非线性挤压。门控机制控制哪些信息进、哪些信息出。

我个人的理解方式:

把细胞状态想象成一个记笔记的本子。遗忘门决定撕掉哪些页,输入门决定新写哪些内容,输出门决定这一时刻翻到哪一页给别人看。你看,是不是好记多了?

LSTM确实缓解了梯度消失问题,但代价是参数量翻了好几倍。一个LSTM单元有4组权重矩阵(遗忘、输入、输出、候选状态),训练速度远低于原始RNN。

2.4 GRU:轻量化的替代方案

门控循环单元(GRU)是2014年提出的,比LSTM晚。它把LSTM的三个门简化为两个:

  1. 更新门zₜ:合并了遗忘门和输入门的功能
  2. 重置门rₜ:控制历史信息对当前候选状态的影响

GRU没有单独的细胞状态,直接把隐藏状态hₜ当记忆体用。结构更简洁,参数量更少。

参数量对比(假设输入维度d=512,隐藏维度d=256):

原始RNN: 4 * d * d = 524,288
LSTM:   16 * d * d = 2,097,152
GRU:    12 * d * d = 1,572,864

GRU在参数量上比LSTM少了约25%,在很多任务上效果差不多。我在做文本生成项目时做过对比,GRU训练速度快了30%,BLEU分数只低了0.2个点。性价比很高。

2.5 三者的对比表格

我做了一张表,方便你对照选择:

模型 核心机制 参数量(相对) 长距离依赖 训练速度 适用场景
原始RNN 隐藏状态循环 低(1倍) 差(20步以上几乎无效) 快 短序列、简单任务
LSTM 门控+细胞状态 高(4倍) 好(可记忆100步以上) 慢 长序列、精度优先
GRU 门控+简化结构 中(3倍) 较好(接近LSTM) 中 工程落地、速度与效果平衡

经验之谈:

我踩过一个坑:做金融时序预测时,以为数据越长越准,直接用LSTM吃了2000个时间步。结果训练了三天,loss死活降不下去。后来才意识到,LSTM虽然能记长距离,但2000步的梯度路径太深,局部细节反而学不好。最后切成了滑动窗口+双向LSTM,效果才出来。别迷信长序列。

2.6 无法绕过的根本局限

RNN家族(包括LSTM和GRU)有三个硬伤,这也是Transformer能取而代之的原因:

  • 串行计算:t时刻必须等t-1时刻算完,GPU并行能力被浪费。想想看,一个200词的句子要串行跑200步,而Transformer一步到位。
  • 长距离依赖仍然不够好:LSTM/GRU虽然比RNN强,但当我需要记住第1个词和第100个词的关系时,信息早就被衰减或压缩了。Transformer的注意力机制可以直接看任意两个位置。
  • 训练不稳定:梯度爆炸虽然能用裁剪解决,但超参数调起来很烦。我见过团队花一周调LSTM的学习率和梯度阈值,换成Transformer两天就收敛了。

下面这张图总结了它们的演进关系,你看一眼:

RNN → LSTM → GRU 的演进关系 原始 RNN 简单记忆 梯度消失严重 LSTM 三门控 + 细胞状态 参数量大 GRU 双门控 + 简化 参数量适中 增加遗忘门/输入门/输出门 合并为更新门/重置门 ⚠ 共同局限 1. 串行计算,无法充分利用 GPU 并行 2. 长距离依赖仍然不够理想 3. 超参数敏感,训练不稳定 最终被 Transformer 取代

2.7 回头看:为什么需要Transformer?

有了前面的铺垫,现在你就能理解Transformer的设计动机了。

RNN/LSTM/GRU的核心问题是顺序依赖。你必须按时间步一个一个算,GPU的并行能力被浪费了。而且,不管你用多复杂的门控,信息在长距离传递中总会衰减。

Transformer的方案是:不要递归,用注意力机制。一次性看到整个序列,任意两个位置直接建立联系。这既解决了并行问题,也解决了长距离依赖问题。

但别急着否定RNN家族。我在实际项目中发现,对于短序列(比如<20个词)、实时推理场景(计算资源受限)、或者与CNN结合的特征提取,LSTM和GRU仍然有它们的用武之地。而且,Transformer的很多思想(位置编码、多头注意力)是在解决RNN的问题时被逼出来的。理解这些「前任」,你才能把「现任」用得更好。

小结:

记住三个关键点:

  • RNN因梯度消失无法处理长序列
  • LSTM用门控缓解了问题,但参数量大、训练慢
  • GRU是轻量化替代,参数少、效果接近

它们的共同硬伤是串行计算和长距离依赖不完美,这就是Transformer诞生的直接原因。