循环神经网络(RNN)是另一种比较流行的神经网络,它对文本方面的应用表现非常敏感。一开始看的是吴恩达老师的视频课,但是发现看了一段时间后还是非常的模糊。偶然看到台湾大学李宏毅教授的上课视频,感觉讲的通俗易懂,豁然开朗。依据老师的上课资料与视频写下自己的笔记,加深一下印象。
1Example Application
老师先用一个Slot Filling 的例子,即输入一个句子,预设有几个槽位,将句子的信息插入到对于的槽位。比如 下面所示
输入 I would like to arrive TaiPei on November 2th。那么Taipei对应的就是 Destination目的地,November 2th对应的就是到达的时间。我们假设可以使用神经网络来解决这个问题,神经网络的输入是每个单词,该单词使用向量表示,可以使用1-of N encoding将一个单词转化为向量的方式,当然还有其他表示。那么该神经网络的输出就是该单词属于某个槽位的概率。由于我们只考虑的单词本身,而没有依靠上下文语义去判断该单词是否属于槽位,所以会出现问题。如下所示,输入两个句子
Taipei前面根据不同的词,一个arrive,另一个leave。我们知道前一句taipei是Destination,第二句是place of departure。但是上述的我们训练的神经网络不知道,它仅仅会考虑taipei,然后认定它为一个特定的槽位。如果我们假设神经网络有记忆,那么就可很清晰的分辨出两个taipei是属于不同的槽位的,这就引伸出了RNN,也就是循环神经网络。
2 Recurrent Neural Network
依我自己通俗的,简单的理解RNN的本质就是在一个神经网络中,当前神经元需要考虑上一个或者上一层神经元的输出。如老师所讲述的一个简单结构
将隐藏层的输出存储在记忆中,然后下次输入新的数据时,要考虑记忆中的值。李宏毅老师还举了一个非常简单例子,也就是输入三个向量 ,隐藏的激活函数就是线性函数这种,bias偏差为0,输出为 .如下图所示
输入 时,绿色的隐藏层为2,将值存入蓝色的memory中,输出值为,再次输入 时,由于需要考虑memory中的值,我们只是把他们相加,所以值为 .存入蓝色的memory中,输出值为 ,再输入 时,加上两个6,值为16,最后输出为
上述就是简单的RNN例子及运算,如果将RNN使用在之前的slot clipping中,过程会如下所示
我们将单词一个个输入,再第一个单词arrive 和leave 分别输入后,将他们计算的隐藏层的数值存储起来,再输入taipei时,由于之前存储的值不同,所以会得到不同的结果,当然要使用肯定时需要更深层次的RNN网络。此外还有不存储隐藏层值而存储输出值的,这种叫做Jardan Network. 此外还有双向的RNN。
3 Long Short-term Memory(LSTM)
现在LSTM非常的流行,在NLP上更甚,通常所讲使用的RNN其实就是LSTM。LSTM的神经元架构如下所示,它有4个输入,一个输出。4个输入分别时一个输入数据,一个输入控制门和一个输出控制门,一个遗忘门。其实这些控制门也是相应的函数。如下所示
这是结构图,我们可以之间使用数学公式计算来解释这些门,输入门就是控制输入,如果为sigmoid函数,为1就时允许输入,为0就是输入的值为0 等等。使用数学公式描述LSTM的神经元为如下所示
我们上述所讲的激活函数都是sigmoid函数,如果输入一个z值,通过神经元激活函数计算为,输入控制门输入的值为,门内的函数为计算为,再两者相乘为。到遗忘控制门这,输入值为,memory原先存储的值为,那么新的值为
,然后再通过一个函数计算得出为,经由控制们后,最后的输出为.虽然过程非常的复杂,但是理解起来还是很清晰的,最后李宏毅老师手动举了一个例子用来计算LSTM,真的非常的容易懂。
最后关于这些控制们的输入值,是由一个数据转化为向量得出来的,由于上诉只是一个LSTM的最基本的结构,一层往往有很多个这样的单元,所以我们需要将输入的值变成一个向量,再根据这个向量里面的值,选择作为各种控制门的输入,如下所示
就是上一个输入值训练后存储在momery中的值。LSTM就是很多层这样的结构进行叠加起来。更详细的结构如下所示
说实话一个就看到很头痛,还好这些我们都不需要自己去具体实现,keras可以帮我们具体去实现,我们只需要调用参数就可以了。至于这些参数的具体值,都是由LSTM自己去学习的,也就是向后传播算法,但是是进阶的算法叫做Backpropagation through time(BPTT)。但是RNN有时候训练会不尽人意,在训练时我们希望随着epoch 的增加,RNN的loss函数也会随之下降,但是也可能会出现这样的情况
那是因为RNN的total loss是会剧烈抖动的,因为会剧烈抖动,没法保证平滑下降,如下图所示
表面要么非常平坦,要么非常陡峭(当你的参数值在较为平坦的区域做更新时,因此该区域梯度值比较小,此时的学习率一般会变得的较大,如果突然到达了陡峭的区域,梯度值陡增,再与此时较大的学习率相乘,参数就有很大幅度更新(实线表示的轨迹),因此学习过程非常不稳定。Razvan Pascanu使用了叫做“Clipping”的训练技巧:为梯度设置阈值,超过该阈值的梯度值都会被cut,这样参数更新的幅度就不会过大。