我们前面讲的RNN只是RNN的最简单的版本。前面讲的memory是最单纯的,我们随时都可以把值存到memory里面去,也可以随时读出来。 但是现在比较常用的memory称之为Long Short-term Memory,简写为LSTM。。 这种Long Short-term Memoy是比较复杂的。它有三个门。 当某个神经元的input想要写到Memory cell里面的时候呢,必须先通过一个闸门Input Gate。这个Input Gate打开的时候,才能把值写到Memory cell里面去,如果关起来了,其他神经元就没有办法把值写进去。这个Input Gate是打开还是关闭,是网络自己学的,它可以自己学什么时候要把Input Gate打开,什么时候要把Input Gate关起来。 输出的地方也有一个Output Gate,这个Output Gate会决定说,外界其他的神经元可不可以从memory里面把值读出来。当Output Gate关闭的时候,就没有办法把值读出来了,Output Gate打开的时候才可以把值读出来。跟Input Gate一样,Output Gate什么时候打开,什么时候关闭,也是网络自己学到的。
第三个Gate叫做Forget Gate,Forget Gate是决定说什么时候memory cell把过去记得的东西忘掉。Forget Gate什么时候把里面的值继续保留下来。什么时候忘掉,什么时候保留,也是网络自己学到的。
整个LSTM可以看成有四个input,1个output。这四个input是,想要被存到memory里面的值、操控Input Gate的信号、操控Output Gate 的信号、操控Forget Gate的信号。
还有一个小小的冷知识。LSTM名字是"Long Short-term Memory"而不是"Long-short Term Memory"。"-"应该放在"short"和"term"之间,因为其实还是一个Short-term的memory,只是比较长的短时记忆网络。因为RNN的memory在每个时间点都会被洗掉,所以它的short-term是非常短的,它只记得前一个时间点的事情。而LSTM可以记得比较长时间一点,只要Forget Gate不删除的话,它的值就一直有。
------------------------------------------------------------------------------------------------------------------------------- 更仔细来看它的formulation的话,长的像这样。1是外界的input,是要存到cell中的input;2是Input Gate;3是Forget Gate;4是Output Gate。现在假设要存到cell中的input叫做z;操控Input Gate的信号叫做Zi,所谓操控Input Gate的信号也就是一个数值,待会讲数值是从哪里来的,这个数值被当做一个input;Forget Gate有一个操控它的数值叫做Zf;Output Gate有一个操控的数值叫做Zo。最后的output是a。 假设在有这四个输入之前,cell里面已经存了值c。假设现在输入Z,三个Gate分别由Zi,Zf,Zo操控,那输出a会长什么样子呢? 1. Z 通过激活函数得到g(Z) 2. Zi通过激活函数得到f(Zi)。 Zi,Zf,Zo通过的激活函数通常选择sigmoid函数。选择sigmoid函数的意义就是,sigmoid函数的值在0~1之间。而0~1之间的值代表Gate被打开的程度。如果激活函数的output是1,代表这个Gate是打开的状态。反之代表这个Gate是关起来的。 3. 用g(Z)乘上f(Zi),得到g(Z)f(Zi) 4. Zf通过激活函数得到f(Zf) 5. 把存在memory里面的值c乘上f(Zf),得到cf(Zf) 6. 把cf(Zf)加上g(Z)f(Zi),得到c'。c'就是新的存到memory cell的值。
根据到目前为止的运算,可以说f(Zi)就是控制g(Z)可不可以输入的一个关卡。因为假设f(Zi)等于0,那g(Z)f(Zi)就等于0,那g(Z)就好像没有输入一样;如果f(Zi)等于1,那相当于把g(Z)当做输入。 f(Zf)就决定说,我们要不要把存在memory cell的值给洗掉,假设f(Zf)是1,c会直接通过,就等于还是记得以前的值。如果f(zf)等于0,也就是Forget Gate关闭的时候,0乘以c,就相当于过去存在memory里面的值,就相当于0。Forget Gate的开关跟我们直观的想法是相反的,Forget Gate打开的时候表示记得,关闭的时候表示遗忘。所以它的名字有点奇怪,不过习惯就这么叫了。
7. 把c'写到memory cell中 8. c'通过激活函数得到h(c') 9. Zo通过激活函数得到f(Zo) 10. h(c')乘以f(Zo)得到a。如果f(Zo)等于1,代表h(c')可以通过Output Gate。等于0,output就是0,代表存在memory cell中的值不能被读取出来。
------------------------------------------------------------------------------------------------------------------------------- 也许这样还是没有很清楚,所以后面做了一个人工LSTM。这个投影片做了很久。先讲一下举的例子,网络里面只有一个LSTM的cell。我们的input都是三维的向量,output都是一维的向量。 这个三维的向量跟output还有memory里面的值的关系是什么呢?这个关系是这样子。 假设x2的值是1的时候,x1的值就会被写到memory里面去。假设x2的值是-1的时候,memory就会被reset,就会被遗忘。假设x3等于1的时候,才会把Output Gate打开,才能够看到输出。 假设运来存在memory中的值是0。 当输入100的时候,输出是0. 当输入310的时候,x2=1,把x1加到memory中,3+0=3 当输入200的时候,输出是0 当输入410的时候,x2为1,所以把x1加到memory中,3+4=7 当输入200的时候,输出是0 当输入101的时候,x3为1,输出7 当输入3-10的时候,x2=-1,memory中的值变为0 当输入610的时候,x2=1,把x1加到memory中,0+6=6 当输入101的时候,x3=1,输出6
------------------------------------------------------------------------------------------------------------------------------- 我们来实际做一下运算。下面是一个LSTM的memory cell。LSTM的memory cell总共有4个input,这4个input都是数值。这4个数值是怎么来的呢?是我们input的那个三维的向量(x1,x2,x3)进行线性变换得来的。即x1*w1+x2*w2+x3*w3+b得到。这些w和b应该是多少,是通过training data,用Gradient Descent学到的。假设我们已经知道这些值是多少(如图所示)。 我们实际的输入一组(x1,x2,x3)看看输出是多少。 在实际运算之前呢,我们先根据这些参数(w和b)来分析一下可能会得到的结果。 在1处,只有w1为1,其余全为0,说明就是把x1当做输入。 在2处,x2*100+(-10),也就是说假设x2没有值的时候,因为bias是-10,所以通常Input Gate是被关闭的,因为如果输入-10,通过sigmoid函数,值接近0,代表Input Gate是关闭的。只有在x2有值的时候,x2*100-10就大于0,input就是一个很大的正值,代表Input Gate被打开。 在3处,平时都是被打开的,因为bias为10,经过sigmoid函数得到1,说明遗忘门是打开的,打开意味着不忘记。只有在x2给一个很大的负值的时候,才会把Forget Gate关起来。 在4出,Output Gate通常是关闭的。只有x3是很大的正值的时候,才打开。才有输出。
这也就是我们刚才说的: 当x2为1时,Input Gate打开,x1可以输入进来;Forget Gate打开,没有忘记。cell更新为c+x1。 当x2为-1时,Input Gate关闭,x1输入不进来;Forget Gate关闭,忘记。cell 更新为0. 当x3为1时,Output Gate打开,可以输出。 当x3为0是,Output Gate关闭,输出为0.
好,我们实际的input一下看看。 我们假设g和h都是线性的。假设存在memory里面的初始值是0。我们输入第一个向量(3,1,0)。经过一下8步运算,输出0。
当输入向量(4,1,0)时,得到输出为0。 当输入(2,0,0)的时候计算过程如下: 当输入(1,0,1)时,运算如下: 最后当输入(3,-1,0)时运算如下: ------------------------------------------------------------------------------------------------------------------------------- 看到这里可能会有一个问题,这个东西跟我们以前看到的神经网络很不像。它跟以前的神经网络到底有什么关系呢?可以这样想。 在原来的神经网络里面,我们会有很多的神经元。我们会把input乘上不同的weight,当做是不同神经元的输入。然后每一个神经元都是一个函数,它的输入是一个数值,输出是另外一个数值。 但是如果是LSTM的话呢?其实只要把LSTM的memory的cell想成是一个神经元就好了。 现在的x1,x2只是会乘上不同的weight,当做LSTM的不同的输入。假设只有两个"神经元"。会把输入(x1,x2)乘上一组weight当做input的输入,乘上一组weight当做三个Gate的输入。 我们刚才讲过LSTM有4个input,1个output。对于LSTM来说,这4个input是不一样的。在原来的神经网络中,一个神经元就是一个input,一个output。在LSTM中有4个input,才能产生一个output。所以假设使用的LSTM的"神经元"跟Original Network神经元的数目是相等的,LSTM的参数的量会是Original network的四倍。
------------------------------------------------------------------------------------------------------------------------------- 但是这样讲,可能还是没有办法体会这个跟RNN的关系。所以又画了一个图。这个图也要画非常久。【liupc:我没怎么懂】 假设我们现在有一整排的"神经元",有一整排的LSTM。这一整排的LSTM里面呢,每一个的memory里面,都存了一个值。把这些数值接起来,就变成一个向量。写成c^(t-1)。
现在在时间点t,输入一个向量xt。这个xt首先会做一个线性变换,乘上一个矩阵,变成另外一个向量z。z这个向量的每一个dimension就代表了操控每一个LSTM的input。Z的第一维就丢给第一个cell ,第二维就丢给第二个cell,第三维就丢给第三个cell。
xt会乘上另外一个矩阵,得到zi,zi的维度也跟cell的数目一样。zi的每一个dimension都会去操控每一个memory。第一维操控第一个Input Gate,第二维操控第二个Input Gate...第n维操控第n个Input Gate. 同样,也有Zo和Zf。zf会去操控每一个Forget Gate ,zo会去操控每一个Output Gate。 所以把xt乘上不同的四个不同的transform,得到4个不同的向量。这4个不同的vectors,他们的维度都跟cell的数目是一样的。这4个向量合起来,就回去操控这些memory的运作。
好,我们知道一个memory cell长右边这样。注意四个输入z、zi、zf、zo分别是四个向量的某一个维度的数值。 其运算过程可以画成左边的图。 在下一个时间点,input为xt+1。经过相同的运算。 有人说,这个过程已经够复杂的了。但是这并不是LSTM的最终形态。真正的LSTM会把yt也接进来,当做下一个时间点的输入。也就是说,下一个时间点操控这些Gate的值不是只看那个时间点的X,还要看上一个时间点的output h。
还不止这样,还要加一个东西,叫做"peephole"。这个peephole就是把存在memory里面的值呢,也拉过来。所以在操控LSTM的四个Gate的时候,是同时考虑了x,h,c。把这三个三个向量并在一起,乘上四个不同的transform,得到四个不同的向量。再去操控LSTM。
LSTM不会只有一层,现在胡乱都要叠个五六层才爽。所以大概就长成这样。 每一个第一次看到这个的人,他的反映都是这样: 第一次见到都认为不work,但是现在其实还quite standard。当有个人告诉你说,我用RNN做了什么事情的时候,其实他就是用LSTM。 Keras里面有LSTM,所以上面讲的没听懂就算了,在Keras里面就是打LSTM四个字母就结束了。 Keras其实支持三种RNN,"LSTM","GRU","SimpleRNN"。GRU是LSTM的稍微简化的版本,它只有两个Gate,据说少了一个Gate,performance跟LSTM差不多,但是少了三分之一的参数,不容易overfitting。要用上次将的最简单的RNN的话,需要说是SimpleRNN才行。
|