词向量

自然语言处理问题中,一般以词作为基本单元,例如我们想要分析 "我来自北语" 这句话的情感,一般的做法是先将这句话进行分词,变成我,来自,北语,由于计算机无法处理词,神经网络也无法对词进行处理,所以我们需要将这些词通过某些办法映射成词向量。词向量是用来表示词的向量,也可被认为是词的特征向量。把词映射为实数域向量的技术也叫词嵌入(word embedding)

one-hot

最开始的词嵌入技术是采用one-hot编码,One-Hot编码,又称为一位有效编码,主要是采用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候只有一位有效。

直观理解one-hot编码,比如你现在要处理一篇文本输入给计算机,one-hot的做法是:

1. 首先统计整个文本的词汇的个数N,将所有的词汇排列成表vocab,vocab:我,早上,你好,开学。。。

2.根据词汇表分配编码,每个词对应一个词向量,实际就是一个一维数组,“我”在词汇表vocab的第一个,那么对应的词向量(一维数组)的第一个位置就是1,其余位置置零:[1,0,0 ... 0,0 ];“早上”在词汇表vocab的第二个,那么对应的词向量的第二个位置就是1,其余位置置零: [ 0,1,0 ... 0,0 ];第三个词就是第三个位置为1,其他位置置零;所有的词都按照这样的规则转换成对应的一维数组,也就是词向量了;

那么整个文本就表示成了词向量,比如这个文本就是一句话:今日计划,啥也不干

分词之后得到的词汇表vocab:["今日","计划","啥","也","不干","," ];这个文本的词汇个数就是N=6,

根据one-hot编码依次转换为词向量:

今日:[1,0,0,0,0,0]

计划:[0,1,0,0,0,0]

啥:[0,0,1,0,0,0]

也:[0,0,0,1,0,0]

不干:[0,0,0,0,1,0]

,:[0,0,0,0,0,1]

为什么不用one-hot编码:

很明显的一个缺点就是,维度爆炸,比如现在有一个文本有100万个词,那么每个词按照ont-hot编码就对应一个100万维度的一维数组,这个内存占用是非常高的,

另外一个缺点就是,one-hot编码无法体现出词与词之间的语义联系,任何两个词的余弦相似度都是0:

向量余弦相似度体现词之间的相似程度



word2vec

关于word2vec的原理和使用python的实战推荐一篇博文,博主有个公众号:数据挖掘机养成记

[NLP] 秒懂词向量Word2vec的本质 - 知乎

one-hot编码要求每个类别之间相互独立,如果之间存在某种连续型的关系,文本的词汇之间就是存在关联的存在,所以 distributed respresentation(分布式表示)更加合适,实际就是将高维稀疏的向量降维成稠密的低维向量,一种高维到低维的映射方式。

Wordvec的维基百科解释:

wordvec为一群用来产生词向量的相关模型。这些模型为浅层双层的神经网络,用来训练以重新建构语言学之词文本。网络以词表现,并且需猜测相邻位置的输入词,在word2vec中词袋模型假设下,词的顺序是不重要的。训练完成之后,word2vec模型可用来映射每个词到一个向量,可用来表示词对词之间的关系。该向量为神经网络之隐藏层;

2013 年,Google 团队发表了 word2vec 工具。word2vec 工具主要包含两个模型:跳字模型(skip-gram)连续词袋模型(continuous bag of words,简称 CBOW),以及两种高效训练的方法:负采样(negative sampling)层序 softmax(hierarchical softmax)。值得一提的是,word2vec 词向量可以较好地表达不同词之间的相似度和类比关系。

 Mikolov的原论文:

《Distributed Representations of Sentences and Documents》

《Efficient estimation of word representations in vector space》

关于CBOW和skip-gram模型:

1.用一个词语作为输入,来预测它周围的上下文,那这个模型叫做 Skip-gram 模型

2. 而如果是拿一个词语的上下文作为输入,来预测这个词语本身,则是 CBOW 模型

用两张图来表示CBOW和skip-gram的原理:

CBOW&skip-gram

为什么说word2vec训练的词向量可以表示出词语之间的相似度呢?

这个是基于word2vec算法的假设:在文本中,具有相似上下文的词具有相似的语义

example:

这个其实很好理解的,举个例子,现在有两句文本,分别是:

他们 说 那个 女孩 非常 可爱

这句话如果输入是“女孩”,那么上下文就是“他们” “说” “那个” ”非常“ “可爱” 等这些词

另一句文本是:

他们 说 那个 姑娘 非常 可爱

这个地方很明显,输入是“姑娘”的话,这个输入的上下文词跟刚刚的“女孩”这个词是一样的,所以算法的结果就是“女孩”=“姑娘”一样可爱

word2vec的计算过程就是遍历所有的训练数据,最后就可以得到具有相似的上下文的词具有相似的语义,这些词对应的词向量计算余弦相似度也可以得到较高的值。

关于word2vec中的计算原理,有一篇word2vec的数学原理已经讲解的非常详细了,感兴趣的童鞋可以去看看:

word2vec 中的数学原理详解 - peghoty - 博客园

word2vec的本质:

词向量的本质可以看出是一个只有一层的神经网络,因此必须有输入、输出,训练的目的不是为了得到预测的结果,而是对单词进行分类。最关键的就是获得hidden layer的中的权重。也就是借助sequnece2sequence模型训练过程,得到hidden layer的权重。

训练中的数学原理:

以 基于负采样(negative sampling)的CBOW为例,模型会遍历依次遍历全部的文本,这里有一个概念就是窗口,window size,窗口大小自己定义,一般取5-8左右,代表训练时指定的中心词周围的上下文词的个数,模型的第一层输入是,将所有上下文词都随机初始化成词向量,将这些词向量相加的均值作为CBOW的输入,用这些上下文去预测中心词w

在CBOW模型中,已知词  的上下文  ,需要预测 ,因此,对于给定的 ,词 就是一个正样本,其他词就是负样本了,负样本那么多,全部加入训练那计算量会非常大,于是进行采样处理,选取一部分负样本进行训练;

假定现在已经选好了一个关于 的负样本子集,且对于,定义:

1.1

表示词  的标签,即正样本的标签为1,负样本的标签为0.

对于给定的一个正样本 ,我们希望最大化:

1.2

其中:

1.3

或者写成整体表达式:

1.4

这里仍然表示 中各词的词向量之和,而表示词 对应的一个(辅助)向量,为待训练的参数。

为什么要最大化 呢?将 1.4 带入 1.2 之后,得到新的  的表达式是:

1.5

其中表示当上下文为 时,预测中心词为 的概率,而,则表示当上下文是 时,预测中心词为 的概率,于是可以转换为一个二分类问题,从形式上看,最大化,相当于最大化,同时最小化,,于是达到了目的:增大正样本的概率,同时降低负样本的概率;于是对于给定的语料库 ,函数:

1.6

就作为整体的优化目标,即目标函数;然后按照梯度上升法进行求导数梯度误差值优化等等。

下面给出以样本为例,给出基于Negative Sampling 的 CBOW模型中采用梯度上升法更新各参数的伪代码:

伪代码

word2vec得到的词向量就是其中全部的误差 项的累积和,其中的训练参数是辅助向量,经过梯度上升法更新了误差项之后,遍历所有的上下文向量,将得到的误差累积和加到每个向量中,于是完成一次向量的更新,窗口依次往后移,训练新的目标词和上下文词向量;

全部遍历完语料之后,所有词的向量都是参与了训练且更新 之后的,这些词向量就具备了最开始假设的语义信息,用于下游的一些任务,比如词相似度,词语消歧等任务。

skip-gram的训练过程跟CBOW是大同小异的,只是反过来使用中心词去预测每一个上下文词,具体的训练过程可以参考上文提到的word2vec中的数学原理一文,推导得非常详细。

使用word2vec:

python 中的 gensim 库封装了调用word2vec的接口,只需要几行代码就可以使用word2vec训练好词向量,并且计算词相似度等任务,下面是一些使用的主要代码供参考:

缺点不足:

尽管word2vec训练出的词向量可以表征一定的语义信息,但是训练得到的词向量是静态的,也就是说,一个词只对应一个词向量,那么对于多义词就无法根据上下文去进行处理,举一个大家都用的例子:

He has a large deposit in the bank.

The town stands on the left bank of the river.

这里的“bank" 是完全不同的两个意思,但是使用word2vec训练得到的词表只有一个词向量,那么这个词向量在用于下游任务的时候,更代表哪一种语义呢?这个问题使用静态词向量无法得到解决。

并且在计算词语相似度的时候会发现实验结果存在非常大的噪声,因为基于的假设是上下文相似的词具有相似的语义,所以位置相隔很近的也会具有相似的语义信息,那么在中文里面,一句话的主谓宾,相隔的很近的主语和宾语,是完全不一样的词性,有时候也会得到很高的余弦相似度,比如代词和名词,名词和动词,例如:动词 “打击” 的相似词会出现例如 “悍匪”,“犯罪” 等名词,这显然是不对的,但是因为很多时候:“打击 悍匪”,“打击 犯罪” 经常相隔很近的一起出现在语料里面,所以这一点也是word2vec词向量本身效果不好的一个原因,因为其基本假设存在一些瑕疵。



glove:

官网:GloVe: Global Vectors for Word Representation

官方的代码的GitHub在此 : https://github.com/stanfordnlp/GloVe

上面有训练好的模型可以下载

Glove (Global vectors for word representation),2014年由Stanford NLP Group组织提出,它是一个基于全局词频统计(count-based & overall statistics)的词表征(word representation)工具。

跟word2vec的几点不同:

1. 在表现上 glove 和 word2vec 其实相差不大,Word2vec是局部语料库训练的,其特征提取是基于滑动窗口的;而glove的滑动窗口窗是为了构建co-occurance matrix 共现矩阵,统计了全部语料库里在固定窗口内的词共线的频次,是基于全局语料的,可见glove需要事先统计共现概率;因此,word2vec可以进行在线学习,glove则需要统计固定语料信息。

2. Glove利用了全局信息,使其在训练时收敛更快,训练周期较word2vec较短且效果更好。

golve 原理:

golve 本质上是对共现矩阵进行降维度,下面对glove的基本原理进行一个记录:

1. 首先构建一个词汇的共现矩阵,同样也是构建一个滑动窗口,依次遍历整个语料库,统计在每个窗口下,词汇与词汇之间共同出现的频率,由此构建出词汇共现矩阵,其元素是,代表:在整个语料库中,单词和单词共同出现在语料库中的次数

搬个例子:

i love you but you love him i am sad

这个小小的语料库只有1个句子,涉及到7个单词:i、love、you、but、him、am、sad。

如果我们采用一个窗口宽度为5(左右长度都为2)的统计窗口,那么就有以下窗口内容:

中心词为love,语境词为but、you、him、i;则执行:

;;;

使用这样的窗口统计所有的语料,就得到了共现矩阵

2. 模型思想来源:首先定义:,表示矩阵单词那一行的和

条件概率: 表示单词出现在单词语境中的概率

这里的 语境有多种定义。举个例子,在一段文本序列中,如果词 出现在词 左边或者右边不超过 10 个词的距离,我们可以认为词  出现在词 的环境一次。

然后得到两个条件概率的比率:

3. 然后作者发现,这个存在下表所示的规律:

作者的思想:假设我们已经得到了词向量,如果我们用词向量通过某种函数计算,能够同样得到这样的规律的话,就意味着我们词向量与共现矩阵具有很好的一致性,也就说明我们的词向量中蕴含了共现矩阵中所蕴含的信息。

依据这个思想作者去构建损失函数进行训练

假设用词向量 计算 的函数为:,那么有:

                        

模型的构建细节这篇博客讲的很清楚,感兴趣的童鞋可以去看看:

理解GloVe模型(Global vectors for word representation)_饺子醋的博客-CSDN博客_glove

进步与不足:

1. glove相对于word2vec的局部滑动窗口上下文,采取的是统计整个语料的词汇的共现频率,但是实际上这个全局信息也是根据一个个局部窗口统计得到的,相当于是多个窗口进行训练更新词向量,论文中的结果比word2vec的词向量效果好一些,但是没有根本解决静态词向量这个致命伤,依旧不能称得上非常大的突破。


fasttext:

fastText是一个快速文本分类算法,与基于神经网络的分类算法相比有三大优点:

1、fastText在保持高精度的情况下加快了训练速度和测试速度

2、fastText不需要预训练好的词向量,fastText会自己训练词向量

3、fastText两个重要的优化:Hierarchical Softmax、N-gram

fastText原理:

word2vec把语料库中的每个单词当成原子,它会为每个单词生成一个向量,这忽略了单词内部的形态特征,如“apple”与“apples”,两个单词都有较多的公共字符,即它们的内部形态类似,但是在传统的word2vec中,这种单词内部形态信息因为它们被转换成不同的id丢失了。

为了克服这个问题,fastText使用了字符级别的n-grams来表示一个单词,对于“apple”,假设n的取值为3,则它的trigram有:

""

其中<表示前缀,>表示后缀,我们可以使用这5个trigram的向量叠加来表示“apple”的词向量。

fastText在使用负采样的 skip-gram 模型的基础上,将每个中心词视为子词(subword )的集合,并学习子词的词向量。

给定一个词,通常可以把字符长度在3到6之间的所有子词和特殊子词的并集取出来。假设任意子词的子词向量为,我们可以使用负采样的skip-gram 模型的损失函数:

直接替换成:

可以看到,于是原中心词向量被替换成中心词的子词向量之和,这对于低频词效果会比较好,因为低频词的 n-gram 可以跟其他词共享;跟 word2vec 和 glove 不同的是,词典外的新词,即未登录词可以使用 fastText 中相应的字词向量之和表示。

fastText 对于一些语言比较重要,例如阿拉伯语和德语。例如 德语中有许多复合词,例如乒乓球(英文 table tennis)在德语中叫 "tischtennis"。fasttext可以通过字词表达两个词的相关性,例如 "tischtennis" 和 "tennis"。

模型结构:

fastText模型架构和word2vec中的CBOW很相似, 不同之处是fastText预测标签而CBOW预测的是中间词,即模型架构类似但是模型的任务不同。

fasttext模型架构

其中表示一个文本中的n-gram向量,每个特征是词向量的平均值。cbow用上下文去预测中心词,而此处用全部的n-gram去预测指定类别。输入是embedding 过的词向量,输出是类别lable,fastText是根据文本分类任务来进行训练并且得到词向量这个产物,隐藏层是对多个词向量的叠加平均。

1)CBOW的输入是目标单词的上下文,fastText的输入是多个单词及其n-gram特征,这些单词用来表示单个文档

2)CBOW的输入单词被one-hot编码过,fastText的输入特征时被embedding过

3)CBOW的输出是目标词汇,fastText的输出是文档对应的类标

将整篇文档的词及n-gram向量叠加平均得到文档向量,然后使用文档向量做softmax多分类

结论:

glove使用词向量表达共现词频的对数。

fastText用子词向量之和表达整词。

实战代码参考:

代码参考

fastText 在https://github.com/facebookresearch/fastText/tree/master/python上提供了绑定了fastText库的Python接口及使用示例代码。

参考:

FastText的简单介绍_摆渡者-CSDN博客_fasttext

你可能感兴趣的:(词向量)