三、长短期记忆网络LSTM
循环神经网络的特点就是拥有"记忆",就是考虑历史信息,从历史信息中获取辅助当前的决策。
按记忆能力分:simple rnn(就是前面讲的简单rnn结构)、长短期记忆网络(LSTM)、门控循环单元(GRU)、以及双向RNN(Bi-RNN),这些都是RNN的变体。从RNN->GRU->LSTM,网络的记忆能力更强、计算复杂度更大、实际使用更多。
本篇重点讲LSTM。其实你只要把LSTM吃透,其他变体都会轻松理解的。
(一)LSTM简介
LSTM算法来自1997年Hochreiter & Schmidhuber发表的《Long short-term memory》论文,论文指出,用我们前面学的Simple RNN架构学习较长时间间隔的任务(也就是捕捉长距离关系时)通常需要很长的时间。这是因为误差在反传的过程中容易出现梯度爆炸或者梯度消失,网络训练很久也无法收敛。通俗的说就是Simple RNN无法记住长距离的信息,比如第一个词是个人名,第十个词是他/她,Simple RNN就判断不出他/她指的是谁了,就是学到第十个词,就把第一个词忘记了。what?这怎么行呢?循环神经网络就是要学习词与词之间的关系的一个网络啊?为了解决这个问题,他们提出了长短期记忆网络Long Short Term:LSTM。
虽然《Long short-term memory》这篇论文在RNN领域,乃至DP领域都是极为重要的论文之一。但是论文并没有从理论上论述LSTM为什么能够缓解梯度消失问题,当然也不保证LSTM不存在梯度消失问题,甚至连门结构为什么这么设计也没有解释。至今在网上仍然存在各种理解和争论,而其为什么能缓解梯度消失的理论依据仍然是缺失的。
此后LSTM被Alex Graves进行了改良和推广,LSTM通过特殊的单元结构实现了稳定的信息流动,从而能够学习跨越超过1000个时间步长的任务,同时极大的避免了误差反向传播过程中可能出现的梯度消失或爆炸问题,使得RNN真正意义上能够好用。
很多初学者学习LSTM,建议先看看ChristopherOlah的博文《理解LSTM网络》 https://colah.github.io/posts/2015-08-Understanding-LSTMs/ ,这篇文章非常经典,网上流传也相当之广,是你较快入门LSTM的博文。
(二)LSTM原理及架构
其实如果你是初学者,一上来就学LSTM,可能还真是有一些难度的。所以这里建议你先认认真真看看一看Simple RNN: 【NLP】第二章:循环神经网络RNN、DRNN、 BRNN_rnn循环神经网络csdn-CSDN博客 ,再来看本篇,会好理解一些。
理科真不像文科可以跳着学,理科就得基础一点点打牢,环环相扣的理解下来。如果Simple RNN你都看不懂,那就建议你从机器学习看起:https://blog.csdn.net/friday1203/category_12824289.html ,然后再看深度学习。
1、从整体架构上看
下图上半部分是Simple RNN的架构,下半部分是LSTM的宏观架构。看到架构你心中要明确下面几点:
(1)Simple RNN和LSTM都是具有一种重复神经网络模块的链式的形式。
都是一种使用简单的神经网络模块重复而成的链式结构。你可以想象成搭积木,你可以把RNN想象成是sequence_length个b,依次罗列起来的B,LSTM是sequence_length个c依次罗列起来的C。b和c就是不同的神经网络模块,B和C就是重复的链式结构。RNN和LSTM不同之处仅仅就在于重复积木块不一样,但其重复方式都是一样的,都是根据sequence_length长度进行重复的。
(2)Simple RNN和LSTM的链式结构是时间维度上的链条,不是空间维度上的链条。
我们都知道,RNN和LSTM都是依次处理序列数据的,所以B和C都是一个循环链,就是按时间维度串在一起的链条,而非像FNN\CNN那种,是空间维度上串在一起的链条。所以泛化到任一时刻,它们的架构就是一个b模块(Simple RNN),一个c模块(LSTM),因为仅仅是在时间维度上每个时间步样本依次传播了一次而已,不是空间维度上的传播。
(3)循环网络的链式结构在时间维度上的链条长度是多少呢?
上图中xt是输入序列在t时刻的输入向量。输入序列中有多少个时间步,就将隐藏层展开多少次,每个步态状态对应于展开出来的一个隐藏层。所以链条长度就是你循环了多少次。也就是你一个sequence有几个时间步,链条就有多长。
(4)从哪里能看到循环网络的"记忆"?
循环网络之所以有别FNN/CNN,就是它有"记忆"样本和样本之间信息的能力,这种能力主要是通过它的信息传递方式来实现的,就是通过时间维度上的循环流。
对于SimpleRNN网络来说,其重复模块就是一个隐藏层,隐藏层是捕捉序列信息的,我们称之为"记忆单元",就是上图的ht。
对于LSTM网络来说,它的重复模块叫细胞,细胞上的Ct,Ct叫细胞状态,细胞状态就是记忆样本与样本之间的信息的。
(5)网络的输入
对于RNN的输入来说,并不是每次都必须等步长输入的,就是可以变步长输入,就是没有要求你所有的输入都是等步长,你有几步就循环几次好了,不是说我必须要求都要是比如10步,必须要循环10次,不是的,你有几步循环几次即可。
(6)网络的输出
同理每一时间步都会有输出,但也并不是每个时间步都必须输出的,这个得看我们的任务。不同类型NLP任务会有不同的输出层结构、也就是会有不同的标签输出方式。例如,在对词语/样本进行预测的任务中(比如词性标注、NER实体识别等任务),RNN会在每个时间步都输出词语对应的相应预测标签。但是在对句子进行预测的任务中(例如生成式任务、seq2seq的任务、对句子进行情感分类任务等),RNN可能就只会在最后一个时间步输出句子相对应的预测标签。
(7)网络的训练方式
由于循环神经网络的输出标签的方式不同,所以反向传播的流程自然会和前面学的FNN\CNN有所区别。循环神经网络的训练和普通FNN、CNN网络的训练都不一样,循环神经网络的反向传播是通过时间的反向传播(Backpropagation Through Time, BPTT) 。至于什么是BPTT我们这里不展开,回头单独拿出来讲,避免失焦。
(8)Simple RNN 在训练中比普通的FNN更容易遇到梯度消失或者梯度爆炸
反向传播就是反向求导的,而求导的链式法则和非线性函数的使用,使得反向传播中会有梯度消失和爆炸问题。在文章《On the difficulty of training recurrent neural networks》中就有详细的解释和实验,其表明:BPTT无法解决长时依赖问题(即当前的输出与前面很长的一段序列有关,一般超过十步就无能为力了),因为BPTT会带来所谓的梯度消失或梯度爆炸问题(the vanishing/exploding gradient problem)。也就是说随着时间步的增加,Simple RNN会丧失记忆远信息的能力。
(9)Simple RNN更容易梯度消失的原因
非RNN网络的梯度消失和爆炸通常是采用残差链接(Residual Connection)的方式解决,也就是说给梯度flow建立捷径能够直接反向传播到输入层附近,进而调整这些神经元的权值。而RNN梯度消失与其他深度网络梯度消失虽然原因类似,但却无法通过直连来解决。因为:
RNN是一个时序意义上的深度网络,虽然从表达式上t时刻的loss与之前所有时刻的隐含态h都有关系,即按照时序展开,你会发现已经有类似Residual Connection直接连接每个输入到当前的loss,但是RNN与ResNet的巨大不同在于,这些连接反复使用的都是同一个W。因为Simple RNN是一个时序深度、而非空间深度的网络,所以在每个时间步,其计算的参数W都一样,因为RNN的权值共享嘛。所以普通的FNN都是一连串的、不同的w相乘容易梯度消失,但RNN却是一个w的sequence_size次方这种形式的连乘,并且后面还串一个sigmoid层,都给映射到0-1范围了,所以RNN比FNN更容易梯度消失了。
或者说,RNN在反向传播梯度更新时是矩阵的高次方连乘,且激活函数的导数恒小于1,这就造成在时序上距离远的求导flow路径传输回来的信号太弱,接近0,出现梯度消失的情况。而近处的信号虽然强,但由于共享权值,参数W太简单,很容易就收敛在一个只考虑近处信号的简单神经网络的局部最优解,而这个解通常不是整个网络的局部最优。因此,RNN就在这样一个连局部最优解都不是的位置上训练缓慢,无法调整权重了。
所以说,如果一条序列足够长,那RNN将很难将信息从较早的时间步传送到后面的时间步。因为梯度消失了,就意味着网络权值的更新停止了,梯度更新停止就意味着那些较早的层停止学习了,也就是RNN忘记了它在较长序列中以前看到的内容,只有短时记忆了。所以Simple RNN从其诞生开始,就远算不上是一个好用的架构,直到它的变体LSTM的出现,循环网络才荣耀登场。
(10)LSTM用门结构来缓解梯度消失问题
正是由于RNN是时序的深度,所以无法使用其他深度网络的residual connection的空间直连方式来缓解梯度消失问题,所以RNN的变体——尤其是LSTM,采用门结构的设计成为了必然的选择。
LSTM加入门控,就是并联架构了,此时权值就不用共享了,权值参数就在了两个不同的向量中了。这使得LSTM的细胞状态Ct(就是所谓的"长期记忆")就是由两个矩阵相加的组合了,所以其梯度更新也会来自两个矩阵的梯度之和。只要梯度更新不涉及矩阵连乘,那么梯度消失情况就可得到缓解。因此LSTM也只是缓解了(并非解决)Ct的梯度消失问题,其门状态仍存在梯度消失的情况。GRU同理,只是ht的梯度消失情况被缓解,并非解决。但话又说回来,由于是三个门都是相互并联的,所以长期记忆消失就消失吧,也许是因为这个时间步中长期记忆就是没啥用处,所以消失反倒是合理的。我还有输出门这个第三条线路的梯度,来更新网络参数呢,所以从这个角度看,长期记忆的梯度消失反倒是非常合理了、是我们喜与乐见的、正是我们想要的,而且也不会影响整个网络的训练,因为还有第三条梯度线路呢。
(11)LSTM如何解决梯度爆炸问题的?
梯度爆炸仅在一些网络的权重参数和激活值过大时发生,导致连乘后的数值越来越大。所以解决办法也很简单,就是梯度裁剪,进行上限设置即可。
说明:关于RNN存在的梯度问题,以及LSTM如何缓解梯度问题,其实我们应该是有数学推导的。但其实数学推导也不难,就是非常麻烦,要一层层剥开,数学公式也不好敲,所以我这里就省略了。这是我看完别人的推导后,自己总结的话术表达。如果你听着比较玄学,那你最好也去看看数学推导过程,你就理解了,网上有很多推导的,随便就能搜到。
2、LSTM架构
在Simple RNN中,重复模块h叫记忆单元。记忆单元其实就是一个非常简单的结构:一个单层全连接线性层FNN+一个激活层。这个记忆单元的状态叫隐藏状态,hidden state,它记录着历史(记忆)信息。
在LSTM中,重复模块A则叫细胞cell,A也有一个状态叫细胞状态Ct,细胞状态就是承载长期记忆信息的。A还有一个输出ht,ht是承载短期记忆的,因为ht其实就是每个时间步的输出,那当然就是本次时间步的输出了,那自然就是短期记忆了。
LSTM的这种把长期记忆和短期记忆都分开计算的网络,其细胞架构可就不像RNN的记忆单元那么简单,LSTM的细胞比较复杂,包含四个交互的层,三个Sigmoid 和一个tanh层,并以一种非常特殊的方式进行交互:
说明:上面的图以及后面的门结构图都是我从 https://colah.github.io/posts/2015-08-Understanding-LSTMs/ 这篇博文中截取的,如果看不懂的可以自行查阅原文。
(1)上图的A就是一个细胞cell。也就是LSTM的重复模块。
(2)细胞的输入:cell会接受两个输入,一个是上个时间步的细胞的输出ht-1,一个是这个时间步的样本输入xt。
(3)细胞的输出:cell会输出两个输出,一个是本时间步的细胞输出ht,一个是本时间步的细胞状态Ct,Cell State。
细胞状态Ct代表的是长期记忆,因为它是贯穿整个时序链的数据流。就是Ct是在时间维度上从第一个时间步一直流动到最后一个时间步。所以每个时序循环中都有一个细胞状态的输入和输出。所以细胞状态可以看作就是一个长期记忆链条,这个链条经过每个时序细胞都会有忘有记、该忘该记。那么它是如何做到该忘该记的?就是后面要讲的门结构控制的。
上图中的紫色ht输出其实和红色ht输出是一样的,只是紫色的输出并非是必须的,这个的看你的任务是什么,就是看你的需求,你的任务不需要紫色输出就可以不用输出了。但是只要还有下一个时间步的样本要循环,那红色的ht就必须得输出。当然最后一个时间步也是要输出ht的。从符号也可以看出ht就是隐藏层的输出。我们一般把ht看成短期记忆,因为ht更多的是和本次时间步输入的xt强相关。所以一般认为ht就是从本次循环输入的"词向量"身上学到的信息,所以也叫短期记忆。
也所以Ct+ht就是长短期记忆了,也所以LSTM也叫长短期记忆网络。所以如果你在训练中发现网络长期记忆不行,那你重点考虑的是怎么调Ct了;如果你发现是每个时间步预测的不行,那你就要重点考虑怎么调ht了。就是问题出在哪里的大方向你要清晰。
这里如果不是太理解没关系,因为我们后面还要不断地从各个角度解读这个流程,你就会有切身的体会了。
(4)σ表示的是Sigmoid激活函数,tanh表示的是tanh激活函数。sigmoid可以把数据压缩到0-1之间,tanh则是把数据压缩到-1-1之间。
所以,σ层是用来决定保留还是不保留信息的。或者说是用来更新或者忘记信息的,因为任何数乘以0都得0,乘以1等于本身。所以0就是忘记,1就是记住。或者说0就是“不许任何量通过”,1是“允许任意量通过”,这也是门结构称谓的由来。
所以LSTM的门结构指的就是A中的三个σ(sigmoid激活层)+一个pointwise乘法操作构成的。
第一个σ代表的门被称为遗忘门/忘记门
第二个σ代表的门被称为输入门
第三个σ代表的门被称为输出门
那为什么还有两个tanh激活函数?
LSTM的输入门中的tanh激活函数,这个激活函数是跟在线性层后面的,所以它纯粹就是对输入进行非线性变换,或者是学习数据的。
而LSTM输出门中的tanh激活函数,它不是跟在线性层后面,它是对输入的Ct进行标准化处理的。在LSTM论文中,作者是这样解释的:tanh标准化可以限制有效长期信息Ct的数字范围,避免历史信息在传递过程中变得越来越大,同时还能为输出门赋予一定的非线性性质,这个过程被实践证明有助于保持训练稳定、还能强化算法学习能力,因此在LSTM最终的设计中被保留下来了。看吧,是实践证明的,就是经验喽。
3、LSTM的门结构,及细胞状态
那么LSTM是如何通过遗忘门、输入门和输出门,来调节细胞状态的呢?或者说如何通过这些门,做到该忘的忘,该记住的记住呢?
从上图我们可以总结出:
(1)遗忘门、输入门、输出门的输入数据都是[ht-1, xt],即不仅要输入上个时间步的细胞的隐藏输出ht-1,还得输入这个时间步的样本数据xt。
(2)遗忘门,从公式上看不就是一个线性变换嘛,你可以形象的理解为,它其实就是一个FNN线性层,外套一个sigmoid激活函数。这个全连接线性层的作用就是,通过学习当前时间步的输入数据[ht-1, xt],来生成一个遗忘系数矩阵。这个遗忘矩阵是用来乘以前一个时间步输出的细胞状态(Ct-1)的。这样细胞通过这个门就学习了之前的记忆什么该丢掉,什么该记住。
(3)输入门则是两个并联的FNN线性层。
左侧线路套的是sigmoid激活函数,因为这个层也是学习输入门系数的,就是本次时间步输入的数据[ht-1, xt],哪些是要学习的,哪些是不用学的,就生成一个输入门系数矩阵。和遗忘门一个道理。
右侧线路则是套一个tanh激活函数,因为右侧全连接层才是真正用来学习输入数据[ht-1, xt]本身的。所以两条并联线路各自学习完毕后,二者的乘积就是本次时间步输入数据的一个学习成果。
(4)所以更新细胞状态时,就是遗忘门+输入门。之前的该忘的忘了,该记的记住了;本次时间步的信息该记的记住,不该记的就毙掉。
(5)输出门就更加同理了,也是先学一个输出门系数矩阵Ot,然后对更新后的细胞状态Ct进行tanh标准化处理后,乘以Ot,就是本次时间步的细胞的隐藏输出ht。
(6)输入门的tanh是用来学习本次时间步的输入数据的。但是输出门的tanh则是用来标准化Ct的。就是前者相当于是用来进行非线性变换提取特征的,后者相当于我们熟悉的BN层,是用来调整数据流的。
(7)从公式上看三个门就是三系数矩阵,数据流和这个系数矩阵相乘,就实现了一个"门"的效果。
整体全流程如下图:
至此,这些就是LSTM的原理、架构。下面我们看看pytorch中的lstm层的实现。
(三)在pytorch中实现LSTM
通过上面的各个角度的描述,我们知道其实LSTM和第二章的simple rnn一样,都是一个重复模块而已。所以在pytorch中,LSTM和RNN一样都是可以作为一个单独的层而存在的。本部分是我们从代码角度再次理解LSTM。
1、pytorch中的LSTM类的参数:
input_size:输入样本的特征个数。
hidden_size:隐藏层的神经元个数。
num_layer默认是1。这个参数和RNN中的一模一样,默认是1个LSTM细胞。如果你设置=2,就表示在物理空间维度上堆叠两个LSTM细胞。也就是stacked LSTM,第二个LSTM接收第一个LSTM的输出并计算最终结果。所以也叫深度LSTM。这也是Deep LSTM的来源。
bias:就是偏置嘛。因为都是普通的全连接线性层嘛,一般后面都会跟个偏置的。
batch_first=False,和RNN一样,默认这个参数是False,我们最好输入数据也是(seq, batch, features)这样一个结构,计算效率最高。这个参数其实非常重要,一定得深刻理解,我的RNN博文 【NLP】第二章:循环神经网络RNN、DRNN、 BRNN_rnn循环神经网络csdn-CSDN博客 中有对这个参数的深刻挖掘,大家可以参考。
dropout:dropout层是常见的对抗过拟合的一种手段,就是在神经网络传播的过程中,随机让部分参数为0来对抗过拟合的方法。当某些神经元的参数为0后,就意味着这些神经元和后面层的神经元的连接被切断了,也就是信息传播被切断了,所以可以阻止神经网络的过度学习,达到对抗过拟合的目的。
但是这里要强调的是:对于RNN来说,dropout层drop的是物理空间维度上的神经元,不是时序维度上的神经元!。时序维度的数据传播是不会被dropout的!只是空间维度的传播会被dropout掉!就是参数num_layer中的层与层之间的连接的神经元,会被随机dropout掉!或者说会dropout掉记空间维度上的忆细胞与记忆细胞之间的连接。不会dropout掉时间步和时间步之间的记忆细胞的连接的。或者说只是ht在传播过程中会被dropout掉,但是Ct在传播过程中是不会被dropout掉的。
dropout的参数是(0,1)之间的小数,如果你设置dropout=0.2就表示每次正向传播中,都随机令20%的参数为0。而且这个随机性是不可控的,就是不能用随机数种子让每次的随机性变得固定的。所以如果你设置了dropout,你的网络训练过程是无法复现的。
此外,和其他神经网络中的dropout模式一样,RNN中的dropout参数默认也是在训练过程中起作用的,而在模型预测、评估或推理阶段是不起作用的。因此在训练LSTM的时候,我们也是得使用train()和eval()两种模式来告诉模型当前是在进行训练还是在进行预测。因为在模型训练时会以20%的比例沉默一部分神经元,但是一旦到了测试模式,就不是按比例沉默神经元了,而是全部都不沉默,所有神经元上的数据都*p的方式向前传播了。
说了这么多如果你还不理解这个层,我之前写FNN和CNN都写过这个层,你可以参考【深度视觉】第四章:卷积神经网络架构_第四章卷积网络-CSDN博客 。
bidirectional:和RNN一样,这个参数设置为True的话,数据流在时间维度上就是双向的,和Bi-RNN一模一样的,就是在时间维度上将正向和反向细胞状态进行串联。Bi-RNN的数据流我已经详细演示了,可以参考 【NLP】第二章:循环神经网络RNN、DRNN、 BRNN_rnn循环神经网络csdn-CSDN博客 。所以你可以认为这个参数就是Bi-LSTM的接口,就是考虑上下文的双向LSTM了。
proj_size:也是LSTM网络的一个变体LSTMP,作用是减少LSTM的参数和计算量,提高模型效率和性能的。目前用不到就不展开了。
device:是设备的意思,就是你想让模型在cpu上训练还是在GPU上。
dtype:当然就是数据类型的意思了。自然都默认的是pytorch中的张量数据类型了。
2、LSTM的模型参数
原理和架构都明白后,就迫不及待地在pytorch中创建了一个lstm层,看看我们的理解是否正确。然而一查看参数,竟然是这样的:
很多人到这里就懵掉了,前面不是说LSTM有三个门共4个线性层的嘛,怎么不是4个参数矩阵和4个偏置呢?!是的,到这里很多人都会懵掉,但是我们再仔细看看pytorch中的说明文档,看看pytorch的LSTM的内部处理流程:
是不是破案了。原理我们理解的没错,pytorch只是在数学计算上变了个形。因为ft,it,ot,gt的输入都是一样,都是[ht-1,xt],而且都是一个线性变换+一个激活,所以我们可以用一个参数矩阵,一次矩阵运算就算出ft,it,ot,gt了。但是还有一个问题,ht-1的结构是(batch_size, hidden_size),而xt的结构是(batch_size, input_size),所以二者cat到一起,数据维度和参数维度就不好理解了,也没法乘了,所以pytorch把参数w分成了两个参数矩阵,一个用于变换ht-1,另一个用于变换xt。
那我们下面手动验证一下,看结果一样不一样:
或者这样计算:
可见我们按照我们自己的理解手动计算出来的结果和pytorch计算出来的结果一模一样。这这次印证了我们上面的分析是没错的。
最后总结一个LSTM的终极版数据流:
至此,LSTM的原理、架构、数据流,以及pytorch的实现方式,我们就非常清楚了。
- 终极总结:
其实LSTM和Simple RNN一样,都是由重复模块构成的。这个重复模块在Simple RNN中叫记忆单元,而在LSTM中叫细胞。
从重复的角度看:这个重复是时序空间上的重复,不是真正的物理重复。你可以理解为"你还是一个你自己,只不过是前年的你->去年的你->今年的你->明年的你->后年的你"如此重复的一个链条罢了。
从模块的角度看:如果把多个LSTM或者Simple RNN模块堆叠到一起,那就不是时序空间上堆叠了,这就是实实在在的物理链了,你可以理解为"是实实在在多个克隆的我串联在一起",是物理空间上的重复,是要等量增加参数的。此时就和我们前面的FNN\CNN的层的概念是一致的。当然也是越深层效果越好,参数量越大,计算量也越大。也是我们通常意义上的模型架构。
从Simple RNN的模块到LSTM的模块看:显然LSTM模块比Simple RNN模块复杂多了。从对记忆的贡献来看,Simple RNN其实只有一个线性层来传递记忆信息。但是LSTM的记忆信息则是三条并联的线性层来传递的。你可以类别为LSTM的脑细胞是Simple RNN的三倍,当然LSTM的记忆能力更强了。Simple RNN只用一个线性层,那长期的记忆、短期的记忆,它都混在一起,势必会产生权重冲突(Weight Conflict),进而表现为长短期信息冲突(Long-Short Term Information Conflict),然后无法训练。而LSTM用三条并联线路来记忆,就有能力区别长期记忆和短期记忆,就能计算哪些长期记忆需要记住,哪些需要忘记,而且还有短期信息链路并行,就不会出现无法训练的窘境。所以LSTM模块本身就比Simple RNN模块强大很多。
(四)LSTM变体
至此对LSTM我们从很多个角度都进行了描述,都理解到这个地步了,LSTM变体就更容易理解了。所以这里一鼓作气,把LSTM变体也一笔带过。
我们要知道,不是所有的LSTM都长成一个样子的。实际上,几乎所有包含LSTM的论文都采用了微小的变体。差异非常小,其中最值得了解的是下面三种:
1、peephole连接
是一个流形的LSTM变体,就是由Gers&Schmidhuber(2000)提出的,增加了“peepholeconnection”。就是让门层也会接受细胞状态的输入:
就这么一点点变异,peephole是窥视孔的意思,也不知道窥视了啥,呵呵,anyway就是增加了peephole到每个门上,但是许多论文会加入部分的peephole而非所有都加。
2、使用coupled忘记和输入门
另一个变体是通过使用coupled忘记和输入门。不同于之前是分开确定什么忘记和需要添加什么新的信息,这里是一同做出决定。我们仅仅会当我们将要输入在当前位置时忘记。我们仅仅输入新的值到那些我们已经忘记旧的信息的那些状态。
就是遗忘门和输入门二合一了,两个门变成了事物的两个方面了。
3、GRU
GRU是一个改动较大的变体是Gated Recurrent Unit,门控循环单元,是目前非常流行的一个变体,因为它比LSTM网络要简单,但效果也不弱LSTM,所以非常受欢迎。
从上图可以看出来,GRU改动有点大,不是一两句话就能带过的。所以这里我就不展开了,后面会单独写一篇GRU。
这里只是部分流行的LSTM变体。当然还有很多其他的,如Yao,etal.(2015)提出的DepthGatedRNN。还有用一些完全不同的观点来解决长期依赖的问题,如Koutnik,etal.(2014)提出的ClockworkRNN。
要问哪个变体是最好的?其中的差异性真的重要吗?Greff,etal.(2015)给出了流行变体的比较,结论是他们基本上是一样的。Jozefowicz,etal.(2015)则在超过1万种RNN架构上进行了测试,发现一些架构在某些任务上也取得了比LSTM更好的结果。