定义模型
简单起见,我们考虑一个无偏差项的循环神经网络,且**函数为恒等映射(ϕ(x)=x)。设时间步 t 的输入为单样本 xt∈Rd,标签为 yt,那么隐藏状态 ht∈Rh的计算表达式为
ht=Whxxt+Whhht−1,
其中Whx∈Rh×d和Whh∈Rh×h是隐藏层权重参数。设输出层权重参数Wqh∈Rq×h,时间步t的输出层变量ot∈Rq计算为
ot=Wqhht.
设时间步t的损失为ℓ(ot,yt)。时间步数为T的损失函数L定义为
L=T1t=1∑Tℓ(ot,yt).
我们将L称为有关给定时间步的数据样本的目标函数,并在本节后续讨论中简称为目标函数。
模型计算图
为了可视化循环神经网络中模型变量和参数在计算中的依赖关系,我们可以绘制模型计算图,如图所示。例如,时间步3的隐藏状态h3的计算依赖模型参数Whx、Whh、上一时间步隐藏状态h2以及当前时间步输入x3。
![循环神经网络中如何通过时间反向传播? 循环神经网络中如何通过时间反向传播?](https://pythonjishu.com/wp-content/uploads/2023/04/ReUNfpErDLtk20230408.jpg)
方法
刚刚提到,图6.3中的模型的参数是 Whx, Whh 和 Wqh。与一般的反向传播类似,训练模型通常需要模型参数的梯度∂Whx∂L、∂Whh∂L和∂Wqh∂L。 根据上图的依赖关系,我们可以按照其中箭头所指的反方向依次计算并存储梯度。
首先,目标函数有关各时间步输出层变量的梯度∂ot∂L∈Rq很容易计算:
∂ot∂L=T⋅∂ot∂ℓ(ot,yt).
下面,我们可以计算目标函数有关模型参数Wqh的梯度∂Wqh∂L∈Rq×h。根据计算图,L通过o1,…,oT依赖Wqh。依据链式法则,
∂Wqh∂L=t=1∑Tprod(∂ot∂L,∂Wqh∂ot)=t=1∑T∂ot∂Lht⊤.
其次,我们注意到隐藏状态之间也存在依赖关系。 在计算图中,L只通过oT依赖最终时间步T的隐藏状态hT。因此,我们先计算目标函数有关最终时间步隐藏状态的梯度∂hT∂L∈Rh。依据链式法则,我们得到
∂hT∂L=prod(∂oT∂L,∂hT∂oT)=Wqh⊤∂oT∂L.
接下来对于时间步t<T, 在计算图中,L通过ht+1和ot依赖ht。依据链式法则, 目标函数有关时间步t<T的隐藏状态的梯度∂hT∂L∈Rh需要按照时间步从大到小依次计算: ∂ht∂L=prod(∂ht+1∂L,∂ht∂ht+1)+prod(∂ot∂L,∂ht∂ot)=Whh⊤∂ht+1∂L+Wqh⊤∂ot∂L
将上面的递归公式展开,对任意时间步1≤t≤T,我们可以得到目标函数有关隐藏状态梯度的通项公式
∂ht∂L=i=t∑T(Whh⊤)T−iWqh⊤∂oT+t−i∂L.
由上式中的指数项可见,当时间步数 T 较大或者时间步 t 较小时,目标函数有关隐藏状态的梯度较容易出现衰减和爆炸。这也会影响其他包含∂hT∂L项的梯度,例如隐藏层中模型参数的梯度∂Whx∂L∈Rh×d 和 ∂Whh∂L∈Rh×h。 在计算图中,L通过h1,…,hT依赖这些模型参数。 依据链式法则,我们有
∂Whx∂L=t=1∑Tprod(∂ht∂L,∂Whx∂ht)=t=1∑T∂ht∂Lxt⊤
∂Whh∂L=t=1∑Tprod(∂ht∂L,∂Whh∂ht)=t=1∑T∂ht∂Lht−1⊤
每次迭代中,我们在依次计算完以上各个梯度后,会将它们存储起来,从而避免重复计算。例如,由于隐藏状态梯度∂ht∂L被计算和存储,之后的模型参数梯度∂Whx∂L和∂Whh∂L的计算可以直接读取∂ht∂L的值,而无须重复计算它们。此外,反向传播中的梯度计算可能会依赖变量的当前值。它们正是通过正向传播计算出来的。 举例来说,参数梯度∂Whh∂L的计算需要依赖隐藏状态在时间步t=0,…,T−1的当前值ht(h0是初始化得到的)。这些值是通过从输入层到输出层的正向传播计算并存储得到的。
参考资料
反向传播