一文详解 Word2vec 之 Skip-Gram 模型(实现篇)

前言

上一篇的专栏介绍了Word2Vec中的Skip-Gram模型的结构训练,如果看过的小伙伴可以直接开始动手用TensorFlow实现自己的Word2Vec模型,本篇文章将利用TensorFlow来完成Skip-Gram模型。还不是很了解Skip-Gram思想的小伙伴可以先看一下上一篇的专栏内容。

本篇实战代码的目的主要是加深对Skip-Gram模型中一些思想和trick的理解。由于受限于语料规模、语料质量、算法细节以及训练成本的原因,训练出的结果显然是无法跟gensim封装的Word2Vec相比的,本代码适合新手去理解与练习Skip-Gram模型的思想。

工具介绍

● 语言:Python 3

● 包:TensorFlow(1.0版本)及其它数据处理包(见代码中)

● 编辑器:jupyter notebook

● 线上GPU:floyd (https://www.floydhub.com/)

● 数据集:经过预处理后的维基百科文章(英文)

正文部分

文章主要包括以下四个部分进行代码构造:

- 数据预处理

- 训练样本构建

- 模型构建

- 模型验证

1 数据预处理

关于导入包和加载数据在这里就不写了,比较简单,请参考git上的代码。

数据预处理部分主要包括:

  • 替换文本中特殊符号并去除低频词
  • 对文本分词
  • 构建语料
  • 单词映射表

首先我们定义一个函数来完成前两步,即对文本的清洗和分词操作。

上面的函数实现了替换标点及删除低频词操作,返回分词后的文本。

下面让我们来看看经过清洗后的数据:

有了分词后的文本,就可以构建我们的映射表,代码就不再赘述,大家应该都比较熟悉。

我们还可以看一下文本和词典的规模大小:

整个文本中单词大约为1660万的规模,词典大小为6万左右,这个规模对于训练好的词向量其实是不够的,但可以训练出一个稍微还可以的模型。

2 训练样本构建

我们知道skip-gram中,训练样本的形式是(input word, output word),其中output word是input word的上下文。为了减少模型噪音并加速训练速度,我们在构造batch之前要对样本进行采样,剔除停用词等噪音因素。

采样

在建模过程中,训练文本中会出现很多“the”、“a”之类的常用词(也叫停用词),这些词对于我们的训练会带来很多噪音。在上一篇Word2Vec中提过对样本进行抽样,剔除高频的停用词来减少模型的噪音,并加速训练。

我们采用以下公式来计算每个单词被删除的概率大小:

其中 f(wi) 代表单词 w的出现频次。t为一个阈值,一般介于1e-3到1e-5之间。

上面的代码计算了样本中每个单词被删除的概率,并基于概率进行了采样,现在我们手里就拿到了采样过的单词列表。

构造batch

我们先来分析一下skip-gram的样本格式。skip-gram不同于CBOW,CBOW是基于上下文预测当前input word。而skip-gram则是基于一个input word来预测上下文,因此一个input word会对应多个上下文。我们来举个栗子“The quick brown fox jumps over lazy dog”,如果我们固定skip_window=2的话,那么fox的上下文就是[quick, brown, jumps, over],如果我们的batch_size=1的话,那么实际上一个batch中有四个训练样本。

上面的分析转换为代码就是两个步骤,第一个是找到每个input word的上下文,第二个就是基于上下文构建batch。

首先是找到input word的上下文单词列表:

我们定义了一个get_targets函数,接收一个单词索引号,基于这个索引号去查找单词表中对应的上下文(默认window_size=5)。请注意这里有一个小trick,我在实际选择input word上下文时,使用的窗口大小是一个介于[1, window_size]区间的随机数。这里的目的是让模型更多地去关注离input word更近词。

我们有了上面的函数后,就能够轻松地通过input word找到它的上下文单词。有了这些单词我们就可以构建我们的batch来进行训练:

注意上面的代码对batch的处理。我们知道对于每个input word来说,有多个output word(上下文)。例如我们的输入是“fox”,上下文是[quick, brown, jumps, over],那么fox这一个batch中就有四个训练样本[fox, quick], [fox, brown], [fox, jumps], [fox, over]。

3 模型构建

数据预处理结束后,就需要来构建我们的模型。在模型中为了加速训练并提高词向量的质量,我们采用负采样方式进行权重更新。

输入层到嵌入层

输入层到隐层的权重矩阵作为嵌入层要给定其维度,一般embeding_size设置为50-300之间。

嵌入层的 lookup 通过 TensorFlow 中的 embedding_lookup 实现,详见:

http://t.cn/RofvbgF

嵌入层到输出层

在skip-gram中,每个input word的多个上下文单词实际上是共享一个权重矩阵,我们将每个(input word, output word)训练样本来作为我们的输入。为了加速训练并且提高词向量的质量,我们采用negative sampling的方法来进行权重更新。

TensorFlow中的sampled_softmax_loss,由于进行了negative sampling,所以实际上我们会低估模型的训练loss。详见:http://t.cn/RofvS4t

请注意代码中的softmax_w的维度是vocab_size x embedding_size,这是因为TensorFlow中的sampled_softmax_loss中参数weights的size是[num_classes, dim]。

4 模型验证

在上面的步骤中,我们已经将模型的框架搭建出来,下面就让我们来训练训练一下模型。为了能够更加直观地观察训练每个阶段的情况。我们来挑选几个词,看看在训练过程中它们的相似词是怎么变化的。

训练模型:

在这里注意一下,尽量不要经常去让代码打印验证集相似的词,因为这里会多了一步计算步骤,就是计算相似度,会非常消耗计算资源,计算过程也很慢。所以代码中我设置1000轮打印一次结果。

从最后的训练结果来看,模型还是学到了一些常见词的语义,比如one等计数词以及gold之类的金属词,animals中的相似词也相对准确。

为了能够更全面地观察我们训练结果,我们采用sklearn中的TSNE来对高维词向量进行可视化。详见:http://t.cn/Rofvr7D

上面的图中通过TSNE将高维的词向量按照距离远近显示在二维坐标系中,该图已经在git库中,想看原图的小伙伴去git看~

我们来看一下细节:

上面是显示了整张大图的局部区域,可以看到效果还不错。

关于提升效果的技巧:

  • 增大训练样本,语料库越大,模型学习的可学习的信息会越多。
  • 增加window size,可以获得更多的上下文信息。
  • 增加embedding size可以减少信息的维度损失,但也不宜过大,我一般常用的规模为50-300。

附录:

git代码中还提供了中文的词向量计算代码。同时提供了中文的一个训练语料,语料是我从某招聘网站上爬取的招聘数据,做了分词和去除停用词的操作(可从git获取),但语料规模太小,训练效果并不好。

上面是我用模型训练的中文数据,可以看到有一部分语义被挖掘出来,比如word和excel、office很接近,ppt和project、文字处理等,以及逻辑思维与语言表达等,但整体上效果还是很差。一方面是由于语料的规模太小(只有70兆的语料),另一方面是模型也没有去调参。如果有兴趣的同学可以自己试下会不会有更好的效果。

完整代码请见:

http://t.cn/RofPq2p

====================================分割线================================

本文作者:AI研习社

本文转自雷锋网禁止二次转载,原文链接

时间: 2024-08-03 11:16:24

一文详解 Word2vec 之 Skip-Gram 模型(实现篇)的相关文章

一文详解 Word2vec 之 Skip-Gram 模型(结构篇)

这次的分享主要是对Word2Vec模型的两篇英文文档的翻译.理解和整合,这两篇英文文档都是介绍Word2Vec中的Skip-Gram模型.下一篇专栏文章将会用TensorFlow实现基础版Word2Vec的skip-gram模型,所以本篇文章先做一个理论铺垫. 原文英文文档请参考链接: - Word2Vec Tutorial - The Skip-Gram Model http://t.cn/Rc5RfJ2 - Word2Vec (Part 1): NLP With Deep Learning

一文详解 Word2vec 之 Skip-Gram 模型(训练篇)

第一部分我们了解skip-gram的输入层.隐层.输出层.在第二部分,会继续深入讲如何在skip-gram模型上进行高效的训练. 在第一部分讲解完成后,我们会发现Word2Vec模型是一个超级大的神经网络(权重矩阵规模非常大). 举个栗子,我们拥有10000个单词的词汇表,我们如果想嵌入300维的词向量,那么我们的输入-隐层权重矩阵和隐层-输出层的权重矩阵都会有 10000 x 300 = 300万个权重,在如此庞大的神经网络中进行梯度下降是相当慢的.更糟糕的是,你需要大量的训练数据来调整这些权

《末日公寓》攻略图文详解

<末日公寓>攻略图文详解一<末日公寓>是2012年最考验逃生能力的游戏之一.越是情况危急,你越是需要冷静下来,在地球将面临毁灭性灾难的情况下,肯定有什么办法生存下来,末日公寓将是你,也会是你可能带给人类最后的机会.本篇文章将为大家详细讲述解谜探险游戏末日公寓攻略的内容,希望能给各位玩家提供的末日公寓攻略中得到一些帮助.软件名称:<FinalCastle>价格:6元点击下载更新时间:2012年1月15日大小:77.3 MB进入游戏后,首先是一段剧情介绍,之后才真正开始游戏

【强烈强烈推荐】《ORACLE PL/SQL编程详解》全原创(共八篇)--系列文章导航

原文:[强烈强烈推荐]<ORACLE PL/SQL编程详解>全原创(共八篇)--系列文章导航 <ORACLE PL/SQL编程详解>    系列文章目录导航     --通过知识共享树立个人品牌.           本是成书的,但后来做其他事了,就无偿的贡献出来,被读者夸其目前为止最"实在.经典"的写ORACLE PL/SQL编程的文章-!   觉得对你有帮助,请留言与猛点推荐,谢谢.     [推荐]ORACLE PL/SQL编程详解之一:PL/SQL 程序

一文详解如何用 python 做中文分词

打算绘制中文词云图?那你得先学会如何做中文文本分词.跟着我们的教程,一步步用 Python 来动手实践吧.   需求 在此前发布的文章<从零开始教你用 Python 做词云>一文中,我们介绍了英文文本的词云制作方法.大家玩儿得可还高兴? 文中提过,选择英文文本作为示例,是因为处理起来最简单.但是很快就有读者尝试用中文文本做词云了.按照前文的方法,你成功了吗? 估计是不成功的.因为这里面缺了一个重要的步骤. 观察你的英文文本.你会发现英文单词之间采用空格作为强制分隔符. 例如: Yes Mini

一文详解神经网络 BP 算法原理及 Python 实现

  什么是梯度下降和链式求导法则 假设我们有一个函数 J(w),如下图所示. 梯度下降示意图 现在,我们要求当 w 等于什么的时候,J(w) 能够取到最小值.从图中我们知道最小值在初始位置的左边,也就意味着如果想要使 J(w) 最小,w的值需要减小.而初始位置的切线的斜率a > 0(也即该位置对应的导数大于0),w = w – a 就能够让 w 的值减小,循环求导更新w直到 J(w) 取得最小值.如果函数J(w)包含多个变量,那么就要分别对不同变量求偏导来更新不同变量的值. 所谓的链式求导法则,

为什么ResNet和DenseNet可以这么深?一文详解残差块为何有助于解决梯度弥散问题。

传统的"提拉米苏"式卷积神经网络模型,都以层叠卷积层的方式提高网络深度,从而提高识别精度.但层叠过多的卷积层会出现一个问题,就是梯度弥散(Vanishing),backprop无法有效地把梯度更新到前面的网络层,导致前面的层参数无法更新. 而BatchNormalization(BN).ResNet的skip connection就是为了解决这个问题,BN通过规范化输入数据改变数据分布,在前传过程中消除梯度弥散.而skip connection则能在后传过程中更好地把梯度传到更浅的层次

一文详解英伟达刚发布的 Tesla V100 究竟牛在哪?

众所周知,目前无论是语音识别,还是虚拟个人助理的训练:路线探测,还是自动驾驶系统的研发,在这些人工智能领域,数据科学家们正在面对越来越复杂的 AI 挑战.而为了更好地实现这些颇具未来感的强大功能,就必须在实践中引入一些指数级的更加复杂的深度学习模型. 另一方面,HPC(高性能计算)在现代科学研究中一直起着至关重要的作用.无论是预测天气,新药物的研究,或是探索未来能源,科研人员每天都需要利用大型计算系统对现实世界做各种各样的仿真和预测.而通过引入 AI 技术,HPC 就可以显著提升科研人员进行大数

一文详解高斯混合模型(GMM)在图像处理中的应用(附代码)

  一. 概述 高斯混合模型(GMM)在图像分割.对象识别.视频分析等方面均有应用,对于任意给定的数据样本集合,根据其分布概率, 可以计算每个样本数据向量的概率分布,从而根据概率分布对其进行分类,但是这些概率分布是混合在一起的,要从中分离出单个样本的概率分布就实现了样本数据聚类,而概率分布描述我们可以使用高斯函数实现,这个就是高斯混合模型-GMM. 这种方法也称为D-EM即基于距离的期望最大化.   二. 算法步骤     1. 初始化变量定义-指定的聚类数目K与数据维度D     2. 初始化