计算循环神经网络的梯度是容易的。 我们可以简单地将\sec?中的推广反向传播算法应用于展开的计算图,而不需要特殊化的算法。 由反向传播计算得到的梯度,并结合任何通用的基于梯度的技术就可以训练RNN。

为了获得BPTT算法行为的一些直观理解,我们举例说明如何通过BPTT计算上述RNN公式(\eqn?和\eqn?)的梯度。 计算图的节点包括参数U,V,W,bU,V,W, bcc,以及以tt为索引的节点序列x(t),h(t),o(t)x^{(t)}, h^{(t)},o^{(t)}L(t)L^{(t)}。 对于每一个节点NN,我们需要基于NN后面的节点的梯度,递归地计算梯度NL\nabla_{N} L。 我们从紧接着最终损失的节点开始递归:
LL(t)=1. \begin{aligned} \frac{\partial L}{\partial L^{(t)}} = 1. \end{aligned}

[warning] 这个公式不知道怎么推出来的?

在这个导数中,我们假设输出o(t)o^{(t)}作为softmax函数的参数,我们可以从softmax函数可以获得关于输出概率的向量y^\hat{y}。 我们也假设损失是迄今为止给定了输入后的真实目标y(t)y^{(t)}的负对数似然。

[success]
以下公式推导中:
t代表任意一个时刻,不是某个具体的时刻。
τ\tau代表当前时刻。

对于所有i,ti,t,关于时间步tt输出的梯度o(t)L\nabla_{o^{(t)}} L如下: (o(t)L)i=Loi(t)=LL(t)L(t)oi(t)=y^i(t)1i,y(t). \begin{aligned} (\nabla_{o^{(t)}} L)_i = \frac{\partial L}{\partial o_i^{(t)}} = \frac{\partial L}{\partial L^{(t)}} \frac{\partial L^{(t)}}{\partial o_i^{(t)}} = \hat y_i^{(t)} - \mathbf{1}_{i,y^{(t)}}. \end{aligned}

我们从序列的末尾开始,反向进行计算。 在最后的时间步τ\tau, h(τ)h^{(\tau)}只有o(τ)o^{(\tau)}作为后续节点,因此这个梯度很简单: h(τ)L=Vo(τ)L. \begin{aligned} \nabla_{h^{(\tau)}} L = V^\top \nabla_{o^{(\tau)}} L. \end{aligned}

然后,我们可以从时刻t=τ1t=\tau-1t=1t=1反向迭代, 通过时间反向传播梯度,注意h(t)(t<τ)h^{(t)}(t < \tau)同时具有o(t)o^{(t)}h(t+1)h^{(t+1)}两个后续节点。 因此,它的梯度由下式计算 h(t)L=(h(t+1)h(t))(h(t+1)L)+(o(t)h(t))(o(t)L)=W(h(t+1)L)diag(1(h(t+1))2)+V(o(t)L), \begin{aligned} \nabla_{h^{(t)}} L = \Big( \frac{\partial h^{(t+1)}}{ \partial h^{(t)}} \Big)^\top(\nabla_{h^{(t+1)}} L) + \Big( \frac{\partial o^{(t)}}{ \partial h^{(t)}} \Big)^\top (\nabla_{o^{(t)}} L) \\ = W^\top (\nabla_{h^{(t+1)}} L) \text{diag} \Big( 1 - (h^{(t+1)})^2 \Big) + V^\top ( \nabla_{o^{(t)}} L ), \end{aligned}

[warning] 这个公式怎么推出来的?
(h(t+1)h(t))=W(h(t+1)L)(h(t+1)L)diag(1(h(t+1))2)? \begin{aligned} \Big( \frac{\partial h^{(t+1)}}{ \partial h^{(t)}} \Big)^\top = W^\top \\ (\nabla_{h^{(t+1)}} L) \text{还是} (\nabla_{h^{(t+1)}} L) \\ \text{diag} \Big( 1 - (h^{(t+1)})^2 \Big) \text{这是哪来的}? \end{aligned}

其中diag(1(h(t+1))2)\text{diag} \Big( 1 - (h^{(t+1)})^2 \Big) 表示包含元素1(hi(t+1))21 - (h_i^{(t+1)})^2的对角矩阵。 这是关于时刻t+1t+1与隐藏单元ii关联的双曲正切的Jacobian。

[warning] 双曲正切的Jacobian?

一旦获得了计算图内部节点的梯度,我们就可以得到关于参数节点的梯度。 因为参数在许多时间步共享,我们必须在表示这些变量的微积分操作时谨慎对待。 我们希望实现的等式使用\sec?中的{\tt bprop}方法计算计算图中单一边对梯度的贡献。 然而微积分中的Wf\nabla_{W} f算子,计算WW对于ff的贡献时将计算图中的\emph{所有}边都考虑进去了。 为了消除这种歧义,我们定义只在tt时刻使用的虚拟变量W(t)W^{(t)}作为WW的副本。 然后,我们可以使用W(t)\nabla_{W^{(t)}}表示权重在时间步tt对梯度的贡献。

使用这个表示,关于剩下参数的梯度可以由下式给出: cL=t(o(t)c)o(t)L=to(t)L,bL=t(h(t)b(t))h(t)L=tdiag(1(h(t))2)h(t)L,VL=ti(Loi(t))Voi(t)=t(o(t)L)h(t),WL=ti(Lhi(t))W(t)hi(t)=tdiag(1(h(t))2)(h(t)L)h(t1),UL=ti(Lhi(t))U(t)hi(t)=tdiag(1(h(t))2)(h(t)L)x(t), \begin{aligned} \nabla_{c} L &= \sum_t \Big( \frac{\partial o^{(t)}}{\partial c} \Big)^\top \nabla_{o^{(t)}} L = \sum_t \nabla_{o^{(t)}} L ,\\ \nabla_{b} L &= \sum_t \Big( \frac{\partial h^{(t)}}{\partial b^{(t)}} \Big)^\top \nabla_{h^{(t)}} L = \sum_t \text{diag} \Big( 1 - \big( h^{(t)} \big)^2 \Big) \nabla_{h^{(t)}} L ,\\ \nabla_{V} L &= \sum_t \sum_i \Big( \frac{\partial L} {\partial o_i^{(t)}}\Big) \nabla_{V} o_i^{(t)} = \sum_t (\nabla_{o^{(t)}} L) h^{(t)^\top},\\ \nabla_{W} L &= \sum_t \sum_i \Big( \frac{\partial L} {\partial h_i^{(t)}}\Big) \nabla_{W^{(t)}} h_i^{(t)} \\ &= \sum_t \text{diag} \Big( 1 - \big( h^{(t)} \big)^2 \Big) ( \nabla_{h^{(t)}} L) h^{(t-1)^\top} ,\\ \nabla_{U} L &= \sum_t \sum_i \Big( \frac{\partial L} {\partial h_i^{(t)}}\Big) \nabla_{U^{(t)}} h_i^{(t)} \\ &= \sum_t \text{diag} \Big( 1 - \big( h^{(t)} \big)^2 \Big) ( \nabla_{h^{(t)}} L) x^{(t)^\top} , \end{aligned}

因为计算图中定义的损失的任何参数都不是训练数据x(t)x^{(t)}的父节点,所以我们不需要计算关于它的梯度。

[success]

参数包含U,W,V,b,c.
(1)计算每条边上的梯度
(2)令{L}=1
(3)根据串行相乘并行相加的方法计算{U}, {W}, {V}, {b}, {c}
最后得到与书上相同的结果。

results matching ""

    No results matching ""