RNN(循环神经网络)详解

一、 循环神经网络
      循环神经网络(Recurrent Neural Network,RNN)是一类具有短期记忆能力的神经网络。在循环神经网络中,神经元不但可以接受其它神经元的信息,也可以接受自身的信息,形成具有环路的网络结构。和前馈神经网络相比,循环神经网络更加符合生物神经网络的结构。循环神经网络已经被广泛应用在语音识别、语言模型以及自然语言生成等任务上。循环神经网络的参数学习可以通过随时间反向传播算法(BPTT)[Werbos, 1990]来学习。随时间反向传播算法即按照时间的逆 序将错误信息一步步地往前传递。当输入序列比较长时,会存在梯度爆炸和消失问题[Bengio et al., 1994, Hochreiter and Schmidhuber, 1997, Hochreiter et al., 2001],也称为长程依赖问题。(摘抄:《神经网络与深度学习》)

二、循环神经网络结构

1、为什么使用循环神经网络
        RNN的目的使用来处理序列数据。在传统的神经网络模型中,是从输入层到隐含层再到输出层,层与层之间是全连接的,每层之间的节点是无连接的。但是这种普通的神经网络对于很多问题却无能无力。例如,你要预测句子的下一个单词是什么,一般需要用到前面的单词,因为一个句子中前后单词并不是独立的。RNN之所以称为循环神经网路,即一个序列当前的输出与前面的输出也有关。具体的表现形式为网络会对前面的信息进行记忆并应用于当前输出的计算中,即隐藏层之间的节点不再无连接而是有连接的,并且隐藏层的输入不仅包括输入层的输出还包括上一时刻隐藏层的输出。理论上,RNN能够对任何长度的序列数据进行处理。但是在实践中,为了降低复杂性往往假设当前的状态只与前面的几个状态相关,模型结构如下:

                                                                图一

如果把上面有W的那个带箭头的圈去掉,它就变成了最普通的全连接神经网络。

x是一个向量,它表示输入层的值;
s是一个向量,它表示隐藏层的值;
U是输入层到隐藏层的权重矩阵;
o也是一个向量,它表示输出层的值;
V是隐藏层到输出层的权重矩阵。那
权重矩阵 W就是隐藏层上一次的值作为这一次的输入的权重。因为循环神经网络的隐藏层的值s不仅仅取决于当前这次的输入x,还取决于上一次隐藏层的值s。

注意:在同一层隐藏层中,不同时刻的W,V,U均是相等地,这也就是RNN的参数共享。在进行反向传播时更新这些参数。
2、典型RNN的前向传播

这是RNN神经网络的一个神经元:

                                                                  图二

3、rnn的反向传播

由前向传播得到预测值与真实值构建损失函数,使用梯度下降最小化损失函数。根据图一可得:

 

 需要更新的参数有W、U、V:

这是某个时刻的ws和wx的值,需要把这个时刻之前的所有信息相加:

整体的偏导公式就是将其按时刻再一一加起来。

前面说过激活函数是嵌套在里面的,如果我们把激活函数放进去,拿出中间累乘的那部分:

 我们会发现累乘会导致激活函数导数的累乘,进而会导致“梯度消失“和“梯度爆炸“现象的发生。

至于为什么,我们先来看看这两个激活函数的图像。
这是sigmoid函数的函数图和导数图。
这是tanh函数的函数图和导数图。

 

它们二者是何其的相似,都把输出压缩在了一个范围之内。他们的导数图像也非常相近,我们可以从中观察到,sigmoid函数的导数范围是(0,0.25],tanh函数的导数范围是(0,1],他们的导数最大都不大于1。

这就会导致一个问题,在上面式子累乘的过程中,如果取sigmoid函数作为激活函数的话,那么必然是一堆小数在做乘法,结果就是越乘越小。随着时间序列的不断深入,小数的累乘就会导致梯度越来越小直到接近于0,这就是“梯度消失“现象。其实RNN的时间序列与深层神经网络很像,在较为深层的神经网络中使用sigmoid函数做激活函数也会导致反向传播时梯度消失,梯度消失就意味消失那一层的参数再也不更新,那么那一层隐层就变成了单纯的映射层,毫无意义了,所以在深层神经网络中,有时候多加神经元数量可能会比多家深度好。

你可能会提出异议,RNN明明与深层神经网络不同,RNN的参数都是共享的,而且某时刻的梯度是此时刻和之前时刻的累加,即使传不到最深处那浅层也是有梯度的。这当然是对的,但如果我们根据有限层的梯度来更新更多层的共享的参数一定会出现问题的,因为将有限的信息来作为寻优根据必定不会找到所有信息的最优解。

之前说过我们多用tanh函数作为激活函数,那tanh函数的导数最大也才1啊,而且又不可能所有值都取到1,那相当于还是一堆小数在累乘,还是会出现“梯度消失“,那为什么还要用它做激活函数呢?原因是tanh函数相对于sigmoid函数来说梯度较大,收敛速度更快且引起梯度消失更慢。

还有一个原因是sigmoid函数还有一个缺点,Sigmoid函数输出不是零中心对称。sigmoid的输出均大于0,这就使得输出不是0均值,称为偏移现象,这将导致后一层的神经元将上一层输出的非0均值的信号作为输入。关于原点对称的输入和中心对称的输出,网络会收敛地更好。

RNN的特点本来就是能“追根溯源“利用历史数据,现在告诉我可利用的历史数据竟然是有限的,这就令人非常难受,解决“梯度消失“是非常必要的。这里说两种改善“梯度消失”的方法:

1、选取更好的激活函数
2、改变传播结构

关于第一点,一般选用ReLU函数作为激活函数,ReLU函数的图像为:

ReLU函数的左侧导数为0,右侧导数恒为1,这就避免了小数的连乘,但反向传播中仍有权值的累乘,所以说ReLU函数不能说完全解决了“梯度消失”现象,只能说改善。有研究表明,在RNN中使用ReLU函数配合将权值初始化到单位矩阵附近,可以达到接近LSTM网络的效果。但恒为1的导数容易导致“梯度爆炸“,但设定合适的阈值可以解决这个问题。还有一点就是如果左侧横为0的导数有可能导致把神经元学死,不过设置合适的步长(学习率)也可以有效避免这个问题的发生。

关于第二点,LSTM结构就是传统RNN的改善。

总结一下,sigmoid函数的缺点:
1、导数值范围为(0,0.25],反向传播时会导致“梯度消失“。tanh函数导数值范围更大,相对好一点。
2、sigmoid函数不是0中心对称,tanh函数是,可以使网络收敛的更好。

3、梯度爆炸解决方法:

权重衰减:通过给参数增加 ℓ1 或 ℓ2 范数的正则化项来限制参数的取值范 围,从而使得γ ≤ 1
梯度截断:当梯度的模大于一定 阈值时,就将它截断成为一个较小的数
梯度消失解决方法:

合理的初始化权重值。初始化权重,使每个神经元尽可能不要取极大或极小值,以躲开梯度消失的区域。
使用relu代替sigmoid和tanh作为激活函数。
使用其他结构的RNNs,比如长短时记忆网络(LTSM)和Gated Recurrent Unit(GRU),这是最流行的做法。

代码:

参考:

原文链接:https://blog.csdn.net/fan3652/article/details/95615096
原文链接:https://blog.csdn.net/DFCED/article/details/104982539
原文链接:https://blog.csdn.net/fan3652/article/details/95615096

原文链接:https://blog.csdn.net/zhaojc1995/article/details/80572098

 

  • 8
    点赞
  • 79
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值