深度学习(Deep Learning)读书思考六:循环神经网络一(RNN)

概述

循环神经网络(RNN-Recurrent Neural Network)是神经网络家族中的一员,擅长于解决序列化相关问题。包括不限于序列化标注问题、NER、POS、语音识别等。RNN内容比较多,分红三个小节进行介绍,内容包括RNN基础以及求解算法、LSTM以及变种GRU、RNN相关应用。本节主要介绍web

1.RNN基础知识介绍
2.RNN模型优化以及存在的问题
3.RNN模型变种算法

RNN知识点

RNN提出动机

RNN的提出能够有效解决如下问题:网络

  1. 长期依赖问题:在语言模型、语音识别中须要根据上下文进行推断和预测,上下文的获取能够根据马尔科夫假设获取固定上下文。RNN能够经过中间状态保存上下文信息,做为输入影响下一时序的预测。
  2. 编码:能够将可变输入编码成固定长度的向量。和CNN相比,可以保留全局最优特征。svg

    计算图展开

    RNN经常使用如下公式获取历史状态函数

    ht=f(ht1,xt;θ)

    其中h为隐藏层,用于保存上下文信息,f是激活函数。
    用图模型能够表达为:
    这里写图片描述

RNN潜在可能的展开方式以下:
1)经过隐藏层传递信息
这里写图片描述优化

1.该展开形式很是经常使用,主要包括三层输入-隐藏层、隐藏层-隐藏层、隐藏层到输入层。依赖信息经过隐藏层进行传递。
2.参数U、V、W为共享参数编码

2)输出节点链接到下一时序序列
这里写图片描述atom

应用比较局限,上一时序的输出做为下一时间点的输入,理论上上一时间点的输出比较固定,可以携带的信息比较少。spa

3)只有一个输出节点
这里写图片描述code

只在最后时间点t产生输出,每每可以将变成的输入转换为固定长度的向量表示。

RNN使用形式

在使用RNN时,主要形式有4中,以下图所示。
这里写图片描述

1.一对一形式(左一:Many to Many)每个输入都有对应的输出。
2.多对一形式(左二:Many to one)整个序列只有一个输出,例如文本分类、情感分析等。
3. 一对多形式(左三:One to Many)一个输入产出一个时序序列,经常使用于seq2seq的解码阶段
4.多对多形式(左四:Many to Many)不是每个输入对应一个输出,对应到变成的输出。

RNN数学表达以及优化

RNN前向传播

对于离散时间的RNN问题能够描述为,输入序列

(x1,y1),(x2,y2),(x3,y3)......(xT,yT)

其中时间参数t表示离散序列,不必定是真实时间点。
对于多分类问题,目标是最小化释然函数
mint=1TL(y^(xt),yt)=mintlog p(yt|x1,x2...xt)

根据上面经典的RNN网络结构,前向传播过程以下:
如上图U、V、W分别表示输入到隐藏层、隐藏层到输出以及隐藏到隐藏层的链接参数。
1. 隐藏层节点权值: at=b+Wht1+Uxt
2. 隐藏层非线性变换: ht=tanh(at)
3. 输出层: ot=c+Vht
4. softmax层: y^t=softmax(ot)

RNN优化算法-BPTT

BPTT 是求解RNN问题的一种优化算法,也是基于BP算法改进获得和BP算法比较相似。为直观上理解经过多分类问题进行简单推导。
1. 优化目标,对于多分类问题,BPTT优化目标转换最小化交叉熵:

mintLtLt=kytklogy^tk
这里假设有k个类
2. 因为总的损失L为各个时序点的损失和,所以有
LLt=1

3. 对于输出层中的第i节点有
(otL)i=Loti=LLtLtoti=y^ti1i,yt
最后一步是交叉熵推导结果,步骤省略,了解softmax的都清楚。 1i,yt 表示若是y^t==i则为1,不然为0
4. 隐藏层节点梯度的计算,分为两部分,第一部分 t=T。
(hTL)i=j(oTL)joTjhTi=j(oTL)jVij
经过向量的方式表达为
(hTL)=(oTL)oThT=(oTL)V

5.第二部分, 中间节点 t<T ,对于中间节点须要考虑t+1以及之后时间点传播的偏差,所以计算过程以下。
(htL)i=j(ht+1L)jht+1jhti+k(otL)kotkhti=+=j(ht+1L)jht+1jat+1jat+1jhti+k(otL)kVki=j(ht+1L)j(1ht+1j2)Wji+k(otL)kVki=(ht+1L)diag((1ht+12))Wi+(otL)Vi
经过向量表示以下:
(htL)=(ht+1L)ht+1ht+(otL)otht=(ht+1L)diag((1ht+12))W+(otL)V
其中 diag((1ht+12)) 是由 1ht+1i 的平方组成的对角矩阵。
6.根据中间结果的梯度能够推导出其余参数的梯度,结果以下
cLbLVLWLUL=t(toL)otc=t(toL)=t(thL)htb=t(thL)diag((1ht2))=t(toL)otV=t(toL)htT=t(thL)htW=t(thL)diag((1ht2))ht1T=t(thL)htU=t(thL)diag((1ht2))xtT

7. 到此完成了对全部参数梯度的推导。

梯度弥散和爆炸问题

RNN训练比较困难,主要缘由在于隐藏层参数W,不管在前向传播过程仍是在反向传播过程当中都会乘上屡次。这样就会致使1)前向传播某个小于1的值乘上屡次,对输出影响变小。2)反向传播时会致使梯度弥散问题,参数优化变得比较困难。
这里写图片描述

能够经过梯度公式也能够看出梯度弥散或者爆炸问题。
考虑到通用性,激活函数采用f(x)代替,则对隐藏层到隐藏层参数W梯度公式以下:

WL=t(thL)htW=t(thL)diag(f(ht))ht1
后面部分能够直接获得,下面详细分析它的系数 (thL)

1.考虑当t=T,即为最后一个节点时,根据上面的推导有

(hTL)=(oTL)oThT=(oTL)V

2.当t=T-1时,
(hT1L)=(ThL)ht+1ht=(hTL)diag(f(hT))W
注这里只考虑隐藏层节点对W的偏差传递,没有考虑输出层。
3. 当t=T-2时,
(hT2L)=(T1hL)hT1hT2=(hTL)diag(f(hT))Wdiag(f(hT1))W=(hTL)diag(f(hT))diag(f(hT1))W2

4. 当t=k时
(hkL)=(ThL)j=k+1Thjhj1=(hTL)j=kTdiag(f(hj))W

5.此时 diag(f(hj))W 的结果是一个对角矩阵,若是其中某个元素大于1,则该值会指数倍放大;不然会以指数倍缩小。
6.所以能够看出当序列比较长,即模型有长期依赖问题时,就会产生梯度相关问题。通常状况下BPTT对于序列长度在100之内,不会暴露问题。
7.须要注意的是,若是咱们的训练样本被人工分为子序列,且长度都较小时,不会产生梯度问题。此时比较依赖于前期预处理

梯度问题解决方案

梯度爆炸问题方案

该问题采用截断的方式有效避免,而且取得较好的效果。
这里写图片描述

梯度弥散问题解决方案

针对该问题,有大量的解决方法,效果不一致。
1.有效初始化+ReLU激活函数可以获得较好效果
2.算法上的优化,例如截断的BPTT算法。
3.模型上的改进,例如LSTM、GRU单元均可以有效解决长期依赖问题。
4.在BPTT算法中加入skip connection,此时偏差能够间歇的向前传播。
5.加入一些Leaky Units,思路相似于skip connection

RNN模型改进

主要有两大类思路

双向RNN(Bi-RNN)

此时不只能够依赖前面的上下文,还能够依赖后面的上下文。
这里写图片描述

深度RNN(Deep-RNN)

有多种方式进行深度RNN的组合,左一比较经常使用。
这里写图片描述

总结

经过该小结的总结,能够了解到 1)RNN模型优点以及处理问题形式。 2)标准RNN的数学公式以及BPTT推导 3)RNN模型训练中的梯度问题以及如何避免