赞
踩
由于 Word2Vec 本质其实是一个语言模型,词向量只是这个语言模型的副产物,因此我们首先简单看一下语言模型:
语言模型其实就是计算一个句子出现的概率,例如:
那么一个好的语言模型应该会让句子1的概率大于句子2和句子3。具体来说,假设
W
=
w
1
T
:
=
(
w
1
,
w
2
,
⋯
,
w
T
)
W = w_{1}^T := (w_1, w_2, \cdots, w_T)
W=w1T:=(w1,w2,⋯,wT) 表示由 T 个词排列成的句子,那么句子
w
1
T
w_{1}^T
w1T 的概率为:
P
(
w
1
T
)
=
P
(
w
1
,
w
2
,
⋯
,
w
T
)
=
P
(
w
1
)
⋅
P
(
w
2
∣
w
1
)
⋅
P
(
w
3
∣
w
1
2
)
⋯
P
(
w
T
∣
w
1
T
−
1
)
P(w_{1}^T) = P(w_1, w_2, \cdots, w_T) = P(w_1)\cdot P(w_2|w_1)\cdot P(w_3|w_{1}^2)\cdots P(w_T|w_{1}^{T-1})
P(w1T)=P(w1,w2,⋯,wT)=P(w1)⋅P(w2∣w1)⋅P(w3∣w12)⋯P(wT∣w1T−1)
Bengio 等人在2003年提出的神经概率语言模型如下,包括输入层,投影层,隐藏层和输出层。其中
W
,
p
W,p
W,p 和
U
,
q
U,q
U,q 分别为隐藏层和输出层的参数矩阵及偏置向量。
对于语料中的任意一个词
w
w
w,
C
o
n
t
e
x
t
(
w
)
Context(w)
Context(w) 取其前
n
−
1
n-1
n−1 个词(类似与 n-gram),构成一个训练样本
(
w
,
C
o
n
t
e
x
t
(
w
)
)
(w, Context(w))
(w,Context(w)),其中
C
o
n
t
e
x
t
(
w
)
Context(w)
Context(w) 是输入,
w
w
w 是label。因此上述神经概率语言模型建模的是
P
(
w
i
∣
C
o
n
t
e
x
t
(
w
)
)
:
=
P
(
w
i
∣
w
i
−
n
+
2
i
−
1
)
P(w_i|Context(w)) := P(w_i|w_{i-n+2}^{i-1})
P(wi∣Context(w)):=P(wi∣wi−n+2i−1)。 接下来的计算过程:
x
w
=
concat
{
v
(
w
i
−
n
+
2
)
,
⋯
,
v
(
w
i
−
1
)
}
z
w
=
tanh
(
W
x
w
+
p
)
y
w
=
U
z
w
+
q
其中 y w y_w yw 是一个长度为词典大小的向量,通过softmax归一化,即得 w w w 是词典中任意词的概率。而训练结束后得到的参数矩阵 W W W 及 U U U 均可作为词向量,实践中一般使用 W W W。
分析每一层的参数规模:
因此绝大部分计算集中在输出层以及之后的 softmax 上。因此后面很多的研究,包括 word2vec 都是针对这一部分进行优化的。
神经概率语言模型对比 n-gram 的优势:
- 假如句子 the dog is running in the rain 和 the cat is running in the rain 在语料中各出现了100次和1次。那么在 n-gram 模型中,前者的概率肯定比后者大的。但是在神经语言模型中,由于 dog 和 cat 出现的语境很多时候是相同的,也就意味着这两个词的词向量是类似的,因此这两个句子的概率会是差不多的。 也就是说,这两个句子只要其中一个数量变多,就可以同时增大另一个句子的概率
- 神经概率语言模型自带平滑功能,不需要像 n-gram 一样进行额外处理
Word2vec 的作者在论文中给出了两个模型结构:CBOW 和 Skip-gram :
不难发现两者的区别是 CBOW 建模的是
P
(
w
∣
c
o
n
t
e
x
t
(
w
)
)
P(w|context(w))
P(w∣context(w)),而 Skip-gram 建模的是
P
(
c
o
n
t
e
x
t
(
w
)
∣
w
)
P(context(w)|w)
P(context(w)∣w)。
除此之外,为了优化了上一节提到的,输出层 softmax 计算复杂度过高的问题,Word2vec 还提出了 Hierarchical Softmax 和 Negative Sampling 两种优化方法。
由于 Hierarchical Softmax 中会用到 Huffman 树,因此这里我们先简单介绍一下它。
给定 n 个权值 { w 1 , w 2 , ⋯ , w n } \{w_1, w_2, \cdots, w_n\} {w1,w2,⋯,wn},构建一个二叉树,使得这 n 个权值是它的 n 个叶子节点。构建标准是:
例子:
由此可见这颗 Huffman 树的特点是 词频越大的词离树越近
CBOW
CBOW的结构如下,首先输入层中,
C
o
n
t
e
x
t
(
w
)
Context(w)
Context(w) 是由
w
w
w 的前后各 c 个词构成,并且将这 2c 个向量相加作为输入。投影层与前面的神经语言模型相同。但是在最后的输出层,CBOW摒弃了传统的线性 softmax 层,而采用了一颗 Huffman 树来进行多层分类。计算的复杂度也由
O
(
N
)
O(N)
O(N) 减为
O
(
l
o
g
2
N
)
O(log_2 N)
O(log2N)。如果我们将这颗二叉树改为多叉树,那么可以进一步降低计算复杂度。:
下面还是以二叉 Huffman 树为例来讲解 Hierarchical Softmax 。首先注意到,Huffman 树上的每一个非叶节点的节点上都有一个可学习参数 θ i w \theta_i^w θiw(单词 w w w 在这个节点处的词向量) 。假设当前训练数据的 label 是“足球”,那么从根节点出发到“足球”需要经历四次二分类,二分类的概率通过sigmoid函数来计算,因此有:
其中
σ
(
x
w
T
θ
i
w
)
=
1
1
+
e
−
x
w
T
θ
i
w
\sigma(x_w^T \theta_i^w) = \frac{1}{1+e^{-x_w^T \theta_i^w}}
σ(xwTθiw)=1+e−xwTθiw1。而我们要求的
P
(
足
球
∣
c
o
n
t
e
x
t
(
足
球
)
)
P(足球|context(足球))
P(足球∣context(足球)) 等于:
P
(
足
球
∣
c
o
n
t
e
x
t
(
足
球
)
)
=
∏
i
=
2
5
P
(
d
i
w
∣
x
w
,
θ
i
−
1
w
)
P(足球|context(足球)) = \prod_{i=2}^5 P(d_i^w|x_w, \theta_{i-1}^w)
P(足球∣context(足球))=i=2∏5P(diw∣xw,θi−1w)
由于父节点的所有子节点的概率之和相加总等于父节点上的概率,因此 ∑ w ∈ D P ( w ∣ c o n t e x t ( w ) ) = 1 \sum_{w\in \mathcal{D}} P(w|context(w)) =1 ∑w∈DP(w∣context(w))=1 总是成立的。因此不需要另外归一化。
损失函数采用交叉熵损失:
L
=
∑
w
∈
C
log
P
(
w
∣
c
o
n
t
e
x
t
(
w
)
)
=
∑
w
∈
C
log
∏
j
=
2
l
w
[
σ
(
x
w
T
θ
j
−
1
w
)
]
1
−
d
j
w
⋅
[
1
−
σ
(
x
w
T
θ
j
−
1
w
)
]
d
j
w
=
∑
w
∈
C
∑
j
=
2
l
w
{
(
1
−
d
j
w
)
⋅
log
[
σ
(
x
w
T
θ
j
−
1
w
)
]
+
d
j
w
⋅
log
[
1
−
σ
(
x
w
T
θ
j
−
1
w
)
]
}
接下来就可以通过梯度下降法求解参数 x w , θ j − 1 w x_w,\theta_{j-1}^w xw,θj−1w ,详细可参见 word2vec_中的数学原理详解。
Skip-gram
Skip-gram 的流程与CBOW基本类似,区别只在于输入层由于只有一个词语,因此无需做处理:
而在输出层,
P
(
c
o
n
t
e
x
t
(
w
)
∣
w
)
P(context(w)|w)
P(context(w)∣w) 被定义为:
P
(
c
o
n
t
e
x
t
(
w
)
∣
w
)
=
∏
u
∈
c
o
n
t
e
x
t
(
w
)
P
(
u
∣
w
)
P(context(w)|w) = \prod_{u\in context(w)}P(u|w)
P(context(w)∣w)=u∈context(w)∏P(u∣w)
其中
P
(
u
∣
w
)
P(u|w)
P(u∣w) 类似于CBOW中的计算方法:
P
(
u
∣
w
)
=
∏
j
=
2
l
w
P
(
d
j
u
∣
v
(
w
)
,
θ
j
−
1
w
)
=
∏
j
=
2
l
w
[
σ
(
v
(
w
)
T
θ
j
−
1
u
)
]
1
−
d
j
u
⋅
[
1
−
σ
(
v
(
w
)
T
θ
j
−
1
u
)
]
d
j
u
P(u|w) = \prod_{j=2}^{l^w} P(d_j^u|v(w), \theta_{j-1}^w) = \prod_{j=2}^{l^w} [\sigma(v(w)^T \theta_{j-1}^u)]^{1-d_j^u} \cdot[1-\sigma(v(w)^T \theta_{j-1}^u)]^{d_j^u}
P(u∣w)=j=2∏lwP(dju∣v(w),θj−1w)=j=2∏lw[σ(v(w)Tθj−1u)]1−dju⋅[1−σ(v(w)Tθj−1u)]dju
同样,损失函数是:
L
=
∑
w
∈
C
log
P
(
c
o
n
t
e
x
t
(
w
)
∣
w
)
=
∑
w
∈
C
log
∏
u
∈
c
o
n
t
e
x
t
(
w
)
∏
j
=
2
l
w
[
σ
(
v
(
w
)
T
θ
j
−
1
u
)
]
1
−
d
j
u
⋅
[
1
−
σ
(
v
(
w
)
T
θ
j
−
1
u
)
]
d
j
u
=
∑
w
∈
C
∑
u
∈
c
o
n
t
e
x
t
(
w
)
∑
j
=
2
l
w
{
(
1
−
d
j
u
)
⋅
log
[
σ
(
v
(
w
)
T
θ
j
−
1
u
)
]
+
d
j
u
⋅
log
[
1
−
σ
(
v
(
w
)
T
θ
j
−
1
u
)
]
}
详细请参考 word2vec_中的数学原理详解
Negative Sampling 的实质是把输出层的多分类softmax变成了二分类sigmoid,而分类的依据就是当前数据对是否是邻近词。可以这样做的原因是Word2vec的目的其实是训练中间词向量矩阵,而不是真的需要用这个模型去判断句子的概率。观察交叉熵损失不难发现,每次更新参数主要影响的还是与当前 label 有关的参数,其他的词对应的参数更新很少。 因此是 “从所有词中选出正确的那个” 还是 “做若干次判断是否是邻近词” 对中间词向量矩阵的更新影响不大,但是对于机器翻译这类序列生成任务,Negative Sampling 就不可行了。
由于将其看作二分类问题,因此取负类的时候也无需将所有词语都取遍(否则负类对损失函数的影响太大),一般取5~20个负类词语即可。
还是分 CBOW 和 Skip-gram 两种情况来看 Negative Sampling 是如何实现的。
CBOW
对于训练数据
(
w
,
c
o
n
t
e
x
t
(
w
)
)
(w, context(w))
(w,context(w)),那么 正集就是
w
w
w,负集是除
w
w
w 之外的其他词。当然实际使用的时候不会取遍所有的词,假设现在已经有一个负集
N
E
G
(
w
)
NEG(w)
NEG(w)。那么
P
(
u
∣
c
o
n
t
e
x
t
(
w
)
)
=
{
σ
(
x
w
T
θ
u
)
u
=
w
1
−
σ
(
x
w
T
θ
u
)
u
∈
N
E
G
(
w
)
其中
θ
u
\theta^u
θu 是单词
u
u
u 的词向量。为什么要这样定义呢,因为 当
u
=
w
u = w
u=w 时,我们希望最大化概率
σ
(
x
w
T
θ
u
)
\sigma(x_w^T \theta^u)
σ(xwTθu),而当
u
≠
w
u \neq w
u=w 时,我们希望最小化概率
σ
(
x
w
T
θ
u
)
\sigma(x_w^T \theta^u)
σ(xwTθu)。而将
P
(
u
∣
c
o
n
t
e
x
t
(
w
)
)
P(u|context(w))
P(u∣context(w)) 定义为上述形式,目标函数就等价于最大化:
log
[
∏
u
∈
{
w
}
∪
N
E
G
(
w
)
P
(
u
∣
c
o
n
t
e
x
t
(
w
)
)
]
=
log
[
∏
u
∈
{
w
}
∪
N
E
G
(
w
)
[
σ
(
x
w
T
θ
u
)
]
I
w
(
u
)
⋅
[
1
−
σ
(
x
w
T
θ
u
)
]
1
−
I
w
(
u
)
]
=
∑
u
∈
{
w
}
∪
N
E
G
(
w
)
{
I
w
(
u
)
⋅
log
[
σ
(
x
w
T
θ
u
)
]
+
(
1
−
I
w
(
u
)
)
⋅
log
[
1
−
σ
(
x
w
T
θ
u
)
]
}
之后可以通过梯度下降法优化参数 x w x_w xw 和 θ u \theta^u θu
Skip-gram
Skip-gram 建模的是
P
(
c
o
n
t
e
x
t
(
w
)
∣
u
)
P(context(w)|u)
P(context(w)∣u),给定样本
(
w
,
c
o
n
t
e
x
t
(
w
)
)
(w,context(w))
(w,context(w)),由于这里 label 是
c
o
n
t
e
x
t
(
w
)
context(w)
context(w),那么对于
c
o
n
t
e
x
t
(
w
)
context(w)
context(w) 中的每一个词,我们需要找若干个负样本,要求这些负样本不包含
c
o
n
t
e
x
t
(
w
)
context(w)
context(w)。因此目标函数是:
∏
u
∈
c
o
n
t
e
x
t
(
w
)
∏
u
~
∈
{
u
}
∪
N
E
G
(
u
)
P
(
u
~
∣
w
)
\prod_{u \in context(w)} \prod_{\tilde{u}\in\{u\}\cup NEG(u)}P(\tilde{u}|w)
u∈context(w)∏u~∈{u}∪NEG(u)∏P(u~∣w)
其中:
P
(
u
~
∣
w
)
=
{
σ
(
v
(
w
)
T
θ
u
~
)
u
~
=
u
1
−
σ
(
v
(
w
)
T
θ
u
~
)
u
~
∈
N
E
G
(
u
)
即 P ( u ~ ∣ w ) = [ σ ( v ( w ) T θ u ~ ) ] I u ( u ~ ) ⋅ [ 1 − σ ( v ( w ) T θ u ~ ) ] 1 − I u ( u ~ ) P(\tilde{u}|w) = [\sigma(v(w)^T \theta^{\tilde{u}})]^{I_u(\tilde{u})} \cdot [1 - \sigma(v(w)^T \theta^{\tilde{u}})]^{1-I_u(\tilde{u})} P(u~∣w)=[σ(v(w)Tθu~)]Iu(u~)⋅[1−σ(v(w)Tθu~)]1−Iu(u~)
那么损失函数就是:
log
[
∏
u
∈
c
o
n
t
e
x
t
(
w
)
∏
u
~
∈
{
u
}
∪
N
E
G
(
u
)
P
(
u
~
∣
w
)
]
=
∏
u
∈
c
o
n
t
e
x
t
(
w
)
∏
u
~
∈
{
u
}
∪
N
E
G
(
u
)
{
I
u
(
u
~
)
⋅
log
[
σ
(
v
(
w
)
T
θ
u
~
)
]
+
(
1
−
I
u
(
u
~
)
)
⋅
log
[
1
−
σ
(
v
(
w
)
T
θ
u
~
)
]
}
以 CBOW 为例,我们观察两种方法的最终损失函数:
Hierarchical Softmax
:
∑
w
∈
C
∑
j
=
2
l
w
{
(
1
−
d
j
w
)
⋅
log
[
σ
(
x
w
T
θ
j
−
1
w
)
]
+
d
j
w
⋅
log
[
1
−
σ
(
x
w
T
θ
j
−
1
w
)
]
}
Negative Sampling
:
∑
w
∈
C
∑
u
∈
{
w
}
∪
N
E
G
(
w
)
{
I
w
(
u
)
⋅
log
[
σ
(
x
w
T
θ
u
)
]
+
(
1
−
I
w
(
u
)
)
⋅
log
[
1
−
σ
(
x
w
T
θ
u
)
]
}
结构非常类似,都是若干个二分类的结果相加,区别在于 Hierarchical Softmax 是多个不同的二分类模型的结果相加,而 Negative Sampling 是多个不同样本的二分类结果相加。因此:
- Hierarchical Softmax 中的每个二叉树节点位置都对应一个大小为通过该节点可以到达的词的数量大小的词向量矩阵,而 Negative Sampling 只有一个二分类节点,对应一个词汇量大小的词向量矩阵。因此 Hierarchical Softmax 的参数量是比 Negative Sampling 多很多的
- Hierarchical Softmax 由于词频高的词在 Hoffman 树上的路径短,因此对损失函数的贡献也较小;而 Negative Sampling 中负样本数量是超参数,对所有数据都一样,因此不存在这样的情况
下图是 Mikolov 在其文章 Distributed Representations of Words and Phrases
and their Compositionality 中的实验结果,表明 Negative Sampling 整体效果是优于 Hierarchical Softmax 的,但是当 Negative Sampling 中负样本的数量取值比较大时,其速度会比 Hierarchical Softmax 慢。
对于一些高频词例如 “的”,“在”,“一个” 等等,它们在语料中出现的频率很高,但其实提供的信息很少。因此我们会对这些词进行下采样,具体来说,数据中的每个词都以:
P ( w i ) = max ( 1 − t f ( w i ) , 0 ) P(w_i) = \text{max}(1-\sqrt\frac{t}{f(w_i)}, 0) P(wi)=max(1−f(wi)t ,0)
的概率被丢弃。其中 f ( w i ) = c o u n t ( w i ) ∑ w ∈ C c o u n t ( w ) f(w_i) = \frac{count(w_i)}{\sum_{w\in\mathcal{C}}count(w)} f(wi)=∑w∈Ccount(w)count(wi), t t t 是超参数 (一般设为 1 0 − 4 10^{-4} 10−4)。因此,只有当 f ( w i ) > t f(w_i) > t f(wi)>t 时, w i w_i wi 才有可能被丢弃,且词频越高,被丢弃的概率越大。
下图实验证明了高频词下采样对于速度以及准确性都有提升:
对于一个句子,其中的任何词都需要做为一次中心词,而其对应的上下文词是随机采样窗口在1到max_window_size之间的词,不采用固定而是随机窗口大小的目的是避免模型对窗口大小的依赖。
对于训练数据 ( w , c o n t e x t ( w ) ) (w, context(w)) (w,context(w)),负样本需要在除 w w w 和 c o n t e x t ( w ) context(w) context(w) 之外的词上取。且词频越大的词,它被采样的概率应该越高。因此在实现时可以将每个词的词频作为采样的非规范化概率。原文在实现时采用的是词频的 3 4 \frac{3}{4} 43次幂作为采样概率。
以负采样为例,观察损失函数:
∑
w
∈
C
∑
u
∈
{
w
}
∪
N
E
G
(
w
)
{
I
w
(
u
)
⋅
log
[
σ
(
x
w
T
θ
u
)
]
+
(
1
−
I
w
(
u
)
)
⋅
log
[
1
−
σ
(
x
w
T
θ
u
)
]
}
发现损失函数的形式正是 交叉熵损失 的二分类形式。因此负采样的代码实现非常简单,只需要分别计算中心词
w
w
w 的词向量
embed_in
(
w
)
\text{embed\_in}(w)
embed_in(w) 和正负样本
u
u
u 的词向量
embed_out
(
u
)
\text{embed\_out}(u)
embed_out(u),即可计算上式中的
x
w
T
θ
u
x_w^T \theta^u
xwTθu:
embed_in
(
w
)
T
embed_out
(
u
)
\text{embed\_in}(w)^T\text{embed\_out}(u)
embed_in(w)Tembed_out(u)
实践当中,由于 softmax溢出问题 ,sigmoid函数一般与交叉熵同时计算,因此上述结果可以直接作为 preds 输入到tf.nn.sigmoid_cross_entropy_with_logits(labels, preds)
,即可得到loss值。
Reference:
word2vec_中的数学原理详解
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。