循环神经网络
基本的循环神经网络
它由输入层、一个隐藏层和一个输出层组成:
- x是一个向量,它表示输入层的值
- s是一个向量,它表示隐藏层的值(这里隐藏层面画了一个节点,你也可以想象这一层其实是多个节点,节点数与向量s的维度相同);
- U是输入层到隐藏层的权重矩阵
- o也是一个向量,它表示输出层的值;
- V是隐藏层到输出层的权重矩阵
- 循环神经网络的隐藏层的值s不仅仅取决于当前这次的输入x,还取决于上一次隐藏层的值s。权重矩阵 W就是隐藏层上一次的值作为这一次的输入的权重。
如果我们把上面的图展开,循环神经网络也可以画成下面这个样子:
这个网络在t时刻接收到输入之后$\mathbf{x}_{t}$,隐藏层的值是$\mathbf{s}_{t}$,输出值是$\mathbf{o}_{t}$。关键一点是,$\mathbf{s}_{t}$的值不仅仅取决于$\mathbf{x}_{t}$,还取决于$\mathbf{s}_{t-1}$。我们可以用下面的公式来表示循环神经网络的计算方法:
式1是输出层的计算公式,输出层是一个全连接层,也就是它的每个节点都和隐藏层的每个节点相连。V是输出层的权重矩阵,g是激活函数。式2是隐藏层的计算公式,它是循环层。U是输入x的权重矩阵,W是上一次的值$\mathrm{S}_{t-1}$作为这一次的输入的权重矩阵,f是激活函数。
从上面的公式我们可以看出,循环层和全连接层的区别就是循环层多了一个权重矩阵 W。
如果反复把式2带入到式1,我们将得到:
从上面可以看出,循环神经网络的输出值$O_{t}$,是受前面历次输入值$\mathbf{x}_{t}, \mathbf{x}_{t-1}, \quad \mathbf{x}_{t-2}, \mathbf{x}_{t-3}, \dots$影响的,这就是为什么循环神经网络可以往前看任意多个输入值的原因。
双向循环神经网络
对于语言模型来说,很多时候光看前面的词是不够的,比如下面这句话:
我的手机坏了,我打算____一部新手机。
可以想象,如果我们只看横线前面的词,手机坏了,那么我是打算修一修?换一部新的?还是大哭一场?这些都是无法确定的。但如果我们也看到了横线后面的词是『一部新手机』,那么,横线上的词填『买』的概率就大得多了。
在上一小节中的基本循环神经网络是无法对此进行建模的,因此,我们需要双向循环神经网络,如下图所示:
我们先考虑上图中$y_{2}$的计算。
从上图可以看出,双向卷积神经网络的隐藏层要保存两个值,一个A参与正向计算,另一个值A’参与反向计算。最终的输出值$y_{2}$取决于$A_{2}$和$A_{2}^{\prime}$。其计算方法为:
$A_{2}$和$A_{2}^{\prime}$则分别计算:
正向计算时,隐藏层的值${s}_{t}$与$\mathrm{s}_{t-1}$有关;反向计算时,隐藏层的值${s}_{t}$与${s}_{t_+1}$有关;最终的输出取决于正向和反向计算的加和。现在,我们仿照式1和式2,写出双向循环神经网络的计算方法:
从上面三个公式我们可以看到,正向计算和反向计算不共享权重,也就是说U和U’、W和W’、V和V’都是不同的权重矩阵。
深度循环神经网络
从上面三个公式我们可以看到,正向计算和反向计算不共享权重,也就是说U和U’、W和W’、V和V’都是不同的权重矩阵。
我们把第i个隐藏层的值表示为$s_{t}^{(i)}, s_{t}^{\prime(i)}$,则深度循环神经网络的计算方式可以表示为:
循环神经网络的训练
前向计算
使用前面的式2对循环层进行前向计算:
我们假设输入向量x的维度是m,输出向量s的维度是n,则矩阵U的维度是$n \times m$,矩阵W的维度是$n \times n$。下面是上式展开成矩阵的样子,看起来更直观一些:
$s_{j}^{t}$表示向量s的第j个元素在t时刻的值。$u_{j i}$表示输入层第i个神经元到循环层第j个神经元的权重。$w_{j i}$表示循环层第t-1时刻的第i个神经元到循环层第t个时刻的第j个神经元的权重。
RNN的反向传播
RNN的反向传播与全连接网络的普通反向传播不同,误差除了要往上层网络传播,还要沿着时间方向往$t_{0}$时刻传播。 我们称之为 Backpro Pagation Through Time(BPTT)
BPTT的基本原理和BP是一样的,包含三个步骤
- 前向计算每个神经元的输出值
- 反向计算每个神经元的误差项值$\delta_{j}$,它是误差函数E对神经元$net_{j}$的加权输入的偏导数
- 计算每个权重的梯度
最后在用梯度下降法来更新权重,在前面已经写了前向传播,下面就来计算误差项$\delta_{j}$
误差项的计算
前面提到过,RNN的误差项要往两个方向传播,一个方向是其传递到上一层网络,得到$\delta^{l-1}_{t}$,这部分只和权重矩阵U有关;另一个是方向是将其沿时间线传递到初始$t_{1}$,得到$\delta^{l}_{1}$,这部分只和权重矩阵W有关。
我们先来计算误差沿时间的传播:
用向量$net_{t}$表示神经元在t时刻的加权输入,因为:
可以得到:
我们用a表示列向量,用$a^{T}$表示行向量。上式的第一项是向量函数对向量求导,结果为:
同理,第二项结果为
最后,将两项合在一起,可得:
上式描述了将沿时间往前传递一个时刻的规律$\delta$,有了这个规律,我们就可以求得任意时刻k的误差项$\delta_{k}$:
结果就是将误差项沿时间反向传播的算法
再来计算误差沿网络层的传播:
循环层的加权输入$net^{l}$与上一层的加权输入$net^{l-1}$关系如下:
上式中$net^{l}_{t}$是第l层神经元的加权输入,$net^{l-1}_{t}$是第l-1层神经元的加权输入,$a^{l-1}_{t}$是第l-1层神经元的输出,$f^{l-1}$是第l-1层的激活函数
同样我们可以得到:
所以,
结果就是将误差项沿网络层的算法
权重梯度的计算
首先,我们计算误差函数E对权重矩阵W的梯度$\frac{\partial E}{\partial W}$
只要知道了任意一个时刻的误差项$\delta_{t}$,以及上一个时刻循环层的输出值$s_{t-1}$,就可以按照下面的公式求出权重矩阵在t时刻的梯度$\nabla_{W t} E$
最终的梯度$\nabla_{W } E$是各个时刻的梯度之和:
权重矩阵U也类似:
最终的梯度也是各个时刻的梯度之和:
RNN的梯度爆炸和消失问题
我们根据沿时间的反向传播可以得到
上式$\beta$的定义为矩阵的模的上界。因为上式是一个指数函数,如果t-k很大的话(也就是向前看很远的时候),会导致对应的误差项的值增长或缩小的非常快,这样就会导致相应的梯度爆炸和梯度消失问题(取决于大于1还是小于1)。
LSTM
LSTM(Long Short-Term Memory)是一种RNN网络的结构。它在原始的RNN网络中增加了门结构来解决长距离的依赖和梯度消失,爆炸等问题。
在原始的RNN网络结构中,隐藏层的状态$h_{t}$由$x_{t}$和$h_{t-1}$得到。得到$h_{t}$后一方面用于当前层的模型损失计算,另一方面用于计算下一层的$h_{t+1}$。
我们以最常见的LSTM为例讲述。LSTM的结构如下图:
我可以看到,比起原始的RNN网络结构,LSTM在每个序列索引位置t时刻向前传播的除了和RNN一样的隐藏状态$h_{t}$,还多了另一个隐藏状态,如图中上面的长横线。这个隐藏状态我们一般称为细胞状态(Cell State),记为$c_{t}$。如下图所示:
LSTM遗忘门
遗忘门是控制是否遗忘的,在LSTM中即以一定的概率控制是否遗忘上一层的隐藏细胞状态。遗忘门子结构如下图所示:
图中输入的有上一序列的隐藏状态$h_{t-1}$和本序列数据$x_{t}$,通过一个激活函数,一般是sigmoid,得到遗忘门的输出$f_{t}$。由于sigmoid的输出$f_{t}$在[0,1]之间,因此这里的输出$f_{t}$代表了遗忘上一层隐藏细胞状态的概率。用数学表达式即为:
其中$W_{f}, U_{f}, b_{f}$为系数矩阵和bias,和RNN中的类似。$\sigma$为sigmoid激活函数。
LSTM输入门
输入门(input gate)负责处理当前序列位置的输入,它的子结构如下图:
从图中可以看到输入门由两部分组成,第一部分使用了sigmoid激活函数,输出为$i_{t}$,第二部分使用了tanh激活函数,输出为$a_{t}$, 两者的结果后面会相乘再去更新细胞状态。用数学表达式即为:
同上,其中$W_{i}, U_{i}, b_{i}, W_{a}, U_{a}, b_{a}$为系数矩阵和bias。$\sigma$为sigmoid激活函数。
LSTM更新细胞状态
细胞状态$C_{t}$由两部分组成,第一部分是$C_{t-1}$和遗忘门输出$f_{t}$的乘积,第二部分是输入门的$i_{t}$和$a_{t}$的乘积:
其中$\odot$为element-wise乘积
LSTM输出门
从图中可以看出,隐藏状态$h_{t}$的更新由两部分组成,第一部分是$o_{t}$, 它由上一序列的隐藏状态$h_{t-1}$和本序列数据$x_{t}$,以及激活函数sigmoid得到,第二部分由隐藏状态$C_{t}$和tanh激活函数组成, 即:
参考: