本文重点侧重word2vec数学推导部分,看懂的前提是已假设读者具备word基础,如果看不懂请先转到图解Word2vec,读这一篇就够了!。
1、写在前面
好多做算法的同学,在面试的时候被面试官要求手推word2vec,可能觉得有点难,其实一点都不难,会高中的对数基本知识即可,一起来看吧~
word2vec包括Skip-grams(SG)和Continuous Bag of Words(CBOW)两种形式,其中Skip-grams算法是通过中心词汇推测上下文,CBOW反之,本文以Skip-grams为例,通过中心词汇推测上下文啥意思呢?一图胜千言
输入为中心词汇是banking,
m
m
m 表示词语窗口的长度,表示中心词语前后各有
m
m
m 个词语,整个模型中只有一个条件分布,因为这是一个词袋模型,与位置无关,所以我们的目的就是最大化这些概率。首先我们来定义一个目标函数,我们把目标函数定义为我们预测结果的乘积,极大似然常规操作第一步,连乘如下:
J
′
(
θ
)
=
∏
t
=
1
T
∏
−
m
⩽
j
⩽
m
j
≠
0
p
(
w
t
+
j
∣
w
t
;
θ
)
J'{(\theta)}=\prod_{t=1}^{T}\prod_{-m\leqslant j\leqslant m}^{j\neq 0}p(w_{t+j}|w_t;\theta)
J′(θ)=t=1∏T−m⩽j⩽m∏j=0p(wt+j∣wt;θ)
T
T
T 表示总的词数量,每一个词前后
m
m
m 个词的概率我们都要计算。极大似然常规操作第二步,连乘输入
l
o
g
log
log后将目标函数变成连加,为了方便计算,这里用的是对数似然的相反数:
J
(
θ
)
=
1
T
∑
t
=
1
T
∑
−
m
⩽
j
⩽
m
j
≠
0
p
(
w
t
+
j
∣
w
t
)
J{(\theta)}=\frac{1}{T}\sum_{t=1}^{T}\sum_{-m\leqslant j\leqslant m}^{j\neq 0}p(w_{t+j}|w_t)
J(θ)=T1t=1∑T−m⩽j⩽m∑j=0p(wt+j∣wt)
在上公式中,
P
(
w
t
+
j
∣
w
t
)
P(w_{t+j}|w_t)
P(wt+j∣wt)通过 softmax 得到的,由softmax可得:
P
(
o
∣
c
)
=
e
x
p
(
u
o
T
⋅
v
c
)
∑
w
=
1
V
e
x
p
(
u
w
T
⋅
v
c
)
P(o|c)=\frac{exp(u_o^T\cdot v_c)}{\sum_{w=1}^{V}exp(u_w^T\cdot v_c)}
P(o∣c)=∑w=1Vexp(uwT⋅vc)exp(uoT⋅vc)
结合下面的图一起看上面的公式, v v v 表示 W W W 中的向量, u u u 表示 W ′ W^{'} W′ 中的向量,两者我们分别称为输入输出矩阵,那么到底哪个作为我们词向量最终的 e m b e d d i n g embedding embedding 表示呢?
答案是:都可以!!!
输入输出矩阵都可以用作 e m b e d d i n g embedding embedding,官方采用了输入矩阵,但只是做 e m b e d d i n g embedding embedding 的话,不直接优化效果,采用输入或者输出矩阵没有本质的差别。(为什么没有差别,因为矩阵的本质是变换,就是从一个空间变换到另外一个空间,空间A可以变换到B,用空间B来表示空间A,同样的空间A也可以变换到空间C,用空间C来表示空间A,那么空间B和空间C有什么不同呢?都是可以经过空间A变换得到的,其实没什么不同,只不过是角度不同了,所谓横看成岭侧成峰,远近高低各不同;那么好好的为啥要把A变来变去的?在我们word2vec背景里面那个巨大的onehot词表就是A,因为A太大了呀!!!,所以要进行精简,只要保证精简后的矩阵B/C…etc 能够体现A的主要性质就可以了!!!)
那么 u o u_o uo 指的就是待预测的上下文中某个词 o o o 在输出矩阵的词向量表示, v c v_c vc 指中心词 c c c 在输入矩阵的词向量表示。概率怎么理解呢?由于在中心词 c 有会预测出 V 个结果,对于某个上下文词 o 来说,命中他的概率怎么计算呢?
哦,原来是一个多分类问题,自然想到 s o f t m a x softmax softmax,但是 s o f t m a x softmax softmax 的输入有讲究,这里采用了中心词输入矩阵向量和预测词输出矩阵向量的内积,为什么是内积?因为度量向量最好的方式就是内积,这是容易想到的。
于是损失函数就变成了大家看到的样子~
下图就是整个skip-grams的算法流程以及每一步的解释:
由上图就可以清楚地知道
S
G
SG
SG 算法每一步的流程以及意义了(上图中好巧不巧的看起来词表总量
V
V
V 和隐层维度
N
N
N 一致,但其实绝大部分是不一致的,注意),里面向量的数字不代表真实意思,是瞎编的,重要的是流程,最终我们的损失函数就是比对真实向量与我们计算出来的答案的差距,要最小化损失函数,最大化输出概率。那么怎么去学习这个模型呢,怎么去最小化损失函数呢?肯定是梯度下降法了,所以对损失函数的
v
c
v_c
vc 求偏导(这里停顿一下,考虑为何是对
v
c
v_c
vc ),把常数去掉之后,损失函数就可以表示成:
l
o
g
e
x
p
(
u
o
T
⋅
v
c
)
∑
w
=
1
V
e
x
p
(
u
w
T
⋅
v
c
)
log\frac{exp(u_o^T \cdot v_c)}{\sum_{w=1}^{V}exp(u_w^T \cdot v_c)}
log∑w=1Vexp(uwT⋅vc)exp(uoT⋅vc)
接着对损失函数的
V
c
V_c
Vc求偏导,可得:
∂
∂
v
c
J
(
θ
)
=
∂
∂
v
c
l
o
g
e
x
p
(
u
o
T
⋅
v
c
)
∑
w
=
1
V
e
x
p
(
u
w
T
⋅
v
c
)
\frac{\partial}{\partial v_c}J(\theta) = \frac{\partial}{\partial v_c} log \frac{exp(u_o^T \cdot v_c)}{\sum_{w=1}^{V}exp(u_w^T \cdot v_c)}
∂vc∂J(θ)=∂vc∂log∑w=1Vexp(uwT⋅vc)exp(uoT⋅vc)
对数内部的除法相当于对数外部的减法,那么这个式子可以表示成:
∂ ∂ v c l o g ( e x p ( u o T ⋅ v c ) ) − ∂ ∂ v c l o g ∑ w = 1 V e x p ( u w T ⋅ v c ) \frac{\partial}{\partial v_c}log(exp(u_o^T \cdot v_c)) - \frac{\partial}{\partial v_c}log \sum_{w=1}^{V}exp(u_w^T \cdot v_c) ∂vc∂log(exp(uoT⋅vc))−∂vc∂logw=1∑Vexp(uwT⋅vc)
然后再把这整个式子看成两个部分,首先是第一个部分,因为指数之后再求对数还是本身,所以第一项可以表示成:
∂
∂
v
c
l
o
g
(
e
x
p
(
u
o
T
⋅
v
c
)
)
=
∂
(
u
o
T
⋅
v
c
)
∂
v
c
=
u
o
\frac{\partial}{\partial v_c}log(exp(u_o^T \cdot v_c)) = \frac{\partial(u_o^T \cdot v_c)}{\partial v_c}=u_o
∂vc∂log(exp(uoT⋅vc))=∂vc∂(uoT⋅vc)=uo
所以第一项就是
u
o
u_o
uo,然后看第二部分的计算:
∂
∂
v
c
l
o
g
∑
w
=
1
V
e
x
p
(
u
w
T
⋅
v
c
)
\frac{\partial}{\partial v_c}log \sum_{w=1}^{V}exp(u_w^T \cdot v_c)
∂vc∂logw=1∑Vexp(uwT⋅vc)
对于这种复杂的复合函数求偏导,首先我们就会想到的是复合函数的链式求导法则,那么这个第二项求偏导可以有如下推导:
∂
∂
v
c
l
o
g
∑
w
=
1
V
e
x
p
(
u
w
T
⋅
v
c
)
=
1
∑
w
=
1
V
e
x
p
(
u
w
T
⋅
v
c
)
⋅
∑
x
=
1
V
e
x
p
(
u
x
T
⋅
v
c
)
⋅
∂
(
u
x
T
⋅
v
c
)
∂
v
c
=
1
∑
w
=
1
V
e
x
p
(
u
w
T
⋅
v
c
)
⋅
∑
x
=
1
V
e
x
p
(
u
x
T
⋅
v
c
)
⋅
u
x
=
∑
x
=
1
V
e
x
p
(
u
x
T
⋅
v
c
)
∑
w
=
1
V
e
x
p
(
u
w
T
⋅
v
c
)
⋅
u
x
\begin{aligned} &\frac{\partial}{\partial v_c}log \sum_{w=1}^{V}exp(u_w^T \cdot v_c) \\=& \frac{1}{ \sum_{w=1}^{V}exp(u_w^T \cdot v_c)} \cdot \sum_{x=1}^{V}exp(u_x^T \cdot v_c) \cdot \frac{\partial(u_x^T \cdot v_c)}{\partial v_c} \\=& \frac{1}{ \sum_{w=1}^{V}exp(u_w^T \cdot v_c)} \cdot \sum_{x=1}^{V}exp(u_x^T \cdot v_c) \cdot u_x \\=&\sum_{x=1}^{V}\frac{exp(u_x^T \cdot v_c)}{ \sum_{w=1}^{V}exp(u_w^T \cdot v_c)}\cdot u_x \end{aligned}
===∂vc∂logw=1∑Vexp(uwT⋅vc)∑w=1Vexp(uwT⋅vc)1⋅x=1∑Vexp(uxT⋅vc)⋅∂vc∂(uxT⋅vc)∑w=1Vexp(uwT⋅vc)1⋅x=1∑Vexp(uxT⋅vc)⋅uxx=1∑V∑w=1Vexp(uwT⋅vc)exp(uxT⋅vc)⋅ux
然后这个式子中间的部分正好可以看成是softmax:
e
x
p
(
u
x
T
⋅
v
c
)
∑
w
=
1
V
e
x
p
(
u
w
T
⋅
v
c
)
=
P
(
x
∣
c
)
\frac{exp(u_x^T \cdot v_c)}{ \sum_{w=1}^{V}exp(u_w^T \cdot v_c)} = P(x|c)
∑w=1Vexp(uwT⋅vc)exp(uxT⋅vc)=P(x∣c)
如此,第二项就可以看成是:
∑
x
=
1
V
P
(
x
∣
c
)
⋅
u
x
\sum_{x=1}^{V}P(x|c) \cdot u_x
x=1∑VP(x∣c)⋅ux
上式子可以看成是词
x
x
x 在中心词
c
c
c 出现的情况下出现的概率,然后乘以词
x
x
x 上下文的向量
u
x
u_x
ux,这样就是上下文向量的期望了,所以整个第二项就是所有的上下问向量的平均期望。那么整个损失函数可以表示成:
J
(
θ
)
=
u
o
−
∑
x
=
1
V
P
(
x
∣
c
)
⋅
u
x
=
o
b
s
e
r
v
e
d
−
e
x
p
e
c
t
e
d
\begin{aligned} J(\theta) &= u_o - \sum_{x=1}^{V}P(x|c) \cdot u_x \\ &=observed-expected \end{aligned}
J(θ)=uo−x=1∑VP(x∣c)⋅ux=observed−expected
就是观测值真实值减去期望值,所以我们就要最小化损失函数,让期望值和真实值尽可能接近,通过整个推导过程就很容易理解skip-grams的算法流程和数学推导,希望可以帮助大家对词向量算法的理解有所帮助。
番外篇
在model serving过程中对几百万个候选集逐一跑一遍模型的时间开销显然太大了,因此在通过candidate generation model得到user 和 video的embedding之后,通过最近邻搜索的方法的效率高很多。我们甚至不用把任何model inference的过程搬上服务器,只需要把user embedding和video embedding存到redis或者内存中就好了。
在原文中并没有介绍得到user embedding和video embedding的具体过程,只是在架构图中从softmax朝 model serving module那画了个箭头(如下图红圈内的部分),到底这个user vector和video vector是怎么生成的?
答案是,和word2vec一样的!!!
最后一层Relu比如维度为 k k k,那么进入 s o f t m a x softmax softmax 之前要经过一个 k × n k \times n k×n 的变换, n n n 是candidate videos数量,那么该 k × n k \times n k×n 矩阵不就是所有 video embedding 集合么!!!