LSTM 与 GRU:留得住的记忆
循环神经网络忘得太快,门控记忆单元修好了这一点。LSTM 与 GRU 如何决定留下什么、丢掉什么,以及它们为何统治了 NLP 十年。
基础 RNN 的记忆是漏的。它的隐藏状态每走一步都被覆盖掉一点,于是靠前的信息还没等到用上就淡了;再加上梯度消失问题,网络连「把它记住」都学不会。1997 年提出、到 2010 年代中期已成主流的 LSTM 就是补上的那一手:给网络一块显式的记忆,让它能主动选择保护。
问题的精确表述
在普通 RNN 里,隐藏状态每一步都被整体重写。你没法对它说「这一条事实接下来 40 个词别动」。每走一步,过去就被抹得更糊一点。网络想把 France 带到后面去预测 French,可真到那一步时,France 已经淡得认不出来了。
LSTM 的答案是另开一条 细胞状态(cell state)——一条贯穿整个序列的记忆传送带,沿途只做少量刻意的修改。信息可以搭着它走上很多步几乎不变形,这正是长距离依赖需要的东西。
门:记忆上的可学习阀门
LSTM 用三个 门(gate)控制细胞状态。每个门都是一个小型可学习层,输出 0 到 1 之间的数——把它想成阀门:0 表示「完全关死」,1 表示「全部放行」。门的取值由当前输入和上一步的隐藏状态算出来,所以网络学的是什么时候开关它们。
- 遗忘门。 看新输入,决定从细胞状态里擦掉什么。句子读到新的主语时,它可能清掉旧主语的语法性别。
- 输入门。 决定把哪些新信息写进细胞状态。新主语的语法性别被存进去。
- 输出门。 决定把细胞状态的哪一部分暴露出来,作为这一步预测所用的隐藏状态。
关键的巧妙之处在遗忘门那条路径上。细胞状态主要是被加上去,而不是被反复相乘,所以梯度能反向流过很多步而不消失。门会学着为重要的信息让这条路保持畅通。这是机制,不是比喻:真正打败梯度消失的,就是这种加法式的细胞状态。
走一遍具体例子
拿这句来说:"The keys, which were on the table, are ___"。要在 are 和 is 之间选 are,网络必须跨越中间整个从句,记住主语是复数(keys)。
- 走到
keys:输入门把「主语是复数」写进细胞状态。 - 经过
which were on the table:遗忘门保住这条复数事实,让从句里的词依次经过而不覆盖它。 - 走到空格处:输出门把「主语是复数」浮上来,模型预测出
are。
普通 RNN 会在从句中间的某处丢掉这个复数标记。LSTM 把它保护在细胞状态上。
GRU:精简版表亲
GRU(gated recurrent unit,门控循环单元)2014 年提出,把 LSTM 做了简化。它把细胞状态和隐藏状态合成一个,门的数量从三个减到两个:
- 重置门——计算新的候选状态时,忽略多少过去的状态。
- 更新门——新旧状态按多大比例混合,一举承担 LSTM 遗忘门和输入门的职责。
门少意味着参数少、训练快。实际用起来,GRU 和 LSTM 在多数任务上表现相当;数据和算力有限时常用 GRU,序列又长又复杂时用 LSTM。怎么选通常靠实验,不靠理论。
它们让什么成为可能
门控 RNN 当了大约十年应用 NLP 的骨干。生产环境的机器翻译、语音识别、文本生成都靠它们撑着。把它们堆成编码器-解码器对,就成了 Google 翻译所跑的序列到序列模型。如果你在 2015 到 2018 年前后用过一个语言类 app,里面多半有 LSTM。
跨不过去的那道坎
LSTM 治好了记忆,没治好串行。
要算第 100 步,LSTM 还是得先按顺序算完第 1 到 99 步,因为每个细胞状态都依赖上一个。这是循环结构自带的,任何门控设计都去不掉。在擅长大规模并行的 GPU 上,这种被迫的串行是训练速度和序列长度的一道硬顶。
还有一个更隐蔽的限制。就算有门控,把一整个长序列塞进一个固定大小的细胞状态,本身就是瓶颈。细节越靠前,越要和它之后的全部内容争夺同一份有限的记忆。门控把有效范围从大约 10 步拉长到几百步,但没有让远距离访问变得免费——后来的自注意力做到了这一点:任意位置一步就能触达任意另一个位置。
这两个限制——串行计算和固定大小的记忆瓶颈——正是 Transformer 要摆脱的东西。transformer 为什么胜出把整个对比并排摆了出来。
要点回顾
- LSTM 增加了一条显式的 细胞状态,一块贯穿序列、只做刻意修改的记忆。
- 三个 门(遗忘、输入、输出)学会擦掉什么、写入什么、暴露什么;加法式的细胞状态打败了梯度消失。
- GRU 用两个门和更少的参数做同样的事,实际表现相当。
- 门控 RNN 撑起了大约十年的生产级翻译和语音。
- 它们修好了记忆,没修好 串行处理,固定大小的状态仍是瓶颈。这些限制终结了 RNN 时代。
下一篇: 序列到序列——把两个 RNN 串起来,把一段序列变成另一段,这就是神经翻译背后的架构。