主要是记录网易云课堂上的网络课序列模型的笔记
date | version | comments |
---|---|---|
2019/10/04 | V0.1 | Init |
循环序列模型
模型基础
序列模型就是使用序列数据的模型,所谓序列数据可以理解为一维时间信号等,常见应用于:
场景 | 输入 | 输出 |
---|---|---|
语言识别 | 语音信号 | 识别的文本 |
音乐生成 | (空) | 一段音符 |
语句分类(电影打分场景) | 一段评论 | 评分 |
DNA片段 | 片段 | 识别片段的信息 |
机器翻译 | 英语 | 德语 |
视频动作识别 | 分帧的视频 | 识别动作,如跑步 |
名字识别 | 一段文本 | 句子中的姓名 |
序列模型与图片有一个很大的不同是,序列的长度可能是不一样的,如找一个句子中的名字,每个句子的长度都是不一样的,所以使用常规的输入方式是不可以的,有一种方式是对输入的每个元素进行枚举的one-hot处理,比如在NPL中,假设有一个词典是10000个字,那么这个字的输入就用他的位置信息的one-hot表达,如apple在这个词典中是101个词,那么
x
a
p
p
l
e
=
[
0
,
0
,
0...0
,
1
,
0
,
0
,
.
.
.
,
0
]
x_{apple}=[0,0,0...0,1,0,0,...,0]
xapple=[0,0,0...0,1,0,0,...,0],1前面有100个0。这样,送入一个词的输入长度就是一样的,假设有
T
x
T_x
Tx个词,就相当于是一个
T
x
T_x
Tx的batch。
那么简单一点,把输入的x在一个方向上堆叠,或者一起送入网络训练,比方这样:
输入
x
<
t
>
x^{<t>}
x<t>在经过网络处理后,输出为
y
<
t
>
y^{<t>}
y<t>,这样有2个问题:
- 输入参数非常多,一个x是10000维的,假设第一层神经元个数为100个就是100万个参数了,参数没有信息共享。
- 每次的样本的输入/输出的个数不同。
所以需要更好的网络——循环神经网络。
RNN的网络结构如下:
第一个元素的输入经过运算得到输出,然后将一个次的激活值与第二个元素的输入一起计算第二个元素的输出,这样将前面的信息利用起来了。
a
<
0
>
a^{<0>}
a<0>通常就是一个零向量,进一步地,将权重表示出来,就可以看到权重共享的概念了,
简单说明一下,
W
a
x
W_{ax}
Wax表示这个权重矩阵会和X做运算,得到的输出为a
W
a
a
W_{aa}
Waa表示这个权重矩阵会和a做运算,得到的输出为a
W
y
a
W_{ya}
Wya表示这个权重矩阵会和a做运算,得到的输出为y
对于第t个输入有:
a
<
t
>
=
g
1
(
W
a
x
X
<
t
>
+
W
a
a
a
<
t
−
1
>
+
b
a
)
y
^
<
t
>
=
g
2
(
W
y
a
a
<
t
>
+
b
y
)
a^{<t>}=g_1(W_{ax}X^{<t>}+W_{aa}a^{<t-1>}+b_a)\\\hat y^{<t>}=g_2(W_{ya}a^{<t>}+b_y)
a<t>=g1(WaxX<t>+Waaa<t−1>+ba)y^<t>=g2(Wyaa<t>+by)激活函数
g
1
g_1
g1通常为tanh或ReLU,
g
2
g_2
g2通常为sigmoid等。对于其中一个RNN元来说,就是:
进一步地,为了数学表达式方便书写,使得:
W
a
x
X
<
t
>
+
W
a
a
a
<
t
−
1
>
=
W
a
[
a
<
t
−
1
>
,
x
<
t
>
]
=
[
W
a
a
W
a
x
]
[
a
<
t
−
1
>
x
<
t
>
]
W_{ax}X^{<t>}+W_{aa}a^{<t-1>}=W_a[a^{<t-1>},x^{<t>}]=\lbrack\begin{array}{cc}W_{aa}&W_{ax}\end{array}\rbrack\begin{bmatrix}a^{<t-1>}\\x^{<t>}\end{bmatrix}
WaxX<t>+Waaa<t−1>=Wa[a<t−1>,x<t>]=[WaaWax][a<t−1>x<t>]所以:
a
<
t
>
=
g
1
(
W
a
[
a
<
t
−
1
>
,
x
<
t
>
]
+
b
a
)
y
^
<
t
>
=
g
2
(
W
y
a
a
<
t
>
+
b
y
)
a^{<t>}=g_1(W_a[a^{<t-1>},x^{<t>}]+b_a)\\\hat y^{<t>}=g_2(W_{ya}a^{<t>}+b_y)
a<t>=g1(Wa[a<t−1>,x<t>]+ba)y^<t>=g2(Wyaa<t>+by)假设一共有
T
x
T_x
Tx个输入元素,输出个数为
T
y
=
T
x
T_y=T_x
Ty=Tx,损失函数的表达式设定为交叉熵函数,那么
L
<
t
>
=
−
y
<
t
>
l
o
g
y
^
<
t
>
+
(
1
−
y
<
t
>
)
l
o
g
(
1
−
y
^
<
t
>
)
L^{<t>}=-y^{<t>}log\hat y^{<t>}+(1-y^{<t>})log(1-\hat y^{<t>})
L<t>=−y<t>logy^<t>+(1−y<t>)log(1−y^<t>)整个输入的损失函数为:
L
(
y
^
,
y
)
=
∑
t
L
<
t
>
(
y
^
<
t
>
,
y
<
t
>
)
L(\hat y,y)=\sum\limits_t{L^{<t>}(\hat y^{<t>},y^{<t>})}
L(y^,y)=t∑L<t>(y^<t>,y<t>)反向传播过程也比较好理解了。
除了这样的
T
x
=
T
y
T_x=T_y
Tx=Ty的RNN模型以外,还有:
语言模型和序列生成
一个句子有长有短,所以使用一般的神经网络结构不适用的。假定模型字典为10000个词,并且包含UNK表示不在字典中的词,EOS表示句子结尾,那么就是10002x1个元素的的向量表示一个单词,则个词的index在这个字典中的这个位置表示为1,其他位置均为0。
使用RNN构建语言模型:
- 训练集:一个很大的语言文本语料库;
- Tokenize:将句子使用字典库标记化;
- 其中,未出现在字典库中的词使用“UNK”来表示;
- 第一步:使用零向量对输出进行预测,即预测第一个单词是某个单词的可能性;
- 第二步:通过前面的输入,逐步预测后面一个单词出现的概率;
- 训练网络:使用softmax损失函数计算损失,对网络进行参数更新,提升语言模型的准确率。
序列生成模型在第一个输入时候直接输入一个0向量,然后计算各个单词出现的概率,然后将第一个真实结果作为
X
<
2
>
=
y
<
1
>
X^{<2>}=y^{<1>}
X<2>=y<1>进行第二次运算,得到的结果是
y
^
<
2
>
\hat y^{<2>}
y^<2>为在第一个词准确的情况下的条件概率。。。。。。继续进行后面的词的条件概率计算。假设整个句子只有3个词,那么这个句子的概率可以表示为:
P
(
y
<
1
>
,
y
<
2
>
,
y
<
3
>
)
=
P
(
y
<
1
>
)
P
(
y
<
2
>
∣
y
<
1
>
)
P
(
y
<
3
>
∣
y
<
1
>
,
y
<
2
>
)
P(y^{<1>},y^{<2>},y^{<3>})=P(y^{<1>})P(y^{<2>}|y^{<1>})P(y^{<3>}|y^{<1>},y^{<2>})
P(y<1>,y<2>,y<3>)=P(y<1>)P(y<2>∣y<1>)P(y<3>∣y<1>,y<2>)
如果要进行随机序列生成的话,那么在第一个0向量输入以后,在输出中随机选择一个词进行后续运算这叫新序列采样(在输出层的激活函数使用softmax)。
梯度消失问题
假设有一个句子为The cat, which eat two fishes, was full. 发现主语与谓语之间有好几个单词的距离,但是RNN的输入是一个单词一个RNN cell,导致了间隔开了好几个RNN cell,由于梯度消失问题,RNN网络不擅长处理这样的信息。有了门循环控制单元Gated Recurrent Unit(GRU),LSTM等。
GRU
GRU模型在一般的序列模型上还有一个记忆单元,在这里使用C表示,有如下模型[1,2],图中蓝色的是更新(update)模块:
模型有以下计算:
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
)
c
<
t
>
=
Γ
u
∗
c
~
<
t
>
+
(
1
−
Γ
u
)
∗
c
<
t
−
1
>
\widetilde c^{<t>}=tanh(W_c[c^{<t-1>},x^{<t>}]+b_c)\\{\Gamma _u}=\sigma (W_{u}[c^{<t-1>}, x^{<t>}] + b_{u})\\c^{<t>} = {\Gamma _u}*\widetilde c^{<t>} + (1-{\Gamma _u})*c^{<t-1>}
c
<t>=tanh(Wc[c<t−1>,x<t>]+bc)Γu=σ(Wu[c<t−1>,x<t>]+bu)c<t>=Γu∗c
<t>+(1−Γu)∗c<t−1>
- c < t > = a < t > c^{<t>}=a^{<t>} c<t>=a<t>,实际上记忆细胞输出是在 t t t时间步上的激活值 a a a;
- c ~ < t > = t a n h ( W c [ c < t − 1 > , x < t > ] + b c ) \widetilde c^{<t>}=tanh(W_c[c^{<t-1>},x^{<t>}]+b_c) c <t>=tanh(Wc[c<t−1>,x<t>]+bc),在每步上给定一个候选值 c ~ < t > \widetilde c^{<t>} c <t>,用于代替原来的记忆细胞 c < t > c^{<t>} c<t>;
- Γ 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),记忆细胞的更新规则,门控值处于0-1之间,根据跟新公式能够有效地缓解梯度消失的问题;
- 其中, c < t > , c ~ < t > , Γ u c^{<t>},\widetilde c^{<t>}, \Gamma_u c<t>,c <t>,Γu有相同的维度。
以上是一个简化的GRU,一个完整的GRU可以表示为: c ~ < t > = tanh ( W c [ Γ r ∗ c < t − 1 > , x < t > ] + b c ) Γ u = σ ( W u [ c < t − 1 > , x < t > ] + b u ) Γ r = σ ( W r [ c < t − 1 > , x < t > ] + b r ) c < t > = Γ u ∗ c ~ < t > + ( 1 − Γ u ) ∗ c < t − 1 > c < t > = a < t > \widetilde c^{<t>} = \tanh (W_{c}[{\Gamma _r}*c^{<t-1>}, x^{<t>}] + b_{c}) \\ {\Gamma _u}=\sigma (W_{u}[c^{<t-1>}, x^{<t>}] + b_{u}) \\ {\Gamma _r}=\sigma (W_{r}[c^{<t-1>}, x^{<t>}] + b_{r}) \\ c^{<t>} = {\Gamma _u}*\widetilde c^{<t>} + (1-{\Gamma _u})*c^{<t-1>} \\ c^{<t>} = a^{<t>} c <t>=tanh(Wc[Γr∗c<t−1>,x<t>]+bc)Γu=σ(Wu[c<t−1>,x<t>]+bu)Γr=σ(Wr[c<t−1>,x<t>]+br)c<t>=Γu∗c <t>+(1−Γu)∗c<t−1>c<t>=a<t>
长短时记忆模型(Long Short Time Memery, LTSM)
在比较理解GRU的计算过程与图的基础上[3],看LTSM是比较简单的了,GRU有两个门,LSTM有三个门,一个更新门(update) ,一个遗忘门(forget),一个输出门(output)。
Γ
f
\Gamma_f
Γf为遗忘门,
Γ
u
\Gamma_u
Γu为更新门,
Γ
o
\Gamma_o
Γo为输出门,LSTM的数学描述为:
c
~
<
t
>
=
tanh
(
W
c
[
a
<
t
−
1
>
,
x
<
t
>
]
+
b
c
)
Γ
u
=
σ
(
W
u
[
a
<
t
−
1
>
,
x
<
t
>
]
+
b
u
)
Γ
f
=
σ
(
W
f
[
a
<
t
−
1
>
,
x
<
t
>
]
+
b
f
)
Γ
o
=
σ
(
W
o
[
a
<
t
−
1
>
,
x
<
t
>
]
+
b
o
)
c
<
t
>
=
Γ
u
∗
c
~
<
t
>
+
Γ
f
∗
c
<
t
−
1
>
a
<
t
>
=
Γ
o
∗
tanh
c
<
t
>
\widetilde c^{<t>} = \tanh (W_{c}[a^{<t-1>}, x^{<t>}] + b_{c}) \\ {\Gamma _u}=\sigma (W_{u}[a^{<t-1>}, x^{<t>}] + b_{u}) \\ {\Gamma _f}=\sigma (W_{f}[a^{<t-1>}, x^{<t>}] + b_{f}) \\{\Gamma _o}=\sigma (W_{o}[a^{<t-1>}, x^{<t>}] + b_{o}) \\ c^{<t>} = {\Gamma _u}*\widetilde c^{<t>} + {\Gamma _f}*c^{<t-1>} \\ a^{<t>} = {\Gamma _o}*\tanh c^{<t>}
c
<t>=tanh(Wc[a<t−1>,x<t>]+bc)Γu=σ(Wu[a<t−1>,x<t>]+bu)Γf=σ(Wf[a<t−1>,x<t>]+bf)Γo=σ(Wo[a<t−1>,x<t>]+bo)c<t>=Γu∗c
<t>+Γf∗c<t−1>a<t>=Γo∗tanhc<t>
a
<
t
−
1
>
,
x
<
t
>
a^{<t-1>},x^{<t>}
a<t−1>,x<t>参与了所有的门的运算过程,
a
<
t
−
1
>
a^{<t-1>}
a<t−1>将前面的信息传递下去,
x
<
t
>
x^{<t>}
x<t>的链接则被称为偷窥孔连接。
将多个LSTM模块串联起来这就是LSTM网络:
GRU有两个门,计算比较容易,所以GRU更加容易构建一个大型的网络,而LSTM有三个门,更加复杂,但是使用更加频繁。
双向循环神经网络(Bidirectional RNN)
不管是GRU还是LSTM,都只有前面的信息向后传递,而没有向前面传递的过程,需要向前传递就需要使用到BRNN,所谓的BRNN如下图,在向后传递(A)的同时,还有一个A’是向前传递的,在正常的前向传播计算时候,A’计算的是反向传播过程,而A的反向传播过程才是A’的前向传播过程,这就需首先知道输入的总长度。
输出的表达式为:
y
^
<
t
>
=
g
(
W
y
[
A
<
t
>
,
A
′
<
t
>
]
+
b
y
)
\hat y^{<t>}=g(W_y[A^{<t>},A'^{<t>}]+b_y)
y^<t>=g(Wy[A<t>,A′<t>]+by)其中A和A’可以是GRU也可以是LSTM。
深度RNN模型
之前的模型都是在一个输入只有一个cell,在时间的维度上有多个cell,所谓的深度RNN是在一个输入也有多个cell。
深度RNN模型:
自然语言处理(Natural Language Processing, NLP)
词嵌入
使用One-hot的方式表示词语的位置可以解决输入不等长的问题,也可以共享权重,但是没有描述词语与词语之间的关系,如Man-Woman,是一个相对的概念,King-Queen是与之对应的概念,有一个逻辑题:已知Man=Woman,请问King=?,这里就是Queen。RNN解决不了这个问题,所以引入了词嵌入(Word Embedding)。除了使用One-hot的方式表示词语,还需要使用某些特征来表示这个词的某些属性,例如下表中,使用Gender,Royal,Age等多个特征来表示词语:
Man | Woman | King | Queen | Apple | Orange | |
---|---|---|---|---|---|---|
Gender | -1 | 1 | -0.95 | 0.97 | 0.01 | 0.02 |
Royal | 0.01 | 0.02 | 0.93 | 0.95 | -0.01 | 0.00 |
… | … | … | … | … | … | … |
Age | 0.02 | 0.05 | 0.76 | 0.45 | 0.01 | 0.02 |
在这个表格中只有几个特征,在本文中后续都认为是有300个特征。这300个特征并没有非常严格的含义,是可以自动学习的参数矩阵。
假设有两个句子为:
– | – | – | – | – | – | – |
---|---|---|---|---|---|---|
S1: | Sally | Johnson | is | an | orange | farmer |
S2: | Robert | Lin | is | an | apple | _____ |
在句子一中,某人是什么职业,在第二句中也是类似的表达,但是在One-hot的表达中,任何两个代表的向量内积都是零。根本不能得到他们是“类似”表达的信息。所以不知道横线处是什么。
词嵌入的学习可以使用网络上的大量的文本信息训练(或者下载预训练的模型),然后迁移学习。
在谈下上面的逻辑题:已知Man=Woman,请问King=?,这里就是找一中算法自动推导这个结论,如下表中的特性,
e
m
a
n
=
[
−
1
,
0.01
,
0.03
,
0.09
]
T
e_{man}=[-1,0.01,0.03,0.09]^T
eman=[−1,0.01,0.03,0.09]T ,
e
w
o
m
a
n
=
[
1
,
0.02
,
0.02
,
0.01
]
T
e_{woman}=[1,0.02,0.02,0.01]^T
ewoman=[1,0.02,0.02,0.01]T,那么有:
e
m
a
n
−
e
w
o
m
a
n
=
[
−
2
0
0
0
]
e_{man}-e_{woman}=\begin{bmatrix}-2\\0\\0\\0\end{bmatrix}
eman−ewoman=⎣⎢⎢⎡−2000⎦⎥⎥⎤需要找到一个词w使得
e
k
i
n
g
−
e
w
≈
e
m
a
n
−
e
w
o
m
a
n
e_{king}-e_w\approx e_{man}-e_{woman}
eking−ew≈eman−ewoman在表格中找到这个词就是Queen。
用数学语言表达就是需要找到一个w,使得sim(e_w, e_king-e_man+e_woman)
最大。其中:
s
i
m
(
u
,
v
)
=
u
T
v
∣
∣
u
∣
∣
2
∣
∣
v
∣
∣
2
(余弦相似度)
sim(u,v)=\frac{u^Tv}{||u||_2||v||_2}\tag{余弦相似度}
sim(u,v)=∣∣u∣∣2∣∣v∣∣2uTv(余弦相似度)上图中的词语与特性的矩阵就是嵌入矩阵,用符号
E
E
E表示,假设有10000个词,300个特性,那么
E
E
E就是300x10000的矩阵。需要找到第
i
t
h
i^{th}
ith个词的嵌入向量,那么就是让
E
E
E与这个词的One-hot向量做乘法运算:
e
i
=
E
⋅
O
i
e_i=E·O_i
ei=E⋅Oi 。注意
E
E
E是300x10000的,
O
i
O_i
Oi是10000x1的,所以
e
i
e_i
ei是300x1的。在Keras中,可以直接使用embedding层,而不用乘法,加快运算。
假设有个场景是有如下的一句话,需要预测后面出现的词语是什么:
– | – | – | – | – | – | – | – |
---|---|---|---|---|---|---|---|
句子: | I | want | a | glass | of | orane | _____ |
One-hot索引 | 4343 | 9665 | 1 | 3852 | 6163 | 6257 |
通过嵌入矩阵可以分别计算嵌入向量,如下图,然后将这些嵌入向量堆叠起来编程一个更大的向量,全连接-softmax输出10000的结果,就可以得到最可能的输出是什么,当然也可以不都使用,仅仅使用临近的4(超参数)个词作为全连接输入也是可以的。
Word2Vec
这部分Andrew的讲解有点难理解,结合博客理解更深入[4 ]。
Word2Vec是2013年Mikolov等提出的[5],Word2Vec中的一个重要模型是Skip-grams,假设现在有一句话,I want a glass of orange juice to go along with my cereal.在这个句子中抽取上下文与目标词配对来构造一个监督学习模型。比如抽取的上下文(Content, C)为orange,目标(Target, T)为juice等。通过输入找配对输出的模型可以是
那么softmax就是计算
p
(
t
∣
c
)
=
e
θ
t
T
e
c
∑
j
=
1
10000
e
θ
j
T
e
c
(词典为10000个词的条件下)
p(t|c)=\frac{e^{\theta_t^Te_c}}{\sum\limits_{j=1}^{10000}{e^{\theta_j^Te_c}}}\tag{词典为10000个词的条件下}
p(t∣c)=j=1∑10000eθjTeceθtTec(词典为10000个词的条件下)
θ
t
\theta_t
θt是输出t相关的参数。损失函数可以表示为:
L
(
y
^
,
y
)
=
−
∑
j
=
1
10000
y
j
l
o
g
y
^
j
(yj为10000x1的向量)
L(\hat y,y)=-\sum\limits_{j=1}^{10000}{y_jlog\hat y_j}\tag{yj为10000x1的向量}
L(y^,y)=−j=1∑10000yjlogy^j(yj为10000x1的向量)计算softmax需要计算10000加法以及之前的指数运算,计算量相当大。
减少计算量的一个比较好的办法是Hierarchical Softmax[6],层次Softmax的方法最早由Bengio在05年引入到语言模型中。它的基本思想是将复杂的归一化概率分解为一系列条件概率乘积的形式:
p
(
v
∣
c
o
n
t
e
x
t
)
=
∏
i
=
1
m
p
(
b
i
(
v
)
∣
b
1
(
v
)
,
.
.
.
,
b
i
−
1
(
v
)
,
c
o
n
t
e
x
t
)
p(v|context)=\prod_{i=1}^m{p(b_i(v)|b_1(v), ..., b_{i-1}(v), context)}
p(v∣context)=i=1∏mp(bi(v)∣b1(v),...,bi−1(v),context)其中,每一层条件概率对应一个二分类问题,可以通过一个简单的逻辑回归函数去拟合。这样,我们将对V个词的概率归一化问题,转化成了对logV个词的概率拟合问题。
除了Hierarchical Softmax,还有一种解决Softmax计算量大的方法就是负采样(Negative Sampling)[7]。负采样的思想最初来源于一种叫做Noise-Contrastive Estimation的算法,原本是为了解决那些无法归一化的概率模型的参数预估问题。与改造模型输出概率的Hierarchical Softmax算法不同,NCE算法改造的是模型的似然函数。
所谓负采样,就是首先在语句中遭到正确的content/target对,比如orange/juice,然后在语料中随机找一些词作为target(假的)。比如:
Content | Target | y |
---|---|---|
orange | juice | 1 |
orange | book | 0 |
orange | people | 0 |
orange | Jack | 0 |
orange | my | 0 |
总是一个正样本,有k个负样本。通常如果数据较多,k取2-5,数据量少时候取5-20。对于一个二分类模型来说,可以用下式估计y=1的输出 P ( y = 1 ∣ c , t ) = σ ( θ t T e c ) P(y=1|c,t)=\sigma(\theta_t^Te_c) P(y=1∣c,t)=σ(θtTec)
GloVe(global vector for word representation)[8]
在前面中使用C表示上下文,使用T表示目标,在这里可以使用
X
i
j
X_{ij}
Xij表示在上下文j附近出现i的次数。
X
i
j
X_{ij}
Xij也就是
X
t
c
X_{tc}
Xtc。对于上下文取前后N个词的情况下,
X
i
j
=
X
j
i
X_{ij}=X_{ji}
Xij=Xji。可以使用
(
θ
i
T
e
j
−
log
X
i
j
)
2
(\theta_i^Te_j-\log X_{ij})^2
(θiTej−logXij)2表示上下文与目标临近的情况。将
i
,
j
i,j
i,j遍历就知道所有词语组合的临近情况。但是当
X
i
j
=
0
X_{ij}=0
Xij=0的时候,
log
X
i
j
\log X_{ij}
logXij为负无穷,是不合适的。考虑到
lim
x
→
0
+
x
log
x
=
0
\underset{x\rightarrow0^+}{\lim\;}x\log x=0
x→0+limxlogx=0,那么加一个权重
f
(
X
i
j
)
f(X_{ij})
f(Xij),并且当
X
i
j
=
0
X_{ij}=0
Xij=0时候,
f
(
X
i
j
)
=
0
f(X_{ij})=0
f(Xij)=0,另外还考虑到词出现的频度问题。
m
i
n
i
m
i
z
e
∑
i
=
1
10000
∑
j
=
1
10000
f
(
X
i
j
)
(
θ
i
T
e
j
+
b
i
−
b
j
−
log
X
i
j
)
2
minimize\sum\limits_{i=1}^{10000}\sum\limits_{j=1}^{10000}f(X_{ij})(\theta_i^Te_j+b_i-b_j-\log X_{ij})^2
minimizei=1∑10000j=1∑10000f(Xij)(θiTej+bi−bj−logXij)2
可以进一步参考:理解GloVe模型(Global vectors for word representation)
情感分类
对于情感分类的应用场景,例如电影评价-评分的匹配等,可能数据量不多,直接使用RNN来做这样的模型效果可能不佳。可以考虑使用词嵌入的方式优化这样的模型。例如有一个评价是 The moive is excellent. 首先将所有的词转化One-hot的 o x o_x ox,与嵌入矩阵相乘得到嵌入向量 e x e_x ex,将所有的嵌入向量做平均或者求和后使用softmax做一个简单的多分类问题就可以了。由于使用了词嵌入,得到的词语与词语之间的相近信息,这样在样本量不大时候也能得到比较好的结果。
这样的模型不能对“Completely lacking in good taste, good service, and good ambience.”进行准确的判断,因为这个句子中有三个good,但是前面是否定状态,可就是说还是需要考虑一定的语序问题。可以使用RNN+词嵌入的方式。如下图的处理方式:
序列模型和注意力机制
首先再来看下基础模型:
输入 | x < 1 > x^{<1>} x<1> | x < 2 > x^{<2>} x<2> | x < 3 > x^{<3>} x<3> | x < 4 > x^{<4>} x<4> | x < 5 > x^{<5>} x<5> | x < 6 > x^{<6>} x<6> |
---|---|---|---|---|---|---|
Jane | visite | l’Afrique | en | septembre | ||
输出 | y < 1 > y^{<1>} y<1> | y < 2 > y^{<2>} y<2> | y < 3 > y^{<3>} y<3> | y < 4 > y^{<4>} y<4> | y < 5 > y^{<5>} y<5> | y < 6 > y^{<6>} y<6> |
Jane | is | visiting | Africa | in | September |
首先来使用Encode-Decoder的方式来处理这个信息,在Encoder阶段,输入需要处理的信息,在Decoder阶段将输出表达出来[9,10]。
Encoder就是这样的模型,这个方框可以是RNN,GRU或者LSTM都可以,输出的是一个向量,这个向量就表示了输入的信息:
所谓的Decoder其实就是一个One-Many的序列模型,不过这里的输入
a
<
0
>
a^{<0>}
a<0>不再是全零向量,而是Encoder的输出:
不仅文本可以使用Encoder,图片也可以,例如使用AlexNet,图片可以被会这样表达,去掉最后的softmax层,将4096的向量作为Decoder的输入向量,一样可以使用一个序列表示一张图片。
seq2seq
上述的机器翻译模型可以表示为,绿色部分为Encoder,紫色部分为Decoder:
Decoder其实就是第一周的语言模型。所以可以把这样的机器翻译模型叫做条件语言模型。在输入语句的情况下,找到
P
(
y
<
1
>
,
.
.
.
,
y
<
T
y
>
∣
x
)
P(y^{<1>},...,y^{<T_y>}|x)
P(y<1>,...,y<Ty>∣x)最大的输出。 首先了解一下贪心搜索(greedy search),在输入
x
x
x的情况下,首先找
P
(
y
^
<
1
>
∣
x
)
P(\hat y^{<1>}|x)
P(y^<1>∣x)最大的输出,然后找
P
(
y
^
<
2
>
∣
y
^
<
1
>
,
x
)
P(\hat y^{<2>}|\hat y^{<1>},x)
P(y^<2>∣y^<1>,x)。。。但是其实机器翻译是为了让在
x
x
x的条件下,
P
(
y
<
1
>
,
.
.
.
,
y
<
T
y
>
∣
x
)
P(y^{<1>},...,y^{<T_y>}|x)
P(y<1>,...,y<Ty>∣x)整体最大。实际上的效果,贪心搜索的效果并不是那么好。
假设词典是10000个词,一个句子有10个单词,那么所有的组合就有100000个,这样的计算量太大了不适合实际使用,所以就有了集束搜索(Beam Search)。
集束搜索(Beam Search)
集束搜索不将所有组合都进行计算输出,而是选择部分最可能的输出,可以大大减少计算量。假设超参数 B = 3 B=3 B=3。
- Step1 : 首先计算字典中最可能输出的 B B B个词(3个),假设分别是 y ^ 1 < 1 > = i n , y ^ 2 < 1 > = j a n e , y ^ 3 < 1 > = s e p t e m b e r \hat y_1^{<1>}=in,\hat y_2^{<1>}=jane, \hat y_3^{<1>}=september y^1<1>=in,y^2<1>=jane,y^3<1>=september,就可以分别计算出三个 P ( y < 1 > ∣ x ) P(y^{<1>}|x) P(y<1>∣x)
- Step2 : 分别对B个已经有的第一个词的输出进行下一个单词的计算,这样由于每个都能有10000个,所以这里计算的就有30000个结果出来。那么计算 P ( y < 1 > , y < 2 > ∣ x ) = P ( y < 1 > ∣ x ) P ( y < 2 > ∣ y < 1 > , x ) P(y^{<1>},y^{<2>}|x)=P(y^{<1>}|x)P(y^{<2>}|y^{<1>},x) P(y<1>,y<2>∣x)=P(y<1>∣x)P(y<2>∣y<1>,x) P ( y < 1 > ∣ x ) P(y^{<1>}|x) P(y<1>∣x)在Step1中可以得到, P ( y < 2 > ∣ y < 1 > , x ) P(y^{<2>}|y^{<1>},x) P(y<2>∣y<1>,x)在Step2中可以计算得到。继续选择 P ( y < 1 > , y < 2 > ∣ x ) P(y^{<1>},y^{<2>}|x) P(y<1>,y<2>∣x)最大的B个进行后续单词的计算。
可以看到整个句子的最大条件概率可以表示为:
a
r
g
m
a
x
y
∏
t
=
1
T
y
P
(
y
<
t
>
∣
x
,
y
<
1
>
,
.
.
.
,
y
<
t
−
1
>
)
\underset y{argmax}\prod_{t=1}^{T_y}P(y^{<t>}\vert x,y^{<1>},...,y^{<t-1>})
yargmaxt=1∏TyP(y<t>∣x,y<1>,...,y<t−1>)但是由于每个概率都是一个比较小的数,做连乘积后将是一个非常小的数,甚至计算机可能无法准确存储这样的数(保留足够精度)。所以可以用对数的方式来算,对连乘积取对数就是加法:
a
r
g
m
a
x
y
∑
t
=
1
T
y
log
P
(
y
<
t
>
∣
x
,
y
<
1
>
,
.
.
.
,
y
<
t
−
1
>
)
\underset y{argmax}\sum\limits_{t=1}^{T_y}\log P(y^{<t>}\vert x,y^{<1>},...,y^{<t-1>})
yargmaxt=1∑TylogP(y<t>∣x,y<1>,...,y<t−1>)不管取不取对数,由于每个因子都是小于1的,做连乘积时候肯定越来越小,那么模型就倾向于输出一个相对短的结果,这样的值更大一些。小于1的值取对数后为负数,所以也是单词越多,那么数字越小。那么不要取整个的最大了,而是进行长度归一化:
1
T
y
∑
t
=
1
T
y
log
P
(
y
<
t
>
∣
x
,
y
<
1
>
,
.
.
.
,
y
<
t
−
1
>
)
\frac1{T_y}\sum\limits_{t=1}^{T_y}\log P(y^{<t>}\vert x,y^{<1>},...,y^{<t-1>})
Ty1t=1∑TylogP(y<t>∣x,y<1>,...,y<t−1>)实际工程中可能会使用到这样的归一化过程:
1
T
y
α
∑
t
=
1
T
y
log
P
(
y
<
t
>
∣
x
,
y
<
1
>
,
.
.
.
,
y
<
t
−
1
>
)
\frac1{T_y^{\alpha}}\sum\limits_{t=1}^{T_y}\log P(y^{<t>}\vert x,y^{<1>},...,y^{<t-1>})
Tyα1t=1∑TylogP(y<t>∣x,y<1>,...,y<t−1>)其中,
α
=
0.7
\alpha=0.7
α=0.7。如果
α
=
1
\alpha=1
α=1就是完全归一化,
α
=
0
\alpha=0
α=0就是不归一化。
需要了解一下,使用集束搜索得到的结果是在一定条件下的最大值,并不是全局的最大
P
(
y
∣
x
)
P(y|x)
P(y∣x),因为并没有完全遍历所有的输出结果。
再来看下集束搜索的误差分析,有下表的结果,输入x,人工输出为
y
∗
y^*
y∗,算法输出为
y
^
\hat y
y^,那么如何评价人工与算法的误差有多少呢?
输入 | x < 1 > x^{<1>} x<1> | x < 2 > x^{<2>} x<2> | x < 3 > x^{<3>} x<3> | x < 4 > x^{<4>} x<4> | x < 5 > x^{<5>} x<5> |
---|---|---|---|---|---|
Jane | visite | l’Afrique | en | septembre | |
输出人工y* | y < 1 > y^{<1>} y<1> | y < 2 > y^{<2>} y<2> | y < 3 > y^{<3>} y<3> | y < 4 > y^{<4>} y<4> | y < 5 > y^{<5>} y<5> |
Jane | visits | Africa | in | September | |
输出算法 y ^ \hat y y^ | y < 1 > y^{<1>} y<1> | y < 2 > y^{<2>} y<2> | y < 3 > y^{<3>} y<3> | y < 4 > y^{<4>} y<4> | y < 5 > y^{<5>} y<5> |
Jane | visited | Africa | last | September |
这里可以计算两个句子的条件概率 P ( y ∗ ∣ x ) P(y^*|x) P(y∗∣x)和 P ( y ^ ∣ x ) P(\hat y|x) P(y^∣x),有2种情况:
- 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) \leqslant P(\hat y|x) P(y∗∣x)⩽P(y^∣x): y ∗ y^* y∗是更好的结果,但是RNN模型出了问题认为 P ( y ∗ ∣ x ) < P ( y ^ ∣ x ) P(y^*|x)<P(\hat y|x) P(y∗∣x)<P(y^∣x)。
那么去找若干个输入-输出对,就可以确认到底是集束搜索出现了问题还是RNN模型出了问题。如果集束搜索出现了问题比较简单的方式就是增大B,如果RNN模型的问题,那么就是正则化,增加数据集等方法改善模型。
BLEU (Bilingual Evaluation Understudy)
BLEU[11]顾名思义就是双语评价替换,假设有一个法语句子需要翻译成为英文,但是不同的人得到的翻译结果有可能是不同的,但是实际上都能清楚表达意思,这样一个数据只有一个标签就是不合适的,这样,一个机器翻译的句子可能存在多个正确的标签。
假设有一句话的翻译应该是:
ref | s |
---|---|
ref1 | the cat is on the mat. |
ref2 | there is a cat on the mat. |
machine translation | the the the the the the the. |
如果使用翻译的词语出现在句子种就认为得分的话,那么这个机器翻译的得分为
7
/
7
7/7
7/7,因为the是句子的一个词,事实上,这是非常不好的一个翻译结果,所以需要修正评分方式,修正为:对这个词的最大出现次数做限制,由于the在ref1中出现了两次,所以the的最大评分为2分,这样翻译结果的得分就是
2
/
7
2/7
2/7。
但是翻译的结果,并不是只是关心单个单词的出现,还要关心相邻单词的情况,首先是简单的2个相邻单词的情况(bigrams)。假设翻译结果现在是:
ref | s |
---|---|
ref1 | the cat is on the mat. |
ref2 | there is a cat on the mat. |
machine translation | the cat the cat on the mat. |
那么翻译的二元词组(bigram)就是[the cat, cat the, cat on, on the, the mat]。
bigrams | times | times(clipped) |
---|---|---|
the cat | 2 | 1 |
cat the | 1 | 0 |
cat on | 1 | 1 |
on the | 1 | 1 |
the mat | 1 | 1 |
times(clipped)就是在ref中出现的次数,如果有多个ref的话,那就是
m
a
x
(
r
e
f
s
)
max(refs)
max(refs)。那么二元词组的得分就是
t
i
m
e
s
(
c
l
i
p
p
e
d
)
/
t
i
m
e
s
=
4
/
6
times(clipped)/times=4/6
times(clipped)/times=4/6。
一般化来讲,使用
P
x
P_x
Px表示
x
x
x元词组的得分。其中,
x
=
1
,
2
,
3...
x=1,2,3...
x=1,2,3...。那
P
1
=
∑
u
n
i
g
r
a
m
s
C
o
u
n
t
c
l
i
p
p
e
d
(
u
n
i
g
r
a
m
s
)
∑
u
n
i
g
r
a
m
s
C
o
u
n
t
(
u
n
i
g
r
a
m
s
)
P_1=\frac{\sum\limits_{unigrams}Count_{clipped}(unigrams)}{\sum\limits_{unigrams}Count(unigrams)}
P1=unigrams∑Count(unigrams)unigrams∑Countclipped(unigrams)
unigrams表示出现的每个单词。
P
2
P_2
P2的话,表示机器翻译出现每个二元词组,以此类推。
所以:
P
n
=
∑
n
g
r
a
m
s
C
o
u
n
t
c
l
i
p
p
e
d
(
n
g
r
a
m
s
)
∑
n
g
r
a
m
s
C
o
u
n
t
(
n
g
r
a
m
s
)
P_n=\frac{\sum\limits_{ngrams}Count_{clipped}(ngrams)}{\sum\limits_{ngrams}Count(ngrams)}
Pn=ngrams∑Count(ngrams)ngrams∑Countclipped(ngrams)那么Bleu评分就是:
B
l
e
u
=
B
P
×
e
x
p
(
1
n
∑
i
=
1
n
P
i
)
(Bleu)
Bleu=BP\times exp(\frac1n\sum\limits_{i=1}^n{P_i})\tag{Bleu}
Bleu=BP×exp(n1i=1∑nPi)(Bleu)这里的BP是值简短惩罚,由于只用
P
i
P_i
Pi的平均的话,简短的输出的到的得分会更高,因为出错的概率相对低。
B
P
=
{
1
l
e
n
(
M
T
)
>
l
e
n
(
r
e
f
s
)
e
x
p
(
1
−
l
e
n
(
M
T
)
/
l
e
n
(
r
e
f
)
)
o
t
h
e
r
w
i
s
e
BP=\left\{\begin{array}{lc}1&len(MT)>len(refs)\\exp(1-len(MT)/len(ref))&otherwise\end{array}\right.
BP={1exp(1−len(MT)/len(ref))len(MT)>len(refs)otherwise
注意力模型
根据RNN模型的Encoder-Decoder的方式进行机器翻译的话,那么需要先把整个句子读完,然后转化为一个向量,输入Decoder进行解码。当句子非常长的时候,这样的翻译模型效果就会比较差,因为模型无法或者很难或者很长的信息。这就引入了注意力模型[12],注意力模型在很多领域都有较好的应用。
上图中,蓝色的是RNN模型,绿色的是注意力模型。
在进行注意力模型时,就是在上图的模型输出中在加入一层权重的概念,假设输出第一个词的时候,那么第一个输入的权重是多少
α
<
1
,
1
>
\alpha^{<1,1>}
α<1,1>,第二次的权重是多少
α
<
1
,
2
>
\alpha^{<1,2>}
α<1,2>,由相临近的N个词来决定输出,而不需要等到最后了,才输出第一个词是多少,这样更与人类的翻译过程相似。
这里使用的是一个双向的RNN模型,
为了表示方便,采用标记
a
<
t
>
′
=
(
a
<
t
>
′
→
,
a
<
t
>
′
←
)
a^{<t>'}=(\overrightarrow{a^{<t>'}},\overleftarrow{a^{<t>'}})
a<t>′=(a<t>′,a<t>′)表示前后传播的结果。
以下的流程图表示了第一个输出的处理流程,所有的输入信号经过BRNN得到的输出作为输入,并且有权重地输入到C上,来进行实际的输出。
这里有
∑
t
′
α
<
1
,
t
′
>
=
1
\sum\limits_{t'}\alpha^{<1,t'>}=1
t′∑α<1,t′>=1,并且
C
=
C
<
1
>
=
∑
t
′
α
<
1
,
t
′
>
a
<
t
′
>
C=C^{<1>}=\sum\limits_{t'}{\alpha^{<1,t'>}a^{<t'>}}
C=C<1>=t′∑α<1,t′>a<t′>,C表示上下文Content。
对于一个一般的注意力模型:
α
<
t
,
t
′
>
\alpha^{<t,t'>}
α<t,t′>就表示了
y
^
<
t
>
\hat y^{<t>}
y^<t>应该在第
t
′
t'
t′个输入时候的注意力的数量。现在的问题在于如何确定
α
<
t
,
t
′
>
\alpha^{<t,t'>}
α<t,t′>:
α
<
t
,
t
′
>
=
e
x
p
(
e
<
t
,
t
′
>
)
∑
t
′
=
1
T
x
e
x
p
(
e
<
t
,
t
′
>
)
\alpha^{<t,t'>}=\frac{exp(e^{<t,t'>})}{\sum_{t'=1}^{Tx}{exp(e^{<t,t'>})}}
α<t,t′>=∑t′=1Txexp(e<t,t′>)exp(e<t,t′>)这样做的目的是为了让
∑
t
′
α
<
t
,
t
′
>
=
1
\sum_{t'} \alpha^{<t,t'>}=1
∑t′α<t,t′>=1,其中
e
<
t
,
t
′
>
e^{<t,t'>}
e<t,t′>可以通过一个小的网络训练得到。
这样的注意力参数是
O
(
n
3
)
O(n^3)
O(n3)复杂度的,假设输入长度是
T
x
T_x
Tx,输出为
T
y
T_y
Ty,那么注意力参数就有
T
x
×
T
y
T_x\times T_y
Tx×Ty个。在机器翻译上,通常句子不很长,有时候也可以接受,在其他领域上,可能会想办法降低注意力参数的数量。
语言识别
语言识别是seq2seq的另外一个重要的应用。输入一段音频,然后得到音频里面的文字信息。语音识别的一种方式是使用注意力模型,可以做检测。
还有一种方式是采用CTC
损失函数来进行语言识别(Connectionist temporal classification)[13],CTC损失就是在每个输入上都进行输出,假设有10秒的音频,采样为100Hz,那么有1000个输入,在每个输入上都进行输出,假设这段话是Hello, deep learning.
,那么输出可能是HHH_________eee_____llll_l_____ooo_____,(space) dddddd______
这样的,把_
包围的字母都和在一起然后去判断输出是不是正确。
触发字检测(Trigger word detection)
触发字检测就是检测特殊的语言输入,比如家里有小度的,就会使用小度你好
去唤醒小度,这就是触发字检测。
一种方式是在语音模型上,在标签上,这样标注,在语言输入了特征词后的标签作为1,其他的标签作为0.如下图中,在音频中有蓝色标记的地方是有特征词输入的,输出标签设置为1,其他为0,这样去训练网络,捕获特征词。这样数据不平衡,0的输入比1的输入多很多,简单方法就是在1后面再连续做几个输出为1。
On the Properties of Neural Machine Translation: Encoder-Decoder Approaches, https://arxiv.org/abs/1409.1259 ↩︎
Empirical Evaluation of Gated Recurrent Neural Networks on Sequence Modeling, https://arxiv.org/pdf/1412.3555v1.pdf ↩︎
Long Short Time Memery, www.bioinf.jku.at/publications/older/2604.pdf ↩︎
NLP之——Word2Vec详解,https://www.cnblogs.com/guoyaohua/p/9240336.html ↩︎
Mikolov, T., Chen, K., Corrado, G., & Dean, J. (2013, January 17). Efficient Estimation of Word Representations in Vector Space. arXiv.org. ↩︎
Morin, F., & Bengio, Y. (2005). Hierarchical Probabilistic Neural Network Language Model. Aistats. ↩︎
Mnih, A., & Kavukcuoglu, K. (2013). Learning word embeddings efficiently with noise-contrastive estimation, 2265–2273. ↩︎
GloVe: Global Vectors for Word Representation, https://nlp.stanford.edu/projects/glove/ ↩︎
Sutskever I, Vinyals O, Le Q V, et al. Sequence to Sequence Learning with Neural Networks. neural information processing systems, 2014: 3104-3112. https://arxiv.org/pdf/1409.3215.pdf ↩︎
Cho, Kyunghyun, et al. "Learning Phrase Representations using RNN Encoder-Decoder for Statistical Machine Translation." arXiv: Computation and Language (2014). http://emnlp2014.org/papers/pdf/EMNLP2014179.pdf ↩︎
a Method for Automatic Evaluation of Machine Translation,https://www.aclweb.org/anthology/P02-1040.pdf ↩︎
Neural Machine Translation by Jointly Learning to Align and Translate, https://arxiv.org/pdf/1409.0473v7.pdf ↩︎
Connectionist Temporal Classification: Labelling Unsegmented Sequence Data with Recurrent Neural Networks, http://www.cs.toronto.edu/~graves/icml_2006.pdf ↩︎