5. 通过时间反向传播
在前一小节中,若不裁剪梯度,模型将无法正常训练。为了深刻理解这一现象,本节将介绍循环神经网络中梯度的计算和存储方法,即通过时间反向传播(back-propagation through time)。
之前的 正向传播、反向传播和计算图 小节,介绍了神经网络中梯度计算的一般思路,并强调正向传播和反向传播相互依赖。正向传播在循环神经网络中比较直观,而通过时间反向传播其实是反向传播在循环神经网络中的具体应用。需要将循环神经网络按时间步展开,从而得到模型变量和参数之间的依赖关系,并依据链式法则应用反向传播计算并存储梯度。
5.1 定义模型
简单起见,考虑一个无偏差项的循环神经网络,且激活函数为恒等映射( ϕ ( x ) = x \phi(x)=x ϕ(x)=x)。
设时间步 t t t 的输入为单样本 x t ∈ R d \boldsymbol{x}_t \in \mathbb{R}^d xt∈Rd,标签为 y t y_t yt,那么,有隐藏状态 h t ∈ R h \boldsymbol{h}_t \in \mathbb{R}^h ht∈Rh的计算表达式:
h t = W h x x t + W h h h t − 1 , \boldsymbol{h}_t = \boldsymbol{W}_{hx} \boldsymbol{x}_t + \boldsymbol{W}_{hh} \boldsymbol{h}_{t-1}, ht=Whxxt+Whhht−1,
其中, W h x ∈ R h × d \boldsymbol{W}_{hx} \in \mathbb{R}^{h \times d} Whx∈Rh×d和 W h h ∈ R h × h \boldsymbol{W}_{hh} \in \mathbb{R}^{h \times h} Whh∈Rh×h是隐藏层权重参数。
设输出层权重参数 W q h ∈ R q × h \boldsymbol{W}_{qh} \in \mathbb{R}^{q \times h} Wqh∈Rq×h,时间步 t t t的输出层变量 o t ∈ R q \boldsymbol{o}_t \in \mathbb{R}^q ot∈Rq计算为:
o t = W q h h t \boldsymbol{o}_t = \boldsymbol{W}_{qh} \boldsymbol{h}_{t} ot=Wqhht
设时间步 t t t的损失为 ℓ ( o t , y t ) \ell(\boldsymbol{o}_t, y_t) ℓ(ot,yt),时间步数为 T T T的损失函数 L L L定义为:
L = 1 T ∑ t = 1 T ℓ ( o t , y t ) L = \frac{1}{T} \sum_{t=1}^T \ell (\boldsymbol{o}_t, y_t) L=T1t=1∑Tℓ(ot,yt)
此时,将 L L L称为有关给定时间步的数据样本的目标函数,并在本节后续讨论中简称为目标函数。
5.2 模型计算图
为了可视化循环神经网络中模型变量和参数在计算中的依赖关系,可以绘制模型计算图。
例如,时间步3的隐藏状态 h 3 \boldsymbol{h}_3 h3的计算,依赖模型参数 W h x \boldsymbol{W}_{hx} Whx、 W h h \boldsymbol{W}_{hh} Whh、上一时间步隐藏状态 h 2 \boldsymbol{h}_2 h2以及当前时间步输入 x 3 \boldsymbol{x}_3 x3。如下图所示:
5.3 方法
如上图所示,模型的参数为
W
h
x
\boldsymbol{W}_{hx}
Whx、
W
h
h
\boldsymbol{W}_{hh}
Whh 和
W
q
h
\boldsymbol{W}_{qh}
Wqh。
与 正向传播、反向传播和计算图 小节类似,训练模型通常需要模型参数的梯度
∂
L
/
∂
W
h
x
\partial L/\partial \boldsymbol{W}_{hx}
∂L/∂Whx、
∂
L
/
∂
W
h
h
\partial L/\partial \boldsymbol{W}_{hh}
∂L/∂Whh和
∂
L
/
∂
W
q
h
\partial L/\partial \boldsymbol{W}_{qh}
∂L/∂Wqh。
根据上图中的依赖关系,可以按照其中箭头所指的反方向依次计算并存储梯度(为了便于表述,依然采用表达链式法则的运算符 prod \text{prod} prod):
(1) 计算目标函数有关各时间步输出层变量的梯度 ∂ L / ∂ o t ∈ R q \partial L/\partial \boldsymbol{o}_t \in \mathbb{R}^q ∂L/∂ot∈Rq:
∂ L ∂ o t = ∂ ℓ ( o t , y t ) T ⋅ ∂ o t \frac{\partial L}{\partial \boldsymbol{o}_t} = \frac{\partial \ell (\boldsymbol{o}_t, y_t)}{T \cdot \partial \boldsymbol{o}_t} ∂ot∂L=T⋅∂ot∂ℓ(ot,yt)
(2) 计算目标函数有关模型参数 W q h \boldsymbol{W}_{qh} Wqh的梯度 ∂ L / ∂ W q h ∈ R q × h \partial L/\partial \boldsymbol{W}_{qh} \in \mathbb{R}^{q \times h} ∂L/∂Wqh∈Rq×h。结合上图所示, L L L通过 o 1 , … , o T \boldsymbol{o}_1, \ldots, \boldsymbol{o}_T o1,…,oT依赖 W q h \boldsymbol{W}_{qh} Wqh,依据链式法则,有:
∂ L ∂ W q h = ∑ t = 1 T prod ( ∂ L ∂ o t , ∂ o t ∂ W q h ) = ∑ t = 1 T ∂ L ∂ o t h t ⊤ \frac{\partial L}{\partial \boldsymbol{W}_{qh}} = \sum_{t=1}^T \text{prod}\left(\frac{\partial L}{\partial \boldsymbol{o}_t}, \frac{\partial \boldsymbol{o}_t}{\partial \boldsymbol{W}_{qh}}\right) = \sum_{t=1}^T \frac{\partial L}{\partial \boldsymbol{o}_t} \boldsymbol{h}_t^\top ∂Wqh∂L=t=1∑Tprod(∂ot∂L,∂Wqh∂ot)=t=1∑T∂ot∂Lht⊤
(3) 隐藏状态之间也存在依赖关系。 结合上图所示, L L L只通过 o T \boldsymbol{o}_T oT依赖最终时间步 T T T的隐藏状态 h T \boldsymbol{h}_T hT。因此,先计算目标函数有关最终时间步隐藏状态的梯度 ∂ L / ∂ h T ∈ R h \partial L/\partial \boldsymbol{h}_T \in \mathbb{R}^h ∂L/∂hT∈Rh。依据链式法则,有:
∂ L ∂ h T = prod ( ∂ L ∂ o T , ∂ o T ∂ h T ) = W q h ⊤ ∂ L ∂ o T \frac{\partial L}{\partial \boldsymbol{h}_T} = \text{prod}\left(\frac{\partial L}{\partial \boldsymbol{o}_T}, \frac{\partial \boldsymbol{o}_T}{\partial \boldsymbol{h}_T} \right) = \boldsymbol{W}_{qh}^\top \frac{\partial L}{\partial \boldsymbol{o}_T} ∂hT∂L=prod(∂oT∂L,∂hT∂oT)=Wqh⊤∂oT∂L
(4) 对于时间步 t < T t < T t<T, 结合上图所示, L L L通过 h t + 1 \boldsymbol{h}_{t+1} ht+1和 o t \boldsymbol{o}_t ot依赖 h t \boldsymbol{h}_t ht。依据链式法则, 目标函数有关时间步 t < T t < T t<T的隐藏状态的梯度 ∂ L / ∂ h t ∈ R h \partial L/\partial \boldsymbol{h}_t \in \mathbb{R}^h ∂L/∂ht∈Rh,需要按照时间步从大到小依次计算: ∂ L ∂ h t = prod ( ∂ L ∂ h t + 1 , ∂ h t + 1 ∂ h t ) + prod ( ∂ L ∂ o t , ∂ o t ∂ h t ) = W h h ⊤ ∂ L ∂ h t + 1 + W q h ⊤ ∂ L ∂ o t \frac{\partial L}{\partial \boldsymbol{h}_t} = \text{prod} (\frac{\partial L}{\partial \boldsymbol{h}_{t+1}}, \frac{\partial \boldsymbol{h}_{t+1}}{\partial \boldsymbol{h}_t}) + \text{prod} (\frac{\partial L}{\partial \boldsymbol{o}_t}, \frac{\partial \boldsymbol{o}_t}{\partial \boldsymbol{h}_t} ) = \boldsymbol{W}_{hh}^\top \frac{\partial L}{\partial \boldsymbol{h}_{t+1}} + \boldsymbol{W}_{qh}^\top \frac{\partial L}{\partial \boldsymbol{o}_t} ∂ht∂L=prod(∂ht+1∂L,∂ht∂ht+1)+prod(∂ot∂L,∂ht∂ot)=Whh⊤∂ht+1∂L+Wqh⊤∂ot∂L
将上述递归公式展开,对任意时间步 1 ≤ t ≤ T 1 \leq t \leq T 1≤t≤T,存在目标函数有关隐藏状态梯度的通项公式:
- [记] 递归公式展,如何得到该通项公式?
∂ L ∂ h t = ∑ i = t T ( W h h ⊤ ) T − i W q h ⊤ ∂ L ∂ o T + t − i \frac{\partial L}{\partial \boldsymbol{h}_t} = \sum_{i=t}^T {\left(\boldsymbol{W}_{hh}^\top\right)}^{T-i} \boldsymbol{W}_{qh}^\top \frac{\partial L}{\partial \boldsymbol{o}_{T+t-i}} ∂ht∂L=i=t∑T(Whh⊤)T−iWqh⊤∂oT+t−i∂L
由上式中的指数项可见,当时间步数 T T T 较大或者时间步 t t t 较小时,目标函数有关隐藏状态的梯度较容易出现衰减和爆炸。这也会影响其他包含 ∂ L / ∂ h t \partial L / \partial \boldsymbol{h}_t ∂L/∂ht项的梯度:
例如,隐藏层中模型参数的梯度 ∂ L / ∂ W h x ∈ R h × d \partial L / \partial \boldsymbol{W}_{hx} \in \mathbb{R}^{h \times d} ∂L/∂Whx∈Rh×d和 ∂ L / ∂ W h h ∈ R h × h \partial L / \partial \boldsymbol{W}_{hh} \in \mathbb{R}^{h \times h} ∂L/∂Whh∈Rh×h,结合上图所示, L L L通过 h 1 , … , h T \boldsymbol{h}_1, \ldots, \boldsymbol{h}_T h1,…,hT依赖这些模型参数。 依据链式法则,有:
∂ L ∂ W h x = ∑ t = 1 T prod ( ∂ L ∂ h t , ∂ h t ∂ W h x ) = ∑ t = 1 T ∂ L ∂ h t x t ⊤ ∂ L ∂ W h h = ∑ t = 1 T prod ( ∂ L ∂ h t , ∂ h t ∂ W h h ) = ∑ t = 1 T ∂ L ∂ h t h t − 1 ⊤ \begin{aligned} \frac{\partial L}{\partial \boldsymbol{W}_{hx}} &= \sum_{t=1}^T \text{prod}\left(\frac{\partial L}{\partial \boldsymbol{h}_t}, \frac{\partial \boldsymbol{h}_t}{\partial \boldsymbol{W}_{hx}}\right) = \sum_{t=1}^T \frac{\partial L}{\partial \boldsymbol{h}_t} \boldsymbol{x}_t^\top\\ \frac{\partial L}{\partial \boldsymbol{W}_{hh}} &= \sum_{t=1}^T \text{prod}\left(\frac{\partial L}{\partial \boldsymbol{h}_t}, \frac{\partial \boldsymbol{h}_t}{\partial \boldsymbol{W}_{hh}}\right) = \sum_{t=1}^T \frac{\partial L}{\partial \boldsymbol{h}_t} \boldsymbol{h}_{t-1}^\top \end{aligned} ∂Whx∂L∂Whh∂L=t=1∑Tprod(∂ht∂L,∂Whx∂ht)=t=1∑T∂ht∂Lxt⊤=t=1∑Tprod(∂ht∂L,∂Whh∂ht)=t=1∑T∂ht∂Lht−1⊤
如 正向传播、反向传播和计算图 小节所述,对于每次迭代,在上述各梯度依次计算完毕后,会将其进行存储,从而避免重复计算。
例如,由于隐藏状态梯度 ∂ L / ∂ h t \partial L/\partial \boldsymbol{h}_t ∂L/∂ht被计算和存储,之后的模型参数梯度 ∂ L / ∂ W h x \partial L/\partial \boldsymbol{W}_{hx} ∂L/∂Whx和 ∂ L / ∂ W h h \partial L/\partial \boldsymbol{W}_{hh} ∂L/∂Whh的计算可以直接读取 ∂ L / ∂ h t \partial L/\partial \boldsymbol{h}_t ∂L/∂ht的值,而无须重复进行计算。
此外,反向传播中的梯度计算可能会依赖变量的当前值(它们正是通过正向传播计算出来的)。
举例而言,参数梯度
∂
L
/
∂
W
h
h
\partial L/\partial \boldsymbol{W}_{hh}
∂L/∂Whh的计算需要依赖隐藏状态在时间步
t
=
0
,
…
,
T
−
1
t = 0, \ldots, T-1
t=0,…,T−1的当前值
h
t
\boldsymbol{h}_t
ht(
h
0
\boldsymbol{h}_0
h0通过初始化得到),这些值是通过从输入层到输出层的正向传播计算并存储得到的。