深度解析LSTM神经网络的设计原理

推荐会员: 点金大数据 所属分类: 人工智能,行业精选 发布时间: 2018-06-29 09:59
想要搞清楚LSTM中的每个公式的每个细节为什么是这样子设计吗?想知道simple RNN是如何一步步的走向了LSTM吗?觉得LSTM的工作机制看不透?恭喜你打开了正确的文章!
前方核弹级高能预警!本文信息量非常大,文章长且思维连贯性强,建议预留20分钟以上的时间进行阅读。
前置知识1:
简单的循环神经网络,即无隐藏层的循环神经网络,起名叫“simple RNN”,公式如下:

这种方式即在每个时刻做决策的时候都考虑一下上一个时刻的决策结果。画出图来就是酱的:
 
(其中圆球里的下半球代表两向量的内积,上半球代表将内积结果激活)
虽然通过这种简单反馈确实可以看出每个时间点的决策会受前一时间点决策的影响,但是似乎很难让人信服这竟然能跟记忆扯上边!
想一下,人的日常行为流程是这样的。比如你在搭积木,那么每个时间点你的行为都会经历下面的子过程:
1、眼睛看到现在手里的积木。
2、回忆一下目前较高层的积木的场景。
3、结合1和2的信息来做出当前时刻积木插到哪里的决策。
相信聪明的小伙伴已经知道我要表达的意思啦。第1步手里的积木就是当前时刻的外部输入X;第2步就是调用历史时刻的信息/记忆;第3步就是融合X和历史记忆的信息来推理出决策结果,即RNN的一步前向过程的输出y(t)。
有没有更加聪明的小伙伴惊奇的注意到第2步!!!我们在回忆历史的时候,一般不是简单的回忆上一个积木的形状,而是去回忆一个更加模糊而宏观的场景。在这个例子中,这个场景就是最近几次行为所产生出的抽象记忆——即“积木较高层的地形图”!
也就是说,人们在做很多时序任务的时候,尤其是稍微复杂的时序任务时,潜意识的做法并不是直接将上个时刻的输出y(t-1)直接连接进来,而是连接一个模糊而抽象的东西进来!这个东西是什么呢?
当然就是神经网络中的隐结点h啊!也就是说,人们潜意识里直接利用的是一段历史记忆融合后的东西h,而不单单是上一时间点的输出。而网络的输出则取自这个隐结点。所以更合理的刻画人的潜意识的模型应该是这样的:

(记忆在隐单元中存储和流动,输出取自隐单元)
这种加入了隐藏层的循环神经网络就是经典的RNN神经网络!即“standard RNN”。
RNN从simple到standard的变动及其意义对于本文后续内容非常重要哦。
前置知识2:
由于在误差反向传播时,算出来的梯度会随着往前传播而发生指数级的衰减或放大!而且这是在数学上板上钉钉的事情。因此,RNN的记忆单元是短时的。
好啦,那我们就借鉴前辈设计RNN的经验,从simple版本开始,即无隐藏层的、简单完成输出到输入反馈的网络结构开始,去设计一个全新的、可以解决梯度爆炸消失问题从而记住长距离依赖关系的神经网络吧!
那么如何让梯度随着时间的流动不发生指数级消失或者爆炸呢?
好像想起来挺难的,但是这个问题可能中学生会解答!那就是让算出来的梯度恒为1!因为1的任何次方都是1嘛( ̄∇ ̄)
所以按照这个搞笑的想法,我们把要设计的长时记忆单元记为c(以下全部用c指代长时记忆单元),那么我们设计出来的长时记忆单元的数学模型就是这样子喽:
c(t) = c(t-1)
这样的话,误差反向传播时的导数就恒定为1啦~误差就可以一路无损耗的向前传播到网络的前端,从而学习到遥远的前端与网络末端的远距离依赖关系。
不要急不要急,反正假设我们的c中存储了信息,那么c就能把这个信息一路带到输出层没问题吧?在T时刻算出来的梯度信息存储在c里后,它也能把梯度一路带到时刻0而无任何损耗也没问题吧?对吧( ̄∇ ̄)
所以信息的运输问题解决了,那么就要解决对信息进行装箱和卸车的问题。
先来看装箱问题,即如何把新信息写入c里面去呢?

1、乘进去!
2、加进去!
那么这两种哪种可行呢?
其实稍微一想就很容易判断:乘法操作更多的是作为一种对信息进行某种控制的操作(比如任意数与0相乘后直接消失,相当于关闭操作;任意数与大于1的数相乘后会被放大规模等),而加法操作则是新信息叠加旧信息的操作。
下面我们深入的讨论一下乘性操作和加性操作,这在理解LSTM里至关重要。当然,首先,你要掌握偏导的概念和方法、复合函数的求导法则、链式求导法则。有了这三点微积分基础后才能看懂哦。
(害怕数学和基础不够的童鞋可以跳过这里的论乘法和论加法小节。)

噫?也有指数项~不过由于v加了一个偏置1,导致爆炸的可能性远远大于消失。不过通过做梯度截断,也能很大程度的缓解梯度爆炸的影响。
嗯~梯度消失的概率小了很多,梯度爆炸也能勉强缓解,看起来比RNN靠谱多了,毕竟控制好爆炸的前提下,梯度消失的越慢,记忆的距离就越长嘛。
因此,在往长时记忆单元添加信息方面,加性规则要显著优于乘性规则。也证明了加法更适合做信息叠加,而乘法更适合做控制和scaling。
由此,我们就确定应用加性规则啦,至此我们设计的网络应该是这样子的:

那么有没有办法让信息装箱和运输同时存在的情况下,让梯度消失的可能性变的更低,让梯度爆炸的可能性和程度也更低呢?
你想呀,我们往长时记忆单元添加新信息的频率肯定是很低的,现实生活中只有很少的时刻我们可以记很久,大部分时刻的信息没过几天就忘了。因此现在这种模型一股脑的试图永远记住每个时刻的信息的做法肯定是不合理的,我们应该只记忆该记的信息。
显然,对新信息选择记或者不记是一个控制操作,应该使用乘性规则。因此在新信息前加一个控制阀门,只需要让公式【3.1】变为

嗯~由于输入门只会在必要的时候开启,因此大部分情况下公式【4】可以看成
C(t)=C(t-1),也就是我们最理想的状态。由此加性操作带来的梯度爆炸也大大减轻啦,梯度消失更更更轻了。
等等,爱思考的同学可能会注意到一个问题。万一神经网络读到一段信息量很大的文本,以致于这时输入门欣喜若狂,一直保持大开状态,狼吞虎咽的试图记住所有这些信息,会发生什么呢?
显然就会导致c的值变的非常大!
要知道,我们的网络要输出的时候是要把c激活的(参考公式【0.3】),当c变的很大时,sigmoid、tanh这些常见的激活函数的输出就完全饱和了!比如如图tanh:

当c很大时,tanh趋近于1,这时c变得再大也没有什么意义了,因为饱和了!脑子记不住这么多东西!
这种情况怎么办呢?显然relu函数这种正向无饱和的激活函数是一种选择,但是我们总不能将这个网络输出的激活函数限定为relu吧?那也设计的太失败啦!
那怎么办呢?
其实想想我们自己的工作原理就知道啦。我们之所以既可以记住小时候的事情,也可以记住一年前的事情,也没有觉得脑子不够用,不就是因为我们。。。爱忘事嘛。所以还需要加一个门用来忘事!这个门就叫做“遗忘门”吧。这样每个时刻到来的时候,记忆要先通过遗忘门忘掉一些事情再考虑要不要接受这个时刻的新信息。
显然,遗忘门是用来控制记忆消失程度的,因此也要用乘性运算,即我们设计的网络已进化成:

好啦~解决了如何为我们的长时记忆单元可控的添加新信息的问题,又贴心的考虑到并优雅解决了信息输入太过丰富导致输入控制门“合不拢嘴”的尴尬情况,那么是时候考虑我们的长时记忆单元如何输出啦~
有人说,输出有什么好考虑的,当前的输出难道不就仅仅是激活当前的记忆吗?难道不就是最前面说的y(t)=f(c(t))?(其中f(·)为激活函数)
试想,假如人有1万个长时记忆的脑细胞,每个脑细胞记一件事情,那么我们在处理眼前的事情的时候是每个时刻都把这1万个脑细胞里的事情都回忆一遍吗?显然不是呀,我们只会让其中一部分跟当前任务当前时刻相关的脑细胞输出,即应该给我们的长时记忆单元添加一个输出阀门!也就是说应该输出:

嗯~终于看起来好像没有什么问题了。

然而,作为伟大的设计者,怎么能止步于simple呢!我们要像simple RNN推广出standard RNN的做法那样,推广出我们的standard版本!即加入隐藏层!
为什么要加隐藏层已经在本文开头提到了,这也是simpleRNN到standardRNN的核心区别,这也是RNN及其变种可以作为深度学习的主角之一的原因。模仿RNN的做法,我们直接用隐藏层单元h来代替最终输出y:
 
显然,由于h随时都可以被输出门截断,所以我们可以很感性的把h理解为短时记忆单元。
而从数学上看的话,更是短时记忆了,因为梯度流经h的时候,经历的是h(t)->c(t)->h(t-1)的连环相乘的路径(在输入输出门关闭前),显然如前边的数学证明中所述,这样会发生梯度爆炸和消失,而梯度消失的时候就意味着记忆消失了,即h为短时记忆单元。
同样的思路可以再证明一下,由于梯度只从c走的时候,存在一条无连环相乘的路径,可以避免梯度消失。又有遗忘门避免激活函数和梯度饱和,因此c为长时记忆单元。
好啦,我们standard版本的新型网络也完成了!有没有觉得信息量超级大,又乱掉了呢?不要急,贴心的小夕就再带你总结一下我们这个网络的前馈过程:
新时刻t刚刚到来的时候,
1、首先长时记忆单元c(t-1)通过遗忘门g_forget去遗忘一些信息。
2、其中g_forget受当前时刻的外部输入x(t)、上一时刻的输出(短时记忆)h(t-1)、上一时刻的长时记忆c(t-1)的控制。
3、然后由当前时刻外部输入x(t)和上一时刻的短时记忆h(t-1)计算出当前时刻的新信息hat c(t)。
4、然后由输入门g_in控制,将当前时刻的部分新信息hat c(t)写入长时记忆单元,产生新的长时记忆c(t)。
5、其中g_in受x(t)、h(t-1)、c(t-1)的控制。
6、激活长时记忆单元c(t),准备上天(输出)。
7、然后由输出门g_out把控,将至目前积累下来的记忆c(t)选出部分相关的记忆生成这一时刻我们关注的记忆h(t),再把这部分记忆进行输出y(t)。
8、其中输出门g_out受x(t)、h(t-1)和当前时刻的长时记忆c(t)的控制。
前馈的过程写完了,梯度反传的过程就让深度学习平台去自动求导来完成吧~有M倾向的同学可以尝试对上述过程进行手动求导。
好啦,最后对全文的设计过程总结一下:
1、我们为了解决RNN中的梯度消失的问题,为了让梯度无损传播,想到了c(t)=c(t-1)这个朴素却没毛病的梯度传播模型,我们于是称c为“长时记忆单元”。
2、然后为了把新信息平稳安全可靠的装入长时记忆单元,我们引入了“输入门”。
3、然后为了解决新信息装载次数过多带来的激活函数饱和的问题,引入了“遗忘门”。
4、然后为了让网络能够选择合适的记忆进行输出,我们引入了“输出门”。
5、然后为了解决记忆被输出门截断后使得各个门单元受控性降低的问题,我们引入了“peephole”连接。
6、然后为了将神经网络的简单反馈结构升级成模糊历史记忆的结构,引入了隐单元h,并且发现h中存储的模糊历史记忆是短时的,于是记h为短时记忆单元。
7、于是该网络既具备长时记忆,又具备短时记忆,就干脆起名叫“长短时记忆神经网络(Long Short Term Memory Neural Networks,简称LSTM)“啦。
参考文献:
1. Hochreiter S, Schmidhuber J. Long Short-Term Memory[J]. Neural Computation, 1997, 9(8): 1735-1780.
2. Gers F A, Schmidhuber J, Cummins F, et al.Learning to Forget: Continual Prediction with LSTM[J]. Neural Computation,2000, 12(10): 2451-2471.
3. Gers F A, Schraudolph N N, Schmidhuber J, etal. Learning precise timing with lstm recurrent networks[J]. Journal of MachineLearning Research, 2003, 3(1): 115-143.
4. A guide to recurrent neural networks and backpropagation. Mikael Bod ́en.
5. http://colah.github.io/posts/2015-08-Understanding-LSTMs/
6. 《Supervised Sequence Labelling with Recurrent Neural Networks》Alex Graves
7. 《Hands on machine learning with sklearn and tf》Aurelien Geron
8. 《Deep learning》Goodfellow et.
来源:http://dl.dataguru.cn/article-13765-1.html
关键词:

版权声明:本站原创和会员推荐转载文章,仅供学习交流使用,不会用于任何商业用途,转载本站文章请注明来源、原文链接和作者,否则产生的任何版权纠纷与本站无关,如果有文章侵犯到原作者的权益,请您与我们联系删除或者进行授权,联系邮箱:service@datagold.com.cn。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.