在循环神经网络中计算梯度。特别是,我们还发现矩阵连续乘积可以导致梯度消失或者梯度爆炸。我们可能会遇到这样的情况——一些词元没有相关的观测值。例如,在解析网页时,可能有一些辅助HTML代码与评估网页上传达的情绪无关。我们希望有一些机制来 跳过 隐状态表示中的此类词元。

在学术界已经提出了许多方法来解决这个问题。其中最早的方法是"长-短期记忆" (long-short-term memory, LSMT)^[Long Short-Term Memory | MIT Press Journals & Magazine | IEEE Xplore ],这个我们之后再讨论。门控循环单元(gated recurrent unit, GRU)^[[1409.0473] Neural Machine Translation by Jointly Learning to Align and Translate (arxiv.org)]^[[1412.3555v1] Empirical Evaluation of Gated Recurrent Neural Networks on Sequence Modeling (arxiv.org)]是一个稍微简化的变体,通常能够提供同等的效果,并且计算 的速度明显更快。由于它更简单,就让我们从门控循环单元开始。

相关的参考文献我已经放到了最后,点击右上角的那个角标可以直接跳转到最后的相关论文中。


门控神经网络单元相对于循环神经网络的计算来讲,就是多了一个控制选项。相较于RM的不加差别的更新状态。而GRU就是对状态进行选择性的更新,即可以选择更新,也可以选择重置。

重置门和更新门

回忆一下在循环神经网络中,上一层的隐状态和本层的输入会生成本层的隐状态;而在门控循环单元中,我们是生成一个重置门和一个更新门。

image.png

$$ \begin{aligned} \mathbf{R}t = \sigma(\mathbf{X}t \mathbf{W}{xr} + \mathbf{H}{t-1} \mathbf{W}_{hr} + \mathbf{b}r),\ \mathbf{Z}t = \sigma(\mathbf{X}t \mathbf{W}{xz} + \mathbf{H}{t-1} \mathbf{W}{hz} + \mathbf{b}_z), \end{aligned} $$

当然上边的式子我们可以写为化简的状态

$$ \begin{aligned} \mathbf{R}t = \sigma([\mathbf{X}t , \mathbf{H}{t-1}] \mathbf{W}{r} + \mathbf{b}_r),\ \mathbf{Z}t = \sigma([\mathbf{X}t ,\mathbf{H}{t-1}] \mathbf{W}{z} + \mathbf{b}_z), \end{aligned} $$

在这里我们使用的激活函数是sigmoid,它是将数据转换成0或1之间的值。

候选隐藏状态

image.png

接下来,让我们将重置门 $\mathbf{R}_t$ 与我们之前RNN中的常规隐状态更新机制集成,得到在时间步 $t$ 的候选隐藏状态 $\tilde{\mathbf{H}}_t \in \mathbb{R}^{n \times h}$。

$$ \tilde{\mathbf{H}}t = \tanh(\mathbf{X}t \mathbf{W}{xh} + \left(\mathbf{R}t \odot \mathbf{H}{t-1}\right) \mathbf{W}{hh} + \mathbf{b}_h) $$

  • 其中 $\mathbf{W}{xh} \in \mathbb{R}^{d \times h}$ 和 $\mathbf{W}{hh} \in \mathbb{R}^{h \times h}$ 是权重参数,$\mathbf{b}_h \in \mathbb{R}^{1 \times h}$ 是偏置项
  • 符号 $\odot$ 是哈达码乘积(按元素乘积)运算符。
  • 使用 tanh 作为激活函数,确保候选隐藏状态中的值保持在区间 $(-1, 1)$ 之间

计算的结果是候选隐藏状态,因为我们仍然需要结合更新门的操作。

这一步主要是为了展示重置门的作用。

我们先来看一下候选隐藏状态。他在计算与普通RNN的计算有什么差别呢。就是在上一步的隐藏状态加上一步计算,与重置门进行哈达码乘积(按元素乘积)。

经过上一步的sigmoid激活函数计算之后重置门中的值应该是趋近于0或者趋近于1的。

  • 每当重置门 $\mathbf{R}t$ 中的项接近 $1$ 时,那就相当于对上一步的隐藏状态不进行改变。公式就会变成$\tilde{\mathbf{H}}t = \tanh(\mathbf{X}t \mathbf{W}{xh} + \mathbf{H}{t-1} \mathbf{W}{hh} + \mathbf{b}_h)$,这就和普通的循环神经网络没有什么两样。

  • 对于重置门 $\mathbf{R}_t$ 中所有接近 $0$ 的时候,$\tilde{\mathbf{H}}_t = \tanh(\mathbf{X}t \mathbf{W}{xh}+ \mathbf{b}_h)$,我们就可以看做是忽略了上一步的隐藏状态。这一步的候选隐藏状态是以 $\mathbf{X}_t$ 作为输入的计算结果。因此,任何预先存在的隐藏状态都会被重置为默认值。

隐藏状态

image.png 上一步中说了。我们说出来的只是候选隐藏状态。真正的隐藏状态还是要结合更新的来进行计算。那这一步我们就是结合更新门 $\mathbf{Z}_t$ 进行计算。

确定新的隐藏状态 $\mathbf{H}t \in \mathbb{R}^{n \times h}$ 在多大程度上使用旧的状态 $\mathbf{H}{t-1}$ ,以及对新的候选状态 $\tilde{\mathbf{H}}_t$ 的使用量。更新门 $\mathbf{Z}t$ 仅需要在 $\mathbf{H}{t-1}$ 和 $\tilde{\mathbf{H}}_t$ 之间进行按元素的凸组合就可以实现这个目标。这就得出了门控循环单元的最终更新公式:

$$ \mathbf{H}_t = \mathbf{Z}t \odot \mathbf{H}{t-1} + (1 - \mathbf{Z}_t) \odot \tilde{\mathbf{H}}_t $$

之前说过了,经过sigmoid计算之后,更新门的数值也是趋近于0或者1的。

  • 每当更新门 $\mathbf{Z}_t$ 接近 $1$ 时,我们就只保留旧状态。此时,来自 $\mathbf{X}_t$ 的信息基本上被忽略,从而有效地跳过了依赖链条中的时间步 $t$。
  • 当 $\mathbf{Z}_t$ 接近 $0$ 时,新的隐藏状态 $\mathbf{H}_t$ 就会接近候选的隐藏状态 $\tilde{\mathbf{H}}_t$。

这些设计可以帮助我们处理循环神经网络中的梯度消失问题,并更好地捕获时间步距离很长的序列的依赖关系。例如,如果整个子序列的所有时间步的更新门都接近于 $1$,则无论序列的长度如何,在序列起始时间步的旧隐藏状态都将很容易保留并传递到序列结束。

结束

到这GRU就完成了他的任务:

  • 重置门有助于捕获序列中的短期依赖关系。
  • 更新门有助于捕获序列中的长期依赖关系。

相关论文阅读