word2vec代码_快速入门词嵌入之word2vec

8399d8759cbdaf71435dd208e644d54c.png

word2vec是Google在2013年推出的一个工具。word2vec通过训练,可以将所有的词向量化,这样就可以定量的去度量词与词之间的关系,挖掘词之间的联系;同时还可以将词向量输入到各种RNN网络中进一步处理。因此,word2vec 输出的词向量可以被用来做很多自然语言处理相关的工作,比如聚类、找同义词、词性分析等等、文本分析等,是自然语言处理的重要基础。

本文希望能带你快速入门word2vec。

基本概念:语料库(corpus)、词(word)、词汇表(vocabulary)

语料库一般是指一些根据研究需要从自网站、新闻、报纸等采集的大规模文本。而“词”是语料中的最小单位。例如:

Winners do what losers do not want to do.

在处理这段非常简单的语料中,我们会把"winners"作为一个完整词处理,而不会把词分为字符单独处理。通常在自然语言处理(NLP)中,词也是最小单位,所以有“词向量”,但是没有“字符向量“。

而统计语料中出现的不重复的词构成即可构成词汇表。如上段语料中出现了"winners losers what want do not to"这7个词,其中do出现了3次。

为什么要进行词嵌入(word embedding)?

6030b1d2361603b42853b9b1bd577155.png

以机器翻译为例,要把"you"输入到RNN网络中,必须把单词转化为一个向量(即把词“嵌入”到高维空间)。

那么最简单粗暴的词嵌入方法就是one-hot编码:

f0e760d158641a53bbbe58c17710f301.png

那么one-hot编码有什么缺点呢?

  • 维度灾难

一般情况下,常用英语单词约8000个,如果使用one-hot编码,每个词向量就是8000维;对应的如果有100000个词,那么每个词向量就是100000维。在实际应用中,词向量维度太大,会造成网络参数量大、网络推理速度慢、网络运行占用内存高等问题。

  • 编码过于稀疏

在one-hot编码的词向量中,数值几乎全部是0,非常稀疏,很可能导致实际中网络难以收敛。

  • 无法表示词间的关系

有向量

,定义
之间相似度为:

对于one-hot编码,任意两个词间的相似度都为0,这是违背实际情况的。

那么实际情况是什么?举例说明:词"cars"是"car"的复数形式,词"trucks"又是"truck"的复数形式,所以实际中我们希望他们词向量相似度很大:

由于"car"和"truck"词义接近,"car"和"china"词义差别较大,我们也希望有如下关系:

26c5f21c9fe8fdf5102a33654bb424bc.png

那么不禁要问:有没有一种神经网络,输入每个词的one-hot编码,就可以输出符合上述要求的词向量?有,就是word2vec!

592affee1349bd7306b240dea42508fd.png

word2vec详解

Efficient Estimation of Word Representations in Vector Space​arxiv.org word2vec Parameter Learning Explained​arxiv.org

word2vec是一个典型的3层全连接网络:INPUT->PROJECTION->OUTPUT,假设:

  • INPUT层->PROJECTION层权重为
    矩阵
  • PROJECTION层->OUTPUT层权重为
    矩阵

其中

通过训练得到。

581b7a5d32843f6e498945434735d6d3.png
这张图从PROJECTION到OUTPUT有点问题,但是为了便于理解就这么画了,后续再分析

那么:词向量 = 词的one-hot编码向量(转置) x

ca6fae4a45beb2aa825069ff84f56886.png

所以

就是由字典中所有词对应的词向量组成的矩阵:

那么如何训练网络获得

(和
)矩阵?word2vec提出了CBOW与skip-gram结构。

4b8b214bc259502b5a5da186010929c2.png
  • CBOW结构:根据输入周围
    个词来预测出这个词本身(即通过上下文预测词语):

  • skip-gram结构:根据输入词来预测周围
    个词(即预测词语的上下文):

huffman树

huffman树是一种特殊结构的二叉树,通过huffman树编码的huffman码,在通信领域有着广泛的应用。在word2vec模型中构建PROJECTION->OUTPUT的Hierarchical softmax过程中,也使用到了huffman树。

构建huffman树流程:

1.根据给定的n个权值{w1, w2, w3 ... wn},构造n棵只有根节点的二叉树,令起权值为wj
2.在森林中选取两棵根节点权值最小的树作为左右子树,构造一颗新的二叉树,置新二叉树根节点权值为其左右子树根节点权值之和。
  注意,左子树的权值应小于右子树的权值。
3.从森林中删除这两棵树,同时将新得到的二叉树加入森林中。
  换句话说,之前的2棵最小的根节点已经被合并成一个新的结点了。
4.重复上述两步,直到只含一棵树为止,这棵树即是“哈弗曼树”

接下来举例说明如何构造huffman树。

fb3df958122765c3b4d312f154e1e78f.png

假设我们从某书籍中收集了一段语料,统计在语料中出现的词及每个词出现的次数,生成如下词汇表(这里只是举例,现实中的词汇表一定会非常大)。

vocabulary = {
    "are" 32,
    "you": 21,
    "and": 19,
    "very": 10,
    "hi": 7,
    "guys": 6,
    "wise": 2,
    "smart": 3,
}

然后通过每个词在语料中的出现次数建立huffman树,作为PROJECTION->OUTPUT结构。

另外在word2vec中约定:从huffman树根节点(root)开始,每次父节点向左子叶遍历编码为1,向右子叶遍历为0。如and编码为11,smart编码为01110(出现频率越高的词编码越短)。

4c5e2d04b3eaddbefc41ddd0da870a4b.png

在word2vec中使用huffman树的重要原因就是降低训练时的计算量。

一般来说,训练用的语料库都非常大。而在语料库中,有一些词出现频率很高,还有一些词出现频率很低,而且这种频率差异是非常巨大的。那么采用huffman树后,出现频率很高的常用词路径短,计算量小,从而降低了整个word2vec模型在训练时的计算开销。

CBOW(Continuous Bag of Words)结构

3952fa3cb6ed60b420ac1557d9d17128.png

在之前提到过,CBOW根据输入词周围

个词来预测出这个词本身。如果当前网络已经充分训练,那么输入you、are、 wise、and四个词,则应该输出词very。那么CBOW结构的word2vec网络是如何训练的?
  • 从INPUT->PROJECTION层

CBOW结构首先会取中心词的

个上下文词,然后用这些上下文词的one-hot编码向量乘以
权重再求和:

其中

代表词
的one-hot编码向量;
代表
的上下文词的词向量之和(为了便于书写记为
)。
  • 从PROJECTION->OUTPUT层(Hierarchical Softmax)

以词"very"为例在huffman树中需要分类4次(编码为0100),第一次分类结果

概率为:

其中

592ee2cb667a91525697624082e3579a.png

第二次分类为

概率为:

第三次分类为

的概率为:

第四次分类为

的概率为:

所以词"very"最终Hierarchical Softmax最终概率为:

7187da5fe10a5caab373fde0134b5a15.png

推广一下,词

最终Hierarchical Softmax最终概率为

其中

的huffman树路径长度(如"very"为4),而
为:

写成一个表达式:

  • 从OUTPUT->PROJECTION->INPUT训练

在训练时,我们显然希望输入是

个上下文词时输出使
,即概率
越大越好。那么最终优化目标就是对语料中每个词
最大:

其中

代表训练使用的语料库,
代表词
的huffman树路径长度。而优化目标是乘法形式,所以取对数
将优化目标转化为加法:

由于优化目标是使

最大,那么训练采用梯度上升算法,即每当获取新的训练中心词
时都会通过梯度更新一次权重。记:

这里

是中心词为
时的优化目标,即希望通过调整
使
最大。

所以计算

的偏导数:

注意

那么

中的参数
的更新公式为:

除了

,训练还需更新
,所以还要计算
的梯度:

即可更新

中的上下文词的词向量
(注意这里的
):

其中

代表梯度上升学习率。

对于上式一个比较通俗且不严谨的理解:

误差传给了谁,谁就会把梯度返回给传它误差的节点,即“原路送回“。在前传中通过

节点将误差传递给了后续网络,那么在反传中后续网络也要把自己所有的梯度
还给
节点,然后
又会把通梯度返还给
个上下文词的词向量。

cb8e7705f019fdc5e20ed46a77015d39.png

skip-gram结构

ea877472c0629fff14e84b5564b19566.png

在之前提到过,skip-gram根据输入词词来预测出周围

个上下文词。如果当前网络已经充分训练,那么输入very,则应该输出you、are、 wise、and四个上下文词。

从INPUT->PROJECTION计算

的词向量
,然后PROJECTION直接向后续分层softmax输出
(CBOW是求和)。skip-gram的优化目标与CBOW稍微不同:

其中多出的

符号代表skip-gram要通过
个huffman树分别输出
个上下文词,
中的
代表每个输出词对应的
参数。skip-gram与CBOW非常接近,考虑篇幅这里不再介绍。

word2vec实际测试

tmikolov/word2vec​github.com
8491b2c9e1fe928b2b4fa9e0cb59d505.png

Google提供了word2vec的c代码。使用代码和text8语料库训练200维词向量,可以看到与词"google"余弦像速度最大的词依次是"yahoo"和"gmail"。Amazing!

6490d949a4dbb4f91c7d45403a8a0ebd.png

关于word2vec应用,推荐参考词向量和svm对中文句子进行情感分析的代码:

BUPTLdy/Sentiment-Analysis​github.com

word2vec缺点

  • OOV(Out of vocabulary)

在word2vec中,词汇表从开始训练就已经是确定的。那么在使用时,必然会有词不在词汇表中。一般使用<UNKNOW>特殊标志符解决OOV问题,但是当句子中<UNKNOW>过多时必然严重影响精度。

后续ELMO使用char cnn、Bert使用word piece,基本解决了OOV问题。

  • 无法处理多义词

很多词在不同语境是有含义不同,即多义词。而word2vec中所有词的embeding向量都是训练好即固定的,无法在使用时根据上下文调整,导致处理多义词效果差。

ELMO和Bert使用训练language model,动态生成embeding向量,解决多义词问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值