当前位置:   article > 正文

word2vec算法

word2vec

本文是一篇翻译的文章,原文链接是:http://mccormickml.com/2016/04/19/word2vec-tutorial-the-skip-gram-model/
如果你的英语很好,强烈建议直接阅读原文。这篇文章写的非常好,简明扼要,语言流畅。是我认为入门word2vector的最好文章,没有之一。当然,我也不是生硬的翻译,而是理解之后按照自己的逻辑再写出来,希望能更加清晰一些。

1 算法的基本思想

1.1 什么是word2vec

在聊 Word2vec 之前,先聊聊 NLP (自然语言处理)。NLP 里面,最细粒度的是 词语,词语组成句子,句子再组成段落、篇章、文档。所以处理 NLP 的问题,首先就要拿词语开刀。举个简单例子,判断一个词的词性,是动词还是名词。用机器学习的思路,我们有一系列样本(x,y),这里 x 是词语,y 是它们的词性,我们要构建 f(x)->y 的映射,但这里的数学模型 f(比如神经网络、SVM)只接受数值型输入,而 NLP 里的词语,是人类的抽象总结,是符号形式的(比如中文、英文、拉丁文等等),所以需要把他们转换成数值形式,或者说——嵌入到一个数学空间里,这种嵌入方式,就叫词嵌入(word embedding),而 Word2vec,就是词嵌入( word embedding) 的一种我在前作『都是套路: 从上帝视角看透时间序列和数据挖掘』提到,大部分的有监督机器学习模型,都可以归结为:f(x)->y在 NLP 中,把 x 看做一个句子里的一个词语,y 是这个词语的上下文词语,那么这里的 f,便是 NLP 中经常出现的『语言模型』(language model),这个模型的目的,就是判断 (x,y) 这个样本,是否符合自然语言的法则,更通俗点说就是:词语x和词语y放在一起,是不是人话。Word2vec 正是来源于这个思想,但它的最终目的,不是要把 f 训练得多么完美,而是只关心模型训练完后的副产物——模型参数(这里特指神经网络的权重),并将这些参数,作为输入 x 的某种向量化的表示,这个向量便叫做——词向量。

1.2 counting编码举例

word2vector,顾名思义,就是将语料库中的词转化成向量,以便后续在词向量的基础上进行各种计算。最常见的表示方法是counting 编码。假设我们的语料库中是如下三句话:
I like deep learning
I like NLP
I enjoy flying
利用counting编码,我们可以绘出如下矩阵:
在这里插入图片描述
假设语料库中的单词数量是N,则上图矩阵的大小就是N*N,其中的每一行就代表一个词的向量表示。如第一行
0 2 1 0 0 0 0
是单词I的向量表示。其中的2代表I这个单词与like这个词在语料库中共同出现了2次。
似乎我们很简单就完成了“word2vector”是不是?
但是这种办法至少有三个缺陷:

  1. 是词语数量较大时,向量维度高且稀疏,向量矩阵巨大而难以存储
  2. 是向量并不包含单词的语义内容,只是基于数量统计。
  3. 是当有新的词加入语料库后,整个向量矩阵需要更新

尽管我们可以通过SVD来降低向量的维度,但是SVD本身却是一个需要巨大计算量的操作。
很明显,这种办法在实际中并不好用。我们今天学习的skip gram算法可以成功克服以上三个缺陷。它的基本思想是首先将所有词语进行one-hot编码,输入只有一个隐藏层的神经网络,定义好loss后进行训练,后面我们会讲解如何定义loss,这里暂时按下不表。训练完成后,我们就可以用隐藏层的权重来作为词的向量表示!!
这个思想乍听起来很神奇是不是?其实我们早就熟悉它了。auto-encoder时,我们也是用有一个隐藏层的神经网络进行训练,训练完成后,丢去后面的output层,只用隐藏层的输出作为最终需要的向量对象,藉此成功完成向量的压缩。

1.3 Skip-gram 和 CBOW 模型

Skip-gram 和 CBOW 模型是两种常用的word2vec的模型

  • 如果是用一个词语作为输入,来预测它周围的上下文,那这个模型叫做『Skip-gram 模型』
  • 而如果是拿一个词语的上下文作为输入,来预测这个词语本身,则是 『CBOW 模型』

2 举例说明

2.1 构造训练数据

假设我们的语料库中只有一句话:
The quick brown fox jumps over the lazy dog.
这句话中共有8个词(这里The与the算同一个词)。
skip gram算法是怎么为这8个词生成词向量的呢?
我们知道用神经网络训练,大体有如下几个步骤:

  • 准备好data,即X和Y
  • 定义好网络结构
  • 定义好loss
  • 选择合适的优化器
  • 进行迭代训练
  • 存储训练好的网络

所以,我们下面先来关注下如何确定X和Y的形式。
其实非常简单,(x,y)就是一个个的单词对。比如(the,quick)就是一个单词对,the就是样本数据,quick就是该条样本的标签。
那么,如何从上面那句话中生成单词对数据呢?答案就是n-gram方法。多说不如看图:
n-gram

我们以词为单位扫描这句话,每扫描到一个词,都把该词左右各两个词共4个词拿出来,分别与被扫描的单词组成单词对,作为我们的训练数据。
这里有两个细节,一个就是取被扫描单词左右各2个词,这里的2被称为窗口尺寸,是可以调整的,用多大的窗口生成的单词对来训练最好,需要具体问题具体分析。一般来说,取5是很好的经验值。也就是左右各取5个单词,共10个单词。这里我们用2只是为了方便说明问题。
第二个细节就是句子头尾的单词被扫描时,其能取的单词对数要少几个,这个不影响大局,不用理会。
这里我们需要停下来细细琢磨下,我们这样取单词对作为训练数据的目的何在?以(fox,jumps)为例,jumps可以理解为fox的上下文,我们将fox输入神经网络时,希望网络能够告诉我们,在语料库的8个单词中,jumps是更可能出现在fox周围的。
你可能会想,(fox,brown)也是一个单词对,它输入神经网络后,岂不是希望神经网络告诉我们,在8个单词中,brown是更可能出现在fox周围?如果是这样,那么训练完成后的神经网络,输入fox,它的输出会是brown和jumps的哪一个呢?
答案是取决于(fox,brown)和(fox,jumps)两个单词对谁在训练集中出现的次数比较多,神经网络就会针对哪个单词对按照梯度下降进行更多的调整,从而就会倾向于预测谁将出现在fox周围。

2.2 数字化表示单词对

上面我们获得了许多单词对作为训练数据,但是神经网络不能直接接收和输出字符串形式的单词对,所以需要将单词对转化为数字的形式。方法也很简单,就是用one-hot编码,如下图所示:
image.png
(the,quick)单词对就表示成
【(1,0,0,0,0,0,0,0),(0,1,0,0,0,0,0,0)】
这样就可以输入神经网络进行训练了,当我们将the输入神经网络时,希望网络也能输出一个8维的向量,并且第二维尽可能接近1,其他维尽可能接近0。也就是让神经网络告诉我们,quick更可能出现在the的周围。当然,我们还希望这8维向量所有位置的值相加为1,WHY?因为相加为1就可以认为这个8维向量描述的是一个概率分布,正好我们的y值也是一个概率分布(一个位置为1,其他位置为0),我们就可以用交叉熵来衡量神经网络的输出与我们的label y的差异大小,也就可以定义出loss了。什么,你不知道啥是交叉熵?请参考我的另一篇文章【机器学习面试之各种混乱的熵】,应该不会让你失望。

2.3 定义网络结构

通过之前的叙述,我们已经基本知道神经网络应该是什么样子了,总结一下,可以确定如下情况:

  • 神经网络的输入应该是8维的向量
  • 神经网络只有一个隐藏层
  • 神经网络的输出应该是一个8维向量,且各维的值相加为1

有了这些信息,我们可以很容易定义出如下的网络结构:
image.png
观察这个网络结构,我们可以发现,它的隐藏层并没有激活函数,但是输出层却用了softmax,这是为了保证输出的向量是一个概率分布。

2.4 隐藏层

显然,输出层的神经元应该是8个,这样才能输出一个8维的向量。那么隐藏层的神经元应该是多少?
这取决于我们希望得到的词向量是多少维,有多少个隐藏神经元词向量就是多少维。每一个隐藏的神经元接收的输入都是一个8维向量,假设我们的隐藏神经元有3个(仅仅是为了举例说明使用,实际中,google推荐的是300个,但具体多少合适,需要你自己进行试验,怎么效果好怎么来),如此以来,隐藏层的权重就可以用一个8行3列的矩阵来表示,这个8行3列的矩阵的第一行,就是三个隐藏神经元对应于输入向量第一维的权重,如下图所示:
屏幕快照 2018-11-17 下午4.22.52.png
下面就是见证奇迹的时刻!
网络训练完成后,这个8行3列的矩阵的每一行就是一个单词的词向量!如下图所示:
在这里插入图片描述
so,训练完成后,我们只需要保存好隐藏层的权重矩阵即可,输出层此时已经完成历史使命,可以丢掉了。
那么怎么使用去掉了输出层的网络呢?
我们知道,网络的输入是one-hot编码的单词,它与隐藏层权重矩阵相乘实际上是取权重矩阵特定的行,如下图所示:
image.png
这意味着,隐藏层实际上相当于是一个查找表,它的输出就是输入的单词的词向量。

2.4 输出层

当我们从隐藏层获得一个单词的词向量后,就要经过输出层了。
输出层的神经元数量和语料库中的单词数量一样。每一个神经元可以认为对应一个单词的输出权重,词向量乘以该输出权重就得到一个数,该数字代表了输出神经元对应的单词出现在输入单词周围的可能性大小,通过对所有的输出层神经元的输出进行softmax操作,我们就把输出层的输出规整为一个概率分布了。如下图所示:
output layer
这里有一点需要注意,我们说输出的是该单词出现在输入单词周围的概率大小,这个“周围”包含单词的前面,也包含单词的后面。

3 直觉的启示

前面,我们表示,skip gram算法生成的词向量可以包含语义信息,也就是说,语义相近的词其词向量也相近。这里,我们给一个直觉的解释。
首先,语义相近的词往往有着类似的上下文。这是什么意思呢?举例来说,“聪明”和“伶俐”两个词语义是相近的,那么它们的使用场景也是相似的,它们周围的词很大程度上是相近或相同的。
语义相近的词有着相似的上下文,让我们的神经网络在训练过程中对相近的词产生相近的输出向量。网络如何做到这一点呢?答案就是训练完成后,网络能够对语义相近的词产生相近的词向量。因为此时的输出层已经训练完成,不会改变了。
这个直觉式的思考显然是不严谨的,但却能让我们对神经网络有很好的洞见。
记得李宏毅说过,有人问,LSTM设计那么复杂,设计的人怎么知道这样的结构就能达到记忆的效果呢?事实上,不是知道这样做会有记忆的效果才去这样做,而是这样做了,才有这样的效果。是不是有点鸡生蛋蛋生鸡的赶脚?这就是为什么深度学习被称为玄学的原因吧。

4 训练技巧

你可能注意到了,skip-gram算法构造的神经网络神经元太多了,导致权重矩阵非常大。 假设我们的语料库中的词有10000个,生成的词向量为300维。那么权重系数就有100003002那么多,训练如此巨大的网络难度很大。下一篇文章中会介绍一些小技巧,帮助我们减小训练的难度,使得训练是可行的。总得来讲,共有三个技巧,我们一个个看。

4.1 将词组和短语看作独立的单词

这个技巧的原理非常简单。比如文本中有“中华人民共和国”,此时,按照机械的划分,中华、人民、共和国应该是三个词,但是显然,中华人民共和国作为一个单独的词会更加合理一些。
如何从文本中发现词组和短语是一个专门的算法,这里略过了,因为超出了我们今天的主题。

4.2 对高频词进行抽样

让我们回顾一下上一节构造训练数据单词对的方法。
在这里插入图片描述
在上面的构建单词对的过程中,对那些常见的词,如“the”存在两个问题:

  1. 类似(fox,the)这样的单词对并没有什么用,因为此处的the并没有对理解fox产生什么贡献,它太普遍了,以至于在大多数单词的周围都可以发现它。此时,我们只能说the在fox 的周围,却不构成fox 的context。
  2. 上面的办法会产生太多(the,…)样式的单词对,这对于学习单词the的vector来说,实在是太多了。
    解决这两个问题的办法就是subsampling,具体意思是:
    当我们扫描文本中的词时,会根据一定的概率删除这个词,也就是相当于文本中此处没有了这个词。这个概率大小取决于该词在整个语料库中的出现频率。出现频率越高,那么我们删除该词的概率就越大。
    这个很容易理解,以上面的the为例,由于它在整个语料库中出现的频率很高,我们就会删除相当一部分的the,以便减少训练量。

再具体一点,假设我们删除了jump over the
lazy dog 中的the,我们的窗口大小是2,那么,the与其前后各两个词组成的词对就不会称为训练数据,因为the已经被删除了,其次,以the前后各两个词作为输入的词对中,都会减少一个(*,the)的词对。
那么,接下来一个问题就是如何确定删除一个词的概率?直接上公式:
在这里插入图片描述
P(wi)是保留单词wi的概率,z(wi)是该词在整个语料库出现的比例。
我们可以将上面的公式画成图来看看:
在这里插入图片描述
Note:要得到这个图,只需在google中输入
Graph for (sqrt(x/0.001)+1)*0.001/x即可。
至于这个公式怎么来的,说实话,我也不清楚,鉴于它不是本文的重点,我也没有深究,如果有清楚的伙伴,欢迎留言补充。

4.3 负抽样

这个办法才是本文的重头戏,其中的思想对人很有启发性。刚刚听完蚂蚁金服张家兴老师分享的蚂蚁金服人工智能实践,里面提到了问题匹配模型训练中的一个技巧,其思想与负抽样很相似。可见技术是具体的,但技术背后反映出的解决问题的思想却是共通的。
负抽样技术主要解决的问题就是模型难以训练。所以,我们先来看看模型为什么难以训练。
使用SGD训练神经网络的过程就是取出一条样本数据,然后据此去调整神经网络的所有权重,以便网络能够对这条数据的预测更加准确一些。这里的重点是所有权重!
调整所有的权重是多大的工作量呢?在上篇文章中,我们已经有过解释,请参考上篇文章。总之,所有权重是一个巨大数量的系数。对每一条样本,每训练一次,这么多的系数都要进行轻微的调整。显然,超多的训练数据,巨多的权重系数,将使得神经网络的训练非常缓慢和困难。
负抽样解决这一问题的办法就是使得对每一条样本的每一次训练,只更新很小一部分的权重,而不是全都更新。下面我们深入细节来看一下。
假设我们的训练数据是(fox,quick)单词对,回忆一下,此条训练数据的标签就是quick,用one-hot编码后,就是一个8维向量,quick所对应的维度为1,其他维度为0。
也就是说,我们希望神经网络输出的8维向量中,对应quick的维度是1,其他维度是0。在输出层,每一个输出维度实际上对应着一个神经元。
在我们的例子中,我们看到其他应当为0的维度有7个,在实际工作中,这个维度的数量是非常大的,因为我们的词表一般会很大。
所谓负抽样,即是从这些应当为0的维度中随机抽取几个,只更新这几个维度对应的神经元的权重,这既是负抽样的确切含义。当然,同时还要加上输出应当为1的维度所对应的神经元。
具体负抽样时抽几个维度的神经元,取决于具体的问题,google的论文中建议是5到20个。
让我们用一个例子来具体感受一下。假设我们负抽样的维度数为5,我们的词表中有10000个单词,词向量的维度为300,也即是隐藏层有300个神经元。
那么,在输出层,权重矩阵的大小将是30010000。现在我们抽取了5个负的维度(输出应当为0的维度),加上输出为1的维度,只更新这6个维度所对应的神经元。那么需要更新的权重系数是3006=1800个。这只占输出层中所有权重系数的0.06%!!
另外,在隐藏层,我们还要更新输入的单词所对应的300个权重。这是无论用不用负抽样,都要更新的权重。
如果不好理解,我们就具体一点,隐藏层可以看作一个10000*300的矩阵,其中每一行都代表一个单词的300维词向量,我们更新的就是输入单词所对应的那一行的300个权重系数。

4.4 负抽样应当抽谁的样?

上一节中,我们说了负抽样,一般抽5到20 个维度。问题来了,假设是抽5个维度,那么,应当抽哪5个维度呢?负的维度实在太多,如果词表为10000,那么负的维度就有9999个。从这里面抽5个,难道是随机抽吗?
答案是否定的。在抽取这5个维度时,是按照单词在语料库中出现的次数多少来的, 出现次数越多,那么越可能被抽中。具体是按照如下公式来决定的:
image.png

P(w_i)就是w_i这个单词被负抽样抽中的概率。
f(w_i)即是w_i在语料库中出现的次数。
至于为什么要取一次3/4次方,据说是基于经验,这样效果会更好。
五、无总结,不进步
通过这两篇文章,我简要地叙述了skip-gram版的word2vector的原理和部分实现细节。
我觉得最重要的在于体会作者设计这样的神经网络,用n-gram来构造训练数据背后所隐含的思想。这些思想才是我们在实际工作中最紧缺的。
这里留一个问题供大家思考,在负抽样时,为什么要按照单词出现的频率来抽样,这样有什么好处?

总结

通过这两篇文章,我简要地叙述了skip-gram版的word2vector的原理和部分实现细节。
我觉得最重要的在于体会作者设计这样的神经网络,用n-gram来构造训练数据背后所隐含的思想。这些思想才是我们在实际工作中最紧缺的。

Word2vec 相关的参考资料,并给出评价

  1. Mikolov 两篇原论文:
    『Distributed Representations of Sentences and Documents』
    贡献:在前人基础上提出更精简的语言模型(language model)框架并用于生成词向量,这个框架就是 Word2vec
    『Efficient estimation of word representations in vector space』
    贡献:专门讲训练 Word2vec 中的两个trick:hierarchical softmax 和 negative sampling
    优点:Word2vec 开山之作,两篇论文均值得一读
    缺点:只见树木,不见森林和树叶,读完不得要义。
    这里『森林』指 word2vec 模型的理论基础——即 以神经网络形式表示的语言模型
    『树叶』指具体的神经网络形式、理论推导、hierarchical softmax 的实现细节等等
  2. 北漂浪子的博客:『深度学习word2vec 笔记之基础篇』
    优点:非常系统,结合源码剖析,语言平实易懂
    缺点:太啰嗦,有点抓不住精髓
  3. Yoav Goldberg 的论文:『word2vec Explained- Deriving Mikolov et al.’s Negative-Sampling Word-Embedding Method』
    优点:对 negative-sampling 的公式推导非常完备
    缺点:不够全面,而且都是公式,没有图示,略显干枯
  4. Xin Rong 的论文:『word2vec Parameter Learning Explained』:
    !重点推荐!
    理论完备由浅入深非常好懂,且直击要害,既有 high-level 的 intuition 的解释,也有细节的推导过程
    一定要看这篇paper!一定要看这篇paper!一定要看这篇paper!
  5. 来斯惟的博士论文『基于神经网络的词和文档语义向量表示方法研究』以及他的博客(网名:licstar)
    可以作为更深入全面的扩展阅读,这里不仅仅有 word2vec,而是把词嵌入的所有主流方法通通梳理了一遍
  6. 几位大牛在知乎的回答:『word2vec 相比之前的 Word Embedding 方法好在什么地方?』
    刘知远、邱锡鹏、李韶华等知名学者从不同角度发表对 Word2vec 的看法,非常值得一看
  7. Sebastian 的博客:『On word embeddings - Part 2: Approximating the Softmax』
    详细讲解了 softmax 的近似方法,Word2vec 的 hierarchical softmax 只是其中一种

原文链接:

  1. 机器学习必须熟悉的算法之word2vector(一)
  2. 机器学习必须熟悉的算法之word2vector(二)
  3. [NLP] 秒懂词向量Word2vec的本质 - 穆文的文章 - 知乎()
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/寸_铁/article/detail/917236
推荐阅读
  

闽ICP备14008679号