对 RNN 系成员的一些总结。

RNN

这是一个三维低等生物眼里的 RNN:

Rolled RNN

这个细胞(绿色的框)相当于 Keras 中一层 RNN 的隐藏层,一个隐藏层可能有多个神经元。它在 时刻的状态(隐状态)叫做 ,是一个向量,向量维数与这个隐藏层的神经元数量相等,每个神经元的值都是一个标量。

这是一个四维高等生物眼里的 RNN(按时间步展开):

Unrolled RNN

如果画得详细一点:

Unrolled RNN's Details

其中:

  • 时刻的输入向量;
  • 时刻的隐状态;
  • 时刻的输出(只由 决定);
  • 时刻的损失函数,最终的损失函数是
  • 时刻的真实结果(ground truth);
  • :权重矩阵,要学习的参数,在所有时间步中都是共享的;

上一个时间步的隐状态 会在 时刻乘一个权重矩阵 然后重新输入细胞,也就是 同时依赖于

前向传播

符号说明:

  • :激活函数;
  • :偏置向量(bias);
  • :模型在 时刻的最终输出;

公式:

损失函数 的作用就是量化模型在当前位置的损失,即 的差距。

反向传播

整体损失函数:

有参数 ,先对它们随机初始化,然后在每个迭代周期对各参数求梯度,并按梯度的方向更新这些参数以使 最小化:

其中 是学习率, 是损失函数在 位置的偏导数,即梯度。

没有长期依赖,所以偏导好求一些:

而正向传播中, 还有贡献,所以反向传播计算 时刻的梯度时,还需要考虑 时刻的梯度(全导数)。

先求 时刻隐状态的梯度:

  • 时,需要从 时刻递推到 时刻隐状态的梯度:

  • 时,因为已经是最后一个时刻了,所以:

然后 的梯度为:

梯度消失和爆炸

如果直接把 时刻的偏导式展开:

同理, 时刻的偏导式展开为:

通过激活函数得到,假设激活函数为 tanh:

tanh 函数的函数图像和导数图像为:

tanh function

假设激活函数为 sigmoid:

sigmoid 函数的函数图像和导数图像为:

sigmoid function

梯度消失:

可以看到,这俩函数的导数范围都不会超过 1,如果 的初始化值也在 之间,那么就是一堆 之间的小数在连乘,乘到最后就会导致梯度越来越接近于 0,造成梯度消失。

在 DNN 中,某一层的梯度消失就意味着那一层的参数再也不更新,那一层的隐层就变成了单纯的映射层。

而 RNN 中,梯度是累加的,就算较远时刻的梯度趋近于 0,累加后的整体梯度依然不会为 0,整体梯度是不会消失的。但这会造成 RNN 被近距离梯度主导,只能利用的有限的历史数据,难以学到远距离的依赖关系。

但相比 sigmoid,tanh 函数的梯度还是更大一点,所以收敛速度要快一些,且引起梯度消失更慢。

而解决梯度消失可以靠换激活函数(ReLU、LeakyReLU、ELU 等)或改传播结构(LSTM、Batch Normalization、ResNet 残差结构)。

如,ReLU 激活函数的函数图像和导数图像为:

relu function

因为 轴右侧导数恒为 1,所以避免了梯度消失的问题。但恒为 1 的导数容易导致梯度爆炸,所以需要一些调参技巧,比如给梯度设定合适的阈值,如果大于这个阈值,就按这个阈值进行更新。

梯度爆炸:

而如果 的初始化值非常大,那连乘起来就会梯度爆炸。梯度爆炸意味着可能因为过大的优化幅度而跨过最优解,导致前面的学习过程白费。

LSTM

Long Short-Term Memory. Sepp Hochreiter and Jürgen Schmidhuber. Neural Computation 1997. [Paper]

一般来说应该放一张这样的图:

LSTM

同样,这个细胞相当于 Keras 中一层 LSTM 的隐藏层,隐藏层里有四个前馈网络层。图里的 4 个黄色框每个都是一个前馈网络层,它们的激活函数分别为 sigmoid(1,2,4)和 tanh(3)。

Hidden Units(Keras 的 units)就是每个前馈网络层的神经元个数。

另一种画法(论文 Show and Tell),虽然它似乎把 output gate 写成了 output gate (...):

Also a LSTM

LSTM 的核心是一个由 3 个门控制的记忆细胞 时的隐状态 会被用于当前细胞状态的损失计算,和下一细胞状态( 时)的隐状态 的计算,所以 会在 时经过这 3 个门重新进入细胞。

前向传播

传播流程:

LSTM Forward

后面公式中的符号说明:

  • :sigmoid 激活函数,会把矩阵转换为一个介于 0 和 1 之间的值作为门控信号,0 表示完全遗忘,1 表示完全接受;
  • :tanh 激活函数,会把矩阵转换为一个介于 -1 和 1 之间的值;
  • :哈达玛积(Hadamard Product),即俩矩阵对应元素相乘,所以要求俩矩阵同形

遗忘门

Forget Gate

Forget Gate,对上一个细胞状态传进来的信息进行选择性遗忘。会根据 来为上一个细胞状态 计算一个门控信号,计算公式为:

然后把 相乘,就是最终从上一个状态输入的内容:

输入门

Input Gate

Input Gate,对现阶段输入 进行选择性记忆,更新细胞状态。由两个部分构成:

  • sigmoid 激活函数,计算门控信号,控制要记忆哪些内容:

  • tanh 激活函数,计算现阶段新学到的东西:

这俩相乘后的结果就是最终被记下来的现阶段新学到的东西,再加上从上一个细胞状态输入的内容就是更新后的细胞状态。所以细胞状态的更新公式为:

输出门

Output Gate

Output Gate,现在细胞状态已经更新了,所以要决定那些状态最终会被输出(隐状态 )。依然用 sigmoid 激活函数来计算一个门控信号,控制要输出哪些内容:

然后把它跟用 tanh 激活函数放缩过的当前细胞状态 相乘,就是这个阶段最终输出的隐状态:

最终输出

最终的输出 会由 变换得到,常见的做法大概是把 扔进 softmax:

反向传播

传播流程:

LSTM Backward

公式以后再说,我已经跑偏太多了...

GRU

GRU

GRU 是 LSTM 的变体。它只有两个门,重置门 和更新门 (用一个门达到了遗忘和输入的目的)。它还合并了隐状态和细胞状态。它的模型结构比 LSTM 简单,但同时能达到跟 LSTM 相当的效果。

重置门

Reset Gate,先计算重置门控信号 ,用于控制要保留上一个时刻的多少信息:

然后计算当前时刻的候选隐状态(candidate hidden state):

相当于 主要包含了当前输入 的信息,然后有选择性的加入上一时刻的信息()。

更新门

Update Gate,先计算更新门控信号 ,用于控制要从 中遗忘多少信息和要从 中记忆多少信息:

然后直接算出当前时刻隐状态

可以理解为 对标 LSTM 中的遗忘门控, 对标 LSTM 中的输入门控。

Reference