RNN(Recurrent Neural Network, 循环神经网络)
ReNN(Recursive Neural Network, 递归神经网络)
如:(1) 我饿了,我要去食堂___。(2) 我饭卡丢了,我要去食堂___。很显然,第一句话是想表明去食堂就餐,而第二句则很有可能因为刚吃过饭,发现饭卡不见了,去食堂寻找饭卡。而RNN之前,我们常用的语言模型是N-Gram,无论何种语境,可能去食堂大概率匹配的是“吃饭”而不在乎之前的信息。RNN就解决了N-Gram的缺陷,它在理论上可以往前(后)看任意多个词。RNN具有时序上的“记忆”能力,因而在自然语言理解、语音识别等领域取得了显著效果。
RNN模型是一种层内神经元之间形成有向环连接的神经网络模型。RNN模型不属于前馈神经网络模型,它的主要特点在于隐藏层的输出不仅连接到下一层,而且还连接到自身。 这种连接到自身的特点构成了数据的循环。
基本RNN单元(Vanilla RNN)
好的图胜过千言万语。如上图所示,网络可以分为3部分,输入层,隐藏层,输出层。RNN单元层处于隐藏层,我们用单元层替代隐藏层的说法。输入层到单元层的连接权重记为
U
\bold U
U,单元层到输出层的连接权重记为
V
\bold V
V,单元层内部循环连接权重记为
W
\bold W
W。单元层内部可以分为两类神经元,一类是做新旧知识整合的(蓝色圆);一类是做知识抽象的(红色圆)。蓝色圆接收两类输入:新知识和旧知识。红色圆负责抽象知识并更新记忆。
输入层的输入是 X \bold X X,输出是: U T ∗ X \bold U^T*\bold X UT∗X ;
知识整合神经元
接收的输入是:
i
n
p
u
t
0
=
U
T
∗
X
input^0=\bold U^T*\bold X
input0=UT∗X 和
i
n
p
u
t
1
=
W
T
∗
H
r
e
d
input^1=\bold W^T* H_{red}
input1=WT∗Hred
知识整合神经元的功能(即其假设函数/激活函数,即知识是怎么整合的):
H
b
l
u
e
(
i
n
p
u
t
0
,
i
n
p
u
t
1
)
=
i
n
p
u
t
0
+
i
n
p
u
t
1
H_{blue}(input^0,input^1)=input^0+input^1
Hblue(input0,input1)=input0+input1
知识抽象神经元
接收的输入是知识整合神经元的输出,即
i
n
p
u
t
0
+
i
n
p
u
t
1
input^0+input^1
input0+input1
知识抽象神经元的功能就是进行非线性化抽象,如使用tanh激活函数:
H
r
e
d
(
i
n
p
u
t
)
=
e
i
n
p
u
t
−
e
−
i
n
p
u
t
e
i
n
p
u
t
+
e
−
i
n
p
u
t
H_{red}(input)=\frac{e^{input}-e^{-input}}{e^{input}+e^{-input}}
Hred(input)=einput+e−inputeinput−e−input
知识抽象神经元的输出可以作为
t
+
1
t+1
t+1时刻的知识整合神经元的输入,也可以作为当前
t
t
t时刻的输出层的输入。
输出层的输入是 H r e d ( i n p u t ) H_{red}(input) Hred(input),输出取决于输出函数(即输出层激活函数,常用的如Sigmoid、Softmax);
如上图:
t
t
t时刻:
U
3
∗
2
T
∗
X
3
∗
1
=
i
n
p
u
t
2
∗
1
0
\bold U_{3*2}^T*\bold X_{3*1}=input_{2*1}^0
U3∗2T∗X3∗1=input2∗10
t − 1 t-1 t−1时刻保留下来的知识为: H r e d , 2 ∗ 1 t − 1 H_{red,2*1}^{t-1} Hred,2∗1t−1
输入到知识整合神经元中的旧知识为: W 2 ∗ 2 T ∗ H r e d , 2 ∗ 1 t − 1 = i n p u t 2 ∗ 1 1 \bold W_{2*2}^T*H_{red,2*1}^{t-1}=input_{2*1}^1 W2∗2T∗Hred,2∗1t−1=input2∗11
知识整合神经元进行知识整合(同型矩阵才能相加减): i n p u t 2 ∗ 1 0 + i n p u t 2 ∗ 1 1 = H b l u e , 2 ∗ 1 t input_{2*1}^0+input_{2*1}^1=H_{blue,2*1}^t input2∗10+input2∗11=Hblue,2∗1t
知识抽象神经元接收输入 H b l u e , 2 ∗ 1 t H_{blue,2*1}^t Hblue,2∗1t进行非线性化,可以输出到输出层,也可以更新记忆,即由 H r e d t − 1 H_{red}^{t-1} Hredt−1更新为 H r e d , 2 ∗ 1 t H_{red,2*1}^t Hred,2∗1t
上面的过程我们可以简化成图:
实例走一波
基本RNN单元存在的问题
考虑用一个语言模型通过利用以前的文字信息来预测下一个文字。如果我们需要预测“the clouds are in the sky ”这句话的最后一个字,我们不需要其他的信息,通过前面的语境就能知道最后一个字应该是sky。在这种情况下,相关信息与需要该信息的位置距离较近,RNNs能够学习利用近期的信息来执行来处理当前的任务。如下图所示:
假设现在有个更为复杂的任务,考虑到下面这句话“I grew up in France… I speak fluent French .”,现在需要语言模型通过现有以前的文字信息预测该句话的最后一个字。通过以前文字语境可以预测出最后一个字是某种语言,但是要猜测出French,要根据之前的France语境。这样的任务,不同之前,因为这次的有用信息与需要进行处理信息的地方之间的距离较远,这样容易导致RNNs不能学习到有用的信息,最终推导的任务可能失败。如下图所示:
经典LSTM单元(Vanilla LSTM)
虽然基本RNN单元可以对具有时间序列的输入数据建模,但是当输入时间序列长度太长时,基本RNN单元中较早时刻的隐藏层状态很难一直传递下去(被 W \bold W W给稀释了),这会造成信息丢失 ,出现长时间依赖问题( Long-Term Dependency )。 为了解决这个问题 , Sepp Hochreiter和Jurgen Schmidhuber 于 1997年提出了LSTM(Long Short-Term Memory,长短期记忆)单元。
这篇关于LSTM的文章可以参考:理解LSTM(通俗易懂版)
LSTM的核心是细胞状态(即
C
t
C_t
Ct),细胞状态由四个门来控制:输入门、回忆门(忘记门)、记忆门和输出门。
可以看到图中有两个循环,一个是 S t S_t St的循环,一个是 C t C_t Ct的循环。
下面的序号对应图中的序号(偏置参数
b
b
b省略):
1、
U
0
T
∗
X
U_0^T*X
U0T∗X
2、
W
0
T
∗
S
t
−
1
W_0^T*S_{t-1}
W0T∗St−1
3、
U
0
T
∗
X
+
W
0
T
∗
S
t
−
1
U_0^T*X+W_0^T*S_{t-1}
U0T∗X+W0T∗St−1
4、
F
o
r
g
e
t
G
a
t
e
=
S
i
g
m
o
i
d
(
U
0
T
∗
X
+
W
0
T
∗
S
t
−
1
)
ForgetGate=Sigmoid(U_0^T*X+W_0^T*S_{t-1})
ForgetGate=Sigmoid(U0T∗X+W0T∗St−1)
5、
C
t
−
1
C_{t-1}
Ct−1
6、
O
l
d
K
n
o
w
l
e
d
g
e
=
F
o
r
g
e
t
G
a
t
e
∗
C
t
−
1
OldKnowledge=ForgetGate*C_{t-1}
OldKnowledge=ForgetGate∗Ct−1;勾起回忆
7、
U
1
T
∗
X
+
W
1
T
∗
S
t
−
1
U_1^T*X+W_1^T*S_{t-1}
U1T∗X+W1T∗St−1
8、
I
n
p
u
t
G
a
t
e
=
S
i
g
m
o
i
d
(
=
U
1
T
∗
X
+
W
1
T
∗
S
t
−
1
)
InputGate=Sigmoid(=U_1^T*X+W_1^T*S_{t-1})
InputGate=Sigmoid(=U1T∗X+W1T∗St−1);给定目标(题目)
9、
U
2
T
∗
X
+
W
2
T
∗
S
t
−
1
U_2^T*X+W_2^T*S_{t-1}
U2T∗X+W2T∗St−1
10、
M
e
m
o
r
y
G
a
t
e
=
t
a
n
h
(
U
2
T
∗
X
+
W
2
T
∗
S
t
−
1
)
MemoryGate=tanh(U_2^T*X+W_2^T*S_{t-1})
MemoryGate=tanh(U2T∗X+W2T∗St−1)
11、
N
e
w
K
n
o
w
l
e
d
g
e
=
I
n
p
u
t
G
a
t
e
∗
M
e
m
o
r
y
G
a
t
e
NewKnowledge=InputGate*MemoryGate
NewKnowledge=InputGate∗MemoryGate;从题目中抽取新知识,并进行记忆
12、
U
3
T
∗
X
+
W
3
T
∗
S
t
−
1
U_3^T*X+W_3^T*S_{t-1}
U3T∗X+W3T∗St−1
13、
O
u
t
G
a
t
e
=
S
i
g
m
o
i
d
(
U
3
T
∗
X
+
W
3
T
∗
S
t
−
1
)
OutGate=Sigmoid(U_3^T*X+W_3^T*S_{t-1})
OutGate=Sigmoid(U3T∗X+W3T∗St−1)
14、
C
t
=
O
l
d
K
n
o
w
l
e
d
g
e
+
N
e
w
K
n
o
w
l
e
d
g
e
C_t=OldKnowledge+NewKnowledge
Ct=OldKnowledge+NewKnowledge;融合新旧知识,产生新记忆
15、
S
t
=
O
u
t
G
a
t
e
∗
t
a
n
h
(
C
t
)
S_t=OutGate*tanh(C_t)
St=OutGate∗tanh(Ct);根据新记忆答题
上面的过程就是LSTM的前向传播过程。
可以说LSTM就是对记忆的模仿:
第1次输入
U
0
T
∗
X
U_0^T*X
U0T∗X目的是让你回忆旧的知识;
第2次输入
U
1
T
∗
X
U_1^T*X
U1T∗X目的是给你一个目标(填空题)
第3次输入
U
2
T
∗
X
U_2^T*X
U2T∗X目的是让你从题目中抽取新的知识,并进行记忆;
… 融合新旧知识 …
第4次输入
U
3
T
∗
X
U_3^T*X
U3T∗X目的是让你针对目标输出,根据新的记忆完成填空题。
再来画个图理解下:
Peephole Connections(LSTM变体)
Multiplicative LSTM (2017)
LSTMs With Attention
GRU单元
GRU(Gated Recurrent Unit)是RNN单元的又一个变种,也可以解决长时间序列的记忆问题,常用于机器翻译等任务。 与LSTM单元不同, GRU单元的记忆向量并不会显式地在不同时刻之间传递。 GRU单元比LSTM单元更为简单。 从大量实验结果来看,GRU 单元训练的收敛速度比LSTM单元要稍微快一些。
GRU单元包含三种门: 重置门(reset gate)、更新门(update
gate)和记忆门(memory gate)
双向RNN单元
在对句子进行语义分析时,当前词的语义要与上下文语义匹配。 这里所说的“上下文”不仅包括“上文”,也包括“下文” 。 但是,基本RNN单元仅考虑了从
t
−
1
t-1
t−1时刻到
t
t
t时刻的状态转移,即之前时刻的输入对当前的影响。 为了考虑未来时刻的输入对当前的影响,充分利用上下文的语义信息,Mike Schuster等人发明了双向RNN单元。
如上图所示,双向RNN单元中包含两个隐藏层状态,它在基本RNN单元的基础上添加了相反方向的隐藏层状态转移 。
双向RNN单元本质上可以由两个独立的基本RNN单元组合而成,在构造双向 RNN模型时,我们可以直接使用两个基本RNN单元,因此TensorFlow没有提供继承于RNNCell类的双向RNN单元子类。我们也可以借鉴双向RNN单元的思想构建双向LSTM、双向GRU单元等。
从双向RNN单元的原理来看,它适合处理同时具有前后依赖关系的序列型输入数据。除了前面提到的句子语义分析之外,也会有其他场景需要用到双向 RNN单元。例如,在光学字符识别(OCR)中, 输入序列中每一时刻对应一字母。对于任何一个单词中的某一个字母,其出现的概率与其之前和之后的字母都有一定关系。因此,当我们观察到具体应用中的这种特征之后,就
可以选择双向RNN单元构建模型,以提升模型准确率。
RNN参数是如何更新的?
https://stanford.edu/~shervine/teaching/cs-230/cheatsheet-recurrent-neural-networks