跳转到内容

GRU 2014 — 用两个门替代 LSTM 三个门,编码-解码范式登场

是什么

GRU(Gated Recurrent Unit,门控循环单元)是 RNN 的一种改进版。日常类比:把 LSTM 三个调节旋钮砍成两个,少一个但效果差不多。

同一篇论文里 Cho 还提出了编码-解码(Encoder-Decoder)结构:一个 RNN 读完整句话把意思”压”成一个向量,另一个 RNN 根据这个向量一个词一个词生成翻译。

为啥这两件事在同一篇?因为 Cho 当时是为了给统计机器翻译(SMT)里的短语对打分,需要一个”读句子→给分数”的网络,顺手把循环单元也简化了。这两个副产品后来都比 SMT 本身更出名。

为什么重要

不读这篇,下面这些事接不上:

  • 为什么 PyTorch 里 nn.GRUnn.LSTM 并列存在——GRU 这个名字就是从这篇出来的
  • 为什么 seq2seq 的图都画成 “encoder + decoder + 中间一个圆点”——这个范式从这里来
  • 为什么 Bahdanau 2015 attention 论文一上来就批判”固定长度向量是瓶颈”——批判的就是 Cho 这篇
  • 为什么 transformer 之前 RNN 翻译的标准结构是 encoder-decoder

核心要点

GRU 的两个门

LSTM 有 3 个门(input / forget / output)外加一个 cell state。GRU 砍到 2 个门:

  1. 重置门(reset gate)r_t:像橡皮擦。决定旧记忆 h_{t-1} 进入”候选新状态”时被擦掉多少。r=0 表示完全忘记,r=1 表示完全保留。
  2. 更新门(update gate)z_t:像调音台滑块。决定最终状态里,新候选和旧状态的混音比例。z=0 完全用旧的,z=1 完全用新的。

完整算式(4 行):

r_t = σ(W_r·x_t + U_r·h_{t-1}) # 重置门
z_t = σ(W_z·x_t + U_z·h_{t-1}) # 更新门
h~_t = tanh(W·x_t + U·(r_t ⊙ h_{t-1})) # 候选状态
h_t = (1-z_t) ⊙ h_{t-1} + z_t ⊙ h~_t # 最终状态(线性插值)

σ 是 sigmoid, 是逐元素乘。最后一行是关键——它直接在旧状态和新候选之间做加权平均,没有 LSTM 那种”先存 cell 再输出”的两层结构。

编码-解码范式

源句子 x → [Encoder RNN] → c (固定长度向量) → [Decoder RNN] → 目标句子 y
  • 编码器:吃完整句源语言,最后一步隐状态当作 c,代表”整句意思”
  • 解码器:从 c 出发,每一步看 c + 已生成的前几个词 + 当前隐状态,预测下一个词
  • 训练目标:最大化 log P(y|x),端到端可微,反传穿过 encoder 和 decoder

类比:同声传译员先听完一整段话,在脑子里压成一个”意思总结”,再根据这个总结开口翻译。

实践案例

案例 1:PyTorch 里直接用 GRU

import torch.nn as nn
gru = nn.GRU(input_size=128, hidden_size=256, batch_first=True)
# 比 LSTM 参数少约 25%(3 个权重矩阵 vs 4 个)

nn.GRU 这个 API 直接源自 Cho 2014。框架默认给你的就是上面 4 行算式的实现。

案例 2:最小 encoder-decoder(伪代码)

# Encoder
for x_t in source_sentence:
h = gru_enc(x_t, h)
c = h # 整句压成一个向量
# Decoder
y_prev = <BOS>
for _ in range(max_len):
s = gru_dec(concat(y_prev, c), s)
y_prev = softmax(W_out · s)
if y_prev == <EOS>: break

逐部分解释

  • 编码器一路滚到底,最后那个 h 就是上下文 c
  • 解码器每一步都把 c 拼到输入里(防止它”忘记”源句)
  • <BOS>/<EOS> 是开始/结束特殊 token

案例 3:论文里 GRU 真的用在哪

很多人以为 Cho 2014 是端到端神经机器翻译——不是。论文里:

  • 主系统还是 Moses(统计 MT 工具链)
  • RNN encoder-decoder 只是给”源短语→目标短语”对打个条件概率分数
  • 这个分数当作 Moses 的一个额外特征,和其他 14 个特征一起调权重

真正端到端的 NMT 是同年 Sutskever 的 seq2seq(用 LSTM)和次年 Bahdanau 的 attention。

踩过的坑

  1. GRU 没有独立 cell state:LSTM 的 cell 和 hidden 是分开的,GRU 把它们合一。长程依赖很强的任务(比如复制超长序列)有时 LSTM 还是更稳。

  2. reset 和 update 容易记反:reset 控历史进入候选的程度,update 控候选 vs 旧状态的混合比例。一个管”输入端”,一个管”输出端”。

  3. GRU 不一定比 LSTM 好:Cho 2014 没做严格对比,Chung 2014 后续在多任务上得出”差不多”的结论。工程上 GRU 训练略快,但参数少不必然代表泛化更好。

  4. 固定长度 c 是死穴:长句翻译质量急剧下降,因为整句要压进一个 256 维向量。Bahdanau 2015 用 attention 直接打掉这个瓶颈——decoder 每一步重新看一遍源序列加权和。

  5. 以为这篇是 NMT 起点:严格说 NMT 起点是 Sutskever 2014(端到端 LSTM)和 Bahdanau 2015(attention)。Cho 2014 是范式提出 + GRU,但实际系统是 SMT。

适用 vs 不适用场景

适用

  • 序列建模任务里需要循环结构 + 参数比 LSTM 少(嵌入式、移动端)
  • 中等长度序列(< 100 step)的分类、生成、翻译
  • 教学场景:GRU 算式短,更适合手推一遍

不适用

  • 极长依赖(千 step 级别)→ Transformer 或 LSTM 更稳
  • 需要严格并行化训练 → RNN 系列时间步串行,全军覆没,用 Transformer
  • 多模态、多任务大模型 → 标准做法已经全是 attention-based

历史小故事(可跳过)

  • 2014.06:Cho、Bengio 团队(蒙特利尔大学 + LISA 实验室)投 EMNLP 2014,目标是改进 SMT
  • 2014.09:Sutskever 在 NIPS 发表 seq2seq,用 LSTM 做端到端英法翻译,第一次证明纯神经 MT 可行
  • 2014.12:Chung 等在 NIPS Workshop 系统对比 GRU vs LSTM vs tanh-RNN,结论”GRU 和 LSTM 接近,都显著好于 tanh”
  • 2015.05:Bahdanau 把 attention 装进 encoder-decoder,直接打破固定长度瓶颈,BLEU 暴涨
  • 2017:Transformer 出现,RNN 系列在主流 NMT 退场

GRU 单元本身一直留下来——简单、参数少、效果够用。

学到什么

  1. 门控可以更简洁——3 个门未必比 2 个门强,工程里少一个调参旋钮反而省事
  2. Encoder-Decoder 是 seq2seq 的母板——后续 attention / Transformer 的输入输出形态都是这个
  3. 固定长度上下文是诅咒——任何”把整句话压成一个向量”的设计在长输入上都会崩
  4. 范式比单元重要——GRU 是个改进,但 encoder-decoder 范式才是这篇真正改变深度学习走向的贡献

延伸阅读

关联

  • lstm —— GRU 简化自 LSTM 的门控思想
  • attention —— 直接动机:打破 encoder-decoder 的固定长度瓶颈
  • seq2seq —— Sutskever 同年的端到端版本,用 LSTM 但是同范式
  • transformer-2017 —— 终结 RNN 时代,但 encoder-decoder 形态保留
  • bengio-rnn-2003 —— 神经语言模型早期工作,同实验室

反向链接

  • attention —— Attention Is All You Need
  • bert4rec-2019 —— BERT4Rec — 把 BERT 的 MLM 搬进序列推荐做双向建模
  • koren-mf-2009 —— Koren-Bell-Volinsky 2009 — 把推荐系统的 MF 写成 8 页教科书
  • rwkv-2023 —— RWKV — 让 RNN 拿到 Transformer 那张训练并行的入场券
  • sasrec-2018 —— SASRec — 用 Transformer 的 self-attention 替 RNN 做下一步推荐