深度学习(五):循环神经网络(RNN)模型与前向反向传播算法

在前面我们讲到了DNN,以及DNN的特例CNN的模型和前向反向传播算法。链接如下:

深度学习(一):DNN前向传播算法和反向传播算法
深度学习(二):DNN损失函数和激活函数的选择
深度学习(四):卷积神经网络(CNN)模型结构,前向传播算法和反向传播算法介绍。

建议在读本文之前,重点读下前2篇文章。如果不了解DNN的前向和反向传播的话,理解本篇文章会有难度。

这些算法都是前向反馈的,模型的输出和模型本身没有关联关系。今天我们就讨论另一类输出和模型间有反馈的神经网络:循环神经网络(Recurrent Neural Networks ,以下简称RNN),它广泛的用于自然语言处理中的语音识别,手写书别以及机器翻译等领域。

一、RNN概述

在前面讲到的DNN和CNN中,训练样本的输入和输出是比较确定的。但是有一类问题DNN和CNN不好解决,就是训练样本输入是连续的序列,且序列的长短不一,比如基于时间的序列:一段段连续的语音,一段段连续的手写文字。这些序列比较长,且长度不一,比较难直接的拆分成一个个独立的样本来通过DNN/CNN进行训练

而对于这类问题,RNN则比较的擅长。那么RNN是怎么做到的呢?RNN假设我们的样本是基于序列的。比如是从序列索引1到序列索引 τ \tau τ的。对于这其中的任意序列索引号 t t t,它对应的输入是对应的样本序列中的 x ( t ) x^{(t)} x(t)。而模型在序列索引号 t t t位置的隐藏状态 h ( t ) h^{(t)} h(t),则由 x ( t ) x^{(t)} x(t)和在 t − 1 t−1 t1位置的隐藏状态 h ( t − 1 ) h^{(t−1)} h(t1)共同决定。在任意序列索引号 t t t,我们也有对应的模型预测输出 o ( t ) o^{(t)} o(t)。通过预测输出 o ( t ) o^{(t)} o(t)和训练序列真实输出 y ( t ) y^{(t)} y(t),以及损失函数 L ( t ) L^{(t)} L(t),我们就可以用DNN类似的方法来训练模型,接着用来预测测试序列中的一些位置的输出。

下面我们来看看RNN的模型。

二、RNN模型

RNN模型有比较多的变种,这里介绍最主流的RNN模型结构如下:

CSDN图标

上图中左边是RNN模型没有按时间展开的图,如果按时间序列展开,则是上图中的右边部分。我们重点观察右边部分的图。

这幅图描述了在序列索引号 t t t附近RNN的模型。其中:

1) x ( t ) x^{(t)} x(t)代表在序列索引号t时训练样本的输入。同样的, x ( t − 1 ) x^{(t−1)} x(t1) x ( t + 1 ) x^{(t+1)} x(t+1)代表在序列索引号 t − 1 t−1 t1 t + 1 t+1 t+1时训练样本的输入。

2) h ( t ) h^{(t)} h(t)代表在序列索引号 t t t时模型的隐藏状态。 h ( t ) h^{(t)} h(t) x ( t ) x^{(t)} x(t) h ( t − 1 ) h^{(t-1)} h(t1)共同决定。

3) o ( t ) o^{(t)} o(t)代表在序列索引号 t t t时模型的输出。 o ( t ) o^{(t)} o(t)只由模型当前的隐藏状态 h ( t ) h^{(t)} h(t)决定。

4) L ( t ) L^{(t)} L(t)代表在序列索引号 t t t时模型的损失函数。

5) y ( t ) y^{(t)} y(t)代表在序列索引号 t t t时训练样本序列的真实输出。

6) U , W , V U,W,V U,W,V这三个矩阵是我们的模型的线性关系参数,它在整个RNN网络中是共享的,这点和DNN很不相同。 也正因为是共享了,它体现了RNN的模型的“循环反馈”的思想。

三、RNN前向传播算法

有了上面的模型,RNN的前向传播算法就很容易得到了。

对于任意一个序列索引号 t t t,我们隐藏状态 h ( t ) h^{(t)} h(t) x ( t ) x^{(t)} x(t) h ( t − 1 ) h^{(t-1)} h(t1)得到:
h ( t ) = σ ( z ( t ) ) = σ ( U x ( t ) + W h ( t − 1 ) + b ) (1) h^{(t)} = \sigma(z^{(t)}) = \sigma(Ux^{(t)} + Wh^{(t-1)} +b ) \qquad \text{(1)} h(t)=σ(z(t))=σ(Ux(t)+Wh(t1)+b)(1)

其中 σ \sigma σ为RNN的激活函数,一般为tanh, b b b为线性关系的偏倚。

序列索引号 t t t时模型的输出 o ( t ) o^{(t)} o(t)的表达式比较简单:
o ( t ) = V h ( t ) + c (2) o^{(t)} = Vh^{(t)} +c\qquad \text{(2)} o(t)=Vh(t)+c(2)

在最终在序列索引号 t t t时我们的预测输出为:
y ^ ( t ) = σ ( o ( t ) ) (3) \hat{y}^{(t)} = \sigma(o^{(t)})\qquad \text{(3)} y^(t)=σ(o(t))(3)

通常由于RNN是分类模型,所以上面这个激活函数一般是softmax

通过损失函数 L ( t ) L^{(t)} L(t),比如对数似然损失函数,我们可以量化模型在当前位置的损失,即 y ^ ( t ) \hat{y}^{(t)} y^(t) y ( t ) y^{(t)} y(t)的差距。

四、RNN反向传播算法推导

有了RNN前向传播算法的基础,就容易推导出RNN反向传播算法的流程了。RNN反向传播算法的思路和DNN是一样的,即通过梯度下降法一轮轮的迭代,得到合适的RNN模型参数 U , W , V , b , c U,W,V,b,c U,W,V,b,c。由于我们是基于时间反向传播,所以RNN的反向传播有时也叫做BPTT(back-propagation through time)。当然这里的BPTT和DNN也有很大的不同点,即这里所有的 U , W , V , b , c U,W,V,b,c U,W,V,b,c在序列的各个位置是共享的,反向传播时我们更新的是相同的参数

为了简化描述,这里的损失函数我们为对数损失函数,输出的激活函数为softmax函数,隐藏层的激活函数为tanh函数

对于RNN,由于我们在序列的每个位置都有损失函数,因此最终的损失 L L L为:

L = ∑ t = 1 τ L ( t ) (4) L = \sum\limits_{t=1}^{\tau}L^{(t)}\qquad \text{(4)} L=t=1τL(t)(4)

根据公式(2), V , c V,c V,c的梯度计算是比较简单的:
∂ L ∂ c = ∑ t = 1 τ ∂ L ( t ) ∂ c = ∑ t = 1 τ ∂ L ( t ) ∂ o ( t ) ∂ o ( t ) ∂ c = ∑ t = 1 τ ∂ L ( t ) y ^ ( t ) y ^ ( t ) ∂ o ( t ) ∂ o ( t ) ∂ c = ∑ t = 1 τ y ^ ( t ) − y ( t ) (5) \frac{\partial L}{\partial c} = \sum\limits_{t=1}^{\tau}\frac{\partial L^{(t)}}{\partial c} =\sum\limits_{t=1}^{\tau}\frac{\partial L^{(t)}}{\partial o^{(t)}} \frac{\partial o^{(t)}}{\partial c} = \sum\limits_{t=1}^{\tau}\frac{\partial L^{(t)}}{\hat{y}^{(t)}} \frac{\hat{y}^{(t)}}{\partial o^{(t)}} \frac{\partial o^{(t)}}{\partial c} = \sum\limits_{t=1}^{\tau}\hat{y}^{(t)} - y^{(t)}\qquad \text{(5)} cL=t=1τcL(t)=t=1τo(t)L(t)co(t)=t=1τy^(t)L(t)o(t)y^(t)co(t)=t=1τy^(t)y(t)(5)

∂ L ∂ V = ∑ t = 1 τ ∂ L ( t ) ∂ V = ∑ t = 1 τ ∂ L ( t ) ∂ o ( t ) ∂ o ( t ) ∂ V = ∑ t = 1 τ ( y ^ ( t ) − y ( t ) ) ( h ( t ) ) T (6) \frac{\partial L}{\partial V} =\sum\limits_{t=1}^{\tau}\frac{\partial L^{(t)}}{\partial V} = \sum\limits_{t=1}^{\tau}\frac{\partial L^{(t)}}{\partial o^{(t)}} \frac{\partial o^{(t)}}{\partial V} = \sum\limits_{t=1}^{\tau}(\hat{y}^{(t)} - y^{(t)}) (h^{(t)})^T\qquad \text{(6)} VL=t=1τVL(t)=t=1τo(t)L(t)Vo(t)=t=1τ(y^(t)y(t))(h(t))T(6)


有必要介绍下公式(5)和(6)的求导。

对于公式(5),由于激活函数是softmax,损失函数是对数损失,因此该推导过程与深度学习(二):DNN损失函数和激活函数的选择里的公式(4)完全一样。

对于公式(6),为什么 ( h ( t ) ) T (h^{(t)})^T (h(t))T会放在后面,那是因为在实际矩阵求导的链式法则里面,对于两步的链式法则:

1)如果是标量对矩阵求导改成链式法则,那么求导的后半部分不用提前。
比如 y = f ( u ) , u = f ( x ) , y y=f(u), u=f(x), y y=f(u),u=f(x),y为标量, u , x u,x u,x为矩阵,则:
∂ y ∂ x = ∂ y ∂ u ( ∂ u ∂ x ) T \frac{\partial y}{\partial x} =\frac{\partial y}{\partial u}( \frac{\partial u}{\partial x})^T xy=uy(xu)T

2)如果是标量对向量求导改成链式法则,那么求导的后半部分要提前。
比如 y = f ( u ) , u = f ( x ) , y y=f(u), u=f(x), y y=f(u),u=f(x),y为标量, u , x u,x u,x为向量,则:
∂ y ∂ x = ( ∂ u ∂ x ) T ∂ y ∂ u \frac{\partial y}{\partial x} =( \frac{\partial u}{\partial x})^T\frac{\partial y}{\partial u} xy=(xu)Tuy


但是 W , U , b W,U,b W,U,b的梯度计算就比较的复杂了。从RNN的模型可以看出,在反向传播时,在某一序列位置 t t t的梯度损失由当前位置的输出对应的梯度损失和序列索引位置 t + 1 t+1 t+1时的梯度损失两部分共同决定。对于 W W W在某一序列位置 t t t的梯度损失需要反向传播一步步的计算。我们定义序列索引 t t t位置的隐藏状态的梯度为:
δ ( t ) = ∂ L ∂ h ( t ) (7) \delta^{(t)} = \frac{\partial L}{\partial h^{(t)}}\qquad \text{(7)} δ(t)=h(t)L(7)

这样我们可以像DNN一样从 δ ( t + 1 ) \delta^{(t+1)} δ(t+1)递推 δ ( t ) \delta^{(t)} δ(t)
δ ( t ) = ∂ L ∂ o ( t ) ∂ o ( t ) ∂ h ( t ) + ∂ L ∂ h ( t + 1 ) ∂ h ( t + 1 ) ∂ h ( t ) = V T ( y ^ ( t ) − y ( t ) ) + W T δ ( t + 1 ) d i a g ( 1 − ( h ( t + 1 ) ) 2 ) (8) \delta^{(t)} =\frac{\partial L}{\partial o^{(t)}} \frac{\partial o^{(t)}}{\partial h^{(t)}} + \frac{\partial L}{\partial h^{(t+1)}}\frac{\partial h^{(t+1)}}{\partial h^{(t)}} = V^T(\hat{y}^{(t)} - y^{(t)}) + W^T\delta^{(t+1)}diag(1-(h^{(t+1)})^2)\qquad \text{(8)} δ(t)=o(t)Lh(t)o(t)+h(t+1)Lh(t)h(t+1)=VT(y^(t)y(t))+WTδ(t+1)diag(1(h(t+1))2)(8)

δ ( τ ) = ∂ L ∂ o ( τ ) ∂ o ( τ ) ∂ h ( τ ) = V T ( y ^ ( τ ) − y ( τ ) ) (9) \delta^{(\tau)} =\frac{\partial L}{\partial o^{(\tau)}} \frac{\partial o^{(\tau)}}{\partial h^{(\tau)}} = V^T(\hat{y}^{(\tau)} - y^{(\tau)}) \qquad \text{(9)} δ(τ)=o(τ)Lh(τ)o(τ)=VT(y^(τ)y(τ))(9)


有必要介绍下公式(8)和(9)的求导。

先来看公式(8),两部分相加的原因是:
h ( t ) → o ( t ) → L h^{(t)}→o^{(t)}→L h(t)o(t)L
h ( t ) → h ( t + 1 ) → L h^{(t)}→h^{(t+1)}→L h(t)h(t+1)L
所以 L L L h ( t ) h^{(t)} h(t)求导时,要分别经过 o ( t ) o^{(t)} o(t) h ( t + 1 ) h^{(t+1)} h(t+1) h ( t ) h^{(t)} h(t)进行求导。

∂ L ∂ o ( t ) ∂ o ( t ) ∂ h ( t ) \large \frac{\partial L}{\partial o^{(t)}} \frac{\partial o^{(t)}}{\partial h^{(t)}} o(t)Lh(t)o(t)的导数是 V T ( y ^ ( t ) − y ( t ) ) V^T(\hat{y}^{(t)} - y^{(t)}) VT(y^(t)y(t)),这是显然的。

重点是 ∂ L ∂ h ( t + 1 ) ∂ h ( t + 1 ) ∂ h ( t ) \frac{\partial L}{\partial h^{(t+1)}}\frac{\partial h^{(t+1)}}{\partial h^{(t)}} h(t+1)Lh(t)h(t+1)的导数怎么求。根据公式(1)
h ( t + 1 ) = σ ( z ( t + 1 ) ) = σ ( U x ( t + 1 ) + W h ( t ) + b ) (1) h^{(t+1)} = \sigma(z^{(t+1)}) = \sigma(Ux^{(t+1)} + Wh^{(t)} +b ) \qquad \text{(1)} h(t+1)=σ(z(t+1))=σ(Ux(t+1)+Wh(t)+b)(1)

在前面我们介绍过了,隐含层的激活函数是tanh激活函数,即 y = t a n h ( x ) y=tanh(x) y=tanh(x),它的导数为 y ′ = 1 − y 2 y^{'}=1-y^2 y=1y2。结合
深度学习(一):DNN前向传播算法和反向传播算法中公式(12),有
∂ L ∂ h ( t + 1 ) ∂ h ( t + 1 ) ∂ h ( t ) = W T δ ( t + 1 ) ⊙ ( 1 − ( h ( t + 1 ) ) 2 ) = W T δ ( t + 1 ) d i a g ( 1 − ( h ( t + 1 ) ) 2 ) (8) \frac{\partial L}{\partial h^{(t+1)}} \frac{\partial h^{(t+1)}}{\partial h^{(t)}} = W^T\delta^{(t+1)} \odot (1-(h^{(t+1)})^2)=W^T\delta^{(t+1)}diag(1-(h^{(t+1)})^2)\qquad \text{(8)} h(t+1)Lh(t)h(t+1)=WTδ(t+1)(1(h(t+1))2)=WTδ(t+1)diag(1(h(t+1))2)(8)

这里是双曲正切激活函数,用矩阵中对角线元素表示向量中各个值的导数,可以去掉哈达马乘积,转化为矩阵乘法。

对于 W T δ ( t + 1 ) d i a g ( 1 − ( h ( t + 1 ) ) 2 ) W^T\delta^{(t+1)}diag(1-(h^{(t+1)})^2) WTδ(t+1)diag(1(h(t+1))2),正确的运算顺序应该是先 δ ( t + 1 ) d i a g ( 1 − ( h ( t + 1 ) ) 2 ) \delta^{(t+1)}diag(1-(h^{(t+1)})^2) δ(t+1)diag(1(h(t+1))2)(注意这里是哈德玛乘积的意思,即 n n n个元素对应位置相乘,并非 n ∗ 1 n*1 n1乘以 n ∗ n n*n nn),然后再用 W T W^T WT与上面的结果运算。即先进行哈德玛乘积。

知道了公式(8),公式(9)是显然易见的。


有了 δ ( t ) \delta^{(t)} δ(t),计算 W , U , b W,U,b W,U,b就容易了,这里给出 W , U , b W,U,b W,U,b的梯度计算表达式:
∂ L ∂ W = ∑ t = 1 τ ∂ L ∂ h ( t ) ∂ h ( t ) ∂ W = ∑ t = 1 τ d i a g ( 1 − ( h ( t ) ) 2 ) δ ( t ) ( h ( t − 1 ) ) T (10) \frac{\partial L}{\partial W} = \sum\limits_{t=1}^{\tau}\frac{\partial L}{\partial h^{(t)}} \frac{\partial h^{(t)}}{\partial W} = \sum\limits_{t=1}^{\tau}diag(1-(h^{(t)})^2)\delta^{(t)}(h^{(t-1)})^T\qquad \text{(10)} WL=t=1τh(t)LWh(t)=t=1τdiag(1(h(t))2)δ(t)(h(t1))T(10)

∂ L ∂ b = ∑ t = 1 τ ∂ L ∂ h ( t ) ∂ h ( t ) ∂ b = ∑ t = 1 τ d i a g ( 1 − ( h ( t ) ) 2 ) δ ( t ) (11) \frac{\partial L}{\partial b}= \sum\limits_{t=1}^{\tau}\frac{\partial L}{\partial h^{(t)}} \frac{\partial h^{(t)}}{\partial b} = \sum\limits_{t=1}^{\tau}diag(1-(h^{(t)})^2)\delta^{(t)}\qquad \text{(11)} bL=t=1τh(t)Lbh(t)=t=1τdiag(1(h(t))2)δ(t)(11)

∂ L ∂ U = ∑ t = 1 τ ∂ L ∂ h ( t ) ∂ h ( t ) ∂ U = ∑ t = 1 τ d i a g ( 1 − ( h ( t ) ) 2 ) δ ( t ) ( x ( t ) ) T (12) \frac{\partial L}{\partial U} = \sum\limits_{t=1}^{\tau}\frac{\partial L}{\partial h^{(t)}} \frac{\partial h^{(t)}}{\partial U} = \sum\limits_{t=1}^{\tau}diag(1-(h^{(t)})^2)\delta^{(t)}(x^{(t)})^T\qquad \text{(12)} UL=t=1τh(t)LUh(t)=t=1τdiag(1(h(t))2)δ(t)(x(t))T(12)

可以看到,除了梯度表达式不同,RNN的反向传播算法和DNN区别不大。

五、RNN小结

上面总结了通用的RNN模型和前向反向传播算法。当然,有些RNN模型会有些不同,自然前向反向传播的公式会有些不一样,但是原理基本类似。

RNN虽然理论上可以很漂亮的解决序列数据的训练,但是它也像DNN一样有梯度消失时的问题,当序列很长的时候问题尤其严重。因此,上面的RNN模型一般不能直接用于应用领域。在语音识别,手写书别以及机器翻译等NLP领域实际应用比较广泛的是基于RNN模型的一个特例LSTM,下一篇我们就来讨论LSTM模型。

参考文献

循环神经网络(RNN)模型与前向反向传播算法
转自该篇博客。

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值