赞
踩
我们已经知道BP算法, CNN算法, 那么为什么还会有RNN呢?? 什么是RNN, 它到底有什么不同之处? RNN的主要应用领域有哪些呢?这些都是要讨论的问题.
前面我们说了RNN具有时间"记忆"的功能, 那么它是怎么实现所谓的"记忆"的呢?
如图所示, 我们可以看到RNN层级结构较之于CNN来说比较简单, 它主要有输入层,Hidden Layer, 输出层组成.
并且会发现在Hidden Layer 有一个箭头表示数据的循环更新, 这个就是实现时间记忆功能的方法.
如图所示为Hidden Layer的层级展开图。 t − 1 , t , t + 1 t-1, t, t+1 t−1,t,t+1表示时间序列, X X X表示输入的样本, S t S_t St表示样本在时间t处的的记忆, S t = f ( W ∗ S t − 1 + U ∗ X t ) S_t = f(W*S_{t-1} +U*X_t) St=f(W∗St−1+U∗Xt), W W W表示输入的权重, U U U表示此刻输入的样本的权重, V V V表示输出的样本权重。 参数 U 、 V 、 W U、V、W U、V、W是各只有一个,只是随着时间不断更新迭代。
在
t
=
1
t =1
t=1时刻, 一般初始化输入
S
0
=
0
S_0=0
S0=0, 随机初始化
W
,
U
,
V
,
W,U,V,
W,U,V, 进行下面的公式计算:
h
1
=
U
x
1
+
W
s
0
s
1
=
f
(
h
1
)
o
1
=
g
(
V
s
1
)
h_1=Ux_1+Ws_0 \\ s_1=f(h_1) \\ o_1=g(Vs_1)
h1=Ux1+Ws0s1=f(h1)o1=g(Vs1)
其中,
f
f
f和
g
g
g均为激活函数. 其中
f
f
f 可以是
t
a
n
h
,
r
e
l
u
,
s
i
g
m
o
i
d
tanh,relu,sigmoid
tanh,relu,sigmoid 等激活函数,
g
g
g通常是
s
o
f
t
m
a
x
softmax
softmax 也可以是其他。
时间向前推进,此时的状态
s
1
s_1
s1作为时刻1的记忆状态将参与下一个时刻的预测活动,也就是:
h
2
=
U
x
2
+
W
s
1
s
2
=
f
(
h
2
)
o
2
=
g
(
V
s
2
)
h_2=Ux_2+Ws_1 \\ s_2=f(h_2) \\ o_2=g(Vs_2)
h2=Ux2+Ws1s2=f(h2)o2=g(Vs2)
以此类推, 可以得到最终的输出值为:
h
t
=
U
x
t
+
W
s
t
−
1
s
t
=
f
(
h
t
)
o
t
=
g
(
V
s
t
)
h_t=Ux_t+Ws_{t-1} \\ s_t=f(h_t) \\ o_t=g(Vs_t)
ht=Uxt+Wst−1st=f(ht)ot=g(Vst)
注意:
前面我们介绍了RNN的前向传播的方式, 那么RNN的权重参数
W
,
U
,
V
W,U,V
W,U,V都是怎么更新的呢?
每一次的输出值
o
t
o_t
ot都会产生一个误差值
L
t
L_t
Lt, 则总的误差可以表示为:
L
=
∑
t
L
t
L=\sum_{t}L_t
L=t∑Lt
则损失函数可以使用交叉熵损失函数也可以使用平方误差损失函数.
由于每一步的输出不仅仅依赖当前步的网络,并且还需要前若干步网络的状态,那么这种BP改版的算法叫做Backpropagation Through Time(BPTT) , 也就是将输出端的误差值反向传递,运用梯度下降法进行更新。BPTT的中心思想和BP算法相同,沿着需要优化的参数的负梯度方向不断寻找更优的点直至收敛。当然这里的BPTT和DNN中的BP算法也有很大的不同点,即这里所有的
U
,
W
,
V
U, W, V
U,W,V在序列的各个位置是共享的,反向传播时我们更新的是相同的参数。
总的损失函数:
L
=
∑
t
=
1
T
L
t
L=\sum_{t=1}^{T} L_{t}
L=t=1∑TLt
为了方便观察,对状态更新公式进行整理,
s
(
t
)
=
f
(
U
x
(
t
)
+
W
s
(
t
−
1
)
+
b
)
O
(
t
)
=
V
s
(
t
)
+
c
o
~
(
t
)
=
g
(
O
(
t
)
)
对于
V
V
V而言,只和
O
t
O_t
Ot相关,因此更新公式如下:
V
=
V
−
l
r
∗
∂
L
∂
V
=
V
−
l
r
∗
∑
t
=
1
T
∂
L
t
∂
V
=
V
−
l
r
∗
∑
t
=
1
T
∂
L
t
∂
o
^
(
t
)
∂
o
^
(
t
)
∂
O
(
t
)
∂
O
(
t
)
∂
V
对于
W
W
W而言,除了
o
t
o_t
ot之外,还与
s
t
s_t
st相关,因此比较麻烦,不过可以按照偏食法则进行求导。
W
=
W
−
l
r
∗
∂
L
∂
W
=
W
−
l
r
∗
∑
t
=
1
T
∂
L
t
∂
W
∂
L
(
1
)
∂
W
=
∂
L
(
1
)
∂
o
^
(
1
)
∂
o
^
(
1
)
∂
O
(
1
)
∂
O
(
1
)
∂
s
(
1
)
∂
s
(
1
)
∂
W
∂
L
(
2
)
∂
W
=
∂
L
(
2
)
∂
o
^
(
2
)
∂
o
^
(
2
)
∂
O
(
2
)
∂
O
(
2
)
∂
s
(
2
)
(
∂
s
(
2
)
∂
W
+
∂
s
(
2
)
∂
s
(
1
)
∂
s
(
1
)
∂
W
)
∂
L
(
3
)
∂
W
=
∂
L
(
3
)
∂
o
^
(
3
)
∂
o
^
(
3
)
∂
O
(
3
)
∂
O
(
3
)
∂
s
(
3
)
(
∂
s
(
3
)
∂
W
+
∂
s
(
3
)
∂
s
(
2
)
∂
s
(
2
)
∂
W
+
∂
s
(
3
)
∂
s
(
2
)
∂
s
(
2
)
∂
s
(
1
)
∂
s
(
1
)
∂
W
)
when
T
=
3
W
=
W
−
l
r
∗
∑
t
=
1
T
∂
L
(
t
)
∂
W
=
W
−
l
r
∗
(
∂
L
(
1
)
∂
W
+
∂
L
(
2
)
∂
W
+
∂
L
(
3
)
∂
W
)
最后是对U的更新方法.
W
=
W
−
l
r
∗
∂
L
∂
U
=
W
−
l
r
∗
∑
t
=
1
T
∂
L
t
∂
U
∂
L
(
1
)
∂
U
=
∂
L
(
1
)
∂
o
^
(
1
)
∂
o
^
(
1
)
∂
O
(
1
)
∂
O
(
1
)
∂
s
(
1
)
∂
s
(
1
)
∂
U
∂
L
(
2
)
∂
U
=
∂
L
(
2
)
∂
o
^
(
2
)
∂
o
^
(
2
)
∂
O
(
2
)
∂
O
(
2
)
∂
s
(
2
)
(
∂
s
(
2
)
∂
U
+
∂
s
(
2
)
∂
s
(
1
)
∂
s
(
1
)
∂
U
)
∂
L
(
3
)
∂
U
=
∂
L
(
3
)
∂
o
^
(
3
)
∂
o
^
(
3
)
∂
O
(
3
)
∂
O
(
3
)
∂
s
(
3
)
(
∂
s
(
3
)
∂
U
+
∂
s
(
3
)
∂
s
(
2
)
∂
s
(
2
)
∂
U
+
∂
s
(
3
)
∂
s
(
2
)
∂
s
(
2
)
∂
s
(
1
)
∂
s
(
1
)
∂
U
)
when
T
=
3
U
=
U
−
l
r
∗
∑
t
=
1
T
∂
L
(
t
)
∂
U
=
U
−
l
r
∗
(
∂
L
(
1
)
∂
U
+
∂
L
(
2
)
∂
U
+
∂
L
(
3
)
∂
U
)
我们知道,sigmoid 函数的导数范围是(0, 0.25], tanh 函数的导数范围是 (0, 1] ,他们的导数最大都不大于 1。因此在上面求梯度的乘积中,随着时间序列的不断深入,小数的累乘就会导致梯度越来越小直到接近于 0,这就会引起梯度消失现象。梯度消失就意味着那一层的参数再也不更新了,则模型的训练毫无意义。Relu 函数一定程度上可以解决梯度消失的问题,但是容易引起梯度爆炸的问题。此外 tanh 函数的收敛速度要快于 sigmoid 函数,而且梯度消失的速度要慢于 sigmoid 函数。
利用BPTT算法训练网络时容易出现梯度消失的问题,当序列很长的时候问题尤其严重,因此上面的RNN模型一般不能直接应用。而较为广泛使用的是RNN的一个特例LSTM。
输入:
x
t
∈
R
8000
输出:
o
t
∈
R
8000
隐层 (记忆)
:
s
t
∈
R
100
U
∈
R
100
∗
8000
V
∈
R
8000
∗
100
W
∈
R
100
∗
100
其中,
s
t
=
f
(
U
x
t
+
W
s
t
−
1
)
,
o
t
=
g
(
V
s
t
)
函数
g
g
g 代表
s
o
f
t
m
a
x
softmax
softmax层,
f
f
f 一般是
s
i
g
m
o
i
d
sigmoid
sigmoid函数,初始的隐层
s
0
s_0
s0一般就是一个全为0的向量(不是矩阵)
前面我们介绍了RNN的算法, 它处理时间序列的问题的效果很好, 但是仍然存在着一些问题, 其中较为严重的是容易出现梯度消失或者梯度爆炸的问题(BP算法和长时间依赖造成的). 注意: 这里的梯度消失和BP的不一样,这里主要指由于时间过长而造成记忆值较小的现象.
因此, 就出现了一系列的改进的算法, 这里介绍主要的两种算法: LSTM 和 GRU.
LSTM 和 GRU对于梯度消失或者梯度爆炸的问题处理方法主要是:
Long Short Term 网络,一般就叫做 LSTM ,是一种 RNN 特殊的类型,可以学习长期依赖信息。LSTM 通过刻意的设计来避免长期依赖问题。记住长期的信息在实践中是 LSTM 的默认行为,而非需要付出很大代价才能获得的能力!
所有 RNN 都具有一种重复神经网络模块的链式的形式。在标准的 RNN 中,这个重复的模块只有一个非常简单的结构,例如一个 tanh 层((这个tanh层就是一个函数,tanh就是双曲正切函数,可以将输入的值转化为-1到1之间的一个值,通常用于对信息的压缩处理,或者规范化处理)。
下图为LSTM算法的结构图.
图中有三种元素:红色圈圈,黄色方块,黑色信息流。
红色的圈圈就是各种处理过程,×代表乘法,+就是加法。黄色方块代表神经网络的一个层,σ是指sigmoid函数层,把数据压缩到0到1的范围。黑色信息流主要要注意信息的流向。
和RNN不同的是: RNN中,就是个简单的线性求和的过程. 而LSTM可以通过“门”结构来去除或者增加“细胞状态”的信息,实现了对重要内容的保留和对不重要内容的去除. 通过Sigmoid层输出一个0到1之间的概率值,描述每个部分有多少量可以通过,0表示“不允许任务变量通过”,1表示“运行所有变量通过 ”.
用于遗忘的门叫做"遗忘门", 用于信息增加的叫做"信息增加门",最后是用于输出的"输出门". 这里就不展开介绍了.
下面就一步步地分解上面的结构,逐层的理解:
单元状态流就是下面这个水平直线,类似于传送带,直接在整个链上运行,只有一些少量的线性交互。信息在上面流传保持不变会很容易。
因此,它主要用于“记忆”当前的状态,上面包含记忆的删除、更新等。
LSTM有三个“门”来保护和控制cell state。
遗忘门(forget gate)顾名思义,是控制是否遗忘的,在LSTM中即以一定的概率控制是否遗忘上一层的隐藏细胞状态。遗忘门子结构如下图所示:
再次说明一下, h t − 1 h_{t-1} ht−1是上个网络的output(输出), x t x_t xt当前网络的input(输入)。 x t x_t xt在这里的作用是为了根据当前输入的新的信息来决定要忘记哪些历史信息。
信息输入了之后, σ σ σ层就会把信息转化为 f t f_t ft,如果决定要忘记, f t f_t ft就是0,如果这个信息要保留,则为1,选择部分记忆则按照实际情况输出0~1的数。
为什么要有“遗忘门”?例如,当我们碰到一个新的主语,如Peter,因为是男的,所以如果后面要用代词的话,就要用he而不能用she。但是可能我们在理解之前的语句的时候,cell state中保存的主语是Alice,这样的话我们就需要把Alice忘掉,否则后面的代词就不知道咋用了。
输入门(input gate)负责处理当前序列位置的输入,确定什么样的新信息被存放在细胞状态中。这里包含两个部分。第一,
s
i
g
m
o
i
d
sigmoid
sigmoid 层称 “输入门层” 决定什么值我们将要更新。然后一个
t
a
n
h
tanh
tanh 层创建一个新的候选值向量
C
~
t
\tilde{C}_{t}
C~t ,来加入新的
x
t
x_t
xt信息。
在我们语言模型的例子中,我们希望增加新的主语的性别到细胞状态中,来替代旧的需要忘记的主语。所以在更新新的细胞状态时,主要要做的两件事就是决定哪些历史信息该流入当前细胞中(遗忘们控制),决定哪些新的信息该流入细胞中(输入们控制)。
输入门包括两步,第一步是将 x t x_t xt中的信息转换为和 C t − 1 C_{t-1} Ct−1一样长度的向量,也就是对 x t x_t xt标准化的过程,此过程就是上图中下面的带波浪线的 C t C_t Ct所做的事情,第二步就是将带波浪线的 C t C_t Ct也进行一个信息筛选,筛选后的信息才最终会加到 C t C_t Ct中。这个信息筛选功能就是通过和 i t i_t it进行point wise 的相乘来实现的,这和上面的 f t f_t ft非常相似。 f t f_t ft就表示forget, i t i_t it就表示input,一个对原有信息进行筛选,一个对新的信息进行筛选。
下面就是要把两部分筛选的信息合并到一起:
至此,我们的
C
t
−
1
C_{t-1}
Ct−1成功地进化到了
C
t
C_t
Ct,还有一件事没有做,就是要根据
C
t
C_t
Ct产生本步的预测
h
t
h_t
ht。下面就来看看。
终于要输出了,输出的结果依赖于cell state,这时前面的遗忘、输入的作用就显现出来了。
注意这个图里面:
同样的,根据
C
t
C_t
Ct产生
h
t
h_t
ht时,我们也要经过一个筛选,这个筛选就由
o
t
o_t
ot来承担,
o
t
o_t
ot就是代表output的意思。同时,对
C
t
C_t
Ct做了一个
t
a
n
h
tanh
tanh的变换,目的是让其每一位都在-1和1之间。
输入门、遗忘门、输出们所对应的函数都是 sigmoid 函数(因为 Sigmoid 函数的输出值范围为0-1,相当于控制门的百分比过滤),因此输出的结果是[0, 1],当为0时,门完全关闭,当为1时,门完全打开。输入们控制这当前输入值有多少信息流入到当前的计算中,遗忘门控制着历史信息中有多少信息流入到当前计算中,输出们控制着输出值中有多少信息流入到隐层中。所有LSTM除了有三个门来控制当前的输入和输出,其他的和RNN是一致的。
C
~
t
=
tanh
(
W
x
u
x
t
+
W
h
u
h
t
−
1
+
b
u
)
f
t
=
σ
(
W
x
f
x
t
+
W
h
f
h
t
−
1
+
b
f
)
i
t
=
σ
(
W
x
i
x
t
+
W
h
i
h
t
−
1
+
b
i
)
o
t
=
σ
(
W
x
o
x
t
+
W
h
o
h
t
−
1
+
b
o
)
C
t
=
i
t
⊙
C
~
t
+
f
t
⊙
C
t
−
1
h
t
=
o
t
⊙
tanh
(
C
t
)
LSTM模型有两个隐藏状态
h
t
h_t
ht ,
C
t
C_t
Ct ,模型参数几乎是RNN的4倍,因为现在多了
W
f
,
U
f
,
b
f
,
W
a
,
U
a
,
b
a
,
W
i
,
U
i
,
b
i
,
W
o
,
U
o
,
b
o
W_f, U_f, b_f, W_a, U_a, b_a, W_i, U_i, b_i, W_o, U_o, b_o
Wf,Uf,bf,Wa,Ua,ba,Wi,Ui,bi,Wo,Uo,bo 这些参数。
前向传播过程在每个序列索引位置的过程为:
1)更新遗忘门输出:
f
t
=
σ
(
W
f
h
t
−
1
+
U
f
x
t
+
b
f
)
f_t = σ (W_f h_{t-1} + U_fx_t + b_f)
ft=σ(Wfht−1+Ufxt+bf)
2)更新输入门两部分输出:
i
t
=
σ
(
W
i
h
t
−
1
+
U
i
x
t
+
b
i
)
i_t = σ(W_i h_{t-1} + U_i x_t + b_i)
it=σ(Wiht−1+Uixt+bi)
C
~
t
=
t
a
n
h
(
W
a
h
t
−
1
+
U
a
x
t
+
b
a
)
\tilde C_t = tanh(W_a h_{t-1} + U_a x_t + b_a)
C~t=tanh(Waht−1+Uaxt+ba)
3)更新细胞状态:
C
t
=
f
t
C
t
−
1
+
i
t
C
~
t
C_t = f_t C_{t-1}+ i_t \tilde C_t
Ct=ftCt−1+itC~t
4)更新输出门输出:
o
t
=
σ
(
W
o
h
t
−
1
+
U
o
x
t
+
b
o
)
o_t = σ(W_o h_{t-1} + U_o x_t + b_o)
ot=σ(Woht−1+Uoxt+bo)
h
t
=
o
t
t
a
n
h
(
C
t
)
h_t = o_t tanh(C_t)
ht=ottanh(Ct)
5)更新当前序列索引预测输出:
y
t
=
σ
(
V
h
t
+
c
)
y_t = σ(V h_t + c)
yt=σ(Vht+c)
知道了前向传播,反向传播和RNN中的一样,也是借助梯度下降来训练模型,具体的训练过程可以看https://blog.csdn.net/wangyangzhizhou/article/details/76651116
前向的LSTM与后向的LSTM结合成BiLSTM。比如,我们对“我爱中国”这句话进行编码,模型如下图所示。
前向
L
S
T
M
L
LSTM_L
LSTML的依次输入“我”,“爱”,“中国”得到三个向量
[
h
L
0
,
h
L
1
,
h
L
2
]
[h_{L0},h_{L1},h_{L2}]
[hL0,hL1,hL2]。后向
L
S
T
M
R
LSTM_R
LSTMR的依次输入“中国”,“爱”,“我”得到三个向量
[
h
R
0
,
h
R
1
,
h
R
2
]
[h_{R0},h_{R1},h_{R2}]
[hR0,hR1,hR2]。最后将前向和后向的隐向量进行拼接得到
[
h
L
0
,
h
R
2
]
,
[
h
L
1
,
h
R
1
]
,
[
h
L
2
,
h
R
0
]
{[h_{L0},h_{R2} ], [h_{L1},h_{R1} ], [h_{L2},h_{R0}]}
[hL0,hR2],[hL1,hR1],[hL2,hR0],即
[
h
0
,
h
1
,
h
2
]
[h_0,h_1,h_2]
[h0,h1,h2]。
对于情感分类任务来说,我们采用的句子的表示往往是$ [h_{L2},h_{R2}]$。因为其包含了前向与后向的所有信息,如下图所示。
GRU是2014年提出的一种LSTM改进算法. 它将忘记门和输入门合并成为一个单一的更新门, 同时合并了数据单元状态和隐藏状态, 使得模型结构比之于LSTM更为简单. GRU只包含更新门和重置门。
GRU是LSTM的一种变体,综合来看:
1、两者的性能在很多任务上不分伯仲。
2、GRU 参数相对少更容易收敛,但是在数据集较大的情况下,LSTM性能更好。
3、GRU只有两个门(update和reset),LSTM有三个门(forget,input,output)
LSTM还有许多变体,但不管是何种变体,都是对输入和隐层状态做一个线性映射后加非线性激活函数,重点在于额外的门控机制是如何设计,用以控制梯度信息传播从而缓解梯度消失现象。
参考:https://blog.csdn.net/qq_32241189/article/details/80461635
https://blog.csdn.net/zhaojc1995/article/details/80572098
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。