在前面咱们讲到了DNN,以及DNN的特例CNN的模型和前向反向传播算法,这些算法都是前向反馈的,模型的输出和模型自己没有关联关系。今天咱们就讨论另外一类输出和模型间有反馈的神经网络:循环神经网络(Recurrent Neural Networks ,如下简称RNN),它普遍的用于天然语言处理中的语音识别,手写书别以及机器翻译等领域。html
在前面讲到的DNN和CNN中,训练样本的输入和输出是比较的肯定的。可是有一类问题DNN和CNN很差解决,就是训练样本输入是连续的序列,且序列的长短不一,好比基于时间的序列:一段段连续的语音,一段段连续的手写文字。这些序列比较长,且长度不一,比较难直接的拆分红一个个独立的样原本经过DNN/CNN进行训练。git
而对于这类问题,RNN则比较的擅长。那么RNN是怎么作到的呢?RNN假设咱们的样本是基于序列的。好比是从序列索引1到序列索引$\tau$的。对于这其中的任意序列索引号$t$,它对应的输入是对应的样本序列中的$x^{(t)}$。而模型在序列索引号$t$位置的隐藏状态$h^{(t)}$,则由$x^{(t)}$和在$t-1$位置的隐藏状态$h^{(t-1)}$共同决定。在任意序列索引号$t$,咱们也有对应的模型预测输出$o^{(t)}$。经过预测输出$o^{(t)}$和训练序列真实输出$y^{(t)}$,以及损失函数$L^{(t)}$,咱们就能够用DNN相似的方法来训练模型,接着用来预测测试序列中的一些位置的输出。github
下面咱们来看看RNN的模型。算法
RNN模型有比较多的变种,这里介绍最主流的RNN模型结构以下:网络
上图中左边是RNN模型没有按时间展开的图,若是按时间序列展开,则是上图中的右边部分。咱们重点观察右边部分的图。函数
这幅图描述了在序列索引号$t$附近RNN的模型。其中:测试
1)$x^{(t)}$表明在序列索引号$t$时训练样本的输入。一样的,$x^{(t-1)}$和$x^{(t+1)}$表明在序列索引号$t-1$和$t+1$时训练样本的输入。翻译
2)$h^{(t)}$表明在序列索引号$t$时模型的隐藏状态。$h^{(t)}$由$x^{(t)}$和$h^{(t-1)}$共同决定。htm
3)$o^{(t)}$表明在序列索引号$t$时模型的输出。$o^{(t)}$只由模型当前的隐藏状态$h^{(t)}$决定。blog
4)$L^{(t)}$表明在序列索引号$t$时模型的损失函数。
5)$y^{(t)}$表明在序列索引号$t$时训练样本序列的真实输出。
6)$U,W,V$这三个矩阵是咱们的模型的线性关系参数,它在整个RNN网络中是共享的,这点和DNN很不相同。 也正由于是共享了,它体现了RNN的模型的“循环反馈”的思想。
有了上面的模型,RNN的前向传播算法就很容易获得了。
对于任意一个序列索引号$t$,咱们隐藏状态$h^{(t)}$由$x^{(t)}$和$h^{(t-1)}$获得:$$h^{(t)} = \sigma(z^{(t)}) = \sigma(Ux^{(t)} + Wh^{(t-1)} +b )$$
其中$\sigma$为RNN的激活函数,通常为$tanh$, $b$为线性关系的偏倚。
序列索引号$t$时模型的输出$o^{(t)}$的表达式比较简单:$$o^{(t)} = Vh^{(t)} +c $$
在最终在序列索引号$t$时咱们的预测输出为:$$\hat{y}^{(t)} = \sigma(o^{(t)})$$
一般因为RNN是识别类的分类模型,因此上面这个激活函数通常是softmax。
经过损失函数$L^{(t)}$,好比对数似然损失函数,咱们能够量化模型在当前位置的损失,即$\hat{y}^{(t)}$和$y^{(t)}$的差距。
有了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 = \sum\limits_{t=1}^{\tau}L^{(t)}$$
其中$V,c,$的梯度计算是比较简单的:$$\frac{\partial L}{\partial c} = \sum\limits_{t=1}^{\tau}\frac{\partial L^{(t)}}{\partial c} = \sum\limits_{t=1}^{\tau}\hat{y}^{(t)} - y^{(t)}$$$$\frac{\partial L}{\partial V} =\sum\limits_{t=1}^{\tau}\frac{\partial L^{(t)}}{\partial V} = \sum\limits_{t=1}^{\tau}(\hat{y}^{(t)} - y^{(t)}) (h^{(t)})^T$$
可是$W,U,b$的梯度计算就比较的复杂了。从RNN的模型能够看出,在反向传播时,在在某一序列位置t的梯度损失由当前位置的输出对应的梯度损失和序列索引位置$t+1$时的梯度损失两部分共同决定。对于$W$在某一序列位置t的梯度损失须要反向传播一步步的计算。咱们定义序列索引$t$位置的隐藏状态的梯度为:$$\delta^{(t)} = \frac{\partial L}{\partial h^{(t)}}$$
这样咱们能够像DNN同样从$\delta^{(t+1)} $递推$\delta^{(t)}$ 。$$\delta^{(t)} =(\frac{\partial o^{(t)}}{\partial h^{(t)}} )^T\frac{\partial L}{\partial o^{(t)}} + (\frac{\partial h^{(t+1)}}{\partial h^{(t)}})^T\frac{\partial L}{\partial h^{(t+1)}} = V^T(\hat{y}^{(t)} - y^{(t)}) + W^Tdiag(1-(h^{(t+1)})^2)\delta^{(t+1)}$$
对于$\delta^{(\tau)} $,因为它的后面没有其余的序列索引了,所以有:$$\delta^{(\tau)} =( \frac{\partial o^{(\tau)}}{\partial h^{(\tau)}})^T\frac{\partial L}{\partial o^{(\tau)}} = V^T(\hat{y}^{(\tau)} - y^{(\tau)})$$
有了$\delta^{(t)} $,计算$W,U,b$就容易了,这里给出$W,U,b$的梯度计算表达式:$$\frac{\partial L}{\partial W} = \sum\limits_{t=1}^{\tau}diag(1-(h^{(t)})^2)\delta^{(t)}(h^{(t-1)})^T$$$$\frac{\partial L}{\partial b}= \sum\limits_{t=1}^{\tau}diag(1-(h^{(t)})^2)\delta^{(t)}$$$$\frac{\partial L}{\partial U} =\sum\limits_{t=1}^{\tau}diag(1-(h^{(t)})^2)\delta^{(t)}(x^{(t)})^T$$
除了梯度表达式不一样,RNN的反向传播算法和DNN区别不大,所以这里就再也不重复总结了。
上面总结了通用的RNN模型和前向反向传播算法。固然,有些RNN模型会有些不一样,天然前向反向传播的公式会有些不同,可是原理基本相似。
RNN虽然理论上能够很漂亮的解决序列数据的训练,可是它也像DNN同样有梯度消失时的问题,当序列很长的时候问题尤为严重。所以,上面的RNN模型通常不能直接用于应用领域。在语音识别,手写书别以及机器翻译等NLP领域实际应用比较普遍的是基于RNN模型的一个特例LSTM,下一篇咱们就来讨论LSTM模型。
(欢迎转载,转载请注明出处。欢迎沟通交流:liujianping-ok@163.com)
1) Neural Networks and Deep Learning by By Michael Nielsen
2) Deep Learning, book by Ian Goodfellow, Yoshua Bengio, and Aaron Courville
4)CS231n Convolutional Neural Networks for Visual Recognition, Stanford