LSTM(长短期记忆(long short term memory)神经网络)

 

循环神经网络(Recurrent Neural Networks)

    人对于一个问题的思考并不会完全从头开始。比如我们在阅读本篇文章时,我们会根据之前理解过的信息来理解后面看到的文字。在理解当前文字的时候,我们并不会忽略之前看过的文字,从头思考当前文字的含义。

    传统的神经网络并不能做到这一点,这是在对这种序列信息(如语言)进行预测时的一个缺点。比如我们想对电影中的每个片段去做事件分类,传统的神经网络是很难通过利用前面的事件信息来对后面事件进行分类的。

    而循环神经网络(下面简称 RNN)可以通过不停的将信息循环操作,保证信息持续存在,从而解决上述问题。RNN 如下图所示:

        

Python用LSTM进行数据预测 lstm网络python_循环神经网络

    可以看出 A 是一组神经网络(可以理解为一个网络的自循环),它的工作是不停的接收 

Python用LSTM进行数据预测 lstm网络python_神经网络_02

 并且输出 

Python用LSTM进行数据预测 lstm网络python_Python用LSTM进行数据预测_03

 。从图中可以看出 A 允许将信息不停的在内部循环,这样使得它可以保证每一步的计算都保存以前的信息。

    这样讲可能有点晕,更好的理解方式,也是很多文章的做法,将 RNN 的自循环结构展开,像是将同一个网络复制并连成一条线的结构,将自身提取的信息传递给下一个继承者。如下图所示:

        

Python用LSTM进行数据预测 lstm网络python_神经网络_04

    这种链式的结构揭示了 RNN 与序列和列表类型的数据密切相关。 好像它们生来就是为了处理序列类型数据的。

    谁说不是呢?在过去的几年里,RNN 在语音识别、文字建模、翻译、字幕等领域有很成功的应用。在 Andrej Karpathy 写的博客  中讨论了 RNN 取得的惊人成果,这里就不详细讨论了。

    很多成功的案例都有一个共性,就是都用了一种叫 LSTM 的特殊的 RNN 网络结构。下面就来看看 LSTM。

 

长依赖存在的问题

    从之前的描述可以看出来,RNN 理论上是可以将以前的信息与当前的任务进行连接,例如使用以前的视频帧来帮助神经网络理解当前帧。如果 RNN 能做到这一点,那将会是非常的有用。但是它能做到这点吗?答案是不一定。

    有时候我们需要利用近期的信息来执行处理当前的任务。例如,考虑用一个语言模型通过利用以前的文字信息来预测下一个文字。如果我们需要预测 "the clouds are in the sky" 这句话的最后一个字,我们不需要其他的信息,通过前面的语境就能知道最后一个字应该是 "sky"。在这种情况下,相关信息与需要该信息的位置距离较近,RNN 能够学习利用以前的信息来对当前任务进行相应的操作。如下图所示通过输入的 

Python用LSTM进行数据预测 lstm网络python_神经网络_05


Python用LSTM进行数据预测 lstm网络python_Python用LSTM进行数据预测_06

 信息来预测出

Python用LSTM进行数据预测 lstm网络python_激活函数_07

:        

Python用LSTM进行数据预测 lstm网络python_神经网络_08

    假设现在有个更为复杂的任务,考虑到下面这句话 "I grew up in France ... I speak fluent French.",现在需要语言模型通过现有以前的文字信息预测该句话的最后一个字。通过以前文字语境可以预测出最后一个字是某种语言,但是要猜出 Franch,要根据之前的 Franch 语境。这样的任务,不同于之前,因为这次的有用信息与需要进行处理信息的地方之间的距离较远,这样容易导致 RNN 不能学习到有用的信息,最终推导的任务可能失败。如下图所示:

        

Python用LSTM进行数据预测 lstm网络python_激活函数_09

    理论上 RNN 是能够处理这种 "长依赖" 问题的。通过调参来解决这种问题。但是在实践过程中 RNN 无法学习到这种特征。Hochreiter (1991) [German] 和 Bengio, et al. (1994) 深入研究过为什么RNNs没法学习到这种特征。

    庆幸的是 LSTM 这种特殊的 RNN 是没有这个问题的。

 

LSTM 网络

    Long Short Term Memory networks(以下简称LSTM),一种特殊的 RNN 网络,该网络设计出来是为了解决长依赖问题。该网络由 Hochreiter & Schmidhuber (1997) 引入,并有许多人对其进行了改进和普及。它们的工作被用来解决了各种各样的问题,知道目前还被广泛应用。

    所有循环神经网络都具有神经网络的重复模块链的形式。在标准的 RNN 中,该重复模块将具有非常简单的结构,例如单个 tanh 层。标准的 RNN 网络如下图所示:

        

Python用LSTM进行数据预测 lstm网络python_激活函数_10

    LSTM 也具有这种链式结构,但是它的重复单元不同于标准 RNN 网络里的单元只有一个网络层,它的内部有四个网络层。          LSTM 的结构如下图所示:

        

Python用LSTM进行数据预测 lstm网络python_循环神经网络_11

    在解释 LSTM 的详细结构时先定义一下图中各个符号的含义,符号包括下面几种:

        

Python用LSTM进行数据预测 lstm网络python_激活函数_12

    图中黄色类似于 CNN 里的激活函数操作,粉色圆圈表示点操作,单箭头表示数据流向,箭头合并表示向量的合并(concat),箭头分叉表示向量的拷贝操作。

 

LSTM 核心思想

    LSTM 的核心是细胞状态整个(绿色的图表示的是一个cell),用贯穿细胞的水平线表示。

    细胞状态像传送带一样。它贯穿整个细胞却只有很少的分支(少量的线性交互),这样能够保证信息不变的流过整个 RNN。细胞状态如下图所示:

        

Python用LSTM进行数据预测 lstm网络python_神经网络_13

    若只有上面的一条水平线是没法实现添加或者删除信息的。LSTM 网络通过一种被称为门(gate)的结构对细胞状态进行删除或者添加信息。

    门可以实现选择性的让信息通过。主要是通过一个 sigmoid 的神经网络层和一个逐点相乘的操作来实现。如下图所示:

        

Python用LSTM进行数据预测 lstm网络python_循环神经网络_14

    sigmoid 层输出(一个向量)的每个元素都是一个在 0 和 1 之间的实数,表示让对应信息通过 sigmoid 层的权重(占比)。0 表示所有信息都不能通过,1 表示所有信息都通过。

    LSTM 通过三个这样的基本机构来实现信息(细胞状态)的保护和控制。这三个门分别是:遗忘门、输入门、输出门。

 

深入理解 LSTM

    遗忘门

        LSTM 的第一步是决定细胞状态需要丢弃哪些信息。这部分操作是通过一个被称为遗忘门的 sigmoid 单元来处理的。它通过查看 

Python用LSTM进行数据预测 lstm网络python_神经网络_15

 和 

Python用LSTM进行数据预测 lstm网络python_神经网络_02

 信息来输出一个值在 0-1 之间的向量,该向量里面的 0-1 表示细胞状态 

Python用LSTM进行数据预测 lstm网络python_循环神经网络_17

 中的哪些信息保留或丢弃多少。0 表示都不保留,1 表示都保留。遗忘门如下图所示:            

Python用LSTM进行数据预测 lstm网络python_激活函数_18

        其中 

Python用LSTM进行数据预测 lstm网络python_神经网络_15

 表示上一个 cell 的输出,

Python用LSTM进行数据预测 lstm网络python_神经网络_02

 表示当前 cell 的输入,

Python用LSTM进行数据预测 lstm网络python_激活函数_21

 表示 sigmoid 函数。

    输入门

        LSTM 的下一步是决定给细胞状态添加哪些新的信息。实现这个过程需要两个步骤:首先,利用 

Python用LSTM进行数据预测 lstm网络python_神经网络_15

 和 

Python用LSTM进行数据预测 lstm网络python_神经网络_02

 通过一个叫做 "input gate layer" 的 sigmoid 层决定更新哪些信息;然后,利用 

Python用LSTM进行数据预测 lstm网络python_神经网络_15

 和 

Python用LSTM进行数据预测 lstm网络python_神经网络_02

 通过一个 tanh 层 生成一个向量得到新的候选细胞信息(备选的用来更新的内容)

Python用LSTM进行数据预测 lstm网络python_循环神经网络_26

,这些信息可能会被更新到细胞中。这两步描述如下图所示:            

Python用LSTM进行数据预测 lstm网络python_神经网络_27

        下面,将这两部分联合起来,对细胞状态进行一个更新(

Python用LSTM进行数据预测 lstm网络python_循环神经网络_17

 更新为

Python用LSTM进行数据预测 lstm网络python_神经网络_29

)。        将旧的状态 

Python用LSTM进行数据预测 lstm网络python_循环神经网络_17

 与 

Python用LSTM进行数据预测 lstm网络python_循环神经网络_31

 相乘,丢弃掉我们要丢弃的信息。接着加上 

Python用LSTM进行数据预测 lstm网络python_循环神经网络_32

 与 

Python用LSTM进行数据预测 lstm网络python_循环神经网络_26

的乘积。这就是新的候选值,根据我们决定更新每个细胞状态值的大小进行缩放。        (通过遗忘门选择忘记旧细胞信息

Python用LSTM进行数据预测 lstm网络python_循环神经网络_17

的一部分,通过输入门选择添加候选细胞信息

Python用LSTM进行数据预测 lstm网络python_循环神经网络_26

的一部分得到新的细胞信息

Python用LSTM进行数据预测 lstm网络python_神经网络_29


        更新操作如下图所示:

            

Python用LSTM进行数据预测 lstm网络python_神经网络_37

    输出门

        最终,我们需要根据输入的 

Python用LSTM进行数据预测 lstm网络python_神经网络_15

 和 

Python用LSTM进行数据预测 lstm网络python_神经网络_02

 来判断输出细胞的哪些状态特征。这个输出将会基于我们的细胞状态,但是也是一个过滤后的版本。首先,将输入经过一个称为输出门的 sigmoid 层得到判断条件,确定细胞状态的哪个部分将输出出去。接着,将细胞状态通过 tanh 层得到一个 -1~1 之间值的向量,该向量与输出门得到的判断条件相乘就得到了最终该 RNN 单元的输出(仅仅会输出我们确定输出的那部分)。该步骤如下图所示:            

Python用LSTM进行数据预测 lstm网络python_神经网络_40

    还是以语言模型来举例说明,在预测动词形式的时候,我们需要通过输入的主语是单数还是复数来推断输出门输出的预测动词是单数形式还是复数形式。

 

梯度消失和梯度爆炸

    原因:

权重和激活函数的偏导。深层的梯度是多个激活函数偏导乘积的形式来计算,如果这些激活函数的偏导比较小(小于1)或者为 0,那么梯度随时间很容易消失(vanishing);相反,如果这些激活函数的偏导比较大(大于1),那么梯度很有可能就会爆炸(exploding)。因而,梯度的计算和更新非常困难。

    解决方案:

        使用一个合适激活函数,它的梯度在一个合理的范围。LSTM 使用 gate function,有选择的让一部分信息通过。gate 是由一个 sigmoid 单元和一个逐点乘积操作组成,sigmoid 单元输出 1 或 0,用来判断通过还是阻止,然后训练这些 gate 的组合。所以,当 gate 是打开的(梯度接近于1),梯度就不会消失(vanish)。并且 sigmoid 不超过 1,那么梯度也不会爆炸(explod)。

        

Python用LSTM进行数据预测 lstm网络python_循环神经网络_14

    LSTM的效果:

        1、当 gate 是关闭的,那么就会阻止对当前信息的改变,这样以前的依赖信息就会被学到。

        2、当 gate 是打开的时候,并不是完全替换之前的信息,而是在之前信息和现在信息之间做加权平均。所以,无论网络的深度有多深,输入序列有多长,只要 gate 是打开的,网络都会记住这些信息。

 

总结

    之前也提到过 RNN 取得了不错的成绩,这些成绩很多是基于 LSTM 来做的,说明 LSTM 适用于大部分的序列场景应用。

    LSTM 对于 RNN 的使用是一大进步。那么现在还有个问题,是否还有更大的进步?对于很多研究者来说,但是是肯定的,那就是 attention 的问世。attention 的思想是让 RNN 在每一步挑选信息的时候都能从更大的信息集里面挑选出有用信息。例如,利用 RNN 模型为一帧图片生成字母,它将会选择图片有用的部分来得到有用的输入,从而生成有效的输出。