昨天提到RNN的训练方法,提到了最流行的算法BPTT,其实训练RNN除了BPTT以外,还有两种算法:Real-time Recurrent Learning(RTRL)以及Extended Kalman Filtering(EKF),不过工业上基本上都被BPTT占领了,所以后面两个算法就不再介绍。那么本期将讲解为什么训练RNN是非常困难的一件事情,这是因为训练RNN中经常会遇到梯度消失和梯度爆炸现象。阅读本文可以参考的文章有:


《漫谈RNN之基本概念》

《漫谈RNN之训练方法》

《我对随机梯度下降的理解(一)》

《我对随机梯度下降的理解(二)》




RNN框架虽然十分强大,并且是一个图灵完全的模型,但是其非常难于训练。因为通常我们需要采用随机梯度下降算法去训练RNN模型,在这过程中,经常就会遇到梯度消失以及梯度爆炸两个问题。

7.1_.jpg


首先看上面一个典型的循环神经网络在时间维度上的展开图,我们可以假设该循环神经网络的计算公式为:

7.2_.JPG


可能有读者会纳闷,不是还有偏置项b吗?这里偏置项已经考虑在了W中,因为这样计算起来更高效。现在我们考虑输出对t-1时刻的状态s的偏导数,利用链式法则可以得到:

7.3_.JPG



这个时候,随着RNN的时间维度的增大,矩阵W的特征值对偏导数的稳定性就起着非常大的作用了。假设y对s_T的偏导数与W的最大特征值lambda所对应的特征向量方向一致的话,并且假设y对s_T的偏导数向量的幅度为K,那么上式的最后两项乘积的幅度即为lambda*K。不考虑D的影响的话,右边=lambda^T * K。如果lambda小于1,梯度趋近于0,即梯度消失;如果lambda大于1,梯度趋近于无穷大,即梯度爆炸。以上就是关于梯度消失以及梯度爆炸的大致描述。可以看到,RNN的训练不稳定性主要是由权重引起的,这也解释了为什么早期的深度学习的训练误差函数后面要加入权重的L1/L2正则项。



总而言之,梯度消失以及梯度爆炸现象都是由于神经网络的深度加深(时间上或者空间上)而引起的。激活函数在一定程度上对梯度消失以及梯度爆炸起到了加剧或者改善的作用。例如对于传统的sigmoid函数,其导数图像为:

7.4_.JPG


其导数值远低于1,因此会导致梯度消失地更快;而对于tanh函数,其导数图像如下:

7.5_.JPG


tanh函数要稍微好一点,梯度消失明显会慢很多;而对于最近流行的relu函数而言,其导数在负数区域为0,正数区域为1,因此很好地解决了梯度消失的问题。但是relu函数也会有其他问题,因为relu的负数区域均为0,如果权重初始化不是很好偏置的话,那么在训练好一个模型以后,会发现其实很多神经元都是死的。最近,elu函数的提出一定程度上解决了这一问题。



对于梯度爆炸问题而言,我们可以采用gradient clipping的方法来抑制,简而言之,就是当梯度的幅度大于一定的阈值时,就停止梯度继续增大了,这个方法可以解决梯度爆炸的问题。此外,truncated BPTT也能很好地解决梯度消失或梯度爆炸问题。





近期文章预告:

《漫谈RNN之长短期记忆模型LSTM》

《漫谈RNN之简化版长短期记忆模型GRU》

《漫谈RNN之序列建模》

《漫谈RNN之记忆网络》

《漫谈RNN之神经图灵机模型》

《漫谈RNN之注意力机制》

 
 
 
 
 来源:张泽旺 深度学习每日摘要
智造家