RNN的BPTT算法中的梯度消失问题

参考资料链接:https://zhuanlan.zhihu.com/p/22338087

随时间的反向传播(BPTT)

让我们先迅速回忆一下RNN的基本公式,注意到这里在符号上稍稍做了改变(o变成\hat{y}),这只是为了和我参考的一些资料保持一致。
s_{t}=tanh(Ux_{t}+Ws_{t-1})
\hat{y}_{t}=softmax(Vs_{t})

同样把损失值定义为交叉熵损失,如下:
E_{t}(y_{t}, \hat{y}_{t})=-y_{t}log(\hat{y}_{t})
E(y, \hat{y})=\sum_{t}{E_{t}(y_{t}, \hat{y}_{t})}= -\sum_{t}{y_{t}log\hat{y}_{t}}
这里,y_{t}表示时刻t正确的词,\hat{y}_{t}是我们的预测。通常我们会把整个句子作为一个训练样本,所以总体错误是每一时刻的错误的加和。

我们的目标是计算错误值相对于参数U, V, W的梯度以及用随机梯度下降学习好的参数。就像我们要把所有错误相加一样,我们同样会把每一时刻针对每个训练样本的梯度值相加:\frac{\partial{E}}{\partial{W}}=\sum_{t}{\frac{\partial{E}_{t}}{\partial{W}}}
为了计算梯度,我们使用链式求导法则,主要是用反向传播算法往后传播错误。下文使用E_{3}作为例子,主要是为了描述方便。

\frac{\partial{E_{3}}}{\partial{V}} = \frac{\partial{E_{3}}}{\partial{\hat{y}_{3}}} \frac{\partial{\hat{y}_{3}}}{\partial{V}} =\frac{\partial{E_{3}}}{\partial{\hat{y}_{3}}}  \frac{​{\partial{\hat{y}_{3}}}}{\partial{z_{3}}} \frac{\partial{z_{3}}}{\partial{V}} =(\hat{y}_{3}-y_{3})\otimes s_{3}
上面z_{3}=Vs_{3}\otimes是向量的外积。如果你不理解上面的公式,不要担心,我在这里跳过了一些步骤,你可以自己尝试来计算这些梯度值。这里我想说明的一点是梯度值只依赖于当前时刻的结果\hat{y}_{3}, y_{3}, s_{3}。根据这些,计算V的梯度就只剩下简单的矩阵乘积了。

但是对于梯度\frac{\partial{E}_{3}}{\partial{W}}情况就不同了,我们可以像上面一样写出链式法则。
\frac{\partial{E_{3}}}{\partial{W}}= \frac{\partial{E_{3}}}{\partial{\hat{y}_{3}}} \frac{\partial{\hat{y}_{3}}}{\partial{s_{3}}} \frac{\partial{s_{3}}}{\partial{W}}

注意到这里的s_{3}=tanh(Ux_{t}+Ws_{2})依赖于s_{2}s_{2}依赖于Ws_{1},等等。所以为了得到W的梯度,我们不能将s_{2}看作常量。我们需要再次使用链式法则,得到的结果如下:
\frac{\partial{E_{3}}}{\partial{W}}= \sum_{k=0}^{3}{ \frac{\partial{E_{3}}}{\partial{\hat{y}_{3}}} \frac{\partial{\hat{y}_{3}}}{\partial{s_{3}}} \frac{\partial{s_{3}}}{\partial{s_{k}}} \frac{\partial{s_{k}}}{\partial{W}}}

 

我们把每一时刻得到的梯度值加和,换句话说,W在计算输出的每一步中都使用了。我们需要通过将t=3时刻的梯度反向传播至t=0时刻。

梯度消失问题

在教程前一部分,我提到RNN很难学到长范围的依赖——相隔几步的词之间的交互。这是有问题的因为英语中句子的意思通常由相距不是很近的词来决定:“The man who wore a wig on his head went inside”。这个句子讲的是一个男人走了进去,而不是关于假发。但是普通的RNN不可能捕捉这样的信息。要理解为什么,让我们先仔细看一下上面计算的梯度:
\frac{\partial{E_{3}}}{\partial{W}}= \sum_{k=0}^{3}{ \frac{\partial{E_{3}}}{\partial{\hat{y}_{3}}} \frac{\partial{\hat{y}_{3}}}{\partial{s_{3}}} \frac{\partial{s_{3}}}{\partial{s_{k}}} \frac{\partial{s_{3}}}{\partial{W}}}
注意到\frac{\partial{s_{3}}}{\partial{s_{k}}}也需要使用链式法则,例如,\frac{\partial{s_{3}}}{\partial{s_{1}}}=\frac{\partial{s_{3}}}{\partial{s_{2}}} \frac{\partial{s_{2}}}{\partial{s_{1}}}。注意到因为我们是用向量函数对向量求导数,结果是一个矩阵(称为Jacobian Matrix),矩阵元素是每个点的导数。我们可以把上面的梯度重写成:
\frac{\partial{E_{3}}}{\partial{W}}= \sum_{k=0}^{3}{ \frac{\partial{E_{3}}}{\partial{\hat{y}_{3}}} \frac{\partial{\hat{y}_{3}}}{\partial{s_{3}}} (\prod_{j=k+1}^{3} \frac{\partial{s_{j}}}{\partial{s_{j-1}}}) \frac{\partial{s_{k}}}{\partial{W}}}

可以证明上面的Jacobian矩阵的二范数(可以认为是一个绝对值)的上界是1。这很直观,因为激活函数tanh把所有制映射到-1和1之间,导数值得界限也是1:

 

你可以看到tanh和sigmoid函数在两端的梯度值都为0,接近于平行线。当这种情况出现时,我们就认为相应的神经元饱和了。它们的梯度为0使得前面层的梯度也为0。矩阵中存在比较小的值,多个矩阵相乘会使梯度值以指数级速度下降,最终在几步后完全消失。比较远的时刻的梯度值为0,这些时刻的状态对学习过程没有帮助,导致你无法学习到长距离依赖。消失梯度问题不仅出现在RNN中,同样也出现在深度前向神经网中。只是RNN通常比较深(例子中深度和句子长度一致),使得这个问题更加普遍。

很容易想到,依赖于我们的激活函数和网络参数,如果Jacobian矩阵中的值太大,会产生梯度爆炸而不是梯度消失问题。梯度消失比梯度爆炸受到了更多的关注有两方面的原因。其一,梯度爆炸容易发现,梯度值会变成NaN,导致程序崩溃。其二,用预定义的阈值裁剪梯度可以简单有效的解决梯度爆炸问题。梯度消失出现的时候不那么明显而且不好处理。

幸运的是,已经有一些方法解决了梯度消失问题。合适的初始化矩阵W可以减小梯度消失效应,正则化也能起作用。更好的方法是选择ReLU而不是sigmoid和tanh作为激活函数。ReLU的导数是常数值0或1,所以不可能会引起梯度消失。更通用的方案时采用长短项记忆(LSTM)或门限递归单元(GRU)结构。LSTM在1997年第一次提出,可能是目前在NLP上最普遍采用的模型。GRU,2014年第一次提出,是LSTM的简化版本。这两种RNN结构都是为了处理梯度消失问题而设计的,可以有效地学习到长距离依赖,

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值