Word embedding系列(二):word2vec详解

本文参考了http://www.cnblogs.com/pinard/p/7160330.html 这个博客的系列文章,建议如果有空可以看一下原博客,写的容易理解又很深入详细~

word2vec我准备分为四部分介绍:

1.CBOW模型与skip-gram模型

2.基于Hierarchical Softmax的模型

3.基于Negative Sampling的模型

4.代码示例

1.CBOW与Skip-gram

CBOW模型的训练输入是某个词的上下文相关词对应的词向量,输出就是这个词的词向量。

Skip-Gram模型和CBOW的思路是反着的,即输入是一个词的词向量,而输出是它对应的上下文词向量。

如图所示,是一个词w和它的上下文(context(w))的示意图:

2.基于HierarchicalSoftmax的模型

word2vec用霍夫曼树代替隐藏层和输出层的神经元,词频为霍夫曼树节点权重

根节点的词向量: 投影后的词向量,

所有叶子节点: 之前神经网络softmax输出层的神经元,

叶子节点的个数: 词汇表的大小。

cbow和skipgram本质上一样,因为cbow输入的是上下文所有词向量的和,所以这里就只给出一个cbow的示意图。

skipgram和cbow的输出的区别就在于取概率最大的还是概率前n大的。

霍夫曼树中出现频次越高的词离树根越近,也就是说编码越短。在霍夫曼树中,隐藏层到输出层的softmax映射不是一下完成的,而是沿着霍夫曼树一步步完成的,因此这种softmax取名为"Hierarchical Softmax"。

在构建树时,高频放右边。规定沿着左子树走是负类(霍夫曼树编码1),沿着右子树走是正类(霍夫曼树编码0)。使用sigmoid函数来计算是正类还是负类:

P(−)=1−P(+)

xw是当前内部节点的词向量,θ是需要从训练样本求出的逻辑回归的模型参数。被划分为左子树而成为负类的概率为P(−)=1−P(+),判断走左右子树就是看P(−)、P(+)谁大。

目标就是找到合适的所有节点的词向量和所有内部节点参数θ, 使训练样本达到最大似然。对于所有的训练样本,期望最大化所有样本的似然函数乘积。

符号意义如下:

定义w经过的霍夫曼树某一个节点j的逻辑回归概率

那么对于某一个词w,它的最大似然为:

在word2vec中,由于使用的是随机梯度上升法,所以并没有把所有样本的似然乘起来得到真正的训练集最大似然,仅仅每次只用一个样本更新梯度,这样做的目的是减少梯度计算量。

可以得到w的对数似然函数L如下:

使用梯度上升法来得到模型中w词向量和内部节点的模型参数θ,求模型参数的梯度

于是算法流程为:

Cdow和skip-gram的算法流程如图所示。由于上下文是相互的,为了迭代的平衡,Skip-Gram模型并没有和CBOW模型一样对输入进行迭代更新,而是对2c个输出进行迭代更新。

两种算法都是一次迭代对更多的词进行更新。

3.基于Negative Sampling的模型

使用霍夫曼树来代替传统的神经网络,可以提高模型训练的效率。但是如果训练样本里的中心词w是一个很生僻的词,那么就得在霍夫曼树中向下走很久。Negative Sampling将模型变的更加简单,它摒弃了霍夫曼树,采用了NegativeSampling(负采样)的方法来求解。

比如有一个训练样本,中心词是w,它周围上下文共有2c个词,记为context(w)。由于这个中心词w,的确和context(w)相关存在,因此它是一个真实的正例。通过Negative Sampling采样,得到neg个和w不同的中心词wi,i=1,2,..neg,这样context(w)和wi就组成了neg个并不真实存在的负例

利用这一个正例neg个负例,进行二元逻辑回归,得到负采样对应每个词对应的模型参数和每个词的词向量。

(1)负采样方法

如果词汇表的大小为V,那么我们就将一段长度为1的线段分成V份,每份对应词汇表中的一个词。当然每个词对应的线段长度是不一样的,高频词对应的线段长,低频词对应的线段短。每个词w的线段长度由下式决定:

在word2vec中,分子和分母都取了3/4次幂

由于这样划分的是非等距剖分,为了将长度划分为等距,word2vec中将线段划分为M等份,M远大于V,于是采样时只要从M里面随机采样出neg个位置就可以,此时采样到的每一个位置对应到的线段所属的词就是我们的负例词。

ps:其实就是把从词典中随机取词变成了从语料中随机取词

(2)模型计算

正例需要满足:

负例需要满足:

于是整体的目标函数应为最大化下式:

此时对应的似然函数为:

求梯度:

算法流程为:

4.代码与示例

Google c源码:https://code.google.com/archive/p/word2vec/

Genism库版本:https://radimrehurek.com/gensim/models/word2vec.html

Tensorflow basic版本:

https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/tutorials/word2vec/word2vec_basic.py

示例使用gensim库提供的word2vec框架

输入:

选择的《in the name of people》的小说原文作为语料

首先,加载jieba库,对文本进行分词,以行为单位逐行读入文本,对每行(line)进行分词,加入下面的一串人名是为了jieba分词能更准确的把人名分出来。然后将文本中的标点符号替换为空,即去除标点符号,然后将分词结果存入in_the_name_of_people_segment.txt中。

分词结果

训练模型:

现在可以直接读分词后的文件到内存。这里使用了word2vec提供的LineSentence类来读文件,然后用word2vec的模型。

模型出来了,可以用来做什么呢?这里给出几个常用的应用。

首先,我们会有词表中每个词语的词向量表示

两个词的相似度

与一个词最相近的其他词

判断一个文本中最不相似的词

这是用哈利波特英文小说作为语料训练的词向量,经过降维后的可视化展示。可以看到harry、ron、hemion的距离都很近

ok,word2vec的介绍告一段落~

感谢各个博客大神,希望看了这篇文章你没有很晕。有哪些细节不太清楚,欢迎交流~

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180810G1XOJG00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券