导读

  • 本文简单的介绍了Google 于 2013 年开源推出的一个用于获取 word vector 的工具包(word2vec),并且简单的介绍了其中的两个训练模型(Skip-gram,CBOW),以及两种加速的方法(Hierarchical Softmax,Negative Sampling)。

一 、word2vec

  • word2vec最初是由Tomas Mikolov 2013年在ICLR发表的一篇文章[Efficient Estimation of Word Representations in Vector Space], 并且开源了代码,作用是将所有词语投影到K维的向量空间,每个词语都可以用一个K维向量表示。由于它简洁,高效的特点,引起了人们的广泛关注,并应用在很多NLP任务中,用于训练相应的词向量。

1、传统的词表示 --- one-hot representation

  • 这种方法把每个词表示为一个很长的向量。这个向量的维度是词表大小,其中绝大多数元素为 0,只有一个维度的值为 1,这个维度就代表了当前的词。

  • 假如词表是:[气温、已经、开始、回升、了],那么词的词向量分别可以是[1,0,0,0,0],[0,1,0,0,0],[0,0,1,0,0],[0,0,0,1,0],[0,0,0,0,1]。这样的表示方法简单容易理解,而且编程也很容易实现,只需要取对应的索引就能够完成,已经可以解决相当一部分NLP的问题,但是仍然存在不足,即词向量与词向量之间都是相互独立的;我们都知道,词与词之间是有一定的联系的,我们无法通过这种词向量得知两个词在语义上是否相似,并且如果词表非常大的情况下,每个词都是茫茫 0 海中的一个 1,这种高维稀疏的表示也有可能引发维度灾难。为了解决上述问题,就有了词向量的第二种表示方法。

2、Distributed representation --- word embedding

  • word2vec就是通过这种方法将词表示为向量,即通过训练将词表示为限定维度K的实数向量,这种非稀疏表示的向量很容易求它们之间的距离(欧式、余弦等),从而判断词与词语义上的相似性,也就解决了上述one-hot方法表示两个词之间的相互独立的问题。

  • 不过Distributed representation并不是word2vec诞生才有的, Distributed representation 最早是 Hinton 在 1986 年的论文《Learning distributed representations of concepts》中提出的。虽然这篇文章没有说要将词做 Distributed representation,但至少这种先进的思想在那个时候就在人们的心中埋下了火种,到 2000 年之后开始逐渐被人重视。 word2vec之所以会产生这么大的影响,是因为它采用了简化的模型,使得训练速度大为提升,让word embedding这项技术(也就是词的distributed representation)变得实用,能够应用在很多的任务上。

二 、Skip-Gram model and CBOW model

  • 我们先首先来看一下两个model的结构图。

  • 上图示CBOWSkip-Gram的结构图,从图中能够看出,两个模型都包含三层结构,分别是输入层投影层输出层;CBOW模型是在已知当前词上下文context的前提下预测当前词w(t),类似阅读理解中的完形填空;而Skip-Gram模型恰恰相反,是在已知当前词w(t)的前提下,预测上下文context。

  • 对于CBOWSkip-Gram两个模型,word2vec给出了两套框架,用于训练快而好的词向量,他们分别是Hierarchical SoftmaxNegative Sampling,下文将介绍这两种加速方法。

三 、Negative Sampling

1、 Negative Sampling

  • 比如我们的训练样本,中心词是w,它周围上下文共有2c个词,记为context(w)。由于这个中心词w,的确和context(w)相关存在,因此它是一个真实的正例。通过Negative Sampling进行负采样,我们得到neg(负采样的个数)个和w不同的中心词wi,i=1,2,..neg,这样context(w)和wi就组成了neg个并不真实存在的负例。利用这一个正例和neg个负例,我们进行二元逻辑回归(可以理解成一个二分类问题),得到负采样对应每个词wi对应的模型参数以及每个词的词向量。

2、 How to do Negative Sampling?

  • 我们来看一下如何进行负采样,得到neg个负例。word2vec采样的方法并不复杂,如果词汇表的大小为V,那么我们就将一段长度为1的线段分成V份,每份对应词汇表中的一个词。当然每个词对应的线段长度是不一样的,高频词对应的线段长,低频词对应的线段短(根据词频采样,出现的次数越多,负采样的概率越大)。每个词w的线段长度由下式决定:
    -

  • 在采样前,我们将这段长度为1的线段划分成M等份,这里M>>V,这样能够保证每个词对应的线段都会划分成对应的小块,而M份中每一份都会落在某一个词对应的线段上(如下图),采样的时候,我们只需要随机生成neg个数,对应的位置就是采样的负例词。

四 、Hierarchical Softmax

  • 如下图所示:网络结构很简单,仅仅包含三层网络结构,输入层,投影层,输出层。
  • 输入层到投影层是把输入层的所有向量进行加和给投影层,比如,输入的是三个4维词向量:(1,2,3,4),(9,6,11,8),(5,10,7,12),那么我们word2vec映射后的词向量就是(5,6,7,8),对CBOW 模型来说,就是把上下文词向量加和,然而,对于Skip-Gram模型来说就是简单的传值。
  • 最后的输出是构建一颗哈夫曼树,如何去构造简单的哈夫曼树。在这里不在累述;在这里,哈夫曼树的所有叶子节点是词表中的所有词,权值是每个词在词表中出现的次数,也就是词频。

  • 一般得到哈夫曼树后我们会对叶子节点进行哈夫曼编码,由于权重高的叶子节点越靠近根节点,而权重低的叶子节点会远离根节点,这样我们的高权重节点编码值较短,而低权重值编码值较长。这保证的树的带权路径最短,也符合我们的信息论,即我们希望越常用的词(词频越高的词)拥有更短的编码,一般的编码规则是左0右1,但是这都是人为规定的,word2vec中正好采用了相反的编码规则,同时约定左子树的权重不小于右子树的权重。

  • 如何“沿着哈夫曼树一步步完成”呢?
    • 在word2vec中,采用了二元逻辑回归的方法,即规定沿着左子树走,那么就是负类(哈夫曼树编码1),沿着右子树走,那么就是正类(哈夫曼树编码0)。
  • 使用哈夫曼树有什么好处呢?
    • 首先,由于是二叉树,之前计算量为V,现在变成了log2V。
    • 其次,由于使用哈夫曼树是高频的词靠近树根,这样高频词需要更少的时间会被找到,这符合我们的贪心优化思想。

五 、Demo

六 、Experiment Result

1、 Word-Similar Performance

  • 我们在英文语料enwiki-20150112_text.txt(12G)上进行了测试,测试采用的是根据这篇论文 Community Evaluation and Exchange of Word Vectors at wordvectors.org 提供的方法与site(http://www.wordvectors.org/index.php),计算词之间的相似度。
  • 结果如下图所示:由于 pytorch-version 训练速度慢并且demo还没有完善,所以仅在 Cpp-version 和 word2vec源码(C-version)进行了测试对比。以上对比试验均是在相同的参数设置下完成的。

  • 参数设置
    • model: skip-gramloss: Negative Samplingneg: 10
    • dim: 100lr: 0.025windows size: 5minCount: 10iters: 5

  • 上面结果表明,Cpp-versionC-version 训练出来的词向量都能达到一样的性能,甚至还比C-version训练出来词向量稍高一点。

2、 Train Time Performance

  • 由于上述实验是在不同服务器,不同线程数目的情况下进行训练,所以上述实验的训练时间不存在对比,为了测试方便快速,在12G英文语料 enwiki-20150112_text.txt 上取出大约1G的文件,进行重新训练两份词向量,看一下训练时间,下图是实验结果。

  • 上述实验结果能够看出来:Cpp-versionC-version 的训练时间相差不大。

References

[1] Efficient Estimation of Word Representations in Vector Space
[2] Learning distributed representations of concepts
[3] Distributed Representations of Words and Phrasesand their Compositionality
[4] Community Evaluation and Exchange of Word Vectors at wordvectors.org
[5] https://blog.csdn.net/itplus/article/details/37998797(word2vec 中的数学原理详解)
[6] http://www.cnblogs.com/pinard/p/7249903.html(word2vec 原理)

word2vec 理论与实践的更多相关文章

  1. 【C#代码实战】群蚁算法理论与实践全攻略——旅行商等路径优化问题的新方法

    若干年前读研的时候,学院有一个教授,专门做群蚁算法的,很厉害,偶尔了解了一点点.感觉也是生物智能的一个体现,和遗传算法.神经网络有异曲同工之妙.只不过当时没有实际需求学习,所以没去研究.最近有一个这样 ...

  2. Java 理论与实践: 处理 InterruptedException

    捕捉到它,然后怎么处理它? 很多 Java™ 语言方法,例如 Thread.sleep() 和 Object.wait(),都可以抛出InterruptedException.您不能忽略这个异常,因为 ...

  3. Java 理论与实践: 非阻塞算法简介——看吧,没有锁定!(转载)

    简介: Java™ 5.0 第一次让使用 Java 语言开发非阻塞算法成为可能,java.util.concurrent 包充分地利用了这个功能.非阻塞算法属于并发算法,它们可以安全地派生它们的线程, ...

  4. Java 理论与实践: 流行的原子——新原子类是 java.util.concurrent 的隐藏精华(转载)

    简介: 在 JDK 5.0 之前,如果不使用本机代码,就不能用 Java 语言编写无等待.无锁定的算法.在 java.util.concurrent 中添加原子变量类之后,这种情况发生了变化.请跟随并 ...

  5. Java 理论和实践: 了解泛型

    转载自 : http://www.ibm.com/developerworks/cn/java/j-jtp01255.html 表面上看起来,无论语法还是应用的环境(比如容器类),泛型类型(或者泛型) ...

  6. Java 理论与实践: 处理 InterruptedException(转)

    很多 Java™ 语言方法,例如 Thread.sleep() 和 Object.wait(),都可以抛出InterruptedException.您不能忽略这个异常,因为它是一个检查异常(check ...

  7. DDD(领域驱动设计)理论结合实践

    DDD(领域驱动设计)理论结合实践   写在前面 插一句:本人超爱落网-<平凡的世界>这一期,分享给大家. 阅读目录: 关于DDD 前期分析 框架搭建 代码实现 开源-发布 后记 第一次听 ...

  8. Java 理论与实践: 并发集合类

    Java 理论与实践: 并发集合类 DougLea的 util.concurrent 包除了包含许多其他有用的并发构造块之外,还包含了一些主要集合类型 List 和 Map 的高性能的.线程安全的实现 ...

  9. 浅读《视觉SLAM十四讲:从理论到实践》--操作1--初识SLAM

    下载<视觉SLAM十四讲:从理论到实践>源码:https://github.com/gaoxiang12/slambook 第二讲:初识SLAM 2.4.2 Hello SLAM(书本P2 ...

随机推荐

  1. Python3 使用 logging.basicConfig() 配置输出日志中的中文乱码解决办法

    在源码中修改encoding='utf-8',因为 logging.basicConfig() 配置时实际上是用到了4大组件,只不过给了默认值而已,如果不知道怎么找到源码,告诉你们个快捷键,选中你lo ...

  2. Collections常用方法总结

    public class CollectionsTest { public static void main(String[] args) { List<Integer> list = n ...

  3. python学习笔记-list的用法

    1.list的定义 list = [] list = [1,2,'a','b'](list中的元素不一定是一个类型) 2.list的操作 1)list.append(value) 2)list.ins ...

  4. 剑指offer:斐波那契数列

    目录 题目 解题思路 具体代码 题目 题目链接 剑指offer:斐波那契数列 题目描述 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0). n< ...

  5. 封装 RabbitMQ.NET

    这篇文章内容会很短,主要是想给大家分享下我最近在做一个简单的rabbitmq客户端类库的封装的经验总结,说是简单其实一点都不简单.为了节省时间我主要按照Library的执行顺序来介绍,在你看来这里仅仅 ...

  6. 玩lua

    https://my.oschina.net/wangxuanyihaha/blog/186401

  7. 【题解】SDOI2010地精部落

    强!强!强!强!劲啊劲啊劲啊!!!洛谷P2467 非常重要的,就在于发现以下的两条性质: 1.当i与i+1不相邻时,方案数是一样的:交换这两个数,<i+1的必然<i,>i+1的必然& ...

  8. [洛谷P1337][JSOI2004]平衡点 / 吊打XXX

    题目大意:有$n$个重物,每个重物系在一条绳子上.所有绳子系在一起,问绳结最终平衡于何处. 题解:$NOIP$前学学模拟退火,但发现我脸好黑啊... 卡点:脸黑 C++ Code: #include ...

  9. BZOJ3236: [Ahoi2013]作业 树状数组维护 莫队

    水果~~~~ 关于四个while可行性的证明:区间有正确性所以不管那团小东西用没有duang~反它最终总会由于两次覆盖二准确 关于区间种数可行性的证明:他会在0 1间(或两边)来回跳动(过程中),最终 ...

  10. 无人值守安装linux系统

    需要使用到的服务:PXE + DHCP+TFTP+ Kickstart+ FTP KickStart是一种无人职守安装方式 执行 PXE + KickStart安装需要准备内容:  • DHCP 服务 ...