NLP

浅谈词向量

n元模型与word2vec

Posted by Xiaosheng on June 8, 2017

1. 词向量

One-hot Representation

词的向量化表示是自然语言处理中常见的一个操作,是搜索引擎、广告系统、推荐系统等互联网服务背后常见的基础技术。

在互联网服务里,我们经常要比较两个词或者两段文本之间的相关性,这就需要首先要把词表示成计算机适合处理的方式。最自然的方式恐怕莫过于 One-hot Representation。 在这种方式里,每个词被表示成一个 one-hot vector,其长度为字典大小,每个维度对应字典里的一个词,除了这个词对应维度上的值是 $1$,其他元素都是 $0$。例如:

“话筒”表示为 $[0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0…]$
“麦克风”表示为 $[0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,…]$

每个词都是茫茫 $0$ 海中的一个 $1$。

One-hot vector 如果采用稀疏方式存储,即给每个词分配一个数字 ID,就会非常简洁。比如刚才的例子中,话筒记为 3,麦克风记为 8。编程实现的话,用 Hash 表给每个词分配一个编号就可以了。这么简洁的表示方法配合上最大熵、SVM、CRF 等等算法已经很好地完成了 NLP 领域的各种主流任务。

One-hot vector 虽然自然,但是用处有限。比如,在互联网广告系统里,如果用户输入的查询是“话筒”,而有一个广告的关键词是“麦克风”。虽然按照常理,我们知道这两个词之间是近义词,但是这两个词对应的 one-hot vectors 之间的距离度量,无论是欧氏距离还是余弦相似度(cosine similarity),由于其向量正交,都认为这两个词毫无相关性。 得出这种与我们相悖的结论的根本原因是:每个词本身的信息量都太小。所以,仅仅给定两个词,不足以让我们准确判别它们是否相关。要想精确计算相关性,我们还需要更多的信息——从大量数据里通过机器学习方法归纳出来的知识。

Distributed Representation

既然上述这种易于理解的 One-hot Representation 词向量表示方式具有这样的重要缺陷,那么就需要一种既能表示词本身又可以考虑语义距离的词向量表示方法,这就是我们接下来要介绍的 Distributed representation 词向量表示方法。

Distributed representation 最早由 Hinton 在 1986 年提出,相比于 One-hot Representation,它可以将一个词映射到一个维度更低的实数向量,例如:$[0.792, −0.177, −0.107, 0.109, −0.542, …]$。维度以 $50$ 维和 $100$ 维比较常见,当然了,这种向量的表示不是唯一的。Distributed representation 最大的贡献就是让相关或者相似的词,在距离上更接近,距离可以用欧氏距离来衡量,也可以用余弦相似度(cosine similarity)来衡量。这样如“话筒”和“麦克风”的对应词向量的余弦相似度就不再为零了。

下图展示了用数据可视化算法 t-SNE 画出的词语特征在二维上的投影:

1

从图中可以看出,语义相关的词语(如 a, the, these; big, huge)在投影上距离很近,语意无关的词(如 say, business; decision, japan)在投影上的距离很远。另一方面,我们知道两个向量的余弦值在 $[−1,1]$ 的区间内:两个完全相同的向量余弦值为 $1$, 两个相互垂直的向量之间余弦值为 $0$,两个方向完全相反的向量余弦值为 $-1$,即相关性和余弦值大小成正比。因此我们还可以计算两个词向量的余弦相似度:

please input two words: big huge
similarity: 0.899180685161

please input two words: from company
similarity: -0.0997506977351

Distributed representation 用来表示词,通常被称为 Word Representation 或 Word Embedding,中文称为词向量或词嵌入。自从 21 世纪以来,人们逐渐从原始的词向量稀疏表示法过渡到现在的低维空间中的密集表示。用稀疏表示法在解决实际问题时经常会遇到维数灾难,并且语义信息无法表示,无法揭示词语之间的潜在联系。而采用低维空间表示法,不但解决了维数灾难问题,并且挖掘了词语之间的关联属性,从而提高了向量语义上的准确度。

词向量模型

词向量模型可以是概率模型、共生矩阵(co-occurrence matrix)模型或神经元网络模型。在用神经网络求词向量之前,传统做法是统计一个词语的共生矩阵 $X$。$X$ 是一个 $|V|\times|V|$ 大小的矩阵,$X_{ij}$ 表示在所有语料中,词汇表 V(vocabulary)中第 $i$ 个词和第 $j$ 个词同时出现的次数,$|V|$ 为词汇表的大小。对 $X$ 做矩阵分解(如奇异值分解,Singular Value Decomposition),得到的 $U$ 即视为所有词的词向量:

但这样的传统做法有很多问题:

  1. 由于很多词没有出现,导致矩阵极其稀疏,因此需要对词频做额外处理来达到好的矩阵分解效果
  2. 矩阵非常大,维度太高(通常达到 $10^6∗10^6$ 的数量级)
  3. 需要手动去掉停用词(如 although, a,…),不然这些频繁出现的词也会影响矩阵分解的效果

基于神经网络的模型不需要计算存储一个在全语料上统计的大表,而是通过学习语义信息得到词向量,因此能很好地解决以上问题。

2. 语言模型

在这里我们介绍三个训练词向量的模型:$\text{N-gram}$ 模型,$\text{CBOW}$ 模型和 $\text{Skip-gram}$ 模型,它们的中心思想都是通过上下文得到一个词出现的概率。后两个模型,就是近年来最有名的神经元词向量模型 $\text{word2vec}$ 的两种实现方法,由 Tomas Mikolov 在Google 研发,虽然它们很浅很简单,但训练效果很好。

语言模型

在介绍词向量模型之前,我们先来引入一个概念:语言模型。 语言模型旨在为语句的联合概率函数 $P(w_1,…,w_T) $ 建模, 其中 $w_i$ 表示句子中的第 $i$ 个词。语言模型的目标是,希望模型对有意义的句子赋予大概率,对没意义的句子赋予小概率。 这样的模型可以应用于很多领域,如机器翻译、语音识别、信息检索、词性标注、手写识别等,它们都希望能得到一个连续序列的概率。 以信息检索为例,当你在搜索 “how long is a football bame” 时(bame 是一个医学名词),搜索引擎会提示你是否希望搜索 ”how long is a football game”, 这是因为根据语言模型计算出 “how long is a football bame” 的概率很低,而与 bame 近似的,可能引起错误的词中,game 会使该句生成的概率最大。

对语言模型的目标概率 $P(w_1,…,w_T)$,如果假设文本中每个词都是相互独立的,则整句话的联合概率可以表示为其中所有词语条件概率的乘积,即:

然而我们知道语句中的每个词出现的概率都与其前面的词紧密相关, 所以实际上通常用条件概率表示语言模型:

N-gram neural model

在计算语言学中,$\text{N-gram}$ 是一种重要的文本表示方法,表示一个文本中连续的 $n$ 个项。基于具体的应用场景,每一项可以是一个字母、单词或者音节。 $\text{N-gram}$ 模型也是统计语言模型中的一种重要方法,用 $\text{N-gram}$ 训练语言模型时,一般用每个 $\text{N-gram}$ 的历史 $n-1$ 个词语组成的内容来预测第 $n$ 个词。

用神经网络训练语言模型的思想最早由百度 IDL 的徐伟于 2000 年提出,其论文《Can Artificial Neural Networks Learn Language Models?》提出一种用神经网络构建二元语言模型(即 $P(w_t\mid w_{t−1})$)的方法。文中的基本思路与后续的语言模型的差别已经不大了。

Yoshua Bengio 等科学家于 2003 年在著名论文《Neural Probabilistic Language Models》中介绍了如何学习一个神经元网络表示的词向量模型。文中的神经概率语言模型(Neural Network Language Model,NNLM)通过一个线性映射和一个非线性隐层连接,同时学习了语言模型和词向量,即通过学习大量语料得到词语的向量表达,通过这些向量得到整个句子的概率。用这种方法学习语言模型可以克服维度灾难(curse of dimensionality),即训练和测试数据不同导致的模型不准。

注意:由于“神经概率语言模型”说法较为泛泛,我们在这里不用其 NNLM 的本名,考虑到其具体做法,本文中称该模型为 N-gram neural model。

我们在上文中已经讲到用条件概率建模语言模型,即一句话中第 $t$ 个词的概率和该句话的前 $t−1$ 个词相关。可实际上越远的词语其实对该词的影响越小,那么如果考虑一个 n-gram,每个词都只受其前面 n-1 个词的影响,则有:

给定一些真实语料,这些语料中都是有意义的句子,N-gram 模型的优化目标则是最大化目标函数:

其中 $f(w_t,w_{t−1},…,w_{t−n+1})$ 表示根据历史 $n-1$ 个词得到当前词 $w_t$ 的条件概率,$R(\theta)$ 表示参数正则项。

2

上图展示了 N-gram 神经网络模型,对于每个样本,模型输入前 $n-1$ 个词 $w_{t−n+1},…w_{t−1}$,输出句子第 $n$ 个词 $w_t$ 为字典中 |V| 个词的概率。

从下往上看,该模型分为以下几个部分:

  • 输入层:每个输入词 $w_{t−n+1},…w_{t−1}$ 首先通过映射矩阵映射到词向量 $C(w_{t−n+1}),…C(w_{t−1})$。整个模型中使用的是一套唯一的词向量,存储在矩阵 $C$($|V|\times m$ 维)中。其中 $|V|$ 表示字典的大小,$m$ 表示词向量的维度,$w$ 到 $C(w)$ 的转化就是从矩阵中取出一行。然后将 $C(w_{t−n+1}),…C(w_{t−1})$ 这 $n-1$ 个词向量首尾相接拼接成一个大向量($(n−1)m\times1$ 维),记为 $x$。

  • 隐藏层:(设有 $h$ 个隐层单元)就如同普通的神经网络,先使用 $Hx+d$ 计算,$d$ 为偏置项,然后经过一个非线性激活函数 $\tanh$ 得到历史词语的隐层表示:

  • 输出层:(共有 $|V|$ 个单元)每个节点 $g_i$ 表示未经归一化的字典中第 $i$ 个单词的输出概率。最后使用 $\text{softmax}$ 激活函数将输出值 $g$ 归一化成概率。最终,$g$ 的计算公式为:

    其中,$U$($|V|\times h$ 维)是隐藏层到输出层的参数,$W$($|V|\times (n-1)m$ 维)包含了从输入层到输出层的直连边。根据 $\text{softmax}$ 的定义,通过归一化 $g_i$,生成目标词 $w_t$ 的概率为:

整个网络的损失值(cost)为多类分类交叉熵,用公式表示为:

其中 $y^i_k$ 表示第 $i$ 个样本第 $k$ 类的真实标签($0$ 或 $1$),$\text{softmax}(g^i_k)$ 表示第 $i$ 个样本第 $k$ 类 $\text{softmax}$ 输出的概率。最后使用随机梯度下降法把这个模型优化出来就可以了。需要注意的是,一般神经网络的输入层只是一个输入值,而在这里,输入层 $x$ 也是参数(存储在 $C$ 中),也是需要优化的,优化结束之后就获得词向量了。

Continuous Bag-of-Words model(CBOW)

$\text{CBOW}$ 模型通过一个词的上下文(各 $N$ 个词)预测当前词。当 $N=2$ 时,模型如下图所示:

3

具体来说,不考虑上下文的词语输入顺序,$\text{CBOW}$ 是用上下文词语的词向量的均值来预测当前词。即:

其中 $x_t$ 为第 $t$ 个词的词向量,分类分数(score)向量 $z=U * \text{context}$,最终的分类 $y$ 采用 $\text{softmax}$,损失函数采用多类分类交叉熵。

Skip-gram model

$\text{CBOW}$ 的好处是对上下文词语的分布在词向量上进行了平滑,去掉了噪声,因此在小数据集上很有效。而 $\text{Skip-gram}$ 的方法中,用一个词预测其上下文,得到了当前词上下文的很多样本,因此可用于更大的数据集。

4

如上图所示,$\text{Skip-gram}$ 模型的具体做法是,将一个词的词向量映射到 $2n$ 个词的词向量($2n$ 表示当前输入词的前后各 $n$ 个词),然后分别通过 $\text{softmax}$ 得到这 $2n$ 个词的分类损失值之和。

总结

在信息检索中,我们可以根据向量间的余弦夹角,来判断查询和文档关键词这二者间的相关性。在句法分析和语义分析中,训练好的词向量可以用来初始化模型,以得到更好的效果。在文档分类中,有了词向量之后,可以用聚类的方法将文档中同义词进行分组。

参考

PaddlePaddle 教程《词向量》
LICSTAR《Deep Learning in NLP (一)词向量和语言模型》
Poll《文本深度表示模型——word2vec&doc2vec词向量模型》