原文链接:https://blog.csdn.net/L_R_H000/article/details/81320286
最近做完UNIT一个小项目后,结合同时期看KBQA的文章,对NLP/NLU方向产生了比较大的兴趣,想深入学习一下,结合一篇综述Recent Trends in Deep Learning Based Natural Language Processing(参考文献[5]为其阅读笔记)的阐述顺序,把相关的知识补一补,本文即第一部分Word Embedding。
主要参考文献:
[1] word2vec 中的数学原理详解
[2] Word Embedding与Word2Vec
[3] 自然语言处理中的N-Gram模型详解
[4] 有谁可以解释下word embedding?——知乎
[5] 2017-基于DL的NLP研究近况
目录
一、Word Embedding概述
二、Word2vec之前
2.1 one-hot
2.2 n-gram
2.3 co-occurrence matrix
2.4 NLM
三、Word2vec
3.1 CBOW
3.1.1 基于Hierarchical Softmax
3.1.2 基于Negative Sampling
3.2 Skip-gram
3.2.1 基于Hierarchical Softmax
3.2.2 基于Negative Sampling
简单来说,词嵌入(Word Embedding)或者分布式向量(Distributional Vectors)是将自然语言表示的单词转换为计算机能够理解的向量或矩阵形式的技术。由于要考虑多种因素比如词的语义(同义词近义词)、语料中词之间的关系(上下文)和向量的维度(处理复杂度)等等,我们希望近义词或者表示同类事物的单词之间的距离可以理想地近,只有拿到很理想的单词表示形式,我们才更容易地去做翻译、问答、信息抽取等进一步的工作。
在Word Embedding之前,常用的方法有one-hot、n-gram、co-occurrence matrix,但是他们都有各自的缺点,下面会说明。2003年,Bengio提出了NLM,是为Word Embedding的想法的雏形,而在2013年,Mikolov对其进行了优化,即Word2vec,包含了两种类型,Continuous Bag-of-Words Model 和 skip-gram model。
Word Embedding是基于分布式假设(distributional hypothesis):
总的来说,word embedding就是一个词的低维向量表示(一般用的维度可以是几十到几千)。有了一个词的向量之后,各种基于向量的计算就可以实施,如用向量之间的相似度来度量词之间的语义相关性。其基于的分布式假设就是出现在相同上下文(context)下的词意思应该相近。所有学习word embedding的方法都是在用数学的方法建模词和context之间的关系。
作者:李明磊9527
链接:https://www.zhihu.com/question/32275069/answer/197721342
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
但是Word Embedding也有其局限性, 比如:
- 难以对词组做分布式表达
- 受限于上下文window的尺寸,有些词(例如好或坏)的上下文可能没什么不同甚至完全一样,这对情感分析任务的影响非常大
此外,Word Embedding对于应用场景的依赖很强,所以针对特殊的应用场景可能需要重新训练,这样就会很消耗时间和资源,为此Bengio提出了基于负采样(negative sampling)的模型。
下面本文会将对Word2vec之前的常用方法和Word2vec的两种模型做比较详细的记录和理解。
one-hot是最简单的一种处理方式。通俗地去讲,把语料中的词汇去重取出,按照一定的顺序(字典序、出现顺序等)排列为词汇表,则每一个单词都可以表示为一个长度为N的向量,N为词汇表长度,即单词总数。该向量中,除了该词所在的分量为1,其余均置为0。
例如,有语料库如下:
John likes to watch movies. Mary likes movies too.
John also likes to watch football games.
假设我们的词汇表排序结果如下:
{"John": 1, "likes": 2, "to": 3, "watch": 4, "movies": 5, "also":6, "football": 7, "games": 8, "Mary": 9, "too": 10}
那么则有如下word的向量表示:
John: [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
likes: [0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
……
用这样的方式可以利用向量相加进一步表示句子和文本了,但是one-hot有很大的局限性:
n-gram可以表示单词间的位置关系所反映的语义关联,在说明n-gram之前,我们从最初的句子概率进行推导。
假设一个句子S为n个单词有序排列,记为:
我们将其简记为 ,则这个句子的概率为:
对于单个概率意思为该单词在前面单词给定的情况下出现的概率,我们利用贝叶斯公式可以得到:
其中最后一项为在语料中出现的频数。但是长句子或者经过去标点处理后的文本可能很长,而且太靠前的词对于词的预测影响不是很大,于是我们利用马尔可夫假设,取该词出现的概率仅依赖于该词前面的n-1个词,这就是n-gram模型的思想。
所以上面的公式变为:
在这里,我们不对n的确定做算法复杂度上的讨论,详细请参考文献[1],一般来说,n取3比较合适。此外对于一些概率为0的情况所出现的稀疏数据,采用平滑化处理,此类算法很多,以后有时间再具体展开学习。
所以n-gram的主要工作在于确定n之后,对语料中的各种吃词串进行频数统计和平滑化处理,对于所需要的句子概率,只要将之前语料中相关概率取出计算就可以了。
当然实际情况是对做最优化处理,参数确定后以后的概率就可以通过函数确定了,这就需要构造函数,后面的NLM就是做这个工作。
n-gram模型会将前文的语义关联纳入考虑,从而形成联合分布概率表达,但是尽管去前n-1个单词,语料大的情况下计算量还是很大,在模拟广义情境时严重受到了“维度灾难(curse of dimensionality)”。
共现矩阵也是考虑语料中词之间的关系来表示:
一个非常重要的思想是,我们认为某个词的意思跟它临近的单词是紧密相关的。这是我们可以设定一个窗口(大小一般是5~10),如下窗口大小是2,那么在这个窗口内,与rests 共同出现的单词就有life、he、in、peace。然后我们就利用这种共现关系来生成词向量。
例如,现在我们的语料库包括下面三份文档资料:
I like deep learning.
I like NLP.
I enjoy flying.
作为示例,我们设定的窗口大小为1,也就是只看某个单词周围紧邻着的那个单词。此时,将得到一个对称矩阵——共现矩阵。因为在我们的语料库中,I 和 like做为邻居同时出现在窗口中的次数是2,所以下表中I 和like相交的位置其值就是2。这样我们也实现了将word变成向量的设想,在共现矩阵每一行(或每一列)都是对应单词的一个向量表示。
虽然Cocurrence matrix一定程度上解决了单词间相对位置也应予以重视这个问题。但是它仍然面对维度灾难。也即是说一个word的向量表示长度太长了。这时,很自然地会想到SVD或者PCA等一些常用的降维方法。当然,这也会带来其他的一些问题。
窗口大小的选择跟n-gram中确定n也是一样的,窗口放大则矩阵的维度也会增加,所以本质上还是带有很大的计算量,而且SVD算法运算量也很大,若文本集非常多,则不具有可操作性。
神经语言模型(Neural Language Model)是Word Embeddings的基本思想,在很多其他文献中也有神经概率语言模型(Neural Probabilistic Language Model,NPLM)或者神经网络语言模型(Neural Network Language Model,NNLM),都是指一个东西。
NLM的输入是词向量,根据参考文献[1],词向量和模型参数(最终的语言模型)可以通过神经网络训练一同得到。相比于n-gram通过联合概率考虑词之间的位置关系,NLM则是利用词向量进一步表示词语之间的相似性,比如近义词在相似的上下文里可以替代,或者同类事物的词可以在语料中频数不同的情况下获得相近的概率。结合参考文献[1],举一个简单例子:
在一个语料C中,S1=“A dog is sitting in the room.”共出现了10000次,S2="A cat is sitting in the room"出现了1次,按照n-gram的模型,当我们输入“A _____ is sitting in the room”来预测下划线上应该填入的词时,dog的概率会远大于cat,这是针对于语料C得到的概率。但是我们希望相似含义的词在目标向量空间中的距离比不相关词的距离更近,比如v(man)-v(woman)约等于v(gentleman)-v(madam),用这样生成的词向量或者已经训练好的模型在去做翻译、问答等后续工作时,就会很有效果,而NLM利用词向量表示就能达到这样的效果。
注:在参考文献[1]中,作者举的例子是从句子概率角度,我自己的理解稍有不同,将原例放在下面:
NLM的神经网络训练样本同n-gram的取法,取语料中任一词w的前n-1个词作为Context(w),则(Context(w),w)就是一个训练样本了。这里的每一个词都被表示为一个长度为L的词向量,然后将Context(w)的n-1个词向量首位连接拼成(n-1)L的长向量。下面为NLM图解:
【注】此图向量和矩阵的维度与参考文献中相反了
我们得到的输出结果为长度为词汇总数的向量,如果想要第i个分量去表示当上下为context(w)时下一个词为词典中第i个词的概率,还需要softmax归一化,然后我们最初想要的结果便是:
注意:这只是取一个词w后输出的向量y,我们需要的就是通过训练集所有的词都做一遍这个过程来优化得到理想的W,q和U,b。
那么样本中最初的词向量如何获得呢?在参考文献[1]中有这样两段话:
目前我还没有彻底搞懂神经网络中具体的机制,所以暂时标记一下,初步推测是初始化一个矩阵或者可以粗暴地用one-hot(不过这样输入层的L=D,计算量大了很多),然后随着训练的过程,词向量也是不断更新的,详细还要参考最优化理论。
下面要说的Word2vec便是在NLM基础上的优化。
目前学习了解到的Word2vec有基于Hierarchical Softmax和基于Negative Sampling两种方式,参考文献[1]是从两种方式分别讲解了CBOW和Skip-gram的数学构建思路和过程,由于这两个模型是相反的过程,即CBOW是在给定上下文基础上预测中心词,Skip-gram在有中心词后预测上下文,我个人是把两个模型按照两种不同的计算方法做了梳理,当然数学推导还是一样的,只不过我自己看起来更舒服。在此再次感谢@peghoty大牛的详解。
基于前面的介绍,CBOW的思想是取目标词w的上下文(前后相邻词)而不是仅之前的词作为预测前提,类似于共现矩阵的窗口,不同于NLM的是,Context(w)的向量不再是前后连接,而是求和,我们记为,此外还将NLM的隐藏层去掉了。当然最大的区别还是在输出层,基于Hierarchical Softmax的CBOW输出层为一颗霍夫曼树,叶子节点为语料中的词汇,构建依据便是各词的出现频数;基于Negative Sampling则是用随机负采样代替霍夫曼树的构建。
霍夫曼树的构建在这里就不展开说了,比较简单的算法。沿用文献[1]的表示,基于Hierarchical Softmax的CBOW所要构建的霍夫曼树所需参数如下:
:从根结点到w对应结点的路径
:路径上包含结点个数
:到w路径上的的结点
:结点编码,根结点不编码
:非叶子结点(包括根结点)对应的向量
霍夫曼树构建按照频数大小有左右两种,其实都是自己约定的,在这里就不麻烦了,构建后左结点编码为0,为正类,右结点为1,为负类。
根据逻辑回归,一个结点被分为正类的概率为
的一些性质,后面用的到:
所以之前我们要构造的目标函数就可以写为以下形式:
这个公式跟之前看的概率图模型有点像,不过现在有点记不清了,后面我再梳理一下,看看能不能串起来。其中
整体表达式
这是一个单词,我们把对连乘做对数似然函数,然后将语料中所有单词都求和,则目标函数如下:
明确参数有和,我们取其中子式来做关于两个参数的梯度:
因为和是对称的,所以的为:
所以两者就可以更新了:
至此,我们完成了对参数的优化。
参考文献[1]提出了这样一个问题:
我的理解是可以的,可能我对最优化方法的学习还不够全面,从公式拆解上好像更能说的过去,但是对于收敛速度的影响可能会很大,取平均可能优化得到较好的结果较慢。
对于大规模语料,构建霍夫曼树的工作量是巨大的,而且叶子节点为N的霍夫曼数需要新添(N-1)个结点,而随着树的深度增加,参数计算的量也会增加很多很多,得到的词向量也会不够好,为此,Mikolov作出了优化,将构建霍夫曼树改为随机负采样方法。
对于给定的上下文Context(w)去预测w,如果从语料中就是存在(Context(w),w),那么w就是正样本,其他词就是负样本。
我们设负样本集为,词的标签:
即正样本标签为1,负样本标签为0,等同于霍夫曼结点的左右编码,只不过与其取值相反,这样后面的公式也就很好理解了:
同样,我们对两个参数求导:
然后更新参数,公式形式是一样的,不再写了。
可见,对于单词w,基于Hierarchical Softmax将其频数用来构建霍夫曼树,正负样本标签取自结点左右编码;而基于Negative Sampling将其频数作为随机采样线段的子长度,正负样本标签取自从语料中随机取出的词是否为目标词,构造复杂度小于前者。
由于Skip-gram是CBOW的相反操作,输入输出稍有不同,在这里仅贴出关键公式,不再具体说明。
以上均来自参考文献[1],变量表示稍有不同。
这个作者分析较多,还没有完全看懂,后面再补