上一篇:四种基本的神经网络架构
1、RNN概述
上篇文章四种基本的神经网络架构中,我们介绍了RNN(Recurrent Neural Network)。基于RNN的语言模型主要有两方面的应用:
一,基于每个序列在现实世界中出现的可能性对其进行打分,这实际上提供了一个针对语法和语义正确性的度量,语言模型通常为作为机器翻译系统的一部分。
二,语言模型可以用来生成新文本。根据莎士比亚的作品训练语言模型可以生成莎士比亚风格的文本。
RNN背后的思想是利用顺序信息。在传统的神经网络中,我们假设所有的输入(包括输出)之间是相互独立的。对于很多任务来说,这是一个非常糟糕的假设。如果你想预测一个序列中的下一个词,你最好能知道哪些词在它前面,传统神经网络显然不能做到,而这类基于时间的序列:一段段连续的语音,一段段连续的手写文字。这些序列比较长,且长度不一,比较难直接的拆分成一个个独立的样本来通过DNN/CNN进行训练。而对于这类问题,RNN则比较的擅长。那么RNN是怎么做到的呢?RNN假设我们的样本是基于序列的。比如是从序列索引1到序列索引τ的。对于这其中的任意序列索引号t,它对应的输入是对应的样本序列中的
x
t
x^t
xt。而模型在序列索引号t位置的隐藏状态
h
t
h^t
ht,则由
x
t
x^t
xt和在t−1位置的隐藏状态
h
t
−
1
h^{t−1}
ht−1共同决定。在任意序列索引号t,我们也有对应的模型预测输出
o
t
o^t
ot。通过预测输出
o
t
o^t
ot和训练序列真实输出
y
t
y^t
yt,以及损失函数
L
t
L^t
Lt,我们就可以用DNN类似的方法来训练模型,接着用来预测测试序列中的一些位置的输出。RNN之所以循环的,是因为它针对系列中的每一个元素都执行相同的操作,每一个操作都依赖于之前的计算结果。换一种方式思考,可以认为RNN记忆了到当前为止已经计算过的信息。理论上,RNN可以利用任意长的序列信息,但实际中只能回顾之前的几步。这是因为RNN在反向传播的过程中会产生梯度消失或梯度爆炸问题。
2、RNN模型
RNN有比较多的模型,主流RNN模型结构如下:
上图中左边是RNN模型没有按时间展开的图,如果按时间序列展开,则是上图中的右边部分。我们重点观察右边部分的图。这幅图描述了在序列索引号t附近RNN的模型。其中:
1)
x
t
x^t
xt代表在序列索引号t时训练样本的输入。同样的,
x
t
−
1
x^{t-1}
xt−1和
x
t
+
1
x^{t+1}
xt+1代表在序列索引号t−1和t+1时训练样本的输入。
2)
h
t
h^t
ht代表在序列索引号t时模型的隐藏状态。
h
t
h^t
ht由
x
t
x^t
xt和
h
t
−
1
h^{t-1}
ht−1共同决定。
3)
o
t
o^t
ot代表在序列索引号t时模型的输出。
o
t
o^t
ot只由模型当前的隐藏状态
h
t
h^t
ht决定。
4)
L
t
L^t
Lt代表在序列索引号t时模型的损失函数。
5)
y
t
y^t
yt代表在序列索引号t时训练样本序列的真实输出。
6)U,W,V这三个矩阵是我们的模型的线性关系参数,它在整个RNN网络中是共享的,这点和DNN很不相同。 也正因为是共享了,它体现了RNN的模型的“循环反馈”的思想。
3、RNN前向传播算法
有了上面的模型,RNN的前向传播算法就很容易得到了。对于任意一个序列索引号t,我们隐藏状态
h
t
h^t
ht由
x
t
x^t
xt和
h
t
−
1
h^{t−1}
ht−1得到:
h
t
h^t
ht=
σ
(
z
t
)
σ(z^t)
σ(zt)=
σ
(
U
x
t
+
W
h
t
−
1
σ(Ux^t+Wh^{t−1}
σ(Uxt+Wht−1+b)
其中σ为RNN的激活函数,一般为tanh, b为线性关系的偏置。
序列索引号t时模型的输出
o
t
o^t
ot的表达式比较简单:
o
t
=
V
h
t
+
c
o^t=Vh^t+c
ot=Vht+c
在最终在序列索引号t时我们的预测输出为:
y
^
t
\hat{y}^t
y^t=
σ
(
o
t
)
σ(o^t)
σ(ot)
通常由于RNN是识别类的分类模型,所以上面这个激活函数一般是softmax。
通过损失函数
L
t
L^t
Lt,比如对数似然损失函数,我们可以量化模型在当前位置的损失,即
y
^
t
\hat{y}^t
y^t和
y
^
t
\hat{y}^{t}
y^t的差距。
4、RNN反向传播算法推导
有了RNN前向传播算法的基础,就容易推导出RNN反向传播算法的流程了。RNN反向传播算法的思路和DNN是一样的,即通过梯度下降法进行的迭代,得到合适的RNN模型参数U,W,V,b,c。由于我们是基于时间反向传播,所以RNN的反向传播有时也叫做BPTT(back-propagation through time)。当然这里的BPTT和DNN也有很大的不同点,即这里所有的U,W,V,b,c在序列的各个位置是共享的,反向传播时我们更新的是相同的参数。
为了简化描述,这里的损失函数我们为交叉熵损失函数,输出的激活函数为softmax函数,隐藏层的激活函数为tanh函数。
对于RNN,由于我们在序列的每个位置都有损失函数,因此最终的损失L为:
L
=
∑
t
=
1
τ
L
(
t
)
L=\sum_{t=1}^τ{L^{(t)}}
L=∑t=1τL(t),
其中V,c,的梯度计算是比较简单的:
∂
L
∂
c
=
∑
t
=
1
τ
∂
L
(
t
)
∂
c
=
∑
t
=
1
τ
y
^
(
t
)
−
y
(
t
)
\frac{∂L}{∂c}=\sum_{t=1}^τ \frac{∂L^{(t)}}{∂c}=\sum_{t=1}^τ \hat{y}^{(t)}−y^{(t)}
∂c∂L=∑t=1τ∂c∂L(t)=∑t=1τy^(t)−y(t)
∂
L
∂
V
=
∑
t
=
1
τ
∂
L
(
t
)
∂
V
=
∑
t
=
1
τ
(
y
^
(
t
)
−
y
(
t
)
)
(
h
t
)
T
\frac{∂L}{∂V}=\sum_{t=1}^τ \frac {∂L^{(t)}}{∂V}=\sum_ {t=1}^τ (\hat y^{(t)}−y^{(t)})(h^t)^T
∂V∂L=∑t=1τ∂V∂L(t)=∑t=1τ(y^(t)−y(t))(ht)T
但是W,U,b的梯度计算就比较的复杂了。从RNN的模型可以看出,在反向传播时,在某一序列位置t的梯度损失由当前位置的输出对应的梯度损失和序列索引位置t+1时的梯度损失两部分共同决定。对于W在某一序列位置t的梯度损失需要反向传播一步步的计算。我们定义序列索引t位置的隐藏状态的梯度为:
δ
(
t
)
δ^{(t)}
δ(t)=
∂
L
∂
h
(
t
)
\frac{∂L}{∂h^{(t)}}
∂h(t)∂L
这样我们可以像DNN一样从
δ
(
t
+
1
)
δ^{(t+1)}
δ(t+1)递推
δ
(
t
)
δ^{(t)}
δ(t)。
δ
(
t
)
=
(
∂
o
(
t
)
∂
h
(
t
)
)
T
∂
L
∂
o
(
t
)
+
(
∂
h
(
t
+
1
)
∂
h
(
t
)
)
T
∂
L
∂
h
(
t
+
1
)
=
V
T
(
y
^
(
t
)
−
y
(
t
)
)
+
W
T
d
i
a
g
(
1
−
(
h
(
t
+
1
)
)
2
)
δ
(
t
+
1
)
δ^{(t)}=(\frac{∂o^{(t)}}{∂h^{(t)}})^T\frac{∂L}{∂o^{(t)}}+(\frac{∂h^{(t+1)}}{∂h^(t)})^T\frac{∂L}{∂h^{(t+1)}}=V^T(\hat y^{(t)}−y^{(t)})+W^Tdiag(1−(h^{(t+1)})^2)δ^{(t+1)}
δ(t)=(∂h(t)∂o(t))T∂o(t)∂L+(∂h(t)∂h(t+1))T∂h(t+1)∂L=VT(y^(t)−y(t))+WTdiag(1−(h(t+1))2)δ(t+1)
对于
δ
(
τ
)
δ^{(τ)}
δ(τ),由于它的后面没有其他的序列索引了,因此有:
δ
(
τ
)
=
(
∂
o
(
τ
)
∂
h
(
τ
)
)
T
∂
L
∂
o
(
τ
)
=
V
T
(
y
^
(
τ
)
−
y
(
τ
)
)
δ^{(τ)}=(\frac{∂o^{(τ)}}{∂h^{(τ)}})^T\frac{∂L}{∂o^{(τ)}}=V^T(\hat y^{(τ)}−y^{(τ)})
δ(τ)=(∂h(τ)∂o(τ))T∂o(τ)∂L=VT(y^(τ)−y(τ))
有了
δ
(
t
)
δ^{(t)}
δ(t),计算W,U,b就容易了,这里给出W,U,b的梯度计算表达式:
∂
L
∂
W
=
∑
t
=
1
τ
d
i
a
g
(
1
−
(
h
(
t
)
)
2
)
δ
(
t
)
(
h
(
t
−
1
)
)
T
\frac{∂L}{∂W}=\sum_{t=1}^τ diag(1−(h^{(t)})^2)δ^{(t)}(h^{(t−1)})^T
∂W∂L=∑t=1τdiag(1−(h(t))2)δ(t)(h(t−1))T
∂
L
∂
b
=
∑
t
=
1
τ
d
i
a
g
(
1
−
(
h
(
t
)
)
2
)
δ
(
t
)
\frac{∂L}{∂b}=\sum_{t=1}^τ diag(1−(h^{(t)})^2)δ^{(t)}
∂b∂L=∑t=1τdiag(1−(h(t))2)δ(t)
∂
L
∂
U
=
∑
t
=
1
τ
d
i
a
g
(
1
−
(
h
(
t
)
)
2
)
δ
(
t
)
(
x
(
t
)
)
T
\frac{∂L}{∂U}=\sum _{t=1}^τdiag(1−(h^{(t)})^2)δ^{(t)}(x^{(t)})^T
∂U∂L=∑t=1τdiag(1−(h(t))2)δ(t)(x(t))T
除了梯度表达式不同,RNN的反向传播算法和DNN区别不大,因此这里就不再重复总结了。
5、RNN弊端
在实际应用中普通的 RNN 是非常难以训练的:
假设有一段关键文字“xxxx[key]xxx…xxxx”要求 RNN 分析出与 key 相关的 结果,即文字中的 key 是 RNN 进行分析所需要的关键数据。但此时 key 出现在 句子开头(t1),此信息源的记忆要经过非常一段长的时间才可以达到最终状态点, 如图:
前向传播得到误差,反向传递误差时,每次都会乘一个系数 w,当这个 w 小 于 1 时,每次反向传递都会让 RNN 的误差缩小,经过若干次误差反向传递, 到 key 状态时,误差很近似等于 0 的情况,这就叫梯度消失或者梯度弥散,反 之,如果 w 大于 1,每次反向传递都会让 RNN 的误差变大,经过若干次误差的反向传递,到 key 的状态时,误差将会是一个非常大的数(无穷大),这种情况 叫做梯度爆炸。这样导致很难确定一个初始值让 RNN 收敛。为了解决RNN长依赖问题,提出了LSTM(长短期记忆网络)下节将会介绍。
6、参考链接
1、https://www.cnblogs.com/pinard/p/6509630.html
2、https://studentke.github.io/2019/04/21/understand-the-LSTM/
下一篇:LSTM、BiLSTM讲解及实践+GRU讲解