Recurrent Neural Networks
循环神经网络的应用
1.会议识别:输入一段会议的语音信息,输出语音中的内容 2. 音乐生成:根据输入生成音乐,也可以输入空生成音乐 3. 句子分类:根据句子的内容,将句子归类。比如根据用户的评论归类到评价星级 4. DNA序列分析 5. 机器翻译 6. 视频动作识别 7. 名字识别
特点都是输入带有前后或者时间顺序的输入进行识别
符号
对输入来说,我们使用
x
<
t
>
x^{<t>}
x < t > 表示输入序列的每一部分,以输入一个句子为例,每个单词为一个
x
<
t
>
x^{<t>}
x < t > ,我们构造一个单词表,假设单词表中包含10000个单词,那么每个
x
<
t
>
x^{<t>}
x < t > 为10000维的列向量,单词在单词表对应位置处为1,其他所有位置为0,如果碰到不在单词表中的单词,那么用UNK表示。 对输出来说,如果我们的任务是人名检测,那么当该单词为人名时输出为1,其他为0。我们用
y
<
t
>
y^{<t>}
y < t > 表示第
t
t
t 个单词的输出。 接下来使用的符号总结:
x
(
i
)
<
t
>
:第
  
i
  
个样本中的第
  
t
  
个元素
x^{(i)<t>}\text{:第}\;i\;\text{个样本中的第}\;t\;\text{个元素}
x ( i ) < t > :第 i 个样本中的第 t 个元素
y
(
i
)
<
t
>
:第
  
i
  
个样本中的第
  
t
  
个元素的输出
y^{(i)<t>}\text{:第}\;i\;\text{个样本中的第}\;t\;\text{个元素的输出}
y ( i ) < t > :第 i 个样本中的第 t 个元素的输出
T
x
(
i
)
:第
  
i
  
个样本的长度
T_x^{(i)} \text{:第}\;i\;\text{个样本的长度}
T x ( i ) :第 i 个样本的长度
T
y
(
i
)
:第
  
i
  
个样本的输出长度
T_y^{(i)} \text{:第}\;i\;\text{个样本的输出长度}
T y ( i ) :第 i 个样本的输出长度
循环神经网络模型
为什么不直接使用一般的神经网络:
输入输出在不同样本中长度可以不同,一般神经网络不同样本的输入输出大小相同
在文档的不同位置没有可以共享的特征
循环神经网络结构: 这里假设输入输出大小相同,
a
<
0
>
a^{<0>}
a < 0 > 存在多种初始化方法,通常将其初始化为全0。根据结构我们可以知道,循环神经网络后边的输出是与前边的结果相关的,这就构建了前后文本的联系。 一种简单的表示法为: 详细计算公式为:设
a
<
0
>
a^{<0>}
a < 0 > 为全0向量
a
<
1
>
=
g
1
(
W
a
a
a
<
0
>
+
W
a
x
x
<
1
>
+
b
)
a^{<1>} = g_1(W_{aa}a^{<0>}+ W_{ax}x^{<1>} + b)
a < 1 > = g 1 ( W a a a < 0 > + W a x x < 1 > + b )
y
^
<
1
>
=
g
2
(
W
y
a
a
<
1
>
+
b
)
\hat{y}^{<1>} = g_2(W_{ya}a^{<1>} + b)
y ^ < 1 > = g 2 ( W y a a < 1 > + b ) 其中,
g
1
g_1
g 1 通常使用tanh函数激活(也有使用ReLU激活的),
g
2
g_2
g 2 根据输出来选择激活函数,如果输出为二分类问题,那么用sigmoid函数。上式更一般的表述为:
a
<
t
>
=
g
1
(
W
a
a
a
<
t
−
1
>
+
W
a
x
x
<
t
>
+
b
)
a^{<t>} = g_1(W_{aa}a^{<t-1>}+ W_{ax}x^{<t>} + b)
a < t > = g 1 ( W a a a < t − 1 > + W a x x < t > + b )
y
^
<
t
>
=
g
2
(
W
y
a
a
<
t
>
+
b
)
\hat{y}^{<t>} = g_2(W_{ya}a^{<t>} + b)
y ^ < t > = g 2 ( W y a a < t > + b ) 为了减少表示参数,我们将
W
a
x
W_{ax}
W a x 与
W
a
a
W_{aa}
W a a 合并,即
W
a
=
[
W
a
a
∣
W
a
x
]
W_a = \left[\begin{matrix}W_{aa}& | &W_{ax}\end{matrix}\right]
W a = [ W a a ∣ W a x ] 那么
a
<
t
>
=
g
(
W
a
×
[
a
<
t
−
1
>
,
x
<
t
>
]
+
b
a
)
a^{<t>} = g(W_a\times [a^{<t-1>},x^{<t>}] + b_a)
a < t > = g ( W a × [ a < t − 1 > , x < t > ] + b a ) 其中
[
a
<
t
−
1
>
,
x
<
t
>
]
=
[
a
<
t
−
1
>
x
<
t
>
]
[a^{<t-1>},x^{<t>}] = \left[\begin{matrix}a^{<t-1>} \\x^{<t>}\end{matrix}\right]
[ a < t − 1 > , x < t > ] = [ a < t − 1 > x < t > ] 令
W
a
y
=
W
y
W_{ay} = W_y
W a y = W y
y
^
<
t
>
=
g
(
W
y
a
<
t
>
+
b
y
)
\hat{y}^{<t>} = g(W_ya^{<t>} + b_y)
y ^ < t > = g ( W y a < t > + b y )
反向传播
L
<
t
>
(
y
^
<
t
>
,
y
<
t
>
)
=
−
y
<
t
>
log
y
^
<
t
>
−
(
1
−
y
<
t
>
)
log
(
1
−
y
^
<
t
>
)
L^{<t>}(\hat{y}^{<t>},y^{<t>}) = -y^{<t>}\log\hat{y}^{<t>}-(1-y^{<t>})\log(1-\hat{y}^{<t>})
L < t > ( y ^ < t > , y < t > ) = − y < t > log y ^ < t > − ( 1 − y < t > ) log ( 1 − y ^ < t > )
L
(
y
^
,
y
)
=
∑
t
=
1
T
y
L
<
t
>
(
y
^
<
t
>
,
y
<
t
>
)
L(\hat{y}, y) = \sum_{t=1}^{T_y}L^{<t>}(\hat{y}^{<t>},y^{<t>})
L ( y ^ , y ) = t = 1 ∑ T y L < t > ( y ^ < t > , y < t > )
不同类型的循环神经网络
针对循环神经网络的不同任务引入了不同的循环神经网络
many to many:
one to one:一般的神经网络即为one to one
many to one:
one to many:
many to many2(machine translation): 输入x的网络认为是在编码(encode),输出y的网络认为在解码(decode)。
语言模型(language modeling)
训练
语言模型的输出给出了一个句子中各个单词出现的概率。 Training set:一些英语文档 训练开始前需要搭建一个单词字典用于向量化输入和输出。 对于一个句子,我们需要在句子结尾添加一个终止标志符,对于未在字典中的词用 代替。 对于RNN的第一部分,输入为一个零向量,求解输出各个单词的概率构成一个矩阵,第二部分输入句子中的第一个单词,求解在输入第一个单词下预测第二个单词的概率,这个实质上是一个与第一部分输出一样大小的向量,同理,第三部分输入为句子中的第一个和第二个单词,求解在输入前两个单词下预测第三个单词的概率。 loss function和cost function与softmax求解方式相同。
取样
在训练了一个序列模型之后,我们想知道这个模型到底学习到了什么,可以采用sample novel sequence来验证。
x
<
1
>
x^{<1>}
x < 1 > 我们输入一个零向量,
x
<
2
>
x^{<2>}
x < 2 > 我们选择一个一句话的第一个单词输入;对于
y
^
<
1
>
\hat{y}^{<1>}
y ^ < 1 > ,我们使用一个基于概率的随机取样(如np.random.choice),将选择出的输出作为下一层的输入以此类推。 停止的方法:1. 当输出时停止;2. 当运行到一定步数后停止 如果在测试过程中不希望出现,那么设置输出 时持续采样直到输出不为 为止。 同样该方法也可用于用字符构建句子,但是这样存在以下几个缺点:
无法捕捉到句子单词间的前后依赖
句子一般包含多个character,因此训练成本高昂
GRU,LSTM
梯度消失和梯度爆炸
梯度爆炸:梯度修剪,限制梯度的上限来保证梯度不会过大
梯度消失:对于一般的神经网络而言,当网络很深时,反向传播很难影响到最前边层的参数。对于RNN来说,如果句子后边的某一个单词需要依据前边单词判定(如The cats ,which ate…, were full。were需要根据前边的cats判断),一般的RNN网络很难做到,于是造成了梯度消失。
Gated Recurrent Unit(GRU)
一般的RNN结构是将
a
<
t
−
1
>
a^{<t-1>}
a < t − 1 > 与
x
<
t
>
x^{<t>}
x < t > 结合之后经激活函数之后产生
a
<
t
>
a^{<t>}
a < t > ,再由
a
<
t
>
a^{<t>}
a < t > 产生
y
^
\hat{y}
y ^ 。GRU则是对
a
<
t
>
a^{<t>}
a < t > 的产生做了一些改变 设设一级传入的数据为
c
<
t
−
1
>
c^{<t-1>}
c < t − 1 > ,对于 $c^{}和
x
<
t
>
x^{<t>}
x < t > ,我们不仅要产生一个当前的输出,还要产生一个门函数,即
c
~
<
t
>
=
t
a
n
h
(
W
c
[
c
<
t
−
1
>
,
x
<
t
>
]
+
b
c
)
\tilde{c}^{<t>} = tanh(W_c[c^{<t-1>}, x^{<t>}] + b_c)
c ~ < t > = t a n h ( W c [ c < t − 1 > , x < t > ] + b c )
Γ
u
=
σ
(
W
u
[
c
<
t
−
1
>
,
x
<
t
>
+
b
u
)
\Gamma_u = \sigma(W_u[c^{<t-1>}, x^{<t>} + b_u)
Γ u = σ ( W u [ c < t − 1 > , x < t > + b u )
c
<
t
>
=
Γ
u
∗
c
~
<
t
>
+
(
1
−
Γ
u
)
∗
c
<
t
−
1
>
c^{<t>} = \Gamma_u * \tilde{c}^{<t>} + (1-\Gamma_u)*c^{<t-1>}
c < t > = Γ u ∗ c ~ < t > + ( 1 − Γ u ) ∗ c < t − 1 >
Γ
u
\Gamma_u
Γ u 是一个参数均接近0或1的向量,根据式子我们可以知道,记忆单元的某一位置的值是否更新是由门函数决定的,若门函数某一位置为0,那么记忆单元该位置不更新;若为1,那么记忆单元进行更新。以 The cat, which ate …, was full为例,门函数某一位置上的值记录cat的变化,这个值直到was之前均为0,当到was时,门函数的值发生变化,对记忆单元进行更新。 为了更好的捕捉长期依赖,使RNN更有效,提出了Full GRU,即
Γ
u
=
σ
(
W
u
[
c
<
t
−
1
>
,
x
<
t
>
+
b
u
)
\Gamma_u =\sigma(W_u[c^{<t-1>}, x^{<t>} + b_u)
Γ u = σ ( W u [ c < t − 1 > , x < t > + b u )
Γ
r
=
σ
(
W
r
[
c
<
t
−
1
>
,
x
<
t
>
+
b
r
)
\Gamma_r = \sigma(W_r[c^{<t-1>}, x^{<t>} + b_r)
Γ r = σ ( W r [ c < t − 1 > , x < t > + b r )
c
~
<
t
>
=
t
a
n
h
(
W
c
[
Γ
r
∗
c
<
t
−
1
>
,
x
<
t
>
]
+
b
c
)
\tilde{c}^{<t>} = tanh(W_c[\Gamma_r * c^{<t-1>}, x^{<t>}] + b_c)
c ~ < t > = t a n h ( W c [ Γ r ∗ c < t − 1 > , x < t > ] + b c )
c
<
t
>
=
Γ
u
∗
c
~
<
t
>
+
(
1
−
Γ
u
)
∗
c
<
t
−
1
>
c^{<t>} = \Gamma_u * \tilde{c}^{<t>} + (1-\Gamma_u)*c^{<t-1>}
c < t > = Γ u ∗ c ~ < t > + ( 1 − Γ u ) ∗ c < t − 1 >
LSTM
GRU其实是LATM的一个简化版本,LSTM构造更复杂的单元来保证前后之前的依赖 LSTM的状态更新函数为:
c
~
<
t
>
=
t
a
n
h
(
W
c
[
c
<
t
−
1
>
,
x
<
t
>
]
+
b
c
)
\tilde{c}^{<t>} = tanh(W_c[c^{<t-1>}, x^{<t>}] + b_c)
c ~ < t > = t a n h ( W c [ c < t − 1 > , x < t > ] + b c )
Γ
u
=
σ
(
W
u
[
c
<
t
−
1
>
,
x
<
t
>
+
b
u
)
\Gamma_u =\sigma(W_u[c^{<t-1>}, x^{<t>} + b_u)
Γ u = σ ( W u [ c < t − 1 > , x < t > + b u )
Γ
r
=
σ
(
W
r
[
c
<
t
−
1
>
,
x
<
t
>
+
b
r
)
\Gamma_r = \sigma(W_r[c^{<t-1>}, x^{<t>} + b_r)
Γ r = σ ( W r [ c < t − 1 > , x < t > + b r )
Γ
o
=
σ
(
W
o
[
c
<
t
−
1
>
,
x
<
t
>
+
b
o
)
\Gamma_o = \sigma(W_o[c^{<t-1>}, x^{<t>} + b_o)
Γ o = σ ( W o [ c < t − 1 > , x < t > + b o )
c
<
t
>
=
Γ
u
∗
c
~
<
t
>
+
Γ
f
∗
c
<
t
−
1
>
c^{<t>} = \Gamma_u * \tilde{c}^{<t>} + \Gamma_f*c^{<t-1>}
c < t > = Γ u ∗ c ~ < t > + Γ f ∗ c < t − 1 >
a
<
t
>
=
Γ
o
∗
c
<
t
>
a^{<t>} = \Gamma_o*c^{<t>}
a < t > = Γ o ∗ c < t >
GRU 与 LSTM对比
GRU更简单,更易构造大型网络且计算够快,便于扩大模型规模 LSTM更强大和灵活,就一般工程而言,使用LSTM的优先级更高
双向神经网络
在序列的某点处,不仅可以获取前面的信息,也可以获取将来的信息。 网络结构 这种网络的缺点是需要一个完整的数据序列 上图黄色线表示
y
^
<
3
>
\hat{y}^{<3>}
y ^ < 3 > 的输出
Deep RNN
对于深度循环神经网络,三层已经算很深的网络。 也可以对输出添加多层一般神经网络的隐藏层达到加深网络的目的。