赞
踩
RNN存在梯度消失和梯度爆炸的问题。
书上以下图的这句话为例,进行说明;为了正确预测出问号处的单词:
另一方面,可以通过反向传播,将待预测单词位置处的梯度在水平方向上传递到过去(如下图所示),这种有意义的梯度,最终更新模型的权重,使得模型能够学习时间方向上的依赖关系,最终正确做出预测;
但是如果梯度在反向传播的过程中,梯度越向过去传播,越小,则则靠前的模型权重就得不到更新,从而无法让模型编码有用的信息,无法让模型学习并利用水平方向上长期的依赖关系来进行预测;
此外,如果梯度越来越大,会出现梯度爆炸,这会使得模型的学习变得不稳定,也是一个问题;
而这两种问题在RNN中都存在;
下面仅仅从时间方向上看梯度的传播(如下图所示);纵向来的梯度会和水平方向上传递来的梯度相加;因此仅仅分析水平方向上梯度的变化的结论在考虑纵向时也是适用的;
y = t a n h ( x ) y=tanh(x) y=tanh(x)函数的导数为: y ′ = 1 − y 2 y'=1-y^2 y′=1−y2;下图是原函数与导数的图像:
由图像可知,导数值小于 1.0,并且随着 x 远离 0,它的值在变小;因此导数永远小于1,即局部梯度是小数,那么输出侧的梯度乘上局部梯度就会变小;并且如果 x 远离 0,局部梯度会非常小;那么经过这么一个tanh节点,梯度就会变小一次;而水平方向上有好多个tanh节点,那么传播到非常过去的节点,梯度甚至有可能会消失。
RNN 层的激活函数一般使用 tanh 函数,但是如果改为 ReLU 函数, 则有希望抑制梯度消失的问题(当 ReLU 的输入为 x 时,它的输出是 max(0, x))。这是因为,在 ReLU 的情况下,当 x 大于 0 时,反向传播将上游的梯度原样传递到下游,梯度不会“退化”。而且可以在ReLU之前将输入全部变到正数,这样就完全是x了;
简单起见, 这里我们忽略反向传播图中的 tanh 节点;
加法节点梯度不变,因此就没画出来了;
那么简单来看,图中只剩矩阵乘法的节点,如下图所示:
前面说过矩阵相乘的梯度传播公式;这里每经过一个矩阵乘法节点,都要乘上一个局部梯度 W h \boldsymbol{W}_h Wh;
接下来书上初始化了一个梯度为1的矩阵,然后执行了多次局部梯度,并计算了每次反向传播之后梯度的L2范数;代码如下图所示:
下图是实验结果;可见确实有爆炸的趋势;梯度爆炸会导致数值过大,甚至溢出,影响神经网络的学习;
但是有一个问题,如果权重是一个标量,那么如果权重大于1,则肯定梯度会越来越大的;权重是一个矩阵的时候,就又涉及到矩阵的奇异值这个概念了(还需要深入了解);
梯度爆炸的对策为**梯度裁剪**;
裁剪按照下式进行:
i
f
∥
g
^
∥
⩾
t
h
r
e
s
h
o
l
d
:
g
^
=
t
h
r
e
s
h
o
l
d
∥
g
^
∥
g
^
(1)
下面的代码是书上的一个小例子:
def clip_grads(grads, max_norm): total_norm = 0 for grad in grads: total_norm += np.sum(grad**2) # 对梯度矩阵的所有元素求和;因为公式中就是把所有的梯度组合在一起,然后求的范数; total_norm = np.sqrt(total_norm) # 二范数 rate = max_norm / (total_norm + 1e-6) # 公式的变形 if rate < 1: for grad in grads: grad *= rate if __name__ == '__main__': dW1 = np.random.rand(3, 3) * 10 dW2 = np.random.rand(3, 3) * 10 grads = [dW1, dW2] # 对应梯度裁剪公式里面的g max_norm = 5.0 # 范数阈值 clip_grads(grads, max_norm) pass
通过改变RNN的网络结构,改变了存放”记忆“的载体;引入了门结构;即Gated RNN;
这里先看看LSTM;后面再看一下书上的GRU;
LSTM这里的改进涉及:增加了一个记忆单元、输入门、输出门、遗忘门;
下图为RNN和LSTM结构的简略对比:
概括: t a n h ( c t ) tanh(\boldsymbol{c}_t) tanh(ct)编码了目前时刻为止所需要的信息,用输出门来控制信息中各个元素的重要程度;
LSTM的记忆单元 c t \boldsymbol{c}_t ct保存了从过去到时刻 t t t的所有必要信息,基于这个充满必要信息的记忆,向外部的层(和下一时刻的 LSTM)输出隐藏状态 h t \boldsymbol{h}_t ht;如下图所示:
门的概念:
接下来用到的函数的区别:
综合2和3,我们可以说:
输出门:对 t a n h ( c t ) tanh(\boldsymbol{c}_t) tanh(ct)施加门,针对 t a n h ( c t ) tanh(\boldsymbol{c}_t) tanh(ct)中的每个元素,调整它们作为下一时刻的隐藏状态的重要程度;
由于这个门管理当前时刻的输出,即隐藏状态 h t \boldsymbol{h}_t ht,所以称为输出门
输出门的公式如下:
o
=
σ
(
x
t
W
x
(
o
)
+
h
t
−
1
W
h
(
o
)
+
b
(
o
)
)
(2)
\boldsymbol{o}=\sigma\left(\boldsymbol{x}_t \boldsymbol{W}_x^{(\mathrm{o})}+\boldsymbol{h}_{t-1} \boldsymbol{W}_h^{(\mathrm{o})}+\boldsymbol{b}^{(\mathrm{o})}\right) \tag{2}
o=σ(xtWx(o)+ht−1Wh(o)+b(o))(2)
和单纯的RNN的公式如出一辙;输入 x t \boldsymbol{x}_t xt有权重 W x ( o ) \boldsymbol{W}_x^{(\mathrm{o})} Wx(o),上一时刻的隐藏状态 h t − 1 \boldsymbol{h}_{t-1} ht−1有权重 W h ( o ) \boldsymbol{W}_h^{(\mathrm{o})} Wh(o); σ ( ) \sigma() σ()表示sigmoid函数;结果 o \boldsymbol{o} o应该是一个行向量;
然后将
o
\boldsymbol{o}
o和
t
a
n
h
(
c
t
)
tanh(\boldsymbol{c}_t)
tanh(ct)的对应元素相乘,作为输出
h
t
\boldsymbol{h}_t
ht,如下式所示;对应元素相乘即哈达玛积(Hadamard product),用
⊙
\odot
⊙来表示;
h
t
=
o
⊙
tanh
(
c
t
)
(3)
\boldsymbol{h}_t=\boldsymbol{o} \odot \tanh \left(\boldsymbol{c}_t\right) \tag{3}
ht=o⊙tanh(ct)(3)
下图是加入输出门之后的LSTM结构图:
- 前面说了: c t \boldsymbol{c}_t ct基于 c t − 1 \boldsymbol{c}_{t-1} ct−1、 h t − 1 \boldsymbol{h}_{t-1} ht−1、 x t \boldsymbol{x}_t xt经过”某种计算“得到;
- 遗忘门的作用:对上一个LSTM单元传递来的记忆信息进行取舍,告诉模型需要忘记什么;因此设置一个遗忘门作用在 c t − 1 \boldsymbol{c}_{t-1} ct−1上,将需要忘记的赋予更低的重要性;
与输出门类似,遗忘门也是一组权重参数,加上一个sigmoid函数;如下式所示:
f
=
σ
(
x
t
W
x
(
f
)
+
h
t
−
1
W
h
(
f
)
+
b
(
f
)
)
(4)
\boldsymbol{f}=\sigma\left(\boldsymbol{x}_t \boldsymbol{W}_x^{(\mathrm{f})}+\boldsymbol{h}_{t-1} \boldsymbol{W}_h^{(\mathrm{f})}+\boldsymbol{b}^{(\mathrm{f})}\right) \tag{4}
f=σ(xtWx(f)+ht−1Wh(f)+b(f))(4)
其中
W
x
(
f
)
\boldsymbol{W}_x^{(\mathrm{f})}
Wx(f)、
W
h
(
f
)
\boldsymbol{W}_h^{(\mathrm{f})}
Wh(f)、
b
(
f
)
\boldsymbol{b}^{(\mathrm{f})}
b(f)为遗忘门的权重和偏置参数;
σ
(
)
\sigma()
σ()依旧表示sigmoid函数;然后将遗忘门
f
\boldsymbol{f}
f与
c
t
−
1
\boldsymbol{c}_{t-1}
ct−1对应元素相乘,得到当前时刻的记忆单元
c
t
\boldsymbol{c}_{t}
ct;如下式所示:
c
t
=
f
⊙
c
t
−
1
(5)
\boldsymbol{c}_t=\boldsymbol{f} \odot \boldsymbol{c}_{t-1} \tag{5}
ct=f⊙ct−1(5)
加入遗忘门之后LSTM的结构如下图所示:
- 除了遗忘一部分信息,还需要让模型记住一些新的信息;
- 新的信息也有重要程度之分,因此引入输入门,判断新增信息的各个元素的价值有多大;
将新的信息加入到记忆单元中,因此使用tanh函数,而不用sigmoid函数;计算公式如下:
g
=
tanh
(
x
t
W
x
(
g
)
+
h
t
−
1
W
h
(
g
)
+
b
(
g
)
)
(6)
\boldsymbol{g}=\tanh \left(\boldsymbol{x}_t \boldsymbol{W}_x^{(\mathrm{g})}+\boldsymbol{h}_{t-1} \boldsymbol{W}_h^{(\mathrm{g})}+\boldsymbol{b}^{(\mathrm{g})}\right) \tag{6}
g=tanh(xtWx(g)+ht−1Wh(g)+b(g))(6)
相关参数类似前面的输出门和遗忘门的参数;
这是计算的新的信息;将此信息加入到上一时刻的记忆单元 c t − 1 \boldsymbol{c}_{t-1} ct−1中,形成新的记忆;
为了区分新的信息中元素的价值,构建输入门,用输入门对新的信息加权;输入门公式如下:
i
=
σ
(
x
t
W
x
(
i
)
+
h
t
−
1
W
h
(
i
)
+
b
(
i
)
)
(7)
\boldsymbol{i}=\sigma\left(\boldsymbol{x}_t \boldsymbol{W}_x^{(\mathrm{i})}+\boldsymbol{h}_{t-1} \boldsymbol{W}_h^{(\mathrm{i})}+\boldsymbol{b}^{(\mathrm{i})}\right) \tag{7}
i=σ(xtWx(i)+ht−1Wh(i)+b(i))(7)
用这个权值
i
\boldsymbol{i}
i与新增加的信息
g
\boldsymbol{g}
g相乘,对应元素相乘,然后再添加到被筛选过的保留下来的上一时刻的记忆单元
c
t
−
1
\boldsymbol{c}_{t-1}
ct−1中。
加入新增信息和输入门之后LSTM的结构如下:
上一时刻传来的记忆单元有些信息需要被遗忘,因此增加了遗忘门;
当前时刻有新的信息需要添加,且增加的信息也有重要程度之分,因此加了输入门;
1和2形成了当前时刻的记忆单元;
当前时刻输出的隐藏状态原本就是要包含目前为止所有的信息的,因此基于当前时刻的记忆单元,计算当前时刻的隐藏状态;而输出门就是用来调整当前时刻记忆单元作为下一时刻隐藏状态的重要程度的。
另外,从公式上看,不管是哪个门,以及新增的记忆单元,都是基于 h t − 1 \boldsymbol{h}_{t-1} ht−1、 x t \boldsymbol{x}_t xt;每个门的权重参数具体数值不同,但形式相同。
LSTM中最关键的就是记忆单元 c \boldsymbol{c} c,隐藏状态 h \boldsymbol{h} h就是基于 c \boldsymbol{c} c计算得到的;因此LSTM的记忆信息主要来自于 c \boldsymbol{c} c;所以梯度的流动我们主要关注一下记忆单元 c \boldsymbol{c} c部分。
涉及记忆单元的梯度流动如下图所示:
不会梯度消失或者爆炸的原因:
另外,这里的乘法节点是遗忘门处的:
LSTM是Long Short-Term Memory(长短期记忆)的缩写,意思是可以长(Long)时间维持短期记忆(Short-Term Memory):
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。