开始的话:
从基础做起,不断学习,坚持不懈,加油。
一位爱生活爱技术来自火星的程序汪
今天开始好好整理下 N e u r a l Neural Neural N e t w o r k Network Network E m b e d d i n g Embedding Embedding的相关知识。初步预计包括: w o r d 2 v e c word2vec word2vec、 g l o v e glove glove、 f a s t t e x t fasttext fasttext、 e l m o elmo elmo、 b e r t bert bert。希望能尽快整理出来。
话不多说,先开始我们今天的 w o r d 2 v e c word2vec word2vec和 f a s t t e x t fasttext fasttext
按照惯例先上图
D N N DNN DNN中的 c b o w cbow cbow和 s k i p skip skip- g r a m gram gram
在 w o r d 2 v e c word2vec word2vec之前,怎么表示词向量呢?除了 o n e one one- h o t hot hot之外,就已经有用神经网络 D N N DNN DNN来训练词向量来处理词与词之间的关系了。一般采用的是两层神经网络:隐藏层、输出层(输入层一般不算。)
举个栗子:
以
c
b
o
w
cbow
cbow(
C
o
n
t
i
n
u
o
u
s
Continuous
Continuous
B
a
g
Bag
Bag-
o
f
of
of-
W
o
r
d
s
Words
Words)模型为例:
假设输出向量维度为5:
词表大小为10:
输入是某一个中心词(图中的
w
t
w_t
wt)的上下文相关的词(图中除了
w
t
w_t
wt以外的词,用
o
n
e
one
one _
h
o
t
hot
hot编码这4个词),从输入层到隐藏层的权重为
10
∗
5
10*5
10∗5的矩阵,权重是随机初始化的。输入是
4
∗
10
4*10
4∗10的矩阵,输入层到隐藏层的权重是
10
∗
5
10*5
10∗5的矩阵。这样通过下标对应位置上的随机初始化的向量就是输入的4个词的向量,就得到了一个
4
∗
5
4*5
4∗5的矩阵。然后将这个
4
∗
5
4*5
4∗5的矩阵和输出层的神经元(权重也是随机初始化的大小为
5
∗
10
5*10
5∗10)相乘,然后经过线性变化再加和求平均,这样就得到了词汇表中所有词的
s
o
f
t
m
a
x
softmax
softmax概率。我们训练的目标是期望中心词
w
t
w_t
wt的概率是最大的,并输出这特定的一个词
w
t
w_t
wt的词向量(也就是输入层到隐藏层那个权重举证对应的概率最大位置的向量。通过反向传播算法,经过反复的迭代,就可以训练得到很不错的词向量了。
结合图看看
这就是我理解的 D N N DNN DNN中的词向量产生的大致过程。
w o r d 2 v e c word2vec word2vec中的 c b o w cbow cbow和 s k i p skip skip- g r a m gram gram
这和
w
o
r
d
2
v
e
c
word2vec
word2vec中的
c
b
o
w
cbow
cbow 和
s
k
i
p
skip
skip-
g
r
a
m
gram
gram模型还是有许多地方是不一样的。
区别:
第一:从隐藏层到输出层之间,替换掉了线性变换和激活的操作,而是简单的所有向量加和求平均的操作,还是以上面的例子:也就是对四个词向量加和求平均,得到一个向量来表示。
第二:从隐藏层到输出层之间,替换掉了
s
o
f
t
m
a
x
softmax
softmax,取而代之的是霍夫曼树。霍夫曼树的叶子节点就是
v
o
c
a
b
vocab
vocab_
s
i
z
e
size
size大小的词。
根据词表中的各个单词的
c
o
u
n
t
count
count来构建霍夫曼树。
这样就满足了高频词的路径更短,符合贪心优化的思想
另外之前的计算量为
O
(
D
)
O(D)
O(D),现在变为了
O
(
l
o
g
2
D
)
O(log_2D)
O(log2D)
在
w
o
r
d
2
v
e
c
word2vec
word2vec中,采用的是二元逻辑回归的方法:
沿着左子树走,为负类,编码为
1
1
1
沿着右子树走,为正类,编码为
0
0
0
用
s
i
g
m
o
i
d
sigmoid
sigmoid判断正类和负类:
正类:
P
(
+
)
=
σ
(
x
w
T
θ
)
=
1
1
+
e
−
x
w
T
θ
P(+)=σ(x_w^Tθ)=\frac{1}{1+e^{-x_w^Tθ}}
P(+)=σ(xwTθ)=1+e−xwTθ1
负类:
P
(
−
)
=
1
−
P
(
+
)
P(-)=1 - P(+)
P(−)=1−P(+)
x
w
x_w
xw 当前内部节点的词向量
θ
θ
θ 逻辑回归的模型参数,需要学习的
和
L
o
g
i
s
t
i
c
Logistic
Logistic
R
e
g
r
e
s
s
i
o
n
Regression
Regression一样:
对数似然函数
L
L
L为:
L
(
w
)
=
∑
j
=
2
l
w
(
(
1
−
d
j
w
)
l
o
g
[
σ
(
x
w
T
θ
j
−
1
w
)
]
+
d
j
w
l
o
g
[
1
−
σ
(
x
w
T
θ
j
−
1
w
)
]
)
L(w)=∑_{j=2}^{l_w}((1−d^w_j)log[σ(x^T_wθ^w_{j−1})]+d^w_jlog[1−σ(x^T_wθ^w_{j−1})])
L(w)=∑j=2lw((1−djw)log[σ(xwTθj−1w)]+djwlog[1−σ(xwTθj−1w)])
l
w
l_w
lw 节点总数
d
w
d^w
dw 节点的霍夫曼编码
在
w
o
r
d
2
v
e
c
word2vec
word2vec中每次仅用一个样本更新梯度,可以减少梯度计算量,因为我们要求的是
L
(
w
)
L(w)
L(w)的最大值,所以使用的是:
随机梯度上升法
w
=
w
+
α
∇
w
f
(
w
)
w=w+α∇wf(w)
w=w+α∇wf(w)
具体的推导过程就不在这里详细叙述了(也不是我的强项,手动滑稽。)
w o r d 2 v e c word2vec word2vec中的 n e g a t i v e negative negative s a m p l i n g sampling sampling
w o r d 2 v e c word2vec word2vec不仅使用了霍夫曼树来优化最后的输出,还用了另外一种优化方法,那就是 n e g a t i v e negative negative s a m p l i n g sampling sampling(负采样)。最后并不需要构建霍夫曼树。
如何理解呢?
对于上图中的例子,中心词
w
t
w_t
wt,与之相关的
w
t
−
2
w_{t-2}
wt−2到
w
t
+
2
w_{t+2}
wt+2这四个词(假设称为
c
o
n
t
e
n
t
(
w
)
content(w)
content(w))就是正例。那么负例怎么来呢?我们随机选取
N
N
N个词作为
c
o
n
t
e
n
t
(
w
)
content(w)
content(w)的中心词,那么这
N
N
N个就是负例了。
对数的极大似然和霍夫曼树差不多,只不过是N个负例和1个正例的计算量,而不是 l w l_w lw总的节点数量了。
那又如何选取这
N
N
N个词呢?
假设词表大小为
V
V
V,我们将一条直线分为
V
V
V份,每份的长度则为词频与总长度的比。
在
w
o
r
d
2
v
e
c
word2vec
word2vec中设置了
p
o
w
e
r
=
0.75
power = 0.75
power=0.75,来计算每份的长度
l e n ( w ) = c o u n t ( w ) 0.75 ∑ u ∈ v o c a b c o u n t ( u ) 0.75 len(w)=\frac{count(w)^{0.75}}{∑_{u∈vocab}count(u)^{0.75}} len(w)=∑u∈vocabcount(u)0.75count(w)0.75
train_words_pow += wv.vocab[wv.index2word[word_index]].count**power
采样的时候,我们会把这条已经分成 V V V份的线,再次分成 M M M份( M > > V M >> V M>>V ),所以我们只需要在 M M M中采样出 N N N个位置就行,得到的就是我们的负例了。
部分代码片段如下:
if model.negative:
# use this word (label = 1) + `negative` other random words not from this sentence (label = 0)
word_indices = [word.index]
while len(word_indices) < model.negative + 1:
w = model.cum_table.searchsorted(model.random.randint(model.cum_table[-1]))
if w != word.index:
word_indices.append(w)
着重关注:
model.random.randint(model.cum_table[-1])
而其中的 c u m cum cum_ t a b l e table table
def make_cum_table(self, wv, power=0.75, domain=2**31 - 1):
"""Create a cumulative-distribution table using stored vocabulary word counts for
drawing random words in the negative-sampling training routines.
To draw a word index, choose a random integer up to the maximum value in the
table (cum_table[-1]), then finding that integer's sorted insertion point
(as if by bisect_left or ndarray.searchsorted()). That insertion point is the
drawn index, coming up in proportion equal to the increment at that slot.
Called internally from 'build_vocab()'.
"""
vocab_size = len(wv.index2word)
self.cum_table = zeros(vocab_size, dtype=uint32)
# compute sum of all power (Z in paper)
train_words_pow = 0.0
for word_index in xrange(vocab_size):
train_words_pow += wv.vocab[wv.index2word[word_index]].count**power
cumulative = 0.0
for word_index in xrange(vocab_size):
cumulative += wv.vocab[wv.index2word[word_index]].count**power
self.cum_table[word_index] = round(cumulative / train_words_pow * domain)
if len(self.cum_table) > 0:
assert self.cum_table[-1] == domain
f a s t T e x t fastText fastText和 c b o w cbow cbow
最后再来讲一下
f
a
c
e
b
o
o
k
facebook
facebook的
f
a
s
t
T
e
x
t
fastText
fastText。
我理解的
F
a
s
t
t
e
x
t
Fasttext
Fasttext是为了做
t
e
x
t
text
text
c
l
a
s
s
i
f
i
c
a
t
i
o
n
classification
classification的,顺带生成了词向量。
之所以把
f
a
s
t
T
e
x
t
fastText
fastText和
c
b
o
w
cbow
cbow放在一起讲呢?就是因为
f
a
s
t
t
e
x
t
fasttext
fasttext和
c
b
o
w
cbow
cbow的模型架构很相似:
都是 输入层、隐藏层、输出层(
h
i
e
r
a
r
c
h
i
c
a
l
hierarchical
hierarchical
s
o
f
t
m
a
x
softmax
softmax)
不同的是:
-
c b o w cbow cbow的输入是中心词的上下文 c o n t e x t ( w ) context(w) context(w),是经过 o n e one one- h o t hot hot的向量,而 f a s t t e x t fasttext fasttext的输入是文本的分词之后的向量表示(也是简单的加和求平均),最重要的是还有字符级的 N N N- g r a m gram gram的表示作为输入输入的另一部分。
这样对于低频词更友好,可以用字符级的特征来表示一部分信息;
另外对于 O O V OOV OOV也能用字符级的特征来叠加或者表示一部分。 -
最后的输出: c b o w cbow cbow是输出中心词的概率, f a s t t e x t fasttext fasttext输出的是文档对应的类别的概率。
个人还是比较喜欢 f a c e b o o k facebook facebook的产品的,简单至上。
-
f a s t t e x t fasttext fasttext的前半部分就是生成向量来表征 s e n t e n c e sentence sentence:简单的叠加 w o r d s words words- v e c t o r vector vector以及 n n n- g r a m gram gram的 v e c t o r vector vector,然后取平均。
-
得到文档向量之后,就是做 s o f t m a x softmax softmax c l a s s i f i c a t i o n classification classification t a s k task task
-
关键在 n n n- g r a m gram gram特征的引入以及 h h h- s o f t m a x softmax softmax.
谢谢
更多代码请移步我的个人 g i t h u b github github,会不定期更新各种框架。
欢迎关注