循环神经网络
前馈神经网络的缺陷
前馈神经网络每次输入都是独立的,即网络的输出只依赖于当前输入,且要求输入和输出都维度都是固定的,不能任意改变
但现实情况下,要求网络输出不仅和当前时刻输入相关,也和其过去一段时间输出相关,并且时序数据的长度一般式不固定的,比如视频、语音、文本等
给网络增加短期记忆能力
针对上面的问题,延时神经网络(Time Delay Neural Network, TDNN)考虑的是
- 建立一个额外的延时单元,用来存储网络的历史信息
- 在前馈网络的非输出层都添加一个延时器,记录神经元神的最近几次的活性值
- 在第t个时刻,第l层神经元的活性值依赖于第l-1层神经元的最近K个时刻的活性值,即
h_t^{(l)}=f(h_t^{(l-1)},h_{t-1}^{(l-1)},h_{t-K}^{(l-1)})
通过延时器,前馈神经网络就具有了短期记忆的能力
与TDNN对应的数学模型是自回归模型(Auto-Regressive Model, AR)
::: align-center
y_t=w_0+\sum_{k=1}^K w_ky_{t-k}+\epsilon_t
:::
其\epsilon_t是第t时刻的噪声
或非线性自回归模型(NARX)
::: align-center
y_t=f(x_t,x_{t-1},\cdots,x_{t-K_x},y_{t-1},y_{t-2},\cdots,y_{t-K_y})
:::
循环神经网络
循环神经网络(Recurrent Neural Network, RNN)通过使用带自反馈的神经元,能够处理任意长度的数据
先介绍简单循环网络(Simple Recurrent Network, SRN),它只有一个隐藏层,并且隐藏层之前有反馈连接,它的状态更新公式为
::: align-center
h_t=f(Uh_{t-1}+WX_t+b)
:::
其中:
- f(\cdot):激活函数
- U/h_{t-1}:状态-状态权重矩阵/隐藏层的上一个状态
- W/X_t:状态-输入权重矩阵/输入
RNN把每个时刻的状态都看作前馈神经网络的一层,从这带你它可以看作在时间维度上权值共享的神经网络

举个例子:输入为序列数据“深度学习”
- 在时刻t=t_1,输入为“深”,网络产生一个状态h_1,代表对“深”的理解
- 在时刻t=t_2,输入为“度”,网络结合“度”和h_1得出h_2,代表对“深度”的理解
- 在时刻t=t_3,输入为“学”,网络结合“学”和h_2得出h_3,代表对“深度学”的理解
- 在时刻t=t_4,输入为“习”,网络结合“习”和h_3得出h_4,代表对“深度学习”的理解
每个时刻t产生的状态h_t,就像是网络在那个时刻的“快照”或“记忆层”,包含了目前为止接受到的所有序列信息,所以,每个h_t都可以看作是网络在时间t展开时的中间隐藏层
在标准的FNN中,每一层通常都有自己独立的一些权重,而对于RNN来说,如果每个时间步都有一个权重,那模型的参数量将非常大,所以对于RNN,某一层的每个时间步的权重W,U,b一般都是相同的
循环神经网络是图灵完备的,它可近似的解决所有的可计算问题
RNN在机器学习中的应用
根据机器学习任务的特点,RNN的应用可分为:序列到类别模式、同步的序列到序列模式、异步的序列到序列模式
序列到类别模式
这种模式主要用于序列数据的分类问题:输入为序列,输出为类别,它又分为正常模式和按时间进行平均的模式

同步的序列到序列模式
这种模式主要用于信息抽取,例如从无结构的文本中抽取结构化的信息,形成知识

异步的序列到序列模式
应用在编码器-解码器模型中,输入序列和输出序列不需要有严格的对应关系,也不需要保持相同的长度。例如在机器翻译中,输入为源语言的单词序列,输出为目标语言的单词序列

参数学习
这里我们以同步的序列到序列模式为例
给定一个训练样本(x,y),其中x_{1:T}是长度为T的输入序列,y_{1:T}是长度为T为标签序列,定义t时刻的损失函数为
::: align-center
\mathcal{L}_t=\mathcal{L}(y_t,g(h_t))
:::
其中g(h_t)是t时刻下的结果,y_t是t时刻的标签
则整个序列的损失函数为
::: align-center
\mathcal{L}=\sum_{t=1}^T\mathcal{L}_t
:::
之后我们考虑通过梯度下降更新参数,主要有随时间的反向传播算法、实时循环学习算法
随时间的反向传播算法
随时间的反向传播算法(Back Propagation Through Time, BPTT)考虑将RNN看作一个展开的多层前馈神经网络,其中“每一层”对应RNN中的“每一个时刻”,每一层可按照FNN中的BP算法计算梯度
之后BPTT考虑在按时间展开得到的前馈网络中,所有层的参数是共享的,因此参数的真实梯度是所有展开层的参数梯度之和

于是得到整个序列的损失函数关于状态-状态矩阵U的梯度为
::: align-center
\frac{\partial \mathcal{L}}{\partial U}=\sum_{t=1}^T\sum_{k=1}^t\frac{\partial \mathcal{L}}{\partial z_k}\frac{\partial \mathcal{z_k}}{\partial U}=\sum_{t=1}^T\sum_{k=1}^t\delta_{t,k}h_{k-1}^T
:::
同时损失函数关于权重和偏置的梯度类似可得分别为
::: align-center
\begin{aligned}
&\frac{\partial \mathcal{L}}{\partial W}=\sum_{t=1}^T\sum_{k=1}^t\delta_{t,k}x_k^T\\
&\frac{\partial \mathcal{L}}{\partial b}=\sum_{t=1}^T\sum_{k=1}^t\delta_{t,k}
\end{aligned}
:::
其中\delta_{t,k}是误差项
::: align-center
\delta_{t,k}=\frac{\partial \mathcal{L_t}}{\partial z_k}=\frac{\partial \mathcal{L_t}}{\partial z_{k+1}}\frac{\partial z_{k+1}}{\partial h_k}\frac{\partial h_k}{\partial z_k}=\delta_{t,k+1}U^T\odot f'(z_k)
:::
注:这里与U进行的是外积运算,FNN中是与W进行内积运算
特别地,在起始点时
::: align-center
\delta_{t,t}=\frac{\partial \mathcal{L}_t}{\partial z_t}=\frac{\partial \mathcal{L}_t}{\partial h_t}\odot f'(z_k)
:::
但是,BPTT的坏处就是必须等待序列完整输入后才能计算出梯度,这对于存储的开销是巨大的,并且它无法实现在线学习,所以这时就需要下面的前向梯度计算方法
实时循环学习算法 (重要)
实时循环学习算法(Real Time Recurrent Learning, RTRL)通过前向传播的方式计算梯度
从第1个时刻开始,除了计算循环神经网络的隐状态之外,还依次前向计算偏导数
::: align-center
\begin{aligned}
&h_{t}=f(z_{t})=f(Uh_{t-1}+Wx_{t}+b)\\
&\frac{\partial h_{t}}{\partial u_{ij}}=\frac{\partial h_{t}}{\partial z_{t}}
\frac{\partial z_{t}}{\partial u_{ij}}=(\frac{\partial z_{t+}}{\partial u_{ij}}+\frac{\partial h_{t-1}}{\partial u_{ij}}U^T)\frac{\partial h_{t}}{\partial z_{t}}
\end{aligned}
:::
其中\frac{\partial h_{t}}{\partial z_{t}}是激活函数的导数f'(z_{t})
展开\frac{\partial z_{t}}{\partial u_{ij}}获得括号内的项
::: align-center
\begin{aligned}
&\frac{\partial z_{t}}{\partial u_{ij}}=\frac{\partial(Uh_{t-1}+Wx_{t}+b)}{\partial u_{ij}}\\
&=\frac{\partial (Uh_{t-1})}{\partial u_{ij}}+0+0\\
&=\frac{\partial U}{\partial u_{ij}}h_{t-1}+\frac{\partial h_{t-1}}{\partial u_{ij}}U^T
\end{aligned}
:::
由于\frac{\partial U}{\partial u_{ij}}这个矩阵只在(i,j)处为1,故它右乘向量h_t得到的结果为一个向量\mathbb{I_i}\cdot[h_{t-1}]_j,记为\mathbb{I_i([h_{t-1}]_j)},其中\mathbb{I}_i为指示向量,它的第i维为1,其余维为0
故有
::: align-center
\frac{\partial h_{t}}{\partial u_{ij}}=(\mathbb{I}_i([h_{t-1}]_j)+\frac{\partial h_{t-1}}{\partial u_{ij}}U^T)\odot f'(z_{t})
:::
之后就可以使用这个偏导进行参数的更新
::: align-center
\begin{aligned}
&\frac{\partial \mathcal{L}_t}{\partial u_{ij}}=(\frac{\partial h_t}{\partial u_{ij}})^T\frac{\partial \mathcal{L}_t}{\partial h_t}\\
\end{aligned}
:::
与此同时,考虑计算偏导数\frac{\partial h_t}{\partial w_{kl}}并用其更新\frac{\partial \mathcal{L}}{\partial w_{kl}},计算偏导数\frac{\partial h_t}{\partial b_i}并用其更新\frac{\partial \mathcal{L}}{\partial b_i},这里我们不再推导这两项的公式
RNN的长程依赖问题 (重要)
循环神经网络在学习过程中面临的主要问题是梯度弥散(梯度消失)和梯度爆炸问题,如不解决其将很难解决长时间间隔状态之间的依赖关系
比如我们考虑BPTT算法下的
::: align-center
\frac{\partial \mathcal{L}}{\partial U}=\sum_{t=1}^T\sum_{k=1}^t\delta_{t,k}h_{k-1}^T=\prod_{\tau=k}^{t-1}(diag(f'(z_{\tau}))U^T)\delta_{t,t}\approx\gamma^{t-k}\delta_{t,t}
:::
- 若\gamma >1,当t-k\to\infty时将发生梯度爆炸问题
- 若\gamma <1,当t-k\to\infty时将发生梯度弥散问题
诸如此类的问题使得RNN早期的诸如SRN等网络只能学习到短期的依赖关系,很难解决长程依赖问题
对于梯度爆炸的问题,比较容易解决,可以考虑:
- 权重衰减:如添加正则化项限制参数的取值范围
- 梯度截断:梯度大于一个值后将其截断为一个较小的数
而关于梯度消失的问题,则较难解决,它也是RNN的主要问题,为此引入了基于门控的循环神经网络
基于门控的RNN
为了解决长程依赖问题,一种非常好的解决方法是引入门控机制来控制信息的累计速度,包括有选择的加入信息,并有选择的遗忘之前累计的信息
使用门控机制的RNN主要有:长短期记忆网络、门控循环单元网络
长短期记忆网络 LSTM
长短期记忆网络(Long Short-Term Memory Network, LSTM)是RNN的变体,可以有效的解决梯度爆炸/消失问题
它的计算过程为:
- 利用上一时刻的隐状态h_{t-1}和当前输入x_t计算出三个门与候选状态\tilde{c}_t
- 结合遗忘门f_t和输入门i_t来更新记忆单元c_t
- 结合输出门o_t,将内部状态的信息传递给外部状态h_t

LSTM的变体为

门控循环单元网络 GRN
门控循环单元网络(Gated Recurrent Unit, GRU)通过引入门控机制来控制信息更新的方式,比LSTM更加简单
与LSTM不同,GRU不引入额外的记忆单元,而是引入一个更新门来控制当前状态需要从历史状态中保留多少信息,以及需要从候选状态中接受多少信息
GRU的更新见下图

深层循环网络 DRNN
考虑到CNN用多层网络可以捕捉到更复杂的特征,我们也可以考虑堆叠RNN组成深层循环网络(DRNN)用于捕捉更复杂的特征,SRN、LSTM、GRN等都可以作为DRNN的堆叠单元,尤其是后两种因为引入了门控机制可以很好的处理梯度爆炸和梯度弥散问题
这里我们介绍两种堆叠方式:堆叠循环神经网络、双向循环神经网络
堆叠循环神经网络 SRNN
堆叠循环神经网络(Stacked Recurrent Neural Network, SRNN)考虑将多个循环网络堆叠起来,第l层网络的输入是第l-1层网络的输出

双向循环神经网络 Bi-RNN
双向循环神经网络(Bidirectional Recurrent Neural Network, Bi-RNN)由两层循环神经网络构成,它们的输入相同,只是信息传递方向不同

扩展到图结构
暂不整理
全部评论 (0)
暂无评论,快来抢沙发吧~