在观摩了李宏毅老师讲解的LSTM以后感觉豁然开朗,其实并没有很多教程里面说得那么晦涩。
理解LSTM有三个步骤,为什么,是什么,怎么用。
我们知道,用MLP和CNN这些网络在处理图像信息是比较work的。但是在处理语音这种序列信息时,其performance就一般了。比如我想要在某知名订票软件DTrip上预定机票,对手机说了一句“I will arrive Beijing on Oct. 1st.”。我们希望说出这句话以后,系统能帮我们识别出目的地和时间。我们可以很清楚的认识到,一般情况下,arrive后面的单词就是目的地,on后面的短语大部分表示日期,而传统的MLP或者CNN显然缺乏根据上下文做分析的能力。
RNN
RNN的出现能够让之前序列的一些信息被记住,其结构如下图所示:
下面黄色的方块代表输入是一个2维向量,两个绿色的神经元表示hidden layer,红色的神经元表示output,而左侧的两个蓝色方块,表示的就是RNN的精髓所在,即每一次前向传播时,都将绿色神经元的输出拷贝到蓝色方块中,在序列的下一个元素输入时,绿色神经元的计算值由输入(黄色)的线性变换和上一次保存的值(蓝色)两部分构成。
假设上述网络中所有的权值都为1,一开始的蓝色方块值都为0,黄色输入都为1。那很容易算出两个绿色神经元输出都是2,红色的都是4,此时2被拷贝到蓝色方块中做下一次运算。第二次的运算过程如下图:
计算过程与上面一样,不再赘述,此时蓝色方块中的值应被更新为两个6,再做下一次运算,以此类推。
可以看出,RNN考虑了上下文的关系,即后面的判断和决策,不仅仅是由当前的数据决定,还会受到前文中一些数据特征的影响。因此回到一开始的那句话“I will arrive Beijing on Oct. 1st.”,如果此时的输入是“Beijing”,那么此时的RNN中会保存之前“arrive”的某些信息,所以如果有足够的知识,更容易判定此时的输入“Beijing”就是目的地。
RNN在语音识别、机器翻译等一些需要用到序列数据的领域,取得了非常好的成果。
那么为什么还要有LSTM这么看似复杂的模型呢?RNN的问题在于他不能处理“长依赖”的问题,在上面的算法中,我们是用到的是一些近期的信息来处理当前的任务,比如“arrive”和“Beijing”是相邻的,“on”和“Oct. 1st”也是挨着的。
如果现在的输入变成 “我今天跑了马拉松,健身房撸了铁,但是没吃饭,所以饿晕了”。我们显然,这个句子的结局是我饿晕了。但是在RNN中,“饿晕了”一词表示非常疑惑,到底是谁饿晕了。因为“饿晕了”和“我”相距实在是太远了,一个在句首,一个在句末,导致中途失去了“我”的信息,从而RNN无法做到有效的学习。
因此RNN更适合做短期一些的学习,而长期的信息就会被遗忘掉。但幸好LSTM可以用来做稍长期一些的task。
LSTM
LSTM和RNN有相似之处,就是可以存储前面序列的一些信息。一个LSTM的结构如下图所示:
乍一看LSTM的架构比较复杂,但其实梳理一下并不难。首先LSTM由四个部分组成,输入门、输出门、遗忘门和记忆细胞。首先网络的其他部分有一个输入,该输入想进入LSTM首先要经过输入门的同意,如果输入门不同意,则该输入无法对LSTM的cell值产生影响;如果输入门同意,则根据遗忘门的遗忘程度来确定之前信息的保存情况,再和这个输入相加,组成新的cell值。输出门决定是否将这个cell值输出。
所以一个LSTM有四个输入,对应下图中的
z
z
z、
z
i
z_{i}
zi、
z
f
z_{f}
zf和
z
o
z_{o}
zo;还有一个输出
a
a
a。下图表示的是一个LSTM的运算过程:
首先每一个圆圈里面代表的都是Sigmoid函数,目的是将实数集映射到 [0,1] 内。首先输入
z
z
z 经过一个Sigmoid变换得到
g
(
z
)
g(z)
g(z) ,Input Gate的输入
z
i
z_{i}
zi 经过Sigmoid变换得到
f
(
z
i
)
f(z_{i})
f(zi)。随后在第一个黑色节点出将两者相乘,得到
g
(
z
)
f
(
z
i
)
g(z)f(z_{i})
g(z)f(zi),可见如果
f
(
z
i
)
f(z_{i})
f(zi) 的值越接近0,表示拒绝
g
(
z
)
g(z)
g(z) 进入LSTM;如果
f
(
z
i
)
f(z_{i})
f(zi) 越接近于1,表示允许输入
g
(
z
)
g(z)
g(z) 进入LSTM。
在得到了 g ( z ) f ( z i ) g(z)f(z_{i}) g(z)f(zi) 以后,就需要根据遗忘门和原来的cell值,计算出新的cell值。首先将遗忘门输入 z f z_{f} zf 做Sigmoid变换,得到 f ( z f ) f(z_{f}) f(zf),随后将 f ( z f ) f(z_{f}) f(zf) 和原来的记忆细胞值 c c c 做乘法,得到 c f ( z f ) cf(z_{f}) cf(zf),最后加上之前的输入 g ( z ) f ( z i ) g(z)f(z_{i}) g(z)f(zi),就得到新的记忆细胞值 c ′ c' c′,即:
c ′ = g ( z ) f ( z i ) + c f ( z f ) c'=g(z)f(z_{i})+cf(z_{f}) c′=g(z)f(zi)+cf(zf)
然后 c ′ c' c′ 经过一个Sigmoid以后得到 h ( c ′ ) h(c') h(c′) ,再根据输出门输入 z o z_{o} zo 做Sigmoid以后得到的 f ( z o ) f(z_{o}) f(zo),就可以计算输出 a = h ( c ′ ) f ( z o ) a=h(c')f(z_{o}) a=h(c′)f(zo)。和输入门大同小异,如果 f ( z o ) f(z_{o}) f(zo) 接近1,此时的输出值与 h ( c ′ ) h(c') h(c′) 基本一致,表示允许 c ′ c' c′ 输出; f ( z o ) f(z_{o}) f(zo) 接近0,此时的 h ( c ′ ) h(c') h(c′) 接近于0,表示拒绝输出。
那LSTM的长相和传统的神经网络很不一样,怎么能建立一种联系呢?其实把LSTM换一种形式来画,会发现和传统的神经网络还是蛮像的:
输入值 x t x^{t} xt 经过一系列transform以后,得到了LSTM的四个输入,在分别进行一系列的变换得到输出 y t y^{t} yt。这样直觉上LSTM就和平常的神经网络长得比较像了。
实际应用中还有一些额外的连接和trick,这里就不再展开了。
本人纯属小白,有不妥的地方望指正交流~
PS:图片来自李宏毅老师机器学习课件。