BPTT(沿时反向传播算法)基本原理与BP算法一样,包含三个步骤:
- 前向计算每个神经元的输出值
- 反向计算每个神经元的误差项 δ j δ_j δj,它是误差函数E对神经元j的加权输入 n e t j net_j netj的偏导数
- 计算每个权重的梯度
- 最后再用随机梯度下降算法更新权重
循环曾如图所示:
1.1前向计算
循环层的前向计算:
隐层: s t = f ( U x t + W s t − 1 ) s_t=f(Ux_t+Ws_{t-1}) st=f(Uxt+Wst−1)
1.2误差项的计算
BPTT算法将第l层t时刻的误差项 δ t l δ_t^l δtl值沿两个方向传播,一个方向时传递到上一层网络,得到 δ t l − 1 δ_t^{l-1} δtl−1,这部分只和权重矩阵U有关;另一方向是将其沿着时间线传递到初始 t 1 t_1 t1时刻,得到 δ 1 l δ_1^l δ1l,这部分只和权重矩阵W有关。
用向量 n e t j net_j netj表示神经元在t时刻的加权输入:
n e t j = U x t + W s t − 1 net_j=Ux_t+Ws_{t-1} netj=Uxt+Wst−1
s t − 1 = f ( n e t t − 1 ) s_{t-1}=f(net_{t-1}) st−1=f(nett−1)
因此:
∂ n e t t ∂ n e t t − 1 = ∂ n e t t ∂ s t − 1 ∂ s t − 1 ∂ n e t t − 1 \frac{\partial net_t}{\partial net_{t-1}}=\frac{\partial net_t}{\partial s_{t-1}}\frac{\partial s_{t-1}}{\partial net_{t-1}} ∂nett−1∂nett=∂st−1∂nett∂nett−1∂st−1
∂ n e t t ∂ s t − 1 = W \frac{\partial net_t}{\partial s_{t-1}}=W ∂st−1∂nett=W
第二项是一个jacobian矩阵
最后,将两项合在一起,可得:
∂ n e t t ∂ n e t t − 1 = ∂ n e t t ∂ s t − 1 ∂ s t − 1 ∂ n e t t − 1 = W ∗ d i a g [ f ′ ( n e t t − 1 ) ] \frac{\partial net_t}{\partial net_{t-1}}=\frac{\partial net_t}{\partial s_{t-1}}\frac{\partial s_{t-1}}{\partial net_{t-1}}=W*diag[f^{'} (net_{t-1})] ∂nett−1∂nett=∂st−1∂nett∂nett−1∂st−1=W∗diag[f′(nett−1)]
上式描述了将 δ \delta δ沿时间向前传递一个时刻的规律,可以求的任意时刻k的误差项 δ k \delta_k δk:
这就是将误差项沿着时间反向传播的算法。
循环层将误差项反向传递到上一层网络,与普通的全连接层是完全一样的。
循环层的加权输入
n
e
t
l
net^l
netl与上一层的加权输入
n
e
t
l
−
1
net^{l-1}
netl−1关系如下:
n
e
t
t
l
=
U
a
t
l
−
1
+
W
s
t
−
1
net^l_t=Ua^{l-1}_t+Ws_{t-1}
nettl=Uatl−1+Wst−1
a
t
l
−
1
=
f
l
−
1
(
n
e
t
t
l
−
1
)
a^{l-1}_t=f^{l-1}(net^{l-1}_t)
atl−1=fl−1(nettl−1)
上式中
n
e
t
t
l
net^l_t
nettl是第l层神经元的加权输入;
n
e
t
t
l
−
1
net^{l-1}_t
nettl−1是l-1层神经元的加权输入;
a
t
l
−
1
a^{l-1}_t
atl−1是第l-1层神经元的输出;
f
l
−
1
f^{l-1}
fl−1是第l-1层的激活函数。
∂
n
e
t
t
l
∂
n
e
t
t
l
−
1
=
∂
n
e
t
t
l
∂
a
t
l
−
1
∂
a
t
l
−
1
∂
n
e
t
t
l
−
1
=
U
∗
d
i
a
g
[
f
′
l
−
1
(
n
e
t
t
l
−
1
)
]
\frac{\partial net^l_t}{\partial net^{l-1}_t}=\frac{\partial net^l_t}{\partial a^{l-1}_t}\frac{\partial a^{l-1}_t}{\partial net^{l-1}_t}=U*diag[f^{'l-1}(net^{l-1}_t)]
∂nettl−1∂nettl=∂atl−1∂nettl∂nettl−1∂atl−1=U∗diag[f′l−1(nettl−1)]
所以:
δ
t
l
−
1
=
∂
E
∂
n
e
t
t
l
−
1
=
∂
E
∂
n
e
t
t
l
∂
n
e
t
t
l
∂
n
e
t
t
l
−
1
=
δ
t
l
∗
U
∗
d
i
a
g
[
f
′
l
−
1
(
n
e
t
t
l
−
1
)
]
\delta^{l-1}_t=\frac{\partial E}{\partial net^{l-1}_t}=\frac{\partial E}{\partial net^l_t}\frac{\partial net^l_t}{\partial net^{l-1}_t}=\delta^l_t*U*diag[f^{'l-1}(net^{l-1}_t)]
δtl−1=∂nettl−1∂E=∂nettl∂E∂nettl−1∂nettl=δtl∗U∗diag[f′l−1(nettl−1)]
上式就是将误差项传递到上一层算法。
1.3权重梯度的计算
接下来是BPTT算法的最后一步:计算每个权重的梯度
首先计算误差函数E对权重矩阵W的梯度:
∂
E
∂
W
\frac{\partial E}{\partial W}
∂W∂E
上图为我们前两步计算得到的量,包括每个时刻t循环层的输出值
s
t
s_t
st,以及误差项
δ
t
\delta_t
δt
我们知道了任意一个时刻的误差项
δ
t
\delta_t
δt,以及上一个时刻循环层的输出值
s
t
−
1
s_{t-1}
st−1,就可以按照下面的公式求出权重矩阵在t时刻的梯度:
上式中,
δ
i
t
\delta^t_i
δit表示t时刻误差项向量的第i各分量,即第i层的误差项;KaTeX parse error: Double subscript at position 8: s_{t-1}_̲i表示t-1时刻循环层第i各神经元的输出值。
权重梯度推导:
1.4梯度爆炸与梯度消失
RNNs并不能很好地处理较长的序列。主要原因是RNN在训练中很容易发生梯度爆炸和梯度消失,导致训练时梯度不能在较长序列中一直传递下去,从而使RNN无法捕捉到长距离的影响。
三种方法应对梯度消失问题:
1)合理的初始化权重值。初始化权重,使每个神经元尽可能不要取极大或极小值,以躲开梯度消失的区域。
2)使用Relu代替sigmod和tanh作为激活函数。
3)使用其它结构的RNNs,比如长短时记忆网络(LSTM)和Gated Recurrent Unit(GRU),这是最流行的做法。