Word Embedding:An Introduction and Its Application in Sentence Parsing - Part 1

最近在组里做了一个报告,关于词向量以及用词向量来做句子parsing。Slides用LaTex 的Beamer框架做的,花了很长时间来做= =。slides的下载地址在这里。现在就打算把它整理成一个博文,边写边整理思路。

1.传统的词的表示方法

1.1.One-hot Vector

在自然语言的很多任务当中,我们要对corpus中的词进行建模。因此需要对每个词进行表示,传统的表示方法被称为One-hot Vector,它的意思是我对每个词用一个向量来表示,这个向量的长度是语料库(corpus)的词典的大小。比如一句话“I love ShanghaiTech University”。我可以用如下的表示方法:

“I”=[1,0,0,…,0,0]
“love”=[0,0,1,…,0,0]
“ShanghaiTech”=[0,0,,…,1,0]
“University”=[0,0,,…,0,1]

这样的好处是对于一个向量,我看它哪一维度是1就可以代表那个词。坏处也很明显:

  • 如果在一个很大的语料库下,词典的维数会很高,这样在以后的计算中cost会很高。
  • 它不能抓取词与词之间的语义关系。

    1.2.基于类别词的表示

    有一类对词的表示就是对其Assign一个Lable或者一个Lable的分布。比如在主题模型中,我们对每一个文档的每一个词通过生成模型来生成它。这个生成模型的过程是:
    对于每一个文档,
  1. 从一个泊松分布中Sample该文档中词的数量。
  2. 从一个Direchlet分布中Sample该文档所属的topic $\theta$
  3. 对于这篇文档N个词中的每一个词,
    a). Sample一个主题$z_n \sim Multinomial \left(\theta\right)$
    b). 从$p\left(w_n|z_n,\beta \right)$中Sample一个词。$p\left(w_n|z_n,\beta \right)$这个概率分布函数是一个多项式分布,它是指在主题给定条件下产生词$w_n$的概率。

主题模型的一个例子

[Blei, David M., Andrew Y. Ng, and Michael I. Jordan. “Latent dirichlet allocation.” JMLR 2003.]
在上图中,左边的四种颜色的方框是四个主题(topic),在每个topic下的word服从多项式分布(multinomial)。如何产生这篇文章的所有词呢,我们通过右边“折方图”(表示每一个文档的topic分布),对于该分布中的每一个topic我们来通过$P\left(w_n|z_n,\beta \right)$生成word,由于文档的topic不是固定的(是一个随机变量,服从多项式分布),对于每一个topic我们都来产生words,因此我们最后得到多数的words很大程度上能够对那个概率比较大的topic的一种表示。
主题模型
[Blei, David M., Andrew Y. Ng, and Michael I. Jordan. “Latent dirichlet allocation.” JMLR 2003.]
上图是LDA的图模型的表示,$\alpha$,$\eta$是超参数,在训练整个模型之前要确定好。$\theta$,$Z$,$\beta$是我们希望来做推断(inference)的随机变量。在整个模型中我们只可观察到D个文档,每个文档有$W_d$个词。

2.基于矩阵SVD分解的词向量

第二部分我想讨论一下基于矩阵分解的词向量的方法,我们的目的是获得词典中每个词的一个向量表示。那很直接的想法就是我通过语料库来构建一个Co-occurrence矩阵,矩阵的行和列均代表词典的每个词。矩阵中的每一个值是在语料库中相邻词一起出现的次数。下面我们举个例子:
我们现在有如下的语料库:

I love you.
I love you.
I love you.
I like you.
I like you.
I hate her.

通过这个语料库我们可以构建这个Co-occurrence矩阵。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import numpy as np
import matplotlib.pyplot as plt
la = np.linalg
words = ["I","love","you","her","hate","like"]
X = np.array([[0,3,0,0,1,2],
[3,0,3,1,0,0],
[0,3,0,0,0,2],
[0,1,0,0,1,0],
[1,0,0,1,0,0],
[2,0,2,0,0,0]])
U,s,Vh = la.svd(X,full_matrices = False)
for i in xrange(len(words)):
plt.text(U[i,0],U[i,1],words[i])
plt.plot(U[i,0],U[i,1])
plt.show()

这个矩阵就是代码中的变量$X$。我们去分解后的$U$矩阵的前两列的值作为每一个词向量。可视化看一下结果:
用SVD方法来学词向量
我们可以看到,很多信息可以被抓取到,比如,word I和word you在几何关系上面很近。当然,由于语料库很少,深层次的语义还没有被挖掘。这样的方法有什么缺陷呢?可想而知,当语料库很大的时候,词典非常长,矩阵就特别大,我们很难对这个这个矩阵进行SVD分解。于是Bengio等人就在2003年提出了基于神经网络的方法来解决这类问题,后续有很多的变种,都是基于目标函数迭代的思路来得到词向量。我们在下一篇博客在讨论。