Word2vec 模型构建及可视化

文本本质上是一种非结构化的数据,无论过去还是现在,其在数学中的研究远远少于向量。历史上数学家牛顿是第一个在力学情境中研究向量的人。向量的概念已经存在了三个世纪,其科学性已非常成熟。而文本数据的数学探索这个概念只有几十年的历史。现在文本数据的数学思考应用尤其重要。数据的价值已被理解但是还未兑现。大部分商业相关信息最初都是非结构化形式,主要是文本。数据只有读取之后才可见,才能用于商业、教育、政府管理和医疗之中。文本数据的数学探索能够产生洞见提供给医生、企业家、营销人员和教师用来做决策。

语言模型

在深入word2vec算法的细节之前,我们先回顾一下NLP中的一个基本问题:如何计算一段文本序列在某种语言下出现的概率?

之所为称其为一个基本问题,是因为它在很多NLP任务中都扮演着重要的角色。例如,在机器翻译的问题中,如果我们知道了目标语言中每句话的概率,就可以从候选集合中挑选出最合理的句子做为翻译结果返回。

统计语言模型

在统计自然语言处理中,语言模型指的是计算一个句子的概率模型。对于一段文本序列S=w1,w2,...,wT,它的概率可以表示为:


即将序列的联合概率转化为一系列条件概率的乘积。问题变成了如何去预测这些给定previous words下的条件概率p(wt|w1,w2,...,wt−1)。

由于其巨大的参数空间,这样一个原始的模型在实际应用中并没有什么效率。我们更多的是采用其简化版本——Ngram模型


常见的如bigram模型(N=2)和trigram模型(N=3)。

事实上,由于模型复杂度和预测精度的限制,我们很少会考虑N>3的模型。

我们可以用最大似然法去求解N-gram模型的参数—— 等价于去统计每个N-gram的条件词频

N-gram模型仍有其局限性。首先,由于参数空间的爆炸式增长,它无法处理更长程的context(N>3)。其次,它没有考虑词与词之间内在的联系性。例如,考虑"the cat is walking in the bedroom"这句话。如果我们在训练语料中看到了很多类似“the dog is walking in the bedroom”或是“the cat is running in the bedroom”这样的句子,那么,即使我们没有见过这句话,也可以从“cat”和“dog”(“walking”和“running”)之间的相似性,推测出这句话的概率。然而, Ngram模型做不到。

这是因为,N-gram本质上是将词当做一个个孤立的原子单元(atomic unit)去处理的, 这种处理方式对应到数学上的形式是一个个离散的one-hot向量(除了一个词典索引的下标对应的方向上是1,其余方向上都是0)。例如,对于一个大小为5的词典:{"I", "love", "natural", "language", "processing"},“nature”对应的one-hot向量为:[0,0,1,0,0]。显然,one-hot向量的维度等于词典的大小,这在动辄上万甚至百万词典的实际应用中,面临着巨大的维度灾难问题(the curse of dimensionality)。

神经网络语言模型

鉴于N-gram等模型的不足,2003年,Bengio等人发表了一篇开创性的文章:A neural probabilistic language model。在这篇文章里,他们总结出了一套用神经网络建立统计语言模型的框架(Neural Network Language Model,以下简称NNLM),并首次提出了word embedding的概念,从而奠定了包括word2vec在内后续研究word representation learning的基础。

NNLM模型的基本思想可以概括如下:
假定词表中的每一个word都对应着一个连续的特征向量
假定一个连续平滑的概率模型,输入一段词向量的序列,可以输出这段序列的联合概率
同时学习词向量的权重和概率模型里的参数。

值得注意的一点是,这里的词向量也是要学习的参数。

在03年的论文里,Bengio等人采用了一个简单的前向反馈神经网络f(wt−n+1,...,wt)来拟合一个词序列的条件概率p(wt|w1,w2,...,wt−1)。整个模型的网络结构见下图:


可以将整个模型拆分成两部分加以理解:

首先是一个线性的embedding层。它将输入的N−1个one-hot词向量,通过一个共享的D×V的矩阵C,映射为N−1个分布式的词向量(distributed vector)。其中,V是词典的大小,D是embedding向量的维度(一个先验参数)。C矩阵里存储了要学习的word vector。其次是一个简单的前向反馈神经网络g,它由一个tanh隐层和一个softmax输出层组成。通过将embedding层输出的N−1个词向量映射为一个长度为V的概率分布向量,从而对词典中的word在输入context下的条件概率做出预估:

p(wi|w1,w2,...,wt−1)≈f(wi,wt−1,...,wt−n+1)=g(wi,C(wt−n+1),...,C(wt−1))


我们可以通过最小化一个cross-entropy的正则化损失函数来调整模型的参数θ:


其中,模型的参数θ 包括了embedding层矩阵C的元素,和前向反馈神经网络模型g里的权重。这是一个巨大的参数空间。不过,在用SGD学习更新模型的参数时,并不是所有的参数都需要调整(例如未在输入的context中出现的词对应的词向量)。计算的瓶颈主要是在softmax层的归一化函数上(需要对词典中所有的word计算一遍条件概率)。

然而,抛却复杂的参数空间,我们不禁要问,为什么这样一个简单的模型会取得巨大的成功呢?

仔细观察这个模型就会发现,它其实在同时解决两个问题:

一个是统计语言模型里关注的条件概率p(wt|context)的计算;

一个是向量空间模型里关注的词向量的表达。而这两个问题本质上并不独立。通过引入连续的词向量平滑的概率模型,我们就可以在一个连续空间里对序列概率进行建模,从而从根本上缓解数据稀疏性和维度灾难的问题

NNLM缺点

NNLM存在的几个问题:

1. 一个问题是,同Ngram模型一样,NNLM模型只能处理定长的序列。在03年的论文里,Bengio等人将模型能够一次处理的序列长度N提高到了5,虽然相比bigram和trigram已经是很大的提升,但依然缺少灵活性。

因此,Mikolov等人在2010年提出了一种 RNNLM 模型, 递归神经网络代替原始模型里的前向反馈神经网络,并将embedding层与RNN里的隐藏层合并,从而解决了变长序列的问题


2. NNLM的训练太慢了。即便是在百万量级的数据集上,即便是借助了40个CPU进行训练,NNLM也需要耗时数周才能给出一个稍微靠谱的解来。显然,对于现在动辄上千万甚至上亿的真实语料库,训练一个NNLM模型几乎是一个impossible mission。
(一般线上应用 不用该模型)

如果我们只是想得到word的连续特征向量,是不是可以对第二步里的神经网络模型进行简化呢?


Mikolov是这么想的,也是这么做的。他在2013年一口气推出了两篇paper,并开源了一款计算词向量的工具——至此,word2vec横空出世,主角闪亮登场。

下面,我将带领大家简单剖析下word2vec算法的原理。有了前文的基础,理解word2vec算法就变得很简单了。

首先,我们对原始的NNLM模型做如下改造:
  •     移除前向反馈神经网络中非线性的hidden layer,直接将中间层的embedding layer与输出层的softmax layer连接
  •     忽略上下文环境的序列信息:输入的所有词向量均汇总到同一个embedding layer
  •     将future words纳入上下文环境

得到的模型称之为CBOW模型(Continuous Bag-of-Words Model),也是word2vec算法的第一个模型。

Word2vec

Word2Vec 是一种将词转换成向量的方法, Word2Vec 来生成向量捕捉词意并启用与单词相关联的算术运算

例如:向量(king)+向量(woman)-向量(man)=一个接近向量(queen)的向量

2013年Google开源了一款用于词向量计算的工具Word2vec,引起了工业界和学术界的关注。首先,word2vec可以在百万数量级的词典和上亿的数据集上进行高效地训练;其次,该工具得到的训练结果——词向量(word embedding),可以很好地度量词与词之间的相似性。其实word2vec算法的本质上是一个浅层神经网络主要有CBOW模型和Skip-gram模型。当我们在说word2vec算法或模型的时候,其实指的是其背后用于计算word vector的CBoW模型和Skip-gram模型。

其中w(t)代表当前词语位于句子的位置t,同理定义其他记号。在窗口内(上图为窗口大小为5),除了当前词语之外的其他词语共同构成上下文。

CBOW

CBOW ( Continuous Bag-of-Words Model) ,是一种根据上下文的词语预测当前词语的出现概率的模型

CBOW是已知上下文,估算当前词语的语言模型。其学习目标是最大化对数似然函数


其中,w表示语料库C中任意一个词。

输入层(INPUT):是上下文的词语的词向量(什么!我们不是在训练词向量吗?不不不,我们是在训练CBOW模型,词向量只是个副产品,确切来说,是CBOW模型的一个参数。训练开始的时候,词向量是个随机值,随着训练的进行不断被更新)。

投影层(PROJECTION): 对其求和,所谓求和,就是简单的向量加法

输出层(OUTPUT): 输出最可能的w。由于语料库中词汇量是固定的|C|个,所以上述过程其实可以看做一个多分类问题。给定特征,从|C|个分类中挑一个。对于神经网络模型多分类,最朴素的做法是softmax回归。

Skip-gram模型

skip-gram是当前词,来预测上下文。其学习目标是最大化对数似然函数:


softmax回归需要对语料库中每个词语(类)都计算一遍输出概率并进行归一化,在几十万词汇量的语料上无疑是令人头疼的。


如何优化训练词向量


Hierarchical Softmax

两种网络结构的最后一层都是一个大的softmax,起到对于每个词的预测概率起归一化作用,可是在实际训练过程中每次迭代都要通过softmax计算每个词的概率是相当耗费时间,能否优化这个呢?

这个问题早在03年Bengio提出的语言模型也遇到,后来他们提出了Hierarchical Softmax来加速

其基本网络结构都是在下图的基础上,省略掉hidden layer



Huffman树

word2vec训练的时候按照词频将每个词语Huffman编码,由于Huffman编码中词频越高的词语对应的编码越短。所以越高频的词语在Hierarchical Softmax过程中经过的二分类节点就越少,整体计算量就更少。

负采样算法

任何采样算法都应该保证频次越高的样本越容易被采样出来。基本的思路是对于长度为1的线段,根据词语的词频将其公平地分配给每个词语:


counter就是w的词频。于是我们将该线段公平地分配了:


接下来我们只要生成一个0-1之间的随机数,看看落到哪个区间,就能采样到该区间对应的单词了,很公平。
但怎么根据小数找区间呢?速度慢可不行。
word2vec用的是一种查表的方式,将上述线段标上M个“刻度”,刻度之间的间隔是相等的,即1/M:

接着我们就不生成0-1之间的随机数了,我们生成0-M之间的整数,去这个刻度尺上一查就能抽中一个单词了。
在word2vec中,该“刻度尺”对应着table数组。具体实现时,对词频取了0.75次幂:

sigmoid函数

类似的查表方法还有sigmoid函数的计算,因为该函数使用太频繁,而其值仅仅在靠近0的时候才会剧烈变化,远离0的方向很快趋近0和1。所以源码中也采用了“刻度查表”的方法,先算出了很多个刻度对应的函数值,运算中直接查表。

实现

谷歌开源了其代码,有C/C++, python, JAVA, 具体想要快速实验训练一个Word2Vec, 推荐可以使用python 的gensim 模块。

可参考我在语料(SougouCS)上构建和可视化word2vec模型https://github.com/Yang-Charles/Build-and-visualize--word2vec-model


猜你喜欢

转载自blog.csdn.net/u010899985/article/details/79693222
今日推荐