GRU 2014 — 用两个门替代 LSTM 三个门,编码-解码范式登场
是什么
GRU(Gated Recurrent Unit,门控循环单元)是 RNN 的一种改进版。日常类比:把 LSTM 三个调节旋钮砍成两个,少一个但效果差不多。
同一篇论文里 Cho 还提出了编码-解码(Encoder-Decoder)结构:一个 RNN 读完整句话把意思”压”成一个向量,另一个 RNN 根据这个向量一个词一个词生成翻译。
为啥这两件事在同一篇?因为 Cho 当时是为了给统计机器翻译(SMT)里的短语对打分,需要一个”读句子→给分数”的网络,顺手把循环单元也简化了。这两个副产品后来都比 SMT 本身更出名。
为什么重要
不读这篇,下面这些事接不上:
- 为什么 PyTorch 里
nn.GRU和nn.LSTM并列存在——GRU 这个名字就是从这篇出来的 - 为什么 seq2seq 的图都画成 “encoder + decoder + 中间一个圆点”——这个范式从这里来
- 为什么 Bahdanau 2015 attention 论文一上来就批判”固定长度向量是瓶颈”——批判的就是 Cho 这篇
- 为什么 transformer 之前 RNN 翻译的标准结构是 encoder-decoder
核心要点
GRU 的两个门
LSTM 有 3 个门(input / forget / output)外加一个 cell state。GRU 砍到 2 个门:
- 重置门(reset gate)
r_t:像橡皮擦。决定旧记忆h_{t-1}进入”候选新状态”时被擦掉多少。r=0表示完全忘记,r=1表示完全保留。 - 更新门(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 nngru = 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(伪代码)
# Encoderfor x_t in source_sentence: h = gru_enc(x_t, h)c = h # 整句压成一个向量
# Decodery_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。
踩过的坑
-
GRU 没有独立 cell state:LSTM 的 cell 和 hidden 是分开的,GRU 把它们合一。长程依赖很强的任务(比如复制超长序列)有时 LSTM 还是更稳。
-
reset 和 update 容易记反:reset 控历史进入候选的程度,update 控候选 vs 旧状态的混合比例。一个管”输入端”,一个管”输出端”。
-
GRU 不一定比 LSTM 好:Cho 2014 没做严格对比,Chung 2014 后续在多任务上得出”差不多”的结论。工程上 GRU 训练略快,但参数少不必然代表泛化更好。
-
固定长度
c是死穴:长句翻译质量急剧下降,因为整句要压进一个 256 维向量。Bahdanau 2015 用 attention 直接打掉这个瓶颈——decoder 每一步重新看一遍源序列加权和。 -
以为这篇是 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 单元本身一直留下来——简单、参数少、效果够用。
学到什么
- 门控可以更简洁——3 个门未必比 2 个门强,工程里少一个调参旋钮反而省事
- Encoder-Decoder 是 seq2seq 的母板——后续 attention / Transformer 的输入输出形态都是这个
- 固定长度上下文是诅咒——任何”把整句话压成一个向量”的设计在长输入上都会崩
- 范式比单元重要——GRU 是个改进,但 encoder-decoder 范式才是这篇真正改变深度学习走向的贡献
延伸阅读
- 论文 PDF:Cho 2014 arXiv(10 页,3、4 节是 GRU 和 encoder-decoder)
- 对比实验:Chung 2014 — Empirical Evaluation of Gated RNN(GRU vs LSTM 经典对照)
- 可视化讲解:Chris Olah — Understanding LSTMs(最后一节专门讲 GRU 变体)
- lstm —— GRU 的前身,三个门的完整版
- attention —— Bahdanau 2015,专门打击固定长度
c瓶颈
关联
- 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 做下一步推荐