导读
LSTM——长短时记忆网络是一个非常经典的循环神经网络模型,它在普通的RNN基础上做了一些改进,使网络能够记忆很久之前的状态,具体来说就是添加了3个门(遗忘门、输入门和输出门),并且把在原来隐含状态 h t h_{t} ht的基础上又额外分离出了细胞状态 C t C_{t} Ct用于存储之前的记忆,本文就以Colah大神的原文谈一下我的个人理解,希望看完之后对你有帮助。
本文一共分为5个部分:
- 循环神经网络RNN的由来
- 传统RNN结构的缺点以及LSTM的引入
- LSTM网络的结构特点以及公式推导
- LSTM的一些变形
- 总结
一、循环神经网络的由来
人类并不是每时每刻都从一片空白的大脑开始他们的思考。当阅读一篇文章的时候,你都是基于自己已经拥有的对先前所见词的理解来推断当前词的真实含义。我们不会将所有的东西都全部丢弃,然后用空白的大脑进行思考。我们的思想拥有持久性。举两个例子:
1.The clouds are in the ___.
2.I grew up in France… I speak fluent ___.
很明显,第一个例子中需要填入的词是sky
,第二个例子中需要填入的词是French
,原因是基于之前的若干个词来判断的。
传统的神经网络DNN并不能做到这点,看起来也像是一种巨大的弊端。例如,假设你希望对电影中的每个时间点的时间类型进行分类。传统的神经网络应该很难来处理这个问题——使用电影中先前的事件推断后续的事件,而循环神经网络(Recurrent Neural Network,简称RNN)解决了这个问题。它是包含循环的网络,允许信息的持久化。
RNN模型的结构
模型解释:把
x
t
x_{t}
xt输入到神经网络模块
A
A
A中,得到输出值
h
t
h_{t}
ht。循环可以使得信息可以从当前步传递到下一步。
这些循环使得 RNN 看起来非常神秘。然而,如果仔细想想,这样也不比一个正常的神经网络难于理解。RNN可以被看做是同一神经网络的多次复制,每个神经网络模块会把消息(即隐含层的状态)传递给下一个。所以,如果我们将这个循环展开:
链式的特征揭示了 RNN 本质上是与序列和列表相关的。他们是对于以时间顺序为基础的数据的最自然的神经网络架构。
二、传统RNN结构的缺点
RNN最大的弊端在于梯度的消失
问题,导致不能捕获长时间的依赖,具体来说,由于模型保留之前的状态是通过隐含层状态
h
t
h_{t}
ht,而随着层数的叠加,很早之前的隐含状态对后面的隐含状态影响几乎可以忽略了。回到第一部分中举的两个例子,二者的区别是填入的内容所基于的上下文一个离的很近(example1),一个离得很远(example2)。
再看一个例子:
Q:The writer of the books ___?
A. is \quad B.are
如果网络不能保留之前的记忆,很久可能错选B项,这就是传统RNN网络的缺陷。
回到第一部分的RNN展开图中,我们把它用参数具体描述一下,如下:
其中
x
1
.
.
.
x
n
x_{1}...x_{n}
x1...xn是输入序列,
h
1
.
.
.
h
n
h_{1}...h_{n}
h1...hn是隐含状态,由上一时刻的隐含状态
h
t
−
1
h_{t-1}
ht−1和当前时刻的输入
x
t
x_{t}
xt共同决定,
y
1
^
.
.
.
y
n
^
\hat{y_{1}}...\hat{y_{n}}
y1^...yn^是输出,由当前时刻的隐含状态
h
t
h_{t}
ht决定。
假设求某一时刻的隐含状态以及输出,以
h
2
h_{2}
h2和
y
2
y_{2}
y2为例:
h
2
=
t
a
n
h
(
W
x
h
⋅
x
2
+
W
h
h
⋅
h
1
+
b
1
)
,
h_{2} = tanh(W_{xh}·x_{2} + W_{hh}·h_{1} + b_{1}), \\
h2=tanh(Wxh⋅x2+Whh⋅h1+b1),
y 2 ^ = g ( W h y ⋅ h 2 + b 2 ) \hat{y_{2}} = g(W_{hy}·h_{2} + b_{2}) y2^=g(Why⋅h2+b2)
注:若为分类任务g为softmax函数
损失的表示形式为:
l
o
s
s
=
∑
i
=
1
4
J
(
i
)
(
θ
)
loss = \sum_{i=1}^{4}J^{(i)}(\theta)
loss=i=1∑4J(i)(θ)
当反向传播的时候(以计算
J
(
4
)
θ
J^{(4)}\theta
J(4)θ为例):
∂
J
(
4
)
(
θ
)
∂
h
1
=
∂
J
(
4
)
(
θ
)
∂
h
2
⋅
∂
h
2
∂
h
1
=
∂
J
(
4
)
(
θ
)
∂
h
3
⋅
∂
h
3
∂
h
2
⋅
∂
h
2
∂
h
1
=
∂
J
(
4
)
(
θ
)
∂
h
4
⋅
∂
h
4
∂
h
3
⋅
∂
h
3
∂
h
2
⋅
∂
h
2
∂
h
1
\frac{\partial J^{(4)} (\theta)}{\partial h_{1}} = \frac{\partial J^{(4)} (\theta)}{\partial h_{2}} · \frac{\partial h_{2}}{\partial h_{1}} = \frac{\partial J^{(4)} (\theta)}{\partial h_{3}} · \frac{\partial h_{3}}{\partial h_{2}} · \frac{\partial h_{2}}{\partial h_{1}} = \frac{\partial J^{(4)} (\theta)}{\partial h_{4}} · \frac{\partial h_{4}}{\partial h_{3}} · \frac{\partial h_{3}}{\partial h_{2}} · \frac{\partial h_{2}}{\partial h_{1}}
∂h1∂J(4)(θ)=∂h2∂J(4)(θ)⋅∂h1∂h2=∂h3∂J(4)(θ)⋅∂h2∂h3⋅∂h1∂h2=∂h4∂J(4)(θ)⋅∂h3∂h4⋅∂h2∂h3⋅∂h1∂h2
其中利用 h 4 = f ( W h h ⋅ h 3 + W x h ⋅ x 4 + b 4 ) h_{4} = f(W_{hh}·h_{3} + W_{xh} · x_{4} + b_{4}) h4=f(Whh⋅h3+Wxh⋅x4+b4)可以计算 ∂ h 4 ∂ h 3 \frac{\partial h_{4}}{\partial h_{3}} ∂h3∂h4等等。看后半部分的偏导,基本上都是连着好几个 ∂ h i ∂ h i − 1 \frac{\partial h_{i}}{\partial h_{i-1}} ∂hi−1∂hi相乘,所以若该值大于1,连续乘若干个就容易梯度爆炸;若该值小于1,连续乘若干个就容易梯度消失,导致网络无法学习到很久之前的信息。
三、LSTM网络的结构特点以及公式推导
传统的RNN结构只有一个单一的非线性结构,即tanh层
,如下图所示:
即输入为上一时刻的隐含状态
h
t
−
1
h_{t-1}
ht−1和当前时刻的输入
x
t
x_{t}
xt,乘以各自对应的矩阵后(即线性变换)再做一层非线性变换,过一层
t
a
n
h
tanh
tanh函数,得到当前层的隐含状态
h
t
h_{t}
ht,输入到下一个RNN神经元中,或者过softmax做分类得到输出
y
t
y_{t}
yt。
而LSTM对此进行了改进,首先引入了三种门:遗忘门
、输入门
以及输出门
,三个门的作用就是控制输入到门里的东西输出是在
[
0
,
1
]
[0,1]
[0,1]之间的,故激活函数使用sigmoid,而制作三个门的原材料也非常简单,就是利用上一时刻的隐含状态
h
t
−
1
h_{t-1}
ht−1和当前时刻的输入
x
t
x_{t}
xt即可。过程如下:
- 制作遗忘门: f t = σ ( W f ⋅ [ x t , h t − 1 ] + b f ) f_t = \sigma(W_f · [x_t, h_{t - 1}] + b_f) ft=σ(Wf⋅[xt,ht−1]+bf)
- 制作输入门: i t = σ ( W i ⋅ [ x t , h t − 1 ] + b i ) i_t = \sigma(W_i · [x_t, h_{t - 1}] + b_i) it=σ(Wi⋅[xt,ht−1]+bi)
- 制作输出门: o t = σ ( W o ⋅ [ x t , h t − 1 ] + b o ) o_t = \sigma(W_o · [x_t, h_{t - 1}] + b_o) ot=σ(Wo⋅[xt,ht−1]+bo)
其中在tensorflow中 x t x_{t} xt和 h t − 1 h_{t-1} ht−1是tf.placeholder型的,而 W f W_f Wf、 W i W_i Wi、 W o W_o Wo、 b f b_f bf、 b i b_i bi、 b o b_o bo六个量设成tf.Variable型,即随网络一起训练的。
LSTM对传统的RNN网络另一方面的改变是,把隐含状态 h t h_{t} ht分离成两个量:
- 依旧是 h t h_{t} ht,不过不负责保留很久之前的记忆了,它负责当前细胞的预测,和下一个细胞的三个门的制作。
- 从 h t h_{t} ht中分离出了单独的细胞状态 C t C_{t} Ct,专门负责保留较长时间之前的记忆。
综上,LSTM网络按时间展开的结构如下:
下面我们详细的分析一下信息是如何传递的:
1.遗忘过程
LSTM结构的第一步是决定我们会从上一个细胞状态中丢弃什么信息,由上一时刻的细胞状态,包含了很久远以前的记忆,要通过两个东西,才能离开当前细胞:
- 过一遍遗忘门,即决定过去的记忆要有多少保留,多少不保留: C 遗 忘 = f t ∗ C t − 1 C_{遗忘} = f_t * C_{t - 1} C遗忘=ft∗Ct−1;
让我们回到语言模型的例子中来基于已经看到的预测下一个词。在这个问题中,细胞状态可能包含当前主语的性别,因此正确的代词可以被选择出来。当我们看到新的主语,我们希望忘记旧的主语。
2. 还要和当前细胞中计算出来的临时状态
C
t
~
\tilde{C_{t}}
Ct~做相加,最终得到离开当前细胞时要保留多少过去的记忆:
C
t
=
C
遗
忘
+
C
t
~
C_t = C_{遗忘} + \tilde{C_t}
Ct=C遗忘+Ct~;
2.输入过程
下一步是确定什么样的新信息被存放在当前细胞状态中。这里同样包含两个部分:
- 首先制作输入门,
i
t
=
σ
(
W
i
⋅
[
x
t
,
h
t
−
1
]
+
b
i
)
i_t = \sigma(W_i · [x_t, h_{t - 1}] + b_i)
it=σ(Wi⋅[xt,ht−1]+bi);
- 制作好输入门之后,我们还要制作当前细胞的(临时)状态 C t ~ \tilde{C_{t}} Ct~,原材料依旧是上一时刻的隐含状态 h t − 1 h_{t-1} ht−1和当前时刻的输入 x t x_{t} xt,公式如上图所示。
下一步,我们会结合上面做好的两个细胞信息,即上一时刻的细胞状态 C t − 1 C_{t-1} Ct−1和当前时刻的临时细胞状态 C t ~ \tilde{C_{t}} Ct~来对当前状态更新,在我们语言模型的例子中,我们希望增加新的主语的性别到细胞状态中,来替代旧的需要忘记的主语。
3.更新细胞状态
现在是更新旧细胞状态的时间了,将 C t − 1 C_{t-1} Ct−1更新为 C t C_{t} Ct。前面的步骤已经决定了将会做什么,我们现在就是实际去完成。
我们把旧状态
C
t
−
1
C_{t-1}
Ct−1与
f
t
f_{t}
ft相乘,丢弃掉我们确定需要丢弃的信息。接着用新状态
C
t
~
\tilde{C_{t}}
Ct~与
i
t
i_{t}
it相乘,如下图所示,得到新的候选值,根据我们决定更新每个状态的程度进行变化。
在语言模型的例子中,这就是我们实际根据前面确定的目标,丢弃旧代词的性别信息并添加新的信息的地方。
4.输出过程
制作好了当前的最终细胞状态
C
t
C_{t}
Ct后,我们来看怎么用它制作当前细胞的隐含状态
h
t
h_{t}
ht,它是基于我们的细胞状态,但是也是一个过滤后的版本。首先,制作输出门
o
t
o_{t}
ot。接着,我们把细胞状态通过 tanh
进行处理(得到一个在
−
1
-1
−1到
1
1
1之间的值)并将它和输出门相乘,最终我们仅仅会输出我们确定输出的那部分。
回到语言模型中,在语言模型的例子中,因为他就看到了一个代词,可能需要输出与一个动词相关的信息。例如,可能输出是否代词是单数还是负数,这样如果是动词的话,我们也知道动词需要进行的词形变化。
btw,制作好的隐含状态
h
t
h_{t}
ht还要可以过softmax进行多分类任务了(序列标注任务),若是文本分类任务的话,此时就不需要每一层都对
h
t
h_{t}
ht做softmax了,只对最后一层的做softmax即可。
至此,我们就介绍完了LSTM的基本的原理,下面我们看一下它的一些变形。
四、LSTM的一些变形
实际的应用中,几乎所有包含LSTM的论文都采用了微小的变体。差异非常小,但是也值得拿出来讲一下。
其中一个流形的LSTM变体,就是由 Gers & Schmidhuber (2000) 提出的,增加了 “peephole connection”。也就是说,我们让三个门层也接受细胞状态的输入,即制作门的时候需要三种原材料:
x
t
x_{t}
xt、
h
t
−
1
h_{t-1}
ht−1和
C
t
−
1
C_{t-1}
Ct−1(对于输出门是
C
t
C_{t}
Ct)
上面的图例中,我们增加了peephole到每个门上,但是许多论文会加入部分的peephole而非所有都加。
另一个变体是通过使用coupled将遗忘门和输入门二合为一。不同于之前是分开确定什么忘记和需要添加什么新的信息,这里是一同做出决定。我们仅仅会当我们将要输入在当前位置时忘记。我们仅仅输入新的值到那些我们已经忘记旧的信息的那些状态 。
即不用再另外制作输入门了,直接用1减去遗忘门就可以决定输入的比例了。
另一个改动较大的变体是门限循环单元Gated Recurrent Unit (GRU),这是由 Cho, et al. (2014) 提出。它不但将遗忘门和输入门合成了一个单一的门(起名更新门)。同样还混合了细胞状态
C
t
C_{t}
Ct和隐含状态
h
t
h_{t}
ht。最终的模型比标准的LSTM模型要简单,也是非常流行的变体,具体公式如下。
五、总结
总体来说,LSTM一共分为3个过程:
- 过程一,制作遗忘门: f t = σ ( W f ⋅ [ x t , h t − 1 ] + b f ) f_t = \sigma(W_f · [x_t, h_{t - 1}] + b_f) ft=σ(Wf⋅[xt,ht−1]+bf),携带的信息为上一时刻的细胞输出 C t − 1 C_{t - 1} Ct−1(例如上一个主语的性别);
- 过程二:制作输入门: i t = σ ( W i ⋅ [ x t , h t − 1 ] + b i ) i_t = \sigma(W_i · [x_t, h_{t - 1}] + b_i) it=σ(Wi⋅[xt,ht−1]+bi),制作当前细胞携带的信息 C t ~ = t a n h ( W C ⋅ [ x t , h t − 1 ] + b C ) \tilde{C_t} = tanh(W_C · [x_t, h_{t - 1}] + b_C) Ct~=tanh(WC⋅[xt,ht−1]+bC) ,过程一和过程 二的结果加起来作为当前时刻细胞状态(例如当前主语的性别) C t = f t ∗ C t − 1 + i t ∗ C t ~ C_t = f_t * C_{t - 1} + i_t * \tilde{C_t} Ct=ft∗Ct−1+it∗Ct~可直接送往下一 个细胞;
- 过程三:制作输出门: o t = σ ( W o ⋅ [ x t , h t − 1 ] + b o ) o_t = \sigma(W_o · [x_t, h_{t - 1}] + b_o) ot=σ(Wo⋅[xt,ht−1]+bo),制作输出的隐含状态 h t = o t ∗ t a n h ( C t ) h_t = o_t * tanh(C_t) ht=ot∗tanh(Ct)(例如当前主语的单复数形式)