目录
RNN(循环神经网络)
摘要
Introduction(介绍)
LSTM
Three-gate
Memory Cell
LSTM Example
LSTM Structure
Learning Target
Loss Function
Training
Error Surface
Help Techniques
RNN的应用
Many to one
Many to many
RNN v.s. Structured Learning
总结与展望
有记忆力的神经网络,就叫做Recurrent Neural Network(RNN)
本节内容主要是讲讲解RNN或者说最常用的LSTM。
首先举了例子,比如Slot Filling,为了应对复杂得语句,我们希望我们的NN有记忆力,这就是RNN。
其次,讲解LSTM的组成,它由四部分组成,每个LSTM本质上就是一个neuron,特殊之处在于有4个输入,以及LSTM的工作过程和原理。
接着,讲解了如何训练RNN(LSTM),以及训练会遇到的问题梯度消失和梯度爆炸以及解决办法使用Clipping方法。
然后,讲解了RNN的各种应用,特别是在语音方面的应用。
最后,对比RNN和Structured Learning,得出结论Deep and structure is future。
Slot Filling
在智能客服、智能订票系统中,往往会需要slot filling技术,它会分析用户说出的语句,将时间、地址等有效的关键词填到对应的槽上,并过滤掉无效的词语。
词汇要转化成vector,可以使用1-of-N编码等方式,此外我们可以尝试使用Feedforward Neural Network来分析词汇,判断出它是属于时间或是目的地的概率。
但这样做会有一个问题,该神经网络会先处理“arrive”和“leave”这两个词汇,然后再处理“Taipei”,这时对NN来说,输入是相同的,它没有办法区分出“Taipei”是出发地还是目的地,
这个时候我们就希望神经网络是有记忆的,如果NN在看到“Taipei”的时候,还能记住之前已经看过的“arrive”或是“leave”,就可以根据上下文得到正确的答案。
这种有记忆力的神经网络,就叫做Recurrent Neural Network(RNN)。
在RNN中,hidden layer每次产生的output a1、a2,都会被存到memory里,下一次有input的时候,这些neuron就不仅会考虑新输入的x1、x2,还会考虑存放在memory中的a1、a2。
注意到,每次NN的输出都要考虑memory中存储的临时值,而不同的输入产生的临时值也尽不相同,
因此改变输入序列的顺序会导致最终输出结果的改变(Changing the sequence order will change the output)。
用RNN处理Slot Filling的流程举例如下:
注意:上图为同一个RNN在三个不同时间点被分别使用了三次,并非是三个不同的NN
这个时候,即使输入同样是“Taipei”,我们依旧可以根据前文的“leave”或“arrive”来得到不一样的输出
RNN有不同的变形:
Bidirectional RNN
RNN 还可以是双向的,你可以同时训练一对正向和反向的RNN,把它们对应的hidden layer xt 拿出来,都接给一个output layer,得到最后的 yt。
使用Bi-RNN的好处是,NN在产生输出的时候,它能够看到的范围是比较广的,这就相当于RNN在看了整个句子之后,
才决定每个词汇具体要被分配到哪一个槽中,这会比只看句子的前一半要更好。
前文提到的RNN只是最简单的版本,并没有对memory的管理多加约束,可以随时进行读取,而现在常用的memory管理方式叫做长短期记忆(Long Short-term Memory),简称LSTM。
LSTM有三个gate:
整个LSTM可以看做是4个input,1个output:
如果从表达式的角度看LSTM,它比较像下图中的样子
把z、zi、zo、zf通过activation function,分别得到g(z)、f(zi)、f(zo)、f(zf)
其中对zi、zo和zf来说,它们通过的激活函数一般会选sigmoid function,因为它的输出在0~1之间,代表gate被打开的程度,
令g(z)与f(zi)相乘得到g(z)f(zi),然后把原先存放在cell中的c与f(zf)相乘得到cf(zf),两者相加得到存在memory中的新值c' = g(z)f(zi) + cf(zf)
从中也可以看出,forget gate的逻辑与我们的直觉是相反的,控制信号打开表示记得,关闭表示遗忘。
此后,c' 通过激活函数得到h( c' ),与output gate的f(zo)相乘,得到输出h( c' )f(zo)
下图演示了一个LSTM的基本过程,x1、x2、x3是输入序列,y是输出序列,基本原则是:
你可能会觉得上面的结构与平常所见的神经网络不太一样,实际上我们只需要把LSTM整体看做是下面的一个neuron即可:
假设目前我们的hidden layer只有两个neuron,则结构如下图所示:
LSTM for RNN
从上图中你可能看不出LSTM与RNN有什么关系,接下来我们用另外的图来表示它
假设我们现在有一整排的LSTM作为neuron,每个LSTM的cell里都存了一个scalar值,把所有的scalar连接起来就组成了一个vector c ^ t-1
在时间点t,输入了一个vector xt ,它会乘上一个matrix,通过转换得到z,而z的每个dimension就代表了操控每个LSTM的输入值,
同理经过不同的转换得到、和,得到操控每个LSTM的门信号,同理经过不同的转换得到zi、zf和zo,得到操控每个LSTM的门信号。
下图是单个LSTM的运算情景,其中LSTM的4个input分别是z、zi、zf和zo的其中1维,每个LSTM的cell所得到的input都是各不相同的,
但它们却是可以一起共同运算的,整个运算流程如下图左侧所示:
f(zf)与上一个时间点的c^t-1 cell值相乘,并加到经过input gate的输入g(z)f(zi)上,得到这个时刻cell中的值c^t,最终再乘上output gate的信号f(zo),得到输出yt。
上述的过程反复进行下去,就得到下图中各个时间点上,LSTM值的变化情况,其中与上面的描述略有不同的是,
这里还需要把hidden layer的最终输出yt以及当前cell的值ct都连接到下一个时间点的输入上。
因此在下一个时间点操控这些gate值,不只是看输入的x t+1,还要看前一个时间点的输出ht和cell值ct,你需要把x t+1、ht和ct这3个vector并在一起,
乘上4个不同的转换矩阵,去得到LSTM的4个输入值z、zi、zf、zo,再去对LSTM进行操控。
注意:下图是同一个LSTM在两个相邻时间点上的情况
上图是单个LSTM作为neuron的情况,事实上LSTM基本上都会叠多层,如下图所示,
左边两个LSTM代表了两层叠加,右边两个则是它们在下一个时间点的状态。
依旧是Slot Filling的例子,我们需要把model的输出yi与映射到slot的reference vector求交叉熵,
比如“Taipei”对应到的是“dest”这个slot,则reference vector在“dest”位置上值为1,其余维度值为0
RNN的output和reference vector的cross entropy之和就是损失函数,也是要minimize的对象,
需要注意的是,word要依次输入model,比如“arrive”必须要在“Taipei”前输入,不能打乱语序。
有了损失函数后,训练其实也是用梯度下降法,为了计算方便,这里采取了反向传播(Backpropagation)的进阶版,Backpropagation through time,简称BPTT算法:
RNN的训练并没有那么容易,
我们希望随着epoch的增加,参数的更新,loss应该要像下图的蓝色曲线一样慢慢下降,但在训练RNN的时候,
你可能会遇到类似绿色曲线一样的学习曲线,loss剧烈抖动,并且会在某个时刻跳到无穷大,导致程序运行失败,
分析可知,RNN的error surface,即loss由于参数产生的变化,是非常陡峭崎岖的,
下图中,z轴代表loss,x轴和y轴代表两个参数w1和w2,可以看到loss在某些地方非常平坦,在某些地方又非常的陡峭,
如果此时你的训练过程类似下图中从下往上的橙色的点,它先经过一块平坦的区域,又由于参数的细微变化跳上了悬崖,这就会导致loss上下抖动得非常剧烈,
如果你的运气特别不好,一脚踩在悬崖上,由于之前一直处于平坦区域,gradient很小,你会把参数更新的步长(learning rate)调的比较大,
而踩到悬崖上导致gradient突然变得很大,这会导致参数一下子被更新了一个大步伐,导致整个就飞出去了,这就是学习曲线突然跳到无穷大的原因。
想要解决这个问题,就要采用Clipping方法,当gradient即将大于某个threshold的时候,就让它停止增长,比如当gradient大于15的时候就直接让它等于15。
为什么RNN会有这种奇特的特性呢?下图给出了一个直观的解释:
假设RNN只含1个neuron,它是linear的,input和output的weight都是1,没有bias,从当前时刻的memory值接到下一时刻的input的weight是w,按照时间点顺序输入[1, 0, 0, 0, ..., 0]
当第1个时间点输入1的时候,在第1000个时间点,RNN输出的y1000=w999,想要知道参数的梯度w,只需要改变w的值,观察对RNN的输出有多大的影响即可:
因此我们可以解释,RNN训练困难,是由于它把同样的操作在不断的时间转换中重复使用,
从memory接到neuron输入的参数w,在不同的时间点被反复使用,w的变化有时候可能对RNN的输出没有影响,而一旦产生影响,
经过长时间的不断累积,该影响就会被放得无限大,因此RNN经常会遇到这两个问题:
有什么技巧可以帮我们解决这个问题呢?LSTM就是最广泛使用的技巧,它会把error surface上那些比较平坦的地方拿掉,
从而解决梯度消失(gradient vanishing)的问题,但它无法处理梯度崎岖的部分,因而也就无法解决梯度爆炸的问题(gradient explode)。
但由于做LSTM的时候,大部分地方的梯度变化都很剧烈,因此训练时可以放心地把learning rate设的小一些:
Q:为什么要把RNN换成LSTM?A:LSTM可以解决梯度消失的问题
Q:为什么LSTM能够解决梯度消失的问题?
A:RNN和LSTM对memory的处理其实是不一样的:
对RNN来说,w对memory的影响每次都会被清除,而对LSTM来说,除非forget gate被打开,否则w对memory的影响就不会被清除,而是一直累加保留,因此它不会有梯度消失的问题
另一个版本GRU (Gated Recurrent Unit),只有两个gate,需要的参数量比LSTM少,不容易过拟合,
它的基本精神是旧的不去,新的不来,GRU会把input gate和forget gate连起来,当forget gate把memory里的值清空时,input gate才会打开,再放入新的值
此外,还有很多技术可以用来处理梯度消失的问题,比如Clockwise RNN、SCRN等
在Slot Filling中,我们输入一个word vector输出它的label,除此之外RNN还可以做更复杂的事情
Sentiment Analysis
语义情绪分析,我们可以把某影片相关的文章爬下来,并分析其正面情绪or负面情绪
RNN的输入是字符序列,在不同时间点输入不同的字符,并在最后一个时间点输出该文章的语义情绪。
Key term Extraction
关键词分析,RNN可以分析一篇文章并提取出其中的关键词,这里需要把含有关键词标签的文章作为RNN的训练数据
Output is shorter
如果输入输出都是sequence,且输出的sequence比输入的sequence要短,RNN可以处理这个问题
以语音识别为例,输入是一段声音信号,每隔一小段时间就用1个vector来表示,因此输入为vector sequence,而输出则是character vector
如果依旧使用Slot Filling的方法,只能做到每个vector对应1个输出的character,识别结果就像是下图中的“好好好棒棒棒棒棒”,但这不是我们想要的,可以使用Trimming的技术把重复内容消去,剩下“好棒”
但“好棒”和“好棒棒”实际上是不一样的,如何区分呢?
需要用到CTC算法,它的基本思想是,输出不只是字符,还要填充NULL,输出的时候去掉NULL就可以得到连词的效果
下图是CTC的示例,RNN的输出就是英文字母+NULL,google的语音识别系统就是用CTC实现的
RNN,LSTM | HMM,CRF,SVM |
没有考虑整个语句 | 考虑了整个语句 |
cost和error不总是相关 | cost和error相关 |
deep | not always deep |
实际上,二者还可以结合在一起,如下图。
本节学习了RNN和LSTM:从Slot Filling案例引出我们需要有记忆力的神经网络RNN,我们知道了基本的RNN结构已经可以实现记忆了,
但是我们一般使用的是LSTM结构,我们知道了LSTM的组成,工作过程,之所以使用LSTM是因为RNN的训练并没有那么容易,
会出现gradient vanishing和gradient explode,使用LSTM它会把error surface上那些比较平坦的地方拿掉,从而解决梯度消失(gradient vanishing)的问题,
而gradient explode的解决可以将学习率调小。最后,RNN和 Structured Learning是可以结合的,在未来可能RNN和 Structured Learning结合使用是未来的方向,更值得我们关注。