**最近看到一个blog,对LSTM模型介绍的很全面,所以我在这里记录一下。后续会逐渐补充公式推导的部分。
**RNN关键点之一是连接先前的信息到当前的任务中,而LSTM模型是一种特别的RNN。不幸的是RNN对长期依赖信息的学习能力不足,会出现梯度消失等问题。而LSTM网络就是解决长短时的信息依赖问题。
1.简介
LSTM网络全称为 Long Short-Term Memory,长期短期记忆模型,被设计用来学习长期依赖信息。与RNN模型对比,所有 RNN 都具有一种重复神经网络模块的链式的形式。在标准的 RNN 中,这个重复的模块只有一个非常简单的结构,例如一个 tanh 层。如下图所示:
LSTM 同样是这样的结构,但是重复的模块拥有一个不同的结构。不同于单一神经网络层,这里是有四个,以一种非常特殊的方式进行交互。
在上面的图例中,每一条黑线传输着一整个向量,从一个节点的输出到其他节点的输入。粉色的圈代表 pointwise 的操作,诸如向量的和,而黄色的矩阵就是学习到的神经网络层。合在一起的线表示向量的连接,分开的线表示内容被复制,然后分发到不同的位置。
2.详述
LSTM 的关键就是Cell状态,水平线在图上方贯穿运行。上方的横线被用来记忆长期依赖信息,而下方的横线我的理解是存储短期的依赖信息。
2.1LSTM网络中忘记信息功能
LSTM网络中,信息的遗忘主要是使用一个sigmoid函数和一个pointwise乘法。
在上图中,
xt
x
t
与
ht−1
h
t
−
1
作为输入,学习一层网络,并通过sigmoid函数使之处于(0,1)之间。
2.2决定哪些信息被记忆
记忆部分稍微复杂,主要是对输入做sigmoid函数以及tanh函数并做pointwise乘法,最后加到cell中去。
把旧状态
Ct−1
C
t
−
1
与
ft
f
t
相乘,丢弃掉我们确定需要丢弃的信息。接着加上
it
i
t
*
C~t
C
~
t
。这就是新的候选值,根据决定更新每个状态的程度进行变化。
2.3决定哪些信息被输出
最终,我们需要确定输出什么值。这个输出将会基于我们的Cell状态,但是也是一个过滤后的版本。首先,我们运行一个 sigmoid 层来确定Cell状态的哪个部分将输出出去。接着,我们把细胞状态通过 tanh 进行处理(得到一个在 -1 到 1 之间的值)并将它和 sigmoid 门的输出相乘,最终我们仅仅会输出我们确定输出的那部分。
2.4公式推导
以后有待补充
3tanh与sigmoid函数的区别
3.1sigmoid函数
3.2tanh函数
4.RNN网络
本该先介绍RNN网络,不过比较懒放在了后面。
4.1具体流程
step1, raw text: 接触LSTM模型不久,简单看了一些相关的论文,还没有动手实现过。然而至今仍然想不通LSTM神经网络究竟是怎么工作的。
step2, tokenize (中文得分词): sentence1: 接触 LSTM 模型 不久 ,简单 看了 一些 相关的 论文 , 还 没有 动手 实现过 。
sentence2: 然而 至今 仍然 想不通 LSTM 神经网络 究竟是 怎么 工作的。
step3, dictionarize: sentence1: 1 34 21 98 10 23 9 23 sentence2: 17 12 21 12 8 10 13 79 31 44 9 23
step4, padding every sentence to fixed length: sentence1: 1 34 21 98 10 23 9 23 0 0 0 0 0 sentence2: 17 12 21 12 8 10 13 79 31 44 9 23 0
step5, mapping token to an embeddings: sentence1: ,每一列代表一个词向量,词向量维度自行确定;矩阵列数固定为time_step length。
step6, feed into RNNs as input: 假设 一个RNN的time_step 确定为 ,则padded sentence length(step5中矩阵列数)固定为 。一次RNNs的run只处理一条sentence。每个sentence的每个token的embedding对应了每个时序 的输入 。一次RNNs的run,连续地将整个sentence处理完。
step7, get output:看图,每个time_step都是可以输出当前时序 的隐状态 ;但整体RNN的输出 是在最后一个time_step 时获取,才是完整的最终结果。
step8, further processing with the output:我们可以将output根据分类任务或回归拟合任务的不同,分别进一步处理。比如,传给cross_entropy&softmax进行分类……或者获取每个time_step对应的隐状态 ,做seq2seq 网络。
4.2介绍
RNN的一个特点是所有的隐层共享参数,整个网络只用这一套参数。
**RNNs包含输入单元(Input units),输入集标记为
x0,x1,...,xt,xt+1,...
x
0
,
x
1
,
.
.
.
,
x
t
,
x
t
+
1
,
.
.
.
,而输出单元(Output units)的输出集则被标记为
o0,o1,...,ot,ot+1.,..
o
0
,
o
1
,
.
.
.
,
o
t
,
o
t
+
1
.
,
.
.
。RNNs还包含隐藏单元(Hidden units),我们将其输出集标记为
s0,s1,...,st,st+1,...
s
0
,
s
1
,
.
.
.
,
s
t
,
s
t
+
1
,
.
.
.
,这些隐藏单元完成了最为主要的工作。你会发现,在图中:有一条单向流动的信息流是从输入单元到达隐藏单元的,与此同时另一条单向流动的信息流从隐藏单元到达输出单元。在某些情况下,RNNs会打破后者的限制,引导信息从输出单元返回隐藏单元,这些被称为“Back Projections”,并且隐藏层的输入还包括上一隐藏层的状态,即隐藏层内的节点可以自连也可以互连。
**上图将循环神经网络进行展开成一个全神经网络。例如,对一个包含5个单词的语句,那么展开的网络便是一个五层的神经网络,每一层代表一个单词。对于该网络的计算过程如下:
**
xt
x
t
表示第t,t=1,2,3…步(step)的输入。比如,
x1
x
1
为第二个词的one-hot向量(根据上图,
x0
x
0
为第一个词);
PS:使用计算机对自然语言进行处理,便需要将自然语言处理成为机器能够识别的符号,加上在机器学习过程中,需要将其进行数值化。而词是自然语言理解与处理的基础,因此需要对词进行数值化,词向量(Word Representation,Word embeding)[1]便是一种可行又有效的方法。何为词向量,即使用一个指定长度的实数向量v来表示一个词。有一种种最简单的表示方法,就是使用One-hot vector表示单词,即根据单词的数量|V|生成一个|V| * 1的向量,当某一位为1的时候其他位都为零,然后这个向量就代表一个单词。缺点也很明显:
1.由于向量长度是根据单词个数来的,如果有新词出现,这个向量还得增加,麻烦!(Impossible to keep up to date);
2.主观性太强(subjective),这么多单词,还得人工打labor并且adapt.。
现在有一种更加有效的词向量模式,该模式是通过神经网络或者深度学习对词进行训练,输出一个指定维度的向量,该向量便是输入词的表达。如word2vec。
**
st
s
t
为隐藏层的第t步的状态,它是网络的记忆单元。
st
s
t
根据当前输入层的输出与上一步隐藏层的状态进行计算。
st=f(Uxt+Wst−1)
s
t
=
f
(
U
x
t
+
W
s
t
−
1
)
,其中f一般是非线性的激活函数,如tanh或ReLU,在计算
s0
s
0
时,即第一个单词的隐藏层状态,需要用到
s−1
s
−
1
,但是其并不存在,在实现中一般置为0向量;
ot
o
t
是第t步的输出,如下个单词的向量表示,
ot=softmax(Vst)
o
t
=
s
o
f
t
m
a
x
(
V
s
t
)
.
**需要注意的是:
你可以认为隐藏层状态
st
s
t
是网络的记忆单元.
st
s
t
包含了前面所有步的隐藏层状态。而输出层的输出
ot
o
t
只与当前步的
st
s
t
有关,在实践中,为了降低网络的复杂度,往往
st
s
t
只包含前面若干步而不是所有步的隐藏层状态;
**在传统神经网络中,每一个网络层的参数是不共享的。而在RNNs中,每输入一步,每一层各自都共享参数U,V,W。其反应了RNNs中的每一步都在做相同的事,只是输入不同,因此大大地降低了网络中需要学习的参数;这里并没有说清楚,解释一下,传统神经网络的参数是不共享的,并不是表示对于每个输入有不同的参数,而是将RNN是进行展开,这样变成了多层的网络,如果这是一个多层的传统神经网络,那么
xt
x
t
到
st
s
t
之间的U矩阵与
xt+1
x
t
+
1
到
st+1
s
t
+
1
之间的U是不同的,而RNNs中的却是一样的,同理对于s与s层之间的W、s层与o层之间的V也是一样的。
**上图中每一步都会有输出,但是每一步都要有输出并不是必须的。比如,我们需要预测一条语句所表达的情绪,我们仅仅需要关系最后一个单词输入后的输出,而不需要知道每个单词输入后的输出。同理,每步都需要输入也不是必须的。RNNs的关键之处在于隐藏层,隐藏层能够捕捉序列的信息。
4.3梯度消失现象
tanh函数及其导数的图像:
可见tanh导数的值域是(0,1],两端都非常平缓并趋于0。
再看我们的梯度公式:
用的就是tanh导数,在训练的后期,梯度会变得比较小,如果几个趋于0的值相乘的话,乘积就会变得非常小,就会出现梯度消失现象。同样的情况也会出现在sigmoid函数。
由于远距离的时刻的梯度贡献接近于0,因此很难学习到远距离的依赖关系。
也很容易想象到当导数都很大的时候,就会出现梯度爆炸的情况,但是它的受重视程度不如梯度消失问题,原因有二:
- 梯度爆炸很明显,梯度值会变成NaN,程序会崩溃。
- 用一个预定义值来裁剪梯度值是解决梯度爆炸的一个非常简单实用的办法,而梯度消失问题则很难解决。
幸好还有一些办法来解决梯度消失问题。
- 合适的参数初始化可以减少梯度消失的影响。
- 使用ReLU激活函数
- LSTM和GRU架构。
4.4RNN前向传播与反向传播算法推导
4.4.1前向传播推导
4.4.2反向传播推导
有了RNN前向传播算法的基础,就容易推导出RNN反向传播算法的流程了。RNN反向传播算法的思路和DNN是一样的,即通过梯度下降法一轮轮的迭代,得到合适的RNN模型参数U,W,V,b,c。由于我们是基于时间反向传播,所以RNN的反向传播有时也叫做BPTT(back-propagation through time)。当然这里的BPTT和DNN也有很大的不同点,即这里所有的U,W,V,b,c在序列的各个位置是共享的,反向传播时我们更新的是相同的参数。
为了简化描述,这里的损失函数我们为对数损失函数,输出的激活函数为softmax函数,隐藏层的激活函数为tanh函数。
但是W,U,b的梯度计算就比较的复杂了。从RNN的模型可以看出,在反向传播时,在在某一序列位置t的梯度损失由当前位置的输出对应的梯度损失和序列索引位置t+1时的梯度损失两部分共同决定。对于W在某一序列位置t的梯度损失需要反向传播一步步的计算。我们定义序列索引t位置的隐藏状态的梯度为:
引用blog:
https://www.cnblogs.com/pinard/p/6509630.html
https://blog.csdn.net/heyongluoyao8/article/details/48636251
https://www.jianshu.com/p/9dc9f41f0b29