循环神经网络

Posted by Masutangu on September 12, 2022

有些场景下我们需要使用序列模型来进行预测,比如:

  • 文本翻译:输入是连续的,需要结合前文进行翻译
  • 股价:需要结合昨天的股价进行预测

自回归模型

使用过去的数据进行预测,即计算 $P(x_t \mid x_{t-1}, \ldots, x_1)$。通常可以对过去的数据进行建模,即:

\[P(x_t \mid x_{t-1}, \ldots, x_1) = P(x_t \mid f(x_{t-1}, \ldots, x_1))\]

用 $x$ 预测 $x$,而不是用 $x$ 预测 $y$,称为自回归模型

第一种策略是不使用全部序列数据,而是使用时间长度为 $\tau$ 的观察序列 $x_{t-1}, \ldots, x_{t-\tau}$ 进行建模,即:

\[P(x_t \mid x_{t-1}, \ldots, x_1) =P(x_t \mid f(x_{t-1}, \ldots, x_{t-\tau}))\]

这样的好处是参数的数量不变。如果 $P(x_t \mid f(x_{t-1}, \ldots, x_1))=P(x_t \mid f(x_{t-1}, \ldots, x_{t-\tau}))$,那么该序列满足马尔科夫条件(见下文)。

第二种策略是新增隐变量(或称潜变量) $h_t=f(x_1,…x_{t-1})$ 用来表示过去的信息, 则 $x_t = P(x_t \mid h_{t})$。每次输入更新隐状态 $h_t$ ,即 $h_t = g(h_{t-1}, x_{t-1})$ 。由于 $h_t$ 是不可观测的,这类模型也被称为隐变量自回归模型(latent autoregressive models)。

马尔科夫模型

已知 $T$ 个有序随机变量,根据贝叶斯定理,他们的联合分布可以写成条件分布的连乘积:

\[P(x_1, \ldots, x_T) = \prod_{t=1}^T P(x_t \mid x_{t-1}, ...,x_1)\]

如果 $x_t$ 与 $x_{t-\tau}$ 之前的变量无关,即用 $x_{t-1}, \ldots, x_{t-\tau}$ 预测 $x_t$ 和用 $x_{t-1}, \ldots, x_1$ 预测 $x_t$ 效果相同,那该序列就满足马尔科夫条件。如果 $\tau=1$,则为一阶马尔可夫模型(first-order Markov model):

\[P(x_1, \ldots, x_T) = \prod_{t=1}^T P(x_t \mid x_{t-1})\]

假设每个随机变量有 $k$ 个取值,表达条件概率 $P(x_n|x_{n-1})$ 需要 $k\times(k-1)$ 个参数。 对于 $m$ 阶马尔科夫模型而言,$P(x_n|x_{n-1},…,x_{n-M})$ 需要 $k^m \times (k-1)$ 个参数。有没有一种方法即能将当前变量与更早的变量关联起来,又不需要那么多参数?(隐马尔科夫模型 HMM,这里不展开)

循环神经网络 RNN

前面提到,如果在预测的时候考虑更长时间步,会带来参数的指数增长。而 RNN 采用了隐变量模型来解决:

\[P(x_t \mid x_{t-1}, \ldots, x_1) \approx P(x_t \mid h_{t-1})\]

其中 $h_{t-1}$ 是隐状态(hidden state), 也称为隐藏变量(hidden variable), 它存储了到时间步 $t-1$的序列信息,且基于当前输入 $x_t$ 和先前隐状态 $h_{t-1}$ 进行更新:

\[h_t = f(x_{t}, h_{t-1})\]

无隐状态的神经网络

无隐藏状态的单隐藏层的 MLP 中,隐藏层输出为:

\[\mathbf{H} = \phi(\mathbf{X} \mathbf{W}_{xh} + \mathbf{b}_h)\]

输出层输出为:

\[\mathbf{O} = \mathbf{H} \mathbf{W}_{hq} + \mathbf{b}_q\]

有隐状态的神经网络

有隐藏状态的单隐藏层 MLP 中,用 $\mathbf{H}_t$ 表示时间步 $t$ 的隐藏变量,由当前时间步的输入和前一个时间步的隐藏变量计算得出:

\[\mathbf{H}_t = \phi(\mathbf{X}_t \mathbf{W}_{xh} + \mathbf{H}_{t-1} \mathbf{W}_{hh} + \mathbf{b}_h)\]

从 $\mathbf{H}_{t}$ 和 $\mathbf{H}_{t-1}$ 之间的关系可知, 隐藏变量捕获并保留了序列直到其当前时间步的历史信息,隐藏变量也称为隐状态(hidden state)。

在不同的时间步中,隐藏层的权重$\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}$都是同一个。在循环神经网络中计算隐状态的层称为循环层(recurrent layer)。

对于时间步 $t$,输出层的输出和多层感知机类似:

\[\mathbf{O}_t = \mathbf{H}_t \mathbf{W}_{hq} + \mathbf{b}_q\]

下图展示了循环神经网络在三个相邻时间步的计算逻辑。 在任意时间步 $t$,隐状态的计算可以被视为:

  1. 拼接当前时间步$t$的输入$\mathbf{X}_t$和前一时间步$t-1$的隐状态$\mathbf{H}_{t-1}$

  2. 将拼接的结果送入带有激活函数 $\phi$ 的全连接层,全连接层的输出是当前时间步 $t$ 的隐状态 $\mathbf{H}_t$

注意,隐状态中 $\mathbf{X}_t \mathbf{W}_{xh} + \mathbf{H}_{t-1} \mathbf{W}_{hh}$ 的计算, 等同于 $\mathbf{X}_t$ 和 $\mathbf{H}_{t-1}$ 的拼接与 $\mathbf{W}_{xh}$ 和 $\mathbf{W}_{hh}$ 的拼接的矩阵乘法。

循环神经网络的梯度分析

这里用简化模型来分析循环神经网络的梯度,将时间步 $t$ 的隐状态表示为 $h_t$, 输入表示为 $x_t$,输出表示为 $o_t$。输入和隐状态可以拼接后与隐藏层中的一个权重变量相乘,因此用 $w_h$ 和 $w_o$ 来表示隐藏层和输出层的权重。 每个时间步的隐状态和输出可以写为:

\[\begin{aligned}h_t &= f(x_t, h_{t-1}, w_h)\\o_t &= g(h_t, w_o)\end{aligned}\]

其中 $f$ 和 $g$ 分别是隐藏层和输出层的变换。

因此,我们有一个链${\ldots, (x_{t-1}, h_{t-1}, o_{t-1}), (x_{t}, h_{t}, o_t), \ldots}$, 它们通过循环计算彼此依赖。前向传播一次计算一个时间步,然后评估所有 $T$ 个时间步内输出 $o_t$ 和对应标签 $y_t$ 之间的差异:

\[L(x_1, \ldots, x_T, y_1, \ldots, y_T, w_h, w_o) = \frac{1}{T}\sum_{t=1}^T l(y_t, o_t)\]

反向计算 $L$ 关于参数 $w_h$ 的梯度,采用链式法则:

\[\begin{aligned}\frac{\partial L}{\partial w_h} & = \frac{1}{T}\sum_{t=1}^T \frac{\partial l(y_t, o_t)}{\partial w_h} \\& = \frac{1}{T}\sum_{t=1}^T \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{aligned}\]

第一项和第二项很容易计算, 而第三项 $\partial h_t/\partial w_h$ 比较麻烦,$h_t$ 既依赖于 $h_{t-1}$ 又依赖于 $w_h$, 其中 $h_{t-1}$ 的计算也依赖于 $w_h$。 因此,使用链式法则可得:

\[\begin{aligned}\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} \\ & =\frac{\partial f(x_{t},h_{t-1},w_h)}{\partial w_h}+\sum_{i=1}^{t-1}\left(\prod_{j=i+1}^{t} \frac{\partial f(x_{j},h_{j-1},w_h)}{\partial h_{j-1}} \right) \frac{\partial f(x_{i},h_{i-1},w_h)}{\partial w_h}\end{aligned}\]

当 $t$ 很长时,计算 $\partial h_t/\partial w_h$ 需要连乘多个梯度,容易造成梯度消失。

长短期记忆网络

隐变量模型如果保存了较长时间的输入序列,容易造成梯度消失导致难以训练。 解决这一问题方法之一是长短期存储器(long short-term memory,LSTM)。LSTM 引入了记忆元(memory cell)。

输入门、忘记门和输出门

为了控制记忆元,我们需要许多门。 其中一个门用来从单元中输出条目,我们将其称为输出门(output gate)。 另一个门用来决定何时将数据读入单元,我们将其称为输入门(input gate)。 还需要一种机制来重置单元的内容,由遗忘门(forget gate)来管理。

定义 $\mathbf{I}_t$ 为输入门,$\mathbf{F}_t$ 为遗忘门,$\mathbf{O}_t$ 为输出门,他们的计算方法如下:

\[\begin{aligned} \mathbf{I}_t &= \sigma(\mathbf{X}_t \mathbf{W}_{xi} + \mathbf{H}_{t-1} \mathbf{W}_{hi} + \mathbf{b}_i)\\ \mathbf{F}_t &= \sigma(\mathbf{X}_t \mathbf{W}_{xf} + \mathbf{H}_{t-1} \mathbf{W}_{hf} + \mathbf{b}_f)\\ \mathbf{O}_t &= \sigma(\mathbf{X}_t \mathbf{W}_{xo} + \mathbf{H}_{t-1} \mathbf{W}_{ho} + \mathbf{b}_o) \end{aligned}\]

候选记忆元和记忆元

候选记忆元使用 $tanh$ 函数作为激活函数,函数的值范围为(−1,1),计算方法如下:

\[\tilde{\mathbf{C}}_t = \text{tanh}(\mathbf{X}_t \mathbf{W}_{xc} + \mathbf{H}_{t-1} \mathbf{W}_{hc} + \mathbf{b}_c)\]

输入门 $\mathbf{I}_t$ 控制采用多少来自 $\tilde{\mathbf{C}}_t$ 的新数据, 而遗忘门 $\mathbf{F}_t$ 控制保留多少过去的记忆元 $\mathbf{C}_{t-1}$ 的内容:

\[\mathbf{C}_t = \mathbf{F}_t \odot \mathbf{C}_{t-1} + \mathbf{I}_t \odot \tilde{\mathbf{C}}_t\]

如果遗忘门始终为 1 且输入门始终为 0, 则过去的记忆元 $\mathbf{C}_{t-1}$ 将随时间被保存并传递到当前时间步。 引入这种设计是为了缓解梯度消失问题, 并更好地捕获序列中的长距离依赖关系。

记忆元的计算流程如下图:

隐状态

隐状态 $\mathbf{H}_t$ 的计算方法如下:

\[\mathbf{H}_t = \mathbf{O}_t \odot \tanh(\mathbf{C}_t)\]

只要输出门接近 1,我们就能够有效地将所有记忆信息传递给预测部分, 而对于输出门接近 0,我们只保留记忆元内的所有信息,而不需要更新隐状态。

深度循环神经网络

可以将多层循环神经网络堆叠在一起:

假设在时间步 $t$ 有一个小批量的输入数据 $\mathbf{X}_t \in \mathbb{R}^{n \times d}$(样本数为 $n$,每个样本中的输入数为 $d$)。 同时,将 $l^\mathrm{th}$ 隐藏层($l=1,\ldots,L$)的隐状态设为 $\mathbf{H}_t^{(l)} \in \mathbb{R}^{n \times h}$(隐藏单元数为 $h$), 输出层变量设为 $\mathbf{O}_t \in \mathbb{R}^{n \times q}$(输出数为 $q$)。 设置 $\mathbf{H}_t^{(0)} = \mathbf{X}_t$, 第 $l$ 个隐藏层的隐状态使用激活函数 $\phi_l$,则:

\[\mathbf{H}_t^{(l)} = \phi_l(\mathbf{H}_t^{(l-1)} \mathbf{W}_{xh}^{(l)} + \mathbf{H}_{t-1}^{(l)} \mathbf{W}_{hh}^{(l)} + \mathbf{b}_h^{(l)})\]

其中,权重 $\mathbf{W}_{xh}^{(l)} \in \mathbb{R}^{h \times h}$, $\mathbf{W}_{hh}^{(l)} \in \mathbb{R}^{h \times h}$ 和偏置 $\mathbf{b}_h^{(l)} \in \mathbb{R}^{1 \times h}$ 都是第 $l$ 个隐藏层的模型参数。

最后,输出层的计算仅基于第𝑙l个隐藏层最终的隐状态:

\[\mathbf{O}_t = \mathbf{H}_t^{(L)} \mathbf{W}_{hq} + \mathbf{b}_q\]

其中,权重 $\mathbf{W}_{hq} \in \mathbb{R}^{h \times q}$ 和偏置 $\mathbf{b}_q \in \mathbb{R}^{1 \times q}$ 都是输出层的模型参数。

参考文献