应用场景
在自然语言处理的场景下,顺序关系至关重要,比如“我请你吃饭”与“你请我吃饭”,这两句话虽然构成的单词相同,但是其表达的意义却是截然相反。目前较为火热的卷积神经网络(CNN)主要处理图片中像素值之间的空间关系,不能捕获输入的时序信息,而循环神经网络(RNN)对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,利用了RNN的这种能力,使深度学习模型在解决语音识别、语言模型、机器翻译以及时序分析等NLP领域的问题时有所突破。
举个简单的例子
第一句话:I like eating apple!(我喜欢吃苹果!)
第二句话:The Apple is a great company!(苹果是一家很棒的公司!)
现在的任务是要给apple打Label,我们都知道第一个apple是一种水果,第二个apple是苹果公司,假设我们现在有大量的已经标记好的数据以供训练模型,当我们使用全连接的神经网络时,我们做法是把apple这个单词的特征向量输入到我们的模型中,在输出结果时,让我们的label里,正确的label概率最大,来训练模型,但我们的语料库中,有的apple的label是水果,有的label是公司,这将导致模型在训练的过程中,预测的准确程度取决于训练集中哪个label多一些,这样的模型对于我们来说完全没有作用。问题就出在了我们没有结合上下文去训练模型,而是单独的在训练apple这个单词的label,这也是全连接神经网络模型所不能做到的,于是就有了我们的循环神经网络。
原理架构
如图所示,为循环神经网络的基础架构,$x_t$代表t时刻的输入(例如单词的嵌入向量);$W$代表隐藏层的权重矩阵,该矩阵会随着输入不断更新,以便记录历史信息;$O_t$代表t时刻的输出。
RNN之所以可以解决序列问题,是因为它可以记住每一时刻的信息,每一时刻的隐藏层不仅由该时刻的输入层决定,还由上一时刻的隐藏层决定,公式如下:
其中 ,$O_t$ 代表t时刻的输出;$S_t$代表t时刻的隐藏层的值,$S_t$的值不仅仅取决于$X_t$, 还取决于$S_{t-1}$;$g$、$f$对应不同的映射函数。值得注意的一点是,在整个训练过程中,每一时刻所用的都是同样的W,只不过W在不断的更新
常见模型
基础RNN架构
在这里简单举一个例子方便理解:假设存在一个RNN,如下图所示,输入的每个单词的特征向量是二维的,也就是输入层的维度是二维,且隐藏层也假设是二维,输出也假设是二维,所有权重的值都为1且没有偏置且所有激活函数都是线性函数$f(x)=x$。现在输入一个序列到该模型中,我们来一步步求解出输出序列:
输入向量:
你可能会好奇W去哪了?W在实际的计算中,在图像中表示非常困难 ,所以我们可以想象上一时刻的隐藏层的值是被存起来,等下一时刻的隐藏层进来时,上一时刻的隐藏层的值通过与权重相乘,两者相加便得到了下一时刻真正的隐藏层,可以看做每一时刻存下来的值。当然初始时 , 是没有存值的,因此初始值为0
当我们输入第一个嵌入向量[1,1],如下图,其中隐藏层的值,也就是绿色神经元,是通过公式 $S_t = f(UX_t+WS_{t-1})$ 计算得到的,因为所有权重都是1,所以也就是 $11+11+10+10=2$。输出层的值$4$是通过公式$O_t=g(VS_t)$计算得到的,也就是 $21+2*1=4$,得到输出向量[4,4]。
当[1,1]输入过后,我们的记忆里的 $w_1,w_2$ 已经不是0了,而是把这一时刻的隐藏状态放在里面,即变成了2,如图,输入下一个向量[1,1],隐藏层的值通过公式$S_t = f(UX_t+WS_{t-1})$得到,$11+11+12+12=6$ ,输出层的值通过公式$O_t=g(VS_t)$,得到 $61+6*1=12$ ,最终得到输出向量[12,12]:
同理,该时刻过后 $w_1,w_2$ 的值变成了6,也就是输入第二个[1,1]过后所存下来的值,同理,输入第三个向量[2,2],如图,细节过程不再描述,得到输出向量[32,32]:
由此,我们得到了最终的输出序列为:
至此,一个完整的RNN结构我们已经计算了一遍,我们注意到,每一时刻的输出结果都与上一时刻的输入有着非常大的关系,如果我们将输入序列换个顺序,那么我们得到的结果也将是截然不同,这就是RNN的特性,可以处理序列数据,同时对序列也很敏感。
长短时记忆
首先大概介绍一下LSTM,是四个单词的缩写,Long short-term memory,翻译过来就是长短期记忆,是RNN的一种,比普通RNN高级(上面讲的那种),基本一般情况下说使用RNN都是使用LSTM,现在很少有人使用上面讲的那个最基础版的RNN,因为那个存在一些问题,导致随着网络的深度加深,出现了梯度消失与梯度爆炸的问题,LSTM通过它的“门控装置”有效的缓解了这个问题,这也就是为什么我们现在都在使用LSTM而非普通RNN。
既然前面已经说了,LSTM是RNN的一种变体,更高级的RNN,那么它的本质还是一样的,还记得RNN的特点吗,可以有效的处理序列数据,当然LSTM也可以。它在每个时刻都会把隐藏层的值存下来,到下一时刻的时候再拿出来用,这样就保证了,每一时刻含有上一时刻的信息,如图,我们把存每一时刻信息的地方叫做Memory Cell,中文就是记忆细胞,可以这么理解。
打个比喻吧,普通RNN就像一个乞丐,路边捡的,别人丢的,什么东西他都想要,什么东西他都不嫌弃,LSTM就像一个贵族,没有身份的东西他不要,他会精心挑选符合自己身份的物品。这是为什么呢?有没有思考过,原因很简单,乞丐没有选择权,他的能力注定他只能当一个乞丐,因此他没有挑选的权利,而贵族不一样,贵族能力比较强,经过自己的打拼,终于有了地位和身份,所以可以选择舍弃一些低档的东西,这也是能力的凸显。LSTM和普通RNN正是贵族和乞丐,RNN什么信息它都存下来,因为它没有挑选的能力,而LSTM不一样,它会选择性的存储信息,因为它能力强,它有门控装置,它可以尽情的选择。
普通RNN只有中间的Memory Cell用来存所有的信息,而从下图我们可以看到,LSTM多了三个Gate,也就是三个门,什么意思呢?在现实生活中,门就是用来控制进出的,门关上了,你就进不去房子了,门打开你就能进去,同理,这里的门是用来控制每一时刻信息记忆与遗忘的。
依次来解释一下这三个门:
- Input Gate:中文是输入门,在每一时刻从输入层输入的信息会首先经过输入门,输入门的开关会决定这一时刻是否会有信息输入到Memory Cell。
- Output Gate:中文是输出门,每一时刻是否有信息从Memory Cell输出取决于这一道门。
- Forget Gate:中文是遗忘门,每一时刻Memory Cell里的值都会经历一个是否被遗忘的过程,就是由该门控制的,如果打卡,那么将会把Memory Cell里的值清除,也就是遗忘掉。
按照上图的顺序,信息在传递的顺序,是这样的:先经过输入门,看是否有信息输入,再判断遗忘门是否选择遗忘Memory Cell里的信息,最后再经过输出门,判断是否将这一时刻的信息进行输出。其结构大致如图所示:
我们类比着来学习,首先看图中最中间的地方,Cell,我们上面也讲到了memory cell,也就是一个记忆存储的地方,这里就类似于普通RNN的$S_t$,都是用来存储信息的,这里面的信息都会保存到下一时刻,其实标准的叫法应该是$h_t$,因为这里对应神经网络里的隐藏层,所以是hidden的缩写,无论普通RNN还是LSTM其实t时刻的记忆细胞里存的信息,都应该被称为$h_t$。再看最上面的$a$,是这一时刻的输出,也就是类似于普通RNN里的$O_t$。最后,我们再来看这四个$Z,Z_i,Z_f,Z_o$,这四个相辅相成,才造就了中间的Memory Cell里的值,而对于LSTM的输入,这四个$Z,Z_i,Z_f,Z_o$都有输入向量$X_t$的参与。
其中$Z$是最为普通的输入,可以从上图中看到,$Z$是通过该时刻的输入 $X_t$和上一时刻存在memory cell里的隐藏层信息$h_{t-1}$向量拼接,再与权重参数向量$W$点积,得到的值经过激活函数tanh最终会得到一个数值,也就是$Z$,注意只有$Z$的激活函数是tanh,因为$Z$是真正作为输入的,其他三个都是门控装置。再来看$Z_i$,input gate的缩写i,所以也就是输入门的门控装置,$Z_i$同样也是通过该时刻的输入$X_t$和上一时刻隐藏状态,也就是上一时刻存下来的信息$h_{t-1}$向量拼接,在与权重参数向量$W_i$点积(注意每个门的权重向量都不一样,这里的下标i代表input的意思,也就是输入门)。得到的值经过激活函数sigmoid的最终会得到一个0-1之间的一个数值,用来作为输入门的控制信号。以此类推,就不详细讲解$Z_f,Z_o$了,分别是缩写forget和output的门控装置,原理与上述输入门的门控装置类似。
门控循环单元
GRU是LSTM的一种简单的变体,比LSTM网络的结构更加简单,而且效果也不差,运行效率更高,因此也是当前流行的一种网络结构。