引言

今天把RNN、GRU和LSTM整理一下。

从RNN到LSTM再到GRU_LSTM

RNN

循环神经网络是处理时序数据的,它将序列按照顺序分成了很多时间步。在每个时间步,它的输入依赖于前一个时间步的输出(记忆单元)和当前的输入信息。废话不多说,直接上图,上公式。本文其实相当于一个整理,如何想看详细的介绍,建议看最后参考处的文章。

从RNN到LSTM再到GRU_GRU_02


其中从RNN到LSTM再到GRU_LSTM_03表示当前的输入,从RNN到LSTM再到GRU_深度学习_04表示前一个时刻的隐藏状态,初始为0向量。

从RNN到LSTM再到GRU_RNN_05是当前时刻的输出,从RNN到LSTM再到GRU_输入依赖_06是当前时刻的隐藏状态。

首选来看从RNN到LSTM再到GRU_输入依赖_06的计算:
从RNN到LSTM再到GRU_RNN_08
即计算当前时刻隐藏状态的时候,同时考虑了输入从RNN到LSTM再到GRU_LSTM_03和前一个时刻隐藏状态从RNN到LSTM再到GRU_深度学习_04的信息。

为了更好的说明,假设从RNN到LSTM再到GRU_深度学习_11的大小是从RNN到LSTM再到GRU_RNN_12从RNN到LSTM再到GRU_输入依赖_13的大小是从RNN到LSTM再到GRU_LSTM_14,隐藏状态从RNN到LSTM再到GRU_深度学习_04的大小从RNN到LSTM再到GRU_GRU_16,输入从RNN到LSTM再到GRU_LSTM_03的大小从RNN到LSTM再到GRU_深度学习_18,最后偏差从RNN到LSTM再到GRU_GRU_19的大小从RNN到LSTM再到GRU_输入依赖_20

从RNN到LSTM再到GRU_GRU_21

现在要做的事情是把上面这个公式描述简化,以便于理解和记忆。

从RNN到LSTM再到GRU_深度学习_11从RNN到LSTM再到GRU_输入依赖_13按列叠加起来得从RNN到LSTM再到GRU_LSTM_24

从RNN到LSTM再到GRU_GRU_25


从RNN到LSTM再到GRU_深度学习_04从RNN到LSTM再到GRU_LSTM_03按行叠加起来得从RNN到LSTM再到GRU_输入依赖_28

从RNN到LSTM再到GRU_输入依赖_29


这样,公式从RNN到LSTM再到GRU_GRU_30就可以写成:

从RNN到LSTM再到GRU_RNN_31

本文后面也会一直按照这种写法来简化。

得到了从RNN到LSTM再到GRU_输入依赖_06之后,就可以计算从RNN到LSTM再到GRU_RNN_05
从RNN到LSTM再到GRU_深度学习_34
这里的从RNN到LSTM再到GRU_输入依赖_35是激活函数,根据任务的不同可以用sigmoid或softmax。

RNN虽好,但是存在梯度消失和梯度爆炸的问题,导致一旦序列过长,在反向传播时RNN就会出问题。

其中梯度爆炸问题,有一个解决方法是梯度修剪(gradient clipping),就是设定一个阈值,当梯度向量超过某个阈值时,将它减少到阈值。而梯度消失问题更难解决。因此有人提出了GRU来解决这个问题。

LSTM

LSTM是RNN的变种,是为了解决RNN存在的长期依赖问题而专门设计出来的。所谓长期依赖问题是,后面的单词在很长的时间序列后还依赖前面的单词,但由于梯度消失问题,导致前面的单词无法影响到后面的单词。

从RNN到LSTM再到GRU_输入依赖_36


从RNN到LSTM再到GRU_LSTM_03是当前时刻的输入,从RNN到LSTM再到GRU_深度学习_04是上一个时刻的隐藏状态,从RNN到LSTM再到GRU_深度学习_39是上一时刻的单元状态。从RNN到LSTM再到GRU_输入依赖_06是当前时刻的隐藏状态,从RNN到LSTM再到GRU_深度学习_41是当前时刻的单元状态(记忆)。

相当于是LSTM会有两个输出。
其中输出从RNN到LSTM再到GRU_输入依赖_06是与当前的单元状态从RNN到LSTM再到GRU_深度学习_41有关的,而从RNN到LSTM再到GRU_深度学习_41是由前一时刻的单元状态从RNN到LSTM再到GRU_深度学习_39和候选值从RNN到LSTM再到GRU_深度学习_46有关的。 因此我们先来看下候选值从RNN到LSTM再到GRU_深度学习_46的计算公式:
从RNN到LSTM再到GRU_GRU_48

这里的候选值和RNN的隐藏状态计算方法类似。当前单元状态受两个门控制,分别是遗忘门从RNN到LSTM再到GRU_GRU_49和输入门从RNN到LSTM再到GRU_输入依赖_50

遗忘门:
从RNN到LSTM再到GRU_GRU_51
使用sigmoid函数使得门的取值限定为[0,1]之间。
输入门:
从RNN到LSTM再到GRU_深度学习_52
其中,遗忘门用来控制内存中之前的单元状态从RNN到LSTM再到GRU_深度学习_39是否会被遗忘掉,输入门决定候选值(哪些维度)能多大程度的存入当前单元状态从RNN到LSTM再到GRU_深度学习_41
从RNN到LSTM再到GRU_输入依赖_55

基于当前单元状态从RNN到LSTM再到GRU_深度学习_41,就可以得到当前时刻的隐藏状态从RNN到LSTM再到GRU_输入依赖_06
从RNN到LSTM再到GRU_GRU_58
其中从RNN到LSTM再到GRU_RNN_05是输出门,不难猜到,输出门也是由从RNN到LSTM再到GRU_RNN_60计算而来的:
从RNN到LSTM再到GRU_输入依赖_61

输出门控制了当前时刻能输出多少隐藏状态。

基于当前的隐藏状态,可以计算出当前时刻的输出从RNN到LSTM再到GRU_RNN_62
从RNN到LSTM再到GRU_LSTM_63

Peephole LSTM

具有窥视孔连接的LSTM

从RNN到LSTM再到GRU_深度学习_64


其实很简单,就是让门也接受单元状态作为输入。

GRU

GRU 旨在解决RNN 中出现的梯度消失问题。GRU也可以被视为LSTM的变体,启发于LSTM,但更易于实现和计算,且在某些情况能产生同样出色的结果。

GRU把遗忘门和输入门合并成为一个“更新门”,把单元状态和隐藏状态合并,还有其他变化。这样做使得 GRU比标准的LSTM模型更简单。

从RNN到LSTM再到GRU_输入依赖_65

从RNN到LSTM再到GRU_LSTM_03是当前时刻的输入,从RNN到LSTM再到GRU_深度学习_04是上一个时刻的隐藏状态,从RNN到LSTM再到GRU_输入依赖_06是当前时刻计算出来的隐藏状态。
在计算当前时刻的隐藏状态时,它会首先计算一个候选状态从RNN到LSTM再到GRU_深度学习_69,而在计算候选状态时,会考虑重置门的取值。
所以先来看重置门从RNN到LSTM再到GRU_深度学习_70是如何计算的:
从RNN到LSTM再到GRU_LSTM_71
使用sigmoid函数使得门的取值限定为[0,1]之间。

一般这里可以不用考虑偏置,原论文中也没有偏置。

如果重置门近于0,当前候选值从RNN到LSTM再到GRU_深度学习_69会忽略前一个隐藏状态从RNN到LSTM再到GRU_深度学习_04,并用当前的输入从RNN到LSTM再到GRU_LSTM_03来计算。这可以有效地让隐藏状态抛弃任何将来发现的不相关信息。 来看一下候选值的计算公式:
从RNN到LSTM再到GRU_RNN_75

可以看到,和RNN隐藏状态计算类似,不过多了一个重置门,重置门的大小和从RNN到LSTM再到GRU_深度学习_04是一致的,​​​*​​代表逐元素相乘。

计算出来候选值之后,通过更新门来控制前一个隐藏状态有多少信息可以传递到当前隐藏状态。这类似于LSTM的记忆单元,可以让GRU记住长期信息。
来看一下更新门的计算公式:
从RNN到LSTM再到GRU_深度学习_77
门的计算方法类似,不过权重矩阵不同。最后就可以计算当前时刻的隐藏状态了:
从RNN到LSTM再到GRU_输入依赖_78

因为每个隐藏单元都是独立的重置门和更新门,所以每个隐藏单元将学习捕获到不同时间范围的依赖。这些学习捕获短期依赖的单元倾向于使重置门频繁地激活,但学习长期依赖的单元几乎总是激活更新门。

总结

LSTM和GRU都能通过各种门将重要信息保留,保证其在长期传播的时候也不会被丢失。

GRU和LSTM的性能在很多任务上不分伯仲。
GRU有两个门,而LSTM有三个门,因此GRU计算速度更快。
数据集小时倾向于使用GRU,但是数据集很大的情况下,LSTM性能更好。

参考

  1. 吴恩达深度学习——循环神经网络
  2. Learning Phrase Representations using RNN Encoder–Decoder for Statistical Machine Translation翻译
  3. ​RNN, LSTM & GRU​
  4. LSTM背后的数学原理
  5. 从零实现循环神经网络