基本的RNN神经网络有一个很大的问题,就是梯度消失问题。
现在我们举个语言模型的例子,假如看到这个句子"The cat, which already ate much, was full",前后一致,cat是单数,对应was。这个例子中的句子有长期的依赖,最前面的单词对句子后面的单词有影响,但是我们目前见到的基本的RNN模型,不擅长捕获这种长期依赖效应,解释一下为什么。
如上图,你应该还记得之前讨论的,训练很深的网络,我们讨论了梯度消失的问题,比如说一个很深很深的网络,100层甚至更深,对这个网络从左到右做前向传播然后再反向传播。我们知道,如果这是个很深的神经网络,从输出y得到的梯度很难传播回去,很难影响前面层的权重。对于有同样问题的RNN,首先从左到右前向传播,然后反向传播,从右到左,但是反向传播会很困难,因为同样存在梯度消失问题。后面层的输出误差很难影响到前面层的计算。这就意味着,实际上很难让一个神经网络,能够意识到它要记住看到的是单数名词还是复数名词,然后在序列后面生成依赖单复数形式的was或者were,而且在英语里面这中间的内容可以任意长,所以模型需要长时间记住单词是单数还是复数,这样后面的句子才能用到这些信息。
也正是这个原因,所以基本的RNN模型会有很多局部影响,意味着这个输出 y ^ < 3 > \hat{y}^{<3>} y^<3>主要受 y ^ < 3 > \hat{y}^{<3>} y^<3>附近的值的影响,这里的一个数值主要与附近的输入有关,最后的输出基本上很难收到序列靠前的输入的影响,这是因为不管输出是什么,不管是对的还是错的,这个区域都很难反向传播到序列的前面部分,因此模型也很难调整序列前面的计算,这是基本的RNN算法的一个缺点。如果不管的话,RNN会不擅长处理长期依赖的问题。
很深的神经网络,除了会出现梯度消失问题,还会有梯度爆炸问题,在反向传播的时候,随着层数的增多,梯度不仅可能指数型的下降,也可能指数型的上升。事实上,梯度下降在训练RNN时是首要的问题,尽管梯度爆炸也会出现,但是梯度爆炸很明显,因为指数级大的梯度,会让你的参数变得极其大,以至于让你的网络参数崩溃,所以梯度爆炸很容易发现,因为参数会大到崩溃,你会看到很多NaN或者不是数字的情况,这意味着你的网络计算出现了数值溢出。如果你发现了梯度爆炸问题,一个解决方法就是用梯度修剪,梯度修剪就是观察你的梯度向量,如果它大于某个阈值,缩放梯度向量,保证它不会太大,这就是通过一些最大值来修剪的方法,所以如果你遇到了梯度爆炸,如果导致数值很大或者出现了NaN,就用梯度修剪,这是相对比较鲁棒的梯度爆炸的解决方法。然而梯度消失更难解决。