1、简介

LSTM是一种RNN模型, 是对Simple RNN的改进, LSTM可以避免梯度消失的问题, 可以有更长的记忆。原论文 Long Short-term Memory (researchgate.net)](https://www.researchgate.net/publication/13853244_Long_Short-term_Memory))是1997年发表的。下图是LSTM原论文中的截取的图。

image-20231201115008764

LSTM也是一种循环神经网络, 原理跟Simple RNN差不多。

image-20231201120002469

每当读取一个新的输入x就会更新状态h, lstm的结构比simple RNN要复杂很多。Simple RNN只有一个参数矩阵, LSTM有4个参数矩阵, 下面看一下LSTM内部的具体结构。

2、LSTM结构

LSTM最重要的设计是这个传输带, 即为向量C。过去的信息通过传输带送到下一个时刻,不会发生太大的变化, LSTM就是通过传输传输带来避免梯度消失。

image-20231201141239230

LSTM中有很多gate可以有选择的让信息通过, 先来看一下forget gate遗忘门。遗忘门由sigmoid function和Elementwise multiplication两部分组成。输入sigmoid是一个向量a, sigmoid作用到向量a的每个元素上, 把每个元素都压到0和1之间。sigmoid处理后的向量维度与输入sigmoid的向量维度相同。

image-20231201141457555

计算出f之后需要计算传输带向量C和遗忘门向量f的elementwise multiplication。elementwise multiplication是这样计算的, 举个例子, c和f都是4维的向量, 把它们的每个元素分别乘起来就行, 所以elementwise multiplication的结果也是一个四维的向量。

image-20231201142533071

遗忘门有选择的让传输带C的值通过, 假如f的一个元素都是零, 那么C对应的元素就不能通过, 对应的输出也是零。假如f的一个元素是1, 那么C对应的元素就全部通过, 对应的输出就是C本身。可以这里理解: f向量中元素的值可以看做向量C中对应元素的权重。

遗忘门f具体是怎么计算出来的, 看下面的结构图, ft是上一个状态ht-1和当前输入xt的函数。把状态ht-1与输入xt做concatination得到更高的向量, 然后计算矩阵wf与这个向量的乘积得到一个向量,再用sigmoid函数得到向量ft。向量ft的每一个元素都介于0到1之间, 遗忘门有个参数矩阵wf需要经过反向传播从训练数据中学习。

image-20231201143302177

上面是遗忘门forget gate, 下面解释一下input gate输入门。输入门it依赖于旧的向量ht-1和新的输入xt。输入门it的计算与遗忘门很类似, 把旧的状态ht-1与输入xt做concatination, 得到更高维度的向量。然后计算矩阵Wi与这个向量的乘积得到一个向量, 最后再用sigmoid函数得到向量it。it的每一个元素都介于0到1之间, 输入门也有自己的参数矩阵wi, wi也需要通过反向传播从训练数据中学习得到。

image-20231201143923011

还要计算new value C~t, C~t是个向量, 计算跟遗忘门和输入门都很像, 也是把旧的状态ht-1与新的状态xt做concatination, 再乘到参数矩阵Wc上, 区别在于激活函数不是sigmoid,而是tanh。所以计算得到的Ct向量都介于-1到1之间。计算new value C~t也需要一个单独的参数矩阵记作Wc。

image-20231201145112251

上面已经计算出了遗忘门ft、new value C~t以及输入门it,我们还知道传输带旧的值Ct-1, 现在就可以更新传输带C了。用遗忘门ft和传输带旧的值Ct-1计算elementwise multiplication。 遗忘门ft和传输带旧的值Ct-1的维度是相同的向量,计算的乘积也是一个向量, 遗忘门ft可选择性的遗忘Ct-1中的一些元素。如果ft中的一个元素是0,那么Ct-1对应的元素也是0, 也就是Ct-1的元素选择性遗忘掉了。

image-20231201150105584

上面选择性的遗忘掉Ct-1中的一些元素, 现在需要往传输带上添加新的信息, 计算输入门it和新的值C~t的elementwise multiplication。输入门it和新的值C~t都是维度相同的向量。它们的乘积也是维度相同的向量, 把乘积加到传输带上就行。 这样就完成了对传输带的一轮更新。用遗忘门删除了传输带上的一些信息, 然后加入新的信息, 得到传输到新的值Ct。

上面已经更新完传送带C了, 最后一步是计算LSTM的输出,也就是状态向量ht。ht是这么计算的, 首先计算output gate输出门Ot, 输出门Ot跟前面的遗忘门的计算基本一致。输入是旧的状态ht-1和当前输入xt, 通过concatination拼接得到更高维的向量。然后计算矩阵Wo与这个向量的乘积得到一个向量, 最后再利用sigmoid函数得到向量Ot。Ot的每个元素都介于0到1之间, 输出门也有自己的参数矩阵Wo, Wo也需要从训练数据中学习。

image-20231201150938968

现在计算状态向量ht, 对传输带Ct的每个元素求tanh, 把元素压缩到-1和1之间, 然后求这两个元素的elementwise multiplication。红色向量是刚刚求解出来的输出门Ot, 将其与传输带输出的Ct做tanh后的结果相乘就得到了状态向量ht。

下面的结构图中显示,ht有两份copy, 一份copy传输到了下一步, 另外一份copy成了lstm的输出。到第t步位置,一共有7个向量输入到了LSTM, 可以认为所有这些x向量的信息都积累在状态ht里面。

image-20231201153919329

3、LSTM的参数量

LSTM有遗忘门,输入门, new value以及输出门4个模块组成。这四个模块都有各自的参数矩阵W, 所以一共有4个参数矩阵。矩阵的行数是h的维度, 列数是h的维度加上x的维度。所以LSTM参数的数量是4乘以h的维度再乘以h的维度加上x的维度。

image-20231201161857150

4、LSTM代码实现

LSTM的结构虽然复杂, 但是用keras实现起来非常简单, 跟simple RNN的实现几乎一样。用LSTM判断电影评论是正面还是负面, 跟simple RNN一样。让LSTM只输出最后一个状态向量ht, ht就是从一段500个词的电影评论中提取的特征向量, 然后输入线性分类器来判断评论是正面的还是负面的。

image-20231201163212223

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from tensorflow.keras.layers import LSTM, Embedding, Dense
from tensorflow.keras.models import Sequential

# unique words in the dictionary
vocabulary = 10000
# shape(x) = 32
embedding_dim = 32
# sequence length 每条评论500个单词, 去长补短
word_num = 500
# shape(h) = 32
state_dim = 32

# 下面是return_sequences=False的情况
model = Sequential()
model.add(Embedding(vocabulary, embedding_dim, input_length=word_num))
# return_state=False表示只输出最后的ht
model.add(LSTM(units=state_dim, return_sequences=False))
model.add(Dense(1, activation="sigmoid"))
model.summary()

打印的模型概要为:

image-20231201170343815

参数量8320是这样计算的,每个参数矩阵h的维度是32, 乘以h的维度32 再 加上x的维度32。keras默认使用intercept, 所有参数里面还有32个维度的向量, 一个矩阵和一个向量加起来一共有2080个参数。LSTM一共有4个参数矩阵和4个intercept的向量, 所以参数的数量等于2080×4, 一共8320个参数。

8320 = 2080 × 4, 2080 = 32×(32 + 32)+ 32

dropout也可以用在LSTM层上,具体的方法比较复杂。

image-20231201171440573

总结, LSTM与simple RNN的区别就是用了一条传输带让过去的信息很容易传输到下一个时刻, 这样就有了更长的记忆, LSTM的表现总是比simple RNN更好。