《动手学深度学习 Pytorch版》 8.7 通过时间反向传播

8.7.1 循环神经网络的梯度分析

本节主要探讨梯度相关问题,因此对模型及其表达式进行了简化,进行如下表示:

h t = f ( x t , h t − 1 , w h ) o t = g ( h t , w o ) \begin{align} h_t&=f(x_t,h_{t-1},w_h)\\ o_t&=g(h_t,w_o) \end{align} htot=f(xt,ht1,wh)=g(ht,wo)

参数字典:

  • t t t 表示时间步

  • h t h_t ht 表示时间步 t t t 的隐状态

  • x t x_t xt 表示输入

  • o t o_t ot 表示输出

  • w h w_h wh 表示隐藏层权重

  • w o w_o wo 表示输出层权重

  • f f f 表示隐藏层变换

  • g g g 表示输出层权重

前向传播相当简单,一次一个时间步的遍历三元组 ( x t , h t , o t ) (x_t,h_t,o_t) (xt,ht,ot),然后通过一个目标函数在所有 T T T 个时间步内评估输出 o t o_t ot 和对应的标签 y t y_t yt 之间的差异:

L ( x 1 , … , x T , y 1 , … , y T , w h , w o ) = 1 T ∑ t = 1 T l ( y t , o t ) L(x_1,\dots,x_T,y_1,\dots,y_T,w_h,w_o)=\frac{1}{T}\sum^T_{t=1}l(y_t,o_t) L(x1,,xT,y1,,yT,wh,wo)=T1t=1Tl(yt,ot)

对于反向传播,就很棘手了,特别是计算目标函数 L L L 关于参数 w h w_h wh 的梯度时,按照链式法则:

∂ L ∂ w h = 1 T ∑ t = 1 T ∂ l ( y t , o t ) ∂ w h = 1 T ∑ t = 1 T ∂ l ( y t , o t ) ∂ o t ∂ g ( h t , w o ) ∂ h t ∂ h t ∂ w h \begin{align} \frac{\partial L}{\partial w_h}&=\frac{1}{T}\sum^T_{t=1}\frac{\partial l(y_t,o_t)}{\partial w_h}\\ &=\frac{1}{T}\sum^T_{t=1}\frac{\partial l(y_t,o_t)}{\partial o_t}\frac{\partial g(h_t,w_o)}{\partial h_t}\frac{\partial h_t}{\partial w_h} \end{align} whL=T1t=1Twhl(yt,ot)=T1t=1Totl(yt,ot)htg(ht,wo)whht

乘积的第一项和第二项很容易计算, 而第三项 ∂ h t / ∂ w h \partial h_t/\partial w_h ht/wh 是使事情变得棘手的地方,因为我们需要循环地计算参数 w h w_h wh h t h_t ht 的影响。根据定义式中的递归计算, h t h_t ht 既依赖于 h t − 1 h_{t-1} ht1 又依赖于 w h w_h wh,其中 h t − 1 h_{t-1} ht1 的计算也依赖于 w h w_h wh。因此,使用链式法则产生:

∂ h t ∂ w h = ∂ f ( x t , h t − 1 , w h ) ∂ w h + ∂ f ( x t , h t − 1 , w h ) ∂ h t − 1 ∂ h t − 1 ∂ w h \frac{\partial h_t}{\partial w_h}=\frac{\partial f(x_t,h_{t-1},w_h)}{\partial w_h}+\frac{\partial f(x_t,h_{t-1},w_h)}{\partial h_{t-1}}\frac{\partial h_{t-1}}{\partial w_h} whht=whf(xt,ht1,wh)+ht1f(xt,ht1,wh)whht1

消掉递归计算得

∂ h t ∂ w h = ∂ f ( x t , h t − 1 , w h ) ∂ w h + ∑ i = 1 t − 1 ( ∏ j = i + 1 t ∂ f ( x t , h j − 1 , w h ) ∂ h j − 1 ) ∂ f ( x i , h i − 1 , w h ) ∂ w h \frac{\partial h_t}{\partial w_h}=\frac{\partial f(x_t,h_{t-1},w_h)}{\partial w_h}+\sum^{t-1}_{i=1}(\prod^t_{j=i+1}\frac{\partial f(x_t,h_{j-1},w_h)}{\partial h_{j-1}})\frac{\partial f(x_i,h_{i-1},w_h)}{\partial w_h} whht=whf(xt,ht1,wh)+i=1t1(j=i+1thj1f(xt,hj1,wh))whf(xi,hi1,wh)

虽然我们可以使用链式法则递归地计算 ∂ h t / ∂ w h \partial h_t/\partial w_h ht/wh,但当 t t t 很大时这个链就会变得很长。需要想办法来处理这一问题.

8.7.1.1 完全计算

最简单粗暴的方法,可以直接计算,然而,这样的计算非常缓慢,并且可能会发生梯度爆炸,因为初始条件的微小变化就可能会对结果产生巨大的影响。也就是说类似于蝴蝶效应,即初始条件的很小变化就会导致结果发生不成比例的变化。而我们正在寻找的是能够很好地泛化高稳定性模型的估计器。因此,在实践中,这种方法几乎从未使用过。

8.7.1.2 随即截断

可以用一个随机变量替换 ∂ h t / ∂ w h \partial h_t/\partial w_h ht/wh,该随机变量在预期中是正确的,但是会截断序列。 这个随机变量是通过使用序列 ξ t \xi_t ξt 来实现的,序列预定义了 0 < π t < 1 0<\pi_t<1 0<πt<1,其中 P ( ξ t = 0 ) = 1 − π t P(\xi_t=0)=1-\pi_t P(ξt=0)=1πt P ( ξ t = π t − 1 = π t ) P(\xi_t=\pi_t^{-1}=\pi_t) P(ξt=πt1=πt),因此 E ∣ ξ t ∣ = 1 E|\xi_t|=1 Eξt=1。 我们使用它来替换梯度 ∂ h t / ∂ w h \partial h_t/\partial w_h ht/wh 得到:

(8.7.8)

z t = ∂ f ( x t , h t − 1 , w h ) ∂ w h + ξ t ∂ f ( x t , h t − 1 , w h ) ∂ h t − 1 ∂ h t − 1 ∂ w h z_t=\frac{\partial f(x_t,h_{t-1},w_h)}{\partial w_h}+\xi_t\frac{\partial f(x_t,h_{t-1},w_h)}{\partial h_{t-1}}\frac{\partial h_{t-1}}{\partial w_h} zt=whf(xt,ht1,wh)+ξtht1f(xt,ht1,wh)whht1

ξ t \xi_t ξt 的定义中推导出来 E ∣ ξ t ∣ = ∂ h t / ∂ w h E|\xi_t|=\partial h_t/\partial w_h Eξt=ht/wh。每当 ξ t = 0 \xi_t=0 ξt=0 时,递归计算终止在这个 t t t 时间步。这导致了不同长度序列的加权和,其中长序列出现的很少,所以将适当地加大权重。

8.7.1.3 比较策略

《动手学深度学习 Pytorch版》 8.7 通过时间反向传播_第1张图片

行自上而下分别为:

  • 第一行采用随机截断,方法是将文本划分为不同长度的片断;

  • 第二行采用常规截断,方法是将文本分解为相同长度的子序列。这也是我们在循环神经网络实验中一直在做的;

  • 第三行采用通过时间的完全反向传播,结果是产生了在计算上不可行的表达式。

虽然随机截断在理论上具有吸引力,但很可能是由于多种因素在实践中并不比常规截断更好:

  • 首先,在对过去若干个时间步经过反向传播后,观测结果足以捕获实际的依赖关系。

  • 其次,增加的方差抵消了时间步数越多梯度越精确的事实。

  • 第三,我们真正想要的是只有短范围交互的模型。因此,模型需要的正是截断的通过时间反向传播方法所具备的轻度正则化效果。

8.7.2 通过时间反向传播

《动手学深度学习 Pytorch版》 8.7 通过时间反向传播_第2张图片

  • “通过时间反向传播”仅仅适用于反向传播在具有隐状态的序列模型。

  • 截断是计算方便性和数值稳定性的需要。截断包括:规则截断和随机截断。

  • 矩阵的高次幂可能导致神经网络特征值的发散或消失,将以梯度爆炸或梯度消失的形式表现。

  • 为了计算的效率,“通过时间反向传播”在计算期间会缓存中间值。

你可能感兴趣的:(《动手学深度学习,Pytorch版》学习笔记,深度学习,pytorch,人工智能)