机器学习篇:循环神经网络RNN
0 前言
-
卷积神经网络DNN和CNN
-
循环神经网络RNN
-
神经网络发展历史
-
自然语言处理 NLP
循环神经网络想要整理的内容包括:
-
循环神经网络结构
-
经典循环神经网络
-
循环神经网络的变体
1.1 循环神经网络
神经网络可以当作可以拟合任何函数的盒子,而全连接神经网络存在参数过多的维数灾难,卷积神经网络通过使用卷积核作为特征提取做到了局部连接、权值共享。
而针对序列数据,如文本、语音、视频、气象观测数据、股票交易数据等,经典神经网络存在两个问题:
-
输入和输出不固定。样本数据,如文本中,我们并不能限制每个句子长度一致。
-
特征无法复用,导致参数规模庞大产生维数灾难。譬如说卷积神经网络利用卷积核进行特征提取就做到了特征复用,参数共享。
所以引入了循环神经网络(Recurrent neural network, RNN),循环神经网络是一类扩展的人工神经网络,它是为了对序列数据进行建模而产生的。循环神经网络针对对象是序列数据,其核心思想:
-
样本间存在顺序关系,每个样本和它之前的样本存在关联。
-
通过神经网络在时序上的展开,我们能够找到样本之间的序列相关性。
1.2 循环神经网络结构
卷积神经网络通过卷积核来达到参数共享,而循环神经网络是针对的时间序列,时间序列的下一个序列的计算参数由上一个序列计算得出,这样子时间序列的每一个输入都会受到之前输入的影响。循环神经网络RNN的结构如下所示:
其中X是输入的时间序列或者说是一个向量,O也是一个向量,是输出层,S也是一个向量,是隐藏层。U是输入层到隐藏层的权重矩阵,V是隐藏层到输出层的权重矩阵。从下图可以看出,隐藏层的值St不仅仅取决于当前的输入X,还取决于上一次隐藏层的值St-1,权重W矩阵W就是上一次的值作为这一次的输出的权重。
用公式表示如下:
1.2.1 循环神经网络的常见结构包含
one to one:也即是原始神经网络
one to many:譬如说图像描述
many to one:譬如说情感分类,通过一个输入的句子中多个词来获取情感类别,但是存在上下文、长时间的序列损失的缺点。
many to many I:机器翻译,文字序列生成文字序列
many to many II:命名实体识别
1.2.2 网络内部计算过程
前面有简单地了解一下循环神经的网络结构,可得到公式:
其中的Ot是输出,St是传递到下一时间序列并施加影响的向量。但是在这里要提一下激活函数的概念。
之前有提到过,神经网络几乎可以拟合任何函数,但是如果如下所示,仅仅是权重相乘并添加偏置,无论如何,拟合的结果Y'都只会是线性,那么网络的逼近能力就相当有限。所以便引入了非线性函数作为激活函数(激励函数),这样深层神经网络表达能力就更加强大。
早期研究神经网络主要采用sigmoid函数或者tanh函数,输出有界,很容易充当下一层的输入。近些年Relu函数及其改进型(如Leaky-ReLU、P-ReLU、R-ReLU等)在多层神经网络中应用比较多。
在添加了激励单元后,将循环神经网络的计算单元内部展开可以得到如下的结果:
也即是:
1.2.3 循环神经网络遇到的问题
当网络层次越来越深的时候(序列越来越长)就可能产生:梯度爆炸和梯度消失。所谓梯度消失是指,在我们训练模型的过程中,需要按照反向传播来不断训练模型的参数,但是随着网络层次越来越深,反向传播的值无法传到浅层,数据不再变化,无法再训练。
梯度消失和梯度爆炸的本质上上一样的,都是因为网络层数太深而引发的梯度反向转笔中的连乘效应。当我们对sigmoid函数求导,其导数取值范围在0至0.25之间,而我们初始化的网络权值|W|通常都小于1,因此,当层数增多时,小于0的值不断相乘,最后就导致梯度消失的情况出现。同理,梯度爆炸就是当权值|W|过大时,导致|sigmoid'(z)W|>1,最后大于1的值不断相乘,就会产生梯度爆炸。
同时,对于某些进行正确预测可能依赖于很久之前的某些信息的序列,循环神经网络的预测可能不够准确,因为RNN的预测受到的主要影响是较为靠近的输入。如:
The Cat, which already ate apples banana ..., was full The Cats, which already ate apples banana ..., were full
解决方法
-
梯度爆炸:进行梯度修剪,也即是设置一个剪切阈值,如果更新梯度时,梯度超过了这个阈值,那么将其强制限制在这个范围之内。这样可以防止梯度爆炸。
-
梯度消失:1) 改变激活函数,将tanh激活函数更改为ReLU。2)修改网络结构,如GRU和LSTM。作为目前最广为使用的RNN变体,LSTM和GRU通过门控机制很大程度上缓解了RNN的梯度消失问题,但是它们的内部结构看上去十分复杂,使得初学者很难理解其中的原理所在。
2、经典循环神经网络
前最广为使用的RNN变体就是上面所说的LSTM和GRU,相对而言比较复杂。
2.1 LSTM 长短时记忆网络
为了解决梯度消失(Gradient Vanish)的问题,Hochreiter&Schmidhuber 在论文“Long short-term memory, 1997”中提出了 LSTM(Long Short-Term Memory)。原始的LSTM只有输入门(Input Fate)和输出门(Output Gate),后面由 Gers 在"Learning to Forget: Continual Prediction with LSTM, 2000"中提出了改进版本,添加了遗忘门(Forget Gate)。后来,在"LSTM Recurrent Networks Learn Simple Context Free and Context Sensitive Languages, 2001"中 Gers 又加入了 窥视孔连接(Peephole Connection) 的概念。同时,现在常用的深度学习框架 Tensorflow、Pytorch 等在实现 LSTM 上也有一些细微的区别。以上所说的虽然本质都是 LSTM,但结构上还是有所区别,在使用时需要注意一下。
LSTM中重复单元的内部计算如下图所示:
公式如下所示:
其中,
-
遗忘门(forget gate):它决定上一时刻的单元状态C<t-1>(长期记忆)有多少信息保留到当前时刻C<t>。可以保存很久很久之前的信息,解决RNN网络中的长依赖问题。
-
输入门(input gate):它决定当前时刻的网络输入x<t>有多少信息保存到单元状态C<t>。可避免当前无关紧要的内容进入记忆。
-
输出门(output gate):控制单元状态C<t>有多少输出到LSTM的当前输出值h<t>。控制了长期记忆对当前输出的影响。
在我们训练LSTM模型的过程中,目标则是学习8组参数,如下图所示:
2.2 GRU 门控循环单元
LSTM有很多变体,其中较大改动的是Gated Recurrent Unit(GRU),这是由Cho,et al.(2014)提出。它将遗忘门与输入门合成了一个单一的更新门,仅有两个门:更新门(Update Gate)和重置门(reset Gate)。同样还混合了细胞状态和隐藏状态,以及一些其他的改动。最终的模型比标准的LSTM模型要简单。效果和LSTM差不多,但是参数少了1/3,不容易过拟合。作为LSTM的变体,GRU也可以解决RNN网络中的长依赖问题。
GRU中的重置门$ R_t$和更新门$Z_t$的输入均为当前时间的输入$x_t$与上一时间的隐藏状态$h_{t-1}$进行权重及偏置计算后,在经由激活函数sigmoid后计算得到。
而候选隐藏状态$\widetilde{h}_t$,GRU将计算候选隐藏状态来辅助稍后的隐藏状态的计算,将当前时间重置门与上一时间隐藏状态做按元素乘法(若重置门的元素值接近0,则意味着丢弃上一时间的隐藏状态,接近1则表示保留上一时间的隐藏状态。),然后将结果与当前时间输入连结,在经由激活函数tanh后计算得出候选隐藏状态,其所有元素的值域为[-1,1]。
候选隐藏状态$\widetilde{h}t$只是为了更新新的隐藏状态$h_t$,而并不是隐藏状态,所以$h_t$计算需要使用当前时间的更新门$z_t$来对上一步的隐藏状态$h{t-1}$和当前时间步的候选隐藏状态$\widetilde{h}_t$做组合。
3、循环神经网络的变体
这里会涉及循环神经网络RNN的两个变体双向循环网络(Bi-directional RNNs)和深层循环网络(Multi-layer RNNs)。
3.1 双向循环网络(Bi-directional RNNs)
标准的RNN在时刻t的状态只能从过去的序列以及当前的输入中捕获信息,无法使用到后面序列的信息。
BRNN结合时间上从序列起点开始移动的RNN和另一个时间上从序列末尾开始移动的RNN。这允许输出单元能够计算同时依赖于过去和未来且对时刻t的输入值最敏感的表示。
BRNN在每个时刻增加一个隐藏单元,如下图所示(图源:深度学习)
其中隐藏单元h在时间上向前传播,隐藏单元g在时间上向后传播。
BRNN的缺点是必须获取了所有时刻后的输入之后,才能进行每个时刻的输出。从其结构上来看,适合进行自然语言处理,能够克服标准RNN不能处理上下文的缺陷。
3.2 深层循环网络(Deep RNNs)
在标准的RNN中,我们在每一个时刻对该时刻的输入$x_t$的处理都只包含一个隐藏层。而DRNN是由多个隐藏层叠加而成,如下图所示:
DRNN中较低的层起到了将原始输入转化为对更高层的隐藏状态更适合的表示的作用。
一般来说,多层神经网络随着层数增加,其拟合能力会更好。但是增加深度会带来优化困难,而且因为RNN在时间维度上很大,所以一般不会构建很深的RNN。
参考