前言:
出现再段落中的[1]表示参考文献索引,(1)表示参考资料索引
问答总结
- rnn产生的原因是什么?
- 画出rnn示意图,说明参数维度.
- rnn的梯度消失/爆炸问题是怎样的?梯度裁剪是为了解决什么问题。
- LSTM的产生原因是什么,提出时间是什么时候?
- 画出LSTM示意图,说明它为什么可以解决梯度消失问题,其和ResNet有什么关系?
文章目录
一、RNN
1、产生原因
传统的神经网络大多是一对一:一个输入对应一个输出,但是,有时候我们希望处理序列任务,比如翻译等,前面的输入输出和后面的输入输出有关系,这就要求网络要有能够处理很多种输入输出类型并且能够建模它们之间关系的能力。比如下图:
这就导致了循环神经网络(RNN) 的产生。
2、结构
如上图所示,左图是循环神经网络的简化图,RNN
模块自指的箭头表示循环。右边是左图的展开。对于右图,我们首先明确有以下元素:
(1)
x
i
:
x_i:
xi: 输入,在自然语言处理任务中可以是一个单词。
(2)
s
i
:
s_i:
si: 隐藏状态,通过上一时间步隐藏状态
s
i
−
1
s_{i-1}
si−1和当前输入
x
i
x_i
xi确定,
s
0
s_0
s0作为输入由人给定。
(3)
W
,
U
,
V
:
W,U,V:
W,U,V: 参数, 详细用处如公式所示:
s
t
=
f
(
W
s
t
−
1
+
U
x
t
)
s_t = f(Ws_{t-1}+Ux_t)
st=f(Wst−1+Uxt)
其中
f
f
f为非线性函数。
(4)
y
i
:
y_i:
yi: 输出,由当前隐藏状态
h
i
h_i
hi通过参数
V
V
V得到, 比如分类任务:
o
t
=
s
o
f
t
m
a
x
(
V
s
t
)
o_t = softmax(Vs_t)
ot=softmax(Vst)
注: 上方公式省略了偏置项。每个时间步的参数都是共享的.
详细细节可以参看Pytorch官方文档参数说明.
3、简单实例
下图模拟了一个简单的实例示意图,任务为预测下一个字母,给定单词hello
,将其拆分为输入hell
, 输出ello
两部分:
一个有趣的项目 char-rnn.
4、隐藏层蕴含了什么信息
cs231n的讲师进行了一个有趣的工作: 探究Rnn隐藏层蕴含了什么信息,其实验思路如下:
其将所有时间步的隐藏状态相同的位置取出,每个位置实际上是一个细胞,将数值大小转换为颜色进行可视化,作者发现有的位置的细胞可以学到一些很有趣的东西,比如:
- 引号判别细胞:
- 条件语句判别细胞:
等等。
5、图片描述
我们也可以通过cnn
和rnn
的结合生成图像描述:
这里有几个细节:(1) 代表图像的向量在每个时间步都被输入进去,并且增加一个权重矩阵
W
i
h
W_{ih}
Wih对其进行加工。(2) 认为给定一个特殊的起始字符<start>
. (3)当模型预测到特殊结束字符<end>
时,则结束。
效果如下:
6、梯度消失/爆炸问题
对Rnn公式进行简单变形:
h
t
=
t
a
n
h
(
W
h
h
h
t
−
1
+
W
x
h
x
t
)
=
t
a
n
h
(
W
(
h
t
−
1
x
)
)
\begin{aligned} h_t& = tanh(W_{hh}h_{t-1}+W_{xh}x_t) \\ &=tanh(W\begin{pmatrix} h_{t-1}\\ x \end{pmatrix}) \end{aligned}
ht=tanh(Whhht−1+Wxhxt)=tanh(W(ht−1x))
其中
W
∈
R
h
×
2
h
W \in R^{h \times 2h}
W∈Rh×2h, 因此可以画出Rnn内部结构示意图:
其中小圆圈代表矩阵乘法,由矩阵求导可知:
∂
L
N
h
t
−
1
=
∂
L
N
h
t
∂
h
t
∂
h
t
−
1
=
W
h
h
T
∂
L
N
h
t
\frac{\partial L_N}{h_{t-1}}=\frac{\partial L_N}{h_t}\frac{\partial h_t}{\partial h_{t-1}}=W_{hh}^T\frac{\partial L_N}{h_t}
ht−1∂LN=ht∂LN∂ht−1∂ht=WhhTht∂LN
其中
L
N
L_N
LN为第
N
N
N个时间步产生的损失。由上式可知,较后方的损失梯度传到前方,会多次乘以矩阵
W
h
h
T
W_{hh}^T
WhhT, 由矩阵乘向量的性质,(1)中提到,对
A
N
v
A^Nv
ANv, 当
N
N
N足够大时,其实是让
v
v
v往最大特征值对应的特征空间上贴合,并根据特征值大小伸长或缩短。
因此,令
λ
\lambda
λ为
W
h
h
T
W_{hh}^T
WhhT的最大特征值,如果
λ
>
1
\lambda >1
λ>1,则会发生梯度爆炸,若
λ
<
1
\lambda < 1
λ<1则会发生梯度消失。因此对RNN来说,无法学习到长序列信息。
对于
λ
>
1
\lambda >1
λ>1的情况,我们可以通过梯度裁剪来一定程度地解决问题,Pytorch中也内置了torch.nn.utils.clip_grad_norm
函数进行梯度裁剪。
二、LSTM
1、产生原因
既然发现了RNN无法处理长序列的问题,那么如何解决呢? 在1997年,便有人提出了长短期记忆网络(LSTM)对RNN进行改进。
2、结构
LSTM单元运算如下:
据此我们画出结构示意图:
根据图,我们得出LSTM中有如下元素:
(1)
f
f
f: 遗忘门决定记住多少之前信息。
(2)
i
i
i: 输入门决定增加多少当前信息。
(3)
o
o
o: 输出门决定需要输出什么信息。
3、解决梯度问题
仔细观察这个结构,其和RNN有一个很重要的不同,就是向下一个时间步多传入了一个信息,我们通常称其为细胞状态 c t c_t ct
这样,当梯度反向传播时,上方细胞状态的流通路径只涉及到逐位乘和加法,而
f
f
f值是由隐藏状态决定的,是变化的。因此一定程度上解决了梯度消失问题
指的注意的是,这种增加一条捷径防止梯度消失的方法,在ResNet中也有体现. 其横等映射路径也相当于一条高速路,可以直传梯度,这样就一定程度上解决了梯度爆炸/消失问题
三、GRU
GRU于2014年被提出,是LSTM的变体,将LSTM中的3个门减少到了两个,但是在很多任务上都有很好的效果,这里就不详细阐述了。
四、TransFormer
在[1]中,Google提出了一种新型编码器TransFormer, 其基于Attention机制,结合位置编码,取得了很好地效果,最近较强劲的Bert也是基于该编码器设计的,可以说实例强劲。笔者以前阅读过该文章,但是自认为没有深度理解,有时间再写一篇阅读笔记。