十四、循环神经网络(RNN)
我们令
X
(
i
)
<
t
>
X^{(i)<t>}
X(i)<t>表示第
i
i
i个样本中第
t
t
t个元素,
T
x
(
i
)
T_x^{(i)}
Tx(i)表示第
i
i
i个输出序列的长度。
建立一个单词字典,为每一个单词映射编号。
用独热编码代表单词。即
[
0
0
.
.
.
1
.
.
.
0
]
\left [ \begin{matrix} 0 \\ 0 \\ ...\\ 1 \\ ... \\ 0 \\ \end{matrix} \right ]
00...1...0
表示第
i
i
i个单词,记为
o
i
o_{i}
oi。
遇到不在字典表中的单词用
<
U
N
K
>
<UNK>
<UNK>表示。
NLP相关的数据中,测试样本的输入与输出长短不一(
T
x
≠
T
y
T_x\neq T_y
Tx=Ty),且传统的神经网络并没有像CNN那样可以“参数共享”来加速训练效果。
与传统神经网络不同的是,每一个单词作为输入数据进入一层,与前一层的激活函数值
a
<
t
>
a^{<t>}
a<t>一起。
a
<
0
>
a^{<0>}
a<0>通常是零向量或其他初始化值。
对于
y
^
<
l
>
\hat{y}^{<l>}
y^<l>的预测,需要间接的
X
<
1
∼
l
>
X^{<1\sim l>}
X<1∼l>的参与(之前的所有数据)
w
a
a
w_{aa}
waa是用
a
a
a来计算
a
a
a的超参数。
w
a
x
w_{ax}
wax是用
X
X
X来计算
a
a
a的超参数。
w
y
a
w_{ya}
wya是用
a
a
a来计算
y
y
y的超参数。
a
<
t
>
=
g
1
(
w
a
a
a
<
t
−
1
>
+
w
a
x
X
<
t
>
+
b
a
)
a^{<t>}=g_1(w_{aa}a^{<t-1>}+w_{ax}X^{<t>}+b_{a})
a<t>=g1(waaa<t−1>+waxX<t>+ba)
y
^
<
t
>
=
g
2
(
w
y
a
a
<
t
>
+
b
y
)
\hat{y}^{<t>}=g_2(w_{ya}a^{<t>}+b_{y})
y^<t>=g2(wyaa<t>+by)
其中
g
1
(
x
)
=
t
a
n
h
(
x
)
=
s
i
n
h
x
c
o
s
h
x
=
e
x
−
e
−
x
2
e
x
+
e
−
x
2
=
e
x
−
e
−
x
e
x
+
e
−
x
g_1(x)=tanh(x)=\frac{sinhx}{coshx}=\frac{\frac{e^{x}-e^{-x}}{2}}{\frac{e^{x}+e^{-x}}{2}}=\frac{e^{x}-e^{-x}}{e^{x}+e^{-x}}
g1(x)=tanh(x)=coshxsinhx=2ex+e−x2ex−e−x=ex+e−xex−e−x(或者也可以是ReLU)
g
2
(
x
)
g_2(x)
g2(x)是sigmoid函数
循环神经网络则只用它自己,把上一次的结果作为输入值来计算。
为了便于运算,把
w
a
a
w_{aa}
waa与
w
w
a
w_{wa}
wwa合并为增广矩阵。
Loss函数
L
(
y
^
<
t
>
,
y
<
t
>
)
=
−
(
y
<
t
>
log
y
^
<
t
>
+
(
1
−
y
<
t
>
)
log
(
1
−
y
^
<
t
>
)
)
\mathscr{L}(\hat{y}^{<t>},y^{<t>})=-(y^{<t>}\log\hat{y}^{<t>}+(1-y^{<t>})\log(1-\hat{y}^{<t>}))
L(y^<t>,y<t>)=−(y<t>logy^<t>+(1−y<t>)log(1−y^<t>))
L
(
y
^
,
y
)
=
∑
L
(
y
^
<
t
>
,
y
<
t
>
)
\mathscr{L}(\hat{y},y)=\sum{\mathscr{L}(\hat{y}^{<t>},y^{<t>})}
L(y^,y)=∑L(y^<t>,y<t>)
不同类型的RNN
多对多结构( T x = T y T_x=T_y Tx=Ty)
多对多结构( T x ≠ T y T_x\neq T_y Tx=Ty)
类似Transformers架构
多对一结构( T y = 1 T_y=1 Ty=1,如情绪分类)
输入是文本,输出是softmax分类
一对多结构( T x = 1 T_x=1 Tx=1,如音乐生成)
序列生成
将句子的每一个单词,通过某个字典形成一一映射,并在句子结尾增加
<
E
O
S
>
<EOS>
<EOS>。
L
(
y
^
<
t
>
,
y
<
t
>
)
=
−
∑
y
i
<
t
>
log
y
i
^
<
t
>
\mathscr{L}(\hat{y}^{<t>},y^{<t>})=-\sum{y_i^{<t>}\log\hat{y_i}^{<t>}}
L(y^<t>,y<t>)=−∑yi<t>logyi^<t>
L
=
∑
L
<
t
>
(
y
^
<
t
>
,
y
<
t
>
)
\mathscr{L}=\sum{\mathscr{L}^{<t>}(\hat{y}^{<t>},y^{<t>})}
L=∑L<t>(y^<t>,y<t>)
RNN下的梯度消失&梯度爆炸
RNN不擅长长期依赖的问题,且反向传播时,后面的部分难以影响前面的部分,因此梯度的控制会比其他神经网络更困难。
梯度修剪(应对梯度爆炸):当高出某个阈值时进行梯度向量的缩放,使其不会太大。
GRU单元(门控循环单元,可以长时间记忆某个值)
对于一个记忆单元
c
<
t
>
c^{<t>}
c<t>,门单元
Γ
u
,
Γ
r
\Gamma_{u},\Gamma_{r}
Γu,Γr,
令
c
<
t
>
=
a
<
t
>
c^{<t>}=a^{<t>}
c<t>=a<t>,
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>=tanh(wc[Γr∗c<t−1>,X<t>]+bc)(中间的是增广矩阵)
Γ
u
=
σ
(
w
u
[
c
<
t
−
1
>
,
X
<
t
>
]
+
b
u
)
\Gamma_{u}=\sigma(w_u[c^{<t-1>},X^{<t>}]+b_u)
Γu=σ(wu[c<t−1>,X<t>]+bu)
Γ
r
=
σ
(
w
r
[
c
<
t
−
1
>
,
X
<
t
>
]
+
b
r
)
\Gamma_{r}=\sigma(w_r[c^{<t-1>},X^{<t>}]+b_r)
Γr=σ(wr[c<t−1>,X<t>]+br)
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的值来作用,如
Γ
u
=
0
\Gamma_{u}=0
Γu=0时
c
<
t
>
=
c
<
t
−
1
>
c^{<t>}=c^{<t-1>}
c<t>=c<t−1>,
Γ
u
=
1
\Gamma_{u}=1
Γu=1时
c
<
t
>
=
c
~
<
t
>
c^{<t>}=\tilde{c}^{<t>}
c<t>=c~<t>)
(可以注意到,
c
<
t
−
1
>
c^{<t-1>}
c<t−1>的值会传递给
c
<
t
>
c^{<t>}
c<t>,也就可以实现长期记忆!)
LSTM(长短期记忆,GRU的变体)
c
~
<
t
>
=
t
a
n
h
(
w
c
[
a
<
t
−
1
>
,
X
<
t
>
]
+
b
c
)
\tilde{c}^{<t>}=tanh(w_c[a^{<t-1>},X^{<t>}]+b_c)
c~<t>=tanh(wc[a<t−1>,X<t>]+bc)
Γ
u
=
σ
(
w
u
[
a
<
t
−
1
>
,
X
<
t
>
]
+
b
u
)
\Gamma_{u}=\sigma(w_u[a^{<t-1>},X^{<t>}]+b_u)
Γu=σ(wu[a<t−1>,X<t>]+bu)(更新门update)
Γ
f
=
σ
(
w
f
[
a
<
t
−
1
>
,
X
<
t
>
]
+
b
f
)
\Gamma_{f}=\sigma(w_f[a^{<t-1>},X^{<t>}]+b_f)
Γf=σ(wf[a<t−1>,X<t>]+bf)(遗忘门forget)
Γ
o
=
σ
(
w
o
[
a
<
t
−
1
>
,
X
<
t
>
]
+
b
o
)
\Gamma_{o}=\sigma(w_o[a^{<t-1>},X^{<t>}]+b_o)
Γo=σ(wo[a<t−1>,X<t>]+bo)(输出门output)
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>
(可以通过两个门的权值来判断是保留老的值
c
<
t
−
1
>
c^{<t-1>}
c<t−1>还是新的值
c
~
<
t
>
\tilde{c}^{<t>}
c~<t>)
a
<
t
>
=
Γ
o
∗
t
a
n
h
(
c
<
t
>
)
a^{<t>}=\Gamma_{o}*tanh({c}^{<t>})
a<t>=Γo∗tanh(c<t>)
双向神经网络
双向RNN(BRNN)
增加反向循环层,由正向反向的神经元共同决定
y
^
<
t
>
\hat{y}^{<t>}
y^<t>
因此在大部分NLP问题中,用带有LSTM单元的双向RNN网络是最常见的方式!
深层RNN
在原本的基础上将多层RNN堆叠,形成更加复杂但效果可能更好的神经网络。
十五、NLP与单词嵌入
词汇表征
记录单词与单词之间可能的相关性,构成一个矩阵。
词汇嵌入可视化(如t-SNE算法)
命名实体识别
- 获取大量的无标签文本数据/获取预训练模型
- 单词嵌入,获得更小的训练集
- (持续微调)
词嵌入特性(类比推理)
在上图中,我们令Man一列的词向量记为
e
m
a
n
e_{man}
eman,可以发现
e
m
a
n
−
e
w
o
m
a
n
=
[
−
2
0
0
0
]
e_{man}-e_{woman}=\left [ \begin{matrix} -2\\ 0\\ 0\\ 0\\ \end{matrix} \right ]
eman−ewoman=
−2000
,仅仅只是gender(性别)上的不同,
而同样的,
e
k
i
n
g
−
e
q
u
e
e
n
=
[
−
2
0
0
0
]
e_{king}-e_{queen}=\left [ \begin{matrix} -2\\ 0\\ 0\\ 0\\ \end{matrix} \right ]
eking−equeen=
−2000
,说明king和queen也同样只是Gender上有差异。
注意到
e
m
a
n
−
e
w
o
m
a
n
=
e
k
i
n
g
−
e
q
u
e
e
n
e_{man}-e_{woman}=e_{king}-e_{queen}
eman−ewoman=eking−equeen,
对于更加一般化的问题
e
m
a
n
−
e
w
o
m
a
n
=
e
k
i
n
g
−
e
w
e_{man}-e_{woman}=e_{king}-e_{w}
eman−ewoman=eking−ew, 寻找
w
w
w是
e
k
i
n
g
e_{king}
eking对应的哪个单词,
可以考虑比较
e
w
e_w
ew与
e
m
a
n
−
e
w
o
m
a
n
+
e
k
i
n
g
e_{man}-e_{woman}+e_{king}
eman−ewoman+eking的余弦相似度,
记为
s
i
m
(
e
w
,
e
m
a
n
−
e
w
o
m
a
n
+
e
k
i
n
g
)
sim(e_w,e_{man}-e_{woman}+e_{king})
sim(ew,eman−ewoman+eking),其中
s
i
m
(
u
,
v
)
=
u
T
v
∣
∣
u
∣
∣
2
∣
∣
v
∣
∣
2
sim(u,v)=\frac{u^Tv}{||u||_2||v||_2}
sim(u,v)=∣∣u∣∣2∣∣v∣∣2uTv (L2范数,即向量模长)
(分子是内积,分母是模长,即结果是两个向量的夹角余弦值,值越大,夹角越小,越相似。)
嵌入矩阵
学习一个嵌入矩阵
E
E
E,当
E
E
E乘以词向量
o
i
o_i
oi可以得到对应的嵌入向量
e
i
e_i
ei。
(词向量只有0和1,相当于提取出了矩阵中对应的一列)
Word2Vec算法(常用)
skip-grams模型(抽取上下文与目标词配对,预测后面可能的词汇)
只需要输入上下文词
t
t
t,就可以推测目标词
t
t
t。
对于上下文词
c
c
c与目标词
t
t
t,我们得到
e
c
e_{c}
ec后将其输入
s
o
f
t
m
a
x
softmax
softmax单元,并输出
y
^
\hat{y}
y^。
其中softmax单元中,c与t是配对的概率
y
^
=
e
θ
t
T
e
c
∑
θ
j
T
e
c
\hat{y}=\frac{e^{\theta_{t}^{T}e_{c}}}{\sum{\theta_{j}^{T}e_{c}}}
y^=∑θjTeceθtTec(
θ
t
\theta_{t}
θt为配对概率向量参数)
L
(
y
^
,
y
)
=
−
∑
y
i
l
o
g
y
i
^
\mathscr{L}(\hat{y},y)=-\sum{y_{i}log{\hat{y_i}}}
L(y^,y)=−∑yilogyi^,
其中
y
y
y是一个独热编码向量,而
y
^
\hat{y}
y^是一个包含全字典中单词配对可能概率的向量。
分级softmax分类器
因为配对概率需要遍历全部的单词来计算概率,因此速度上不够优秀。
可以使用分级softmax的分类器,其内部结构类似树形,把常用的词汇放在高层,不常用的放在底层。
并非直接判断出归于哪一类,而是逐级二分确定类别。(类似二分查找)
负采样算法
对于一个上下文
c
c
c先寻找一个与之匹配的目标词
t
t
t,记为1作为正样本。
再随机寻找
k
k
k个词
t
′
t'
t′,记为0作为负样本。(即使随机的词真的与
c
c
c有关联也要记为0)
(**数据集越小,
k
k
k越大。**对于小数据集,
k
=
5
k=5
k=5 ~
20
20
20,对于大数据集则
k
=
2
k=2
k=2 ~
5
5
5)
y
^
=
σ
(
θ
t
T
e
c
)
\hat{y}=\sigma(\theta_{t}^{T}e_{c})
y^=σ(θtTec)
GloVe 词向量算法(词频统计)
定义
X
i
j
X_{ij}
Xij为单词
i
i
i在单词
j
j
j中出现的次数,易知
X
i
j
=
X
j
i
X_{ij}=X_{ji}
Xij=Xji
因此,目标是最小化
∑
∑
f
(
X
i
j
)
(
θ
i
T
e
j
+
b
i
+
b
j
′
−
l
o
g
X
i
j
)
2
\sum\sum f(X_{ij})(\theta_{i}^{T}e_{j}+b_i+b_j'-logX_{ij})^2
∑∑f(Xij)(θiTej+bi+bj′−logXij)2。
其中
f
(
0
)
=
0
f(0)=0
f(0)=0(避免
l
o
g
0
log0
log0出现)
情绪分类(RNN实现)
十六、机器翻译(序列模型)
建立一个基于RNN的编码(Encoder)网络与解码(Decoder)网络
机器翻译并非随机生成结果,而是选择最有可能的文本句式使得条件概率
p
(
y
<
1
>
.
.
.
y
<
T
y
>
∣
x
)
p(y^{<1>}...y^{<T_y>}|x)
p(y<1>...y<Ty>∣x)最大化。
(不可以用贪心算法的思路去寻找,局部最优不等于整体最优!)
集束搜索(Beam Research)
对于大小为
m
m
m的字典,对于每一个单词,都有
m
m
m种不同的后继单词,建立编码网络得到可能性最高的
B
B
B(集束宽)种可能。
(当
B
=
1
B=1
B=1时,退化为贪心算法,但
B
B
B越大,维护成本也越大,通常
B
=
10
/
100
/
1000
/
3000
B=10/100/1000/3000
B=10/100/1000/3000)
与BFS/DFS算法不同的是,前者是遍历搜索寻找精确结果,而定向搜索的效率更高,但不一定保证能找到结果。
长度归一化(减少句子长短不一对结果的影响)
即使得
∏
P
(
y
<
t
>
∣
x
,
y
<
1
>
,
.
.
.
y
<
t
−
1
>
)
\prod P(y^{<t>}|x,y^{<1>},...y^{<t-1>})
∏P(y<t>∣x,y<1>,...y<t−1>)最大化
(每一个部分都是条件概率,所以其实连乘的结果为
P
(
y
<
1
>
,
.
.
.
y
<
t
>
∣
x
)
P(y^{<1>},...y^{<t>}|x)
P(y<1>,...y<t>∣x),即每一个单词都正确的概率)
为了计算方便,取对数,转化为使得
∑
l
o
g
P
(
y
<
t
>
∣
x
,
y
<
1
>
,
.
.
.
y
<
t
−
1
>
)
\sum logP(y^{<t>}|x,y^{<1>},...y^{<t-1>})
∑logP(y<t>∣x,y<1>,...y<t−1>)最大化。
(注意到概率都是0~1之间,因此log的值是负数,值越大,结果越大)
归一化,有
1
T
y
α
∑
l
o
g
P
(
y
<
t
>
∣
x
,
y
<
1
>
,
.
.
.
y
<
t
−
1
>
)
\frac{1}{T_y^{\alpha}}\sum logP(y^{<t>}|x,y^{<1>},...y^{<t-1>})
Tyα1∑logP(y<t>∣x,y<1>,...y<t−1>),(
α
\alpha
α表示归一化程度,当
α
=
0
\alpha=0
α=0时表示完全不归一化,
α
=
1
\alpha=1
α=1时表示归一化,通常
α
=
0.7
\alpha=0.7
α=0.7)
错误分析排查
假设一个句子,人工翻译的正确率是 P ( y ∗ ∣ x ) P(y^{*}|x) P(y∗∣x),跑出来的结果是 P ( y ^ ∣ x ) P(\hat{y}|x) P(y^∣x)。
- 当 P ( y ∗ ∣ x ) > P ( y ^ ∣ x ) P(y^{*}|x)>P(\hat{y}|x) P(y∗∣x)>P(y^∣x)但神经网络选择了后者时,说明集束搜索出现了问题。
- 当 P ( y ∗ ∣ x ) ≤ P ( y ^ ∣ x ) P(y^{*}|x)\leq P(\hat{y}|x) P(y∗∣x)≤P(y^∣x)但人工翻译的效果更好,说明RNN出现了问题。
Bleu得分(双语评估替补,衡量机器翻译的指标)
一对相邻单词(2元相邻组)下的Bleu得分
对于一个需要翻译的句子,我们给出若干个参考答案(Reference),记录各种相邻单词对的出现次数
C
o
u
n
t
c
l
i
p
Count_{clip}
Countclip。
长度为
m
m
m的句子,我们两两寻找相邻单词对,共有
n
−
1
n-1
n−1对,记录各种相邻单词对的出现次数
C
o
u
n
t
Count
Count。
Bleu得分=
C
o
u
n
t
c
l
i
p
C
o
u
n
t
\frac{Count_{clip}}{Count}
CountCountclip(见下例)
推广到n元相邻单词
假设
p
n
p_n
pn是某个句子的n元相邻单词的Bleu得分,
则合并Bleu得分=
B
P
∗
e
1
k
∑
i
=
1
k
p
i
BP*e^{\frac{1}{k}\sum^{k}_{i=1}p_i}
BP∗ek1∑i=1kpi
(BP为短句惩罚,把比参考句子短的翻译增加偏小的权值)
B
P
=
{
1
,
机器翻译的句子长度大于参考句子长度
e
1
−
机器翻译句子长度
参考句子长度
,
其他
BP=\begin{cases} 1,&\text 机器翻译的句子长度大于参考句子长度\\ e^{\frac{1-机器翻译句子长度}{参考句子长度}},&\text 其他 \\ \end{cases}
BP={1,e参考句子长度1−机器翻译句子长度,机器翻译的句子长度大于参考句子长度其他
注意力模型(只让神经网络注意前面部分的句子,时间复杂度O(n^3))
底层为一个双向RNN,有正向和反向的激活
a
<
t
>
a^{<t>}
a<t>,为每一个单词计算注意力权重
α
<
t
,
t
′
>
\alpha^{<t,t'>}
α<t,t′>(生成第
t
t
t个单词需要对原文第
t
′
t'
t′个单词多少的注意力权重,且
∑
t
′
α
<
t
,
t
′
>
=
1
\sum_{t'}{\alpha^{<t,t'>}}=1
∑t′α<t,t′>=1)
顶层为一个多对多结构的RNN,其中激活函数
c
<
t
>
=
∑
t
′
α
<
t
,
t
′
>
∗
a
<
t
′
>
c^{<t>}=\sum_{t'}{\alpha^{<t,t'>}*a^{<t'>}}
c<t>=∑t′α<t,t′>∗a<t′>
(即对于第
t
t
t个单词,所有单词乘以其注意力权重综合得到结果)
利用Softmax,我们令
α
<
t
,
t
′
>
=
e
x
p
(
e
<
t
,
t
′
>
)
∑
e
x
p
(
e
<
t
,
t
′
>
)
\alpha^{<t,t'>}=\frac{exp(e^{<t,t'>})}{\sum exp(e^{<t,t'>})}
α<t,t′>=∑exp(e<t,t′>)exp(e<t,t′>)
其中
e
<
t
,
t
′
>
e^{<t,t'>}
e<t,t′>是通过神经网络学习得到的参数,通过
s
<
t
−
1
>
s^{<t-1>}
s<t−1>与
a
<
t
′
>
a^{<t'>}
a<t′>共同学习得到。
语音识别
CTC损失函数
由于识别系统是每隔一个时间步/time step去识别语音内容的,因此会有许多重复的字符。
如“the”变成"tttt___h_eee",不同字母中间用特殊的空白符间隔(此处用下划线表示,并非普通的空格)把两个特殊空白符之间重复的字符合并后删除所有空白符。
触发字检测(通过固定单词触发设备)
在RNN中,把对应的序列标记为1,其他的标记为0