专栏首页PaddlePaddle手把手教你用飞桨做词向量模型 SkipGram

手把手教你用飞桨做词向量模型 SkipGram

飞桨开发者说成员:肥猫、忆臻

在做 NLP 的任务时,一个非常 basic 的操作就是如何编码自然语言中的符号,例如词、短语,甚至词缀。目前流行的方法有大约三种:

特征工程:这类方法依赖于手工特征,例如tf-idf 同时考虑词频和词的稀缺度;

统计方法:统计上常常通过矩阵分解(如SVD、EVD)来建模大规模文档集合;

神经网络:目前非常流行通过神经网络端到端的建模语言模型,得到词向量副产品;

今天要讲解的就是SkipGram 模型就属于第三种方法,它的主要思想是利用的词义的分布式表示。除了让您彻底弄懂什么是语言模型以及 SkipGram 的基本原理。我们还会详细的说明如何一步步的用飞桨(PaddlePaddle)实现它。

1.什么是词向量

首先我们需要了解什么是词向量。NLP和图像不太一样,图像的输入本身就是一个有数值特征的矩阵,而 NLP 的输入通常只是一堆自然语言的符号,不方便计算机直接计算。因此,在计算语言学中,我们通常会希望用数值向量来表示这些符号。例如现在我们希望比较词汇“米饭”与“猪肉”和“家具”之间词义的相似性,可以考虑用下面这样的 two-stage 范式。

• 将词汇用向量来表示,例如这里

以及

• 考虑某种数值距离去度量,例如内积

。这里有

。类似的,同理我们也可以得到

;从数值大小可以判断,与“家具”相比,“米饭”和“猪肉”更相似。

从上面这个例子可以看出,使用向量数值表示法最关键的地方在于如何获取词汇的向量的表示,而 SkipGram 就是一个良方。

2.什么是语言模型

词向量一般不是直接获取的,而是某些任务的副产品。它们通常是随机初始化的,然后通过不断的数值优化过程中获得语义信息,例如上述的相似性。因此,训练词向量的办法可以有很多,但是如何高效的获得高质量的词向量很重要,另外任务也应该有一定的可拓展性,例如语料充足,不需要额外标注。

语言模型是一个非常好的选择。因为它语料充足,只要有文章,有帖子,那就有数据;同时由于其任务的特殊性,不需要人工进行额外的数据标注(网上有很多称这是无监督,但我觉得不是特别合适,不需要数据标注和无监督概念有所差异)。那么什么是语言模型呢?

语言模型就是用来衡量一句话出现的概率的。例如

显然,第二句话一般不会出自于一个神智正常的人之口,因此他的概率很低。而一句话

的概率可以用条件概率分解如下:

这里

表示词

的上下文,是对

的近似,否则计算复杂度是指数的。其中一种近似就是 n-gram,即

如上图所示的例子,当n=5时,

表示已知前 4 个词,预测下一个词的概率。由于让模型提高 P(s) 的概率等价于让模型提高每个 P(wi|ci)的概率,因此语言模型又可以被理解为已知上下文时中心词不确定性的度量。

3.什么是 SkipGram

经过前两节的解释,相信您对词向量有了很深的认识了。这一小节中我将会介绍 SkipGram,一种有效训练语言模型的方法。

说到 SkipGram,一定有同学会想到 CBOW。实际上 CBOW 更符合常人的思考逻辑,它建模词语上下文的方法很简单,如下图所示:

它从若干文档的文段中随机抽取出5 个连续的词, 然后类似做完形填空,希望模型能够根据上下文 预测。而 SkipGram 则恰恰相反,如下图所示,它是拿用中心词去预测上下文:

虽然看起来 CBOW 更合理,但很多文献指出,用 SkipGram 训出来的词向量效果更好。笔者分析可能存在下面一些原因:

• SkipGram 用一个中心词去预测上下文,这样相当于对这个中心词的表示要求更高,这就好像一个学生(中心词)同时受到了多个老师(上下文)的教导(这个学习的过程可以被理解为中间的梯度传播),效果肯定比一个老师教导多个学生(因此梯度是均分的,没有区分性,而且由于梯度均分,容易破坏一个窗口中词向量的异构性)效果要好得多;

• 其次,SkipGram 这种强调中心词的结构对某些具有较低频率的生僻词比较友好,因此低频词也可以学到质量较高的向量表示;

但可能是因为 CBOW 的结构相对简单些,经验显示,CBOW 的训练速度要比 SkipGram 快的多,因此两者其实各有优势。

拿上面提到的例子 “Can you please come here ?” 说明 SkipGram 的流程。假设滑动窗口的长度为 5,那么现在窗口 cover 住了片段 “can you please come here”。此时以中心词 please 为输入并度量与上下文 can, you,come, here 的相似度,优化时希望这个值尽量高。

在工程上,实现词向量模型有很多trick,例如概率平滑化,高频词抽样等。但如果做个 demo 不需要考虑太多这些细节。不过无论是 CBOW 还是 SkipGram 都无法规避一个问题,就是过高的词典容量。正常情况下,英语词典的容量在 3000 ~ 4000 上下,因此当训练语料很大时会造成巨大的计算负担。为了权衡质量和效率,目前最常用的方法就是负采样。通俗的来说,就是我不再把整个词典当成负样本了,而是随机抽取若干词作为负样本。实现时,这个随机抽取的数量是一个超参数,大概是 20 ~ 30 之间,这样很明显大大提高了计算效率。另外,也有人指出,用一些重要性采样的技术可以进一步改善效果。

4.用飞桨实现

现在你已经基本了解了什么是SkipGram,下面我们就用强大的飞桨一步一步实现它。

现在你已经基本了解了什么是SkipGram,而实现它需要借助现有的深度学习框架。飞桨是百度自主研发的深度学习框架,功能非常强大,同时支持稠密参数、稀疏参数并行训练;静态网络、动态网络等。而且有非常丰富的中英文文档,非常方便您使用。下面我们就用强大的飞桨一步一步实现它.

首先,我们需要导入一些必要的计算库。

# PaddlePaddle 计算引擎.
importpaddle
frompaddle import fluid

# 一些常用的科学计算库.
importnumpy as np
importmatplotlib.pyplot as plt

然后设置定义一些超参数,用于控制网络结构和训练逻辑。

EMBEDDING_DIM =64  # 词向量维度.
WINDOW_SIZE =5     #滑动窗口大小.
BATCH_SIZE =200    #迭代 batch 大小.
EPOCH_NUM =10      #训练的轮数.
RANDOM_STATE =0    #设置伪随机数种子.

然后就是文本数据,这里使用飞桨自带(会自动下载)的 PTB 数据集,导入如下:

from paddle.dataset import imikolov

word_vocab =imikolov.build_dict()
vocab_size =len(word_vocab)

# 打印 PTB 数据字典的容量大小.
print("imikolov 字典大小为 "+str(vocab_size))

# 类似 Pytorch 的 DataLoader, 用于在训练时做 batch, 很方便.
data_loader =paddle.batch(imikolov.test(word_vocab, WINDOW_SIZE), BATCH_SIZE)

imikolov字典大小为 2074

下面我们需要搭建SkipGram 的网络结构,我们用一个函数打包如下:

def build_neural_network():
    assertWINDOW_SIZE %2==1
   medium_num = WINDOW_SIZE //2

    # 定义输入变量, 是从文本中截取的连续的文本段.
   var_name_list = [str(i) +"-word"for i inrange(0, WINDOW_SIZE)]
   word_list = [fluid.layers.data(name=n, shape=[1], dtype="int64")for n in var_name_list]

    # 取中心词作为输入, 而周围上下文作为输出.
   input_word = word_list[medium_num]
   output_context = word_list[:medium_num] + word_list[medium_num +1:]

    # 将输入输出都做词向量表示, 并且将输出拼起来.
   embed_input = fluid.layers.embedding(
        input=input_word, size=[vocab_size, EMBEDDING_DIM],
       dtype="float32",is_sparse=True,param_attr="input_embedding")
   embed_output_list = [fluid.layers.embedding(
        input=w, size=[vocab_size, EMBEDDING_DIM], dtype="float32",
       is_sparse=True,param_attr="output_embedding")for w in output_context]
   concat_output = fluid.layers.concat(input=embed_output_list,axis=1)

    # 用 -log(sigmoid(score)) 作为度量损失函数.
    var_score =fluid.layers.matmul(embed_input, concat_output, transpose_x=True)
   avg_loss =0-fluid.layers.mean(fluid.layers.log(fluid.layers.sigmoid(var_score)))

    # 使用 Adam 优化算法, 并注意需要返回变量定义名.
   fluid.optimizer.AdamOptimizer().minimize(avg_loss)
    returnavg_loss, var_name_list

类似于 Tensorflow,运行 PaddlePaddle 计算引擎前需要一些热身代码。

# 确定执行的环境, 如果支持 CUDA 可以调用CUDAPlace 函数.
device_place =fluid.CPUPlace()
executor = fluid.Executor(device_place)

main_program =fluid.default_main_program()
star_program =fluid.default_startup_program()

# 固定伪随机数种子, 一般用于保证论文效果可复现.
main_program.random_seed =RANDOM_STATE
star_program.random_seed =RANDOM_STATE

# 定义模型的架构 (之前定义函数输出) 以及模型的输入.
train_loss, tag_list =build_neural_network()
feed_var_list =[main_program.global_block().var(n) for n in tag_list]
data_feeder =fluid.DataFeeder(feed_list=feed_var_list, place=device_place)

下面开始训练模型的流程,将迭代器产生的 batch 不断喂入网络中:

executor.run(star_program)
forepoch_idx inrange(EPOCH_NUM):
   total_loss, loss_list =0.0, []

    forbatch_data in data_loader():
       total_loss +=float(executor.run(
           main_program, feed=data_feeder.feed(batch_data),
           fetch_list=[train_loss])[0])
   loss_list.append(total_loss)
    print("[迭代轮数{:4d}], 在训练集的损失为{:.6f}".format(epoch_idx, total_loss))

[迭代轮数 0], 在训练集的损失为 75.395110 [迭代轮数 1], 在训练集的损失为 2.346059 [迭代轮数 2], 在训练集的损失为 0.797208 [迭代轮数 3], 在训练集的损失为 0.413886 [迭代轮数 4], 在训练集的损失为 0.254423 [迭代轮数 5], 在训练集的损失为 0.171255 [迭代轮数 6], 在训练集的损失为 0.121907 [迭代轮数 7], 在训练集的损失为 0.090095 [迭代轮数 8], 在训练集的损失为 0.068378 [迭代轮数 9], 在训练集的损失为 0.052923

我们可以将刚才训练过程中的损失用 matplotlib 的库函数画出来。

plt.plot(np.array(range(0, len(loss_list))),loss_list)

好啦,以上就是本次所要分享。总的来说,本节我们主要讲述了什么是词向量,什么是语言模型,SkipGram 算法的内容以及其特性,相对 CBOW 来说它对低频词更友好,而且词向量质量更佳,最后我们还细致的教您一步一步用飞桨实现一个简单的 SkipGram 模型。希望您多多支持,咱们下期再会。

想与更多的深度学习开发者交流,请加入飞桨官方QQ群:796771754

如果您想详细了解更多飞桨的相关内容,请参阅以下文档。

官网地址:https://www.paddlepaddle.org.cn

Skip-Gram相关内容参考项目地址:

https://github.com/PaddlePaddle/models/tree/v1.5.1/PaddleRec/word2vec

本文分享自微信公众号 - PaddlePaddle(PaddleOpenSource)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-09-14

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 百度再出Lens黑科技!用PaddleMobile实现类人眼视觉AI能力

    你知道吗?人类有 70%的信息获取来自于视觉。但目前存在两个问题: ①人眼本身只能看到物理世界,无法看到其背后复杂的信息世界; ②人类的记忆力有限,视野有限,于...

    用户1386409
  • 137% YOLOv3加速、10倍搜索性能提升!这样的惊喜,最新版PaddleSlim有10个

    近年来,深度学习在工业领域的应用越来越广泛,不但提升了企业的自动化生产效率,还为企业的重要决策提供了数据支撑,AI正逐步改变人们的生活和生产方式。由于深度神经网...

    用户1386409
  • 飞桨实战 | DCGAN生成手写数字图片全解析

    生成对抗网络(Generative Adversarial Network,简称GAN)是非监督式学习的一种方法,通过让两个神经网络相互博弈的方式进行学习。

    用户1386409
  • Python 强化训练:第六篇

    谢伟
  • SAP C4C里销售订单行项目为什么无法添加产品

    当我试图在SAP Cloud for Customer的销售订单里添加一个新产品时,遇到错误消息:

    Jerry Wang
  • Cloud for Customer Restriction and Exclusion Product Lists

    版权声明:署名,允许他人基于本文进行创作,且必须基于与原先许可协议相同的许可协议分发本文 (Creative Commons)

    Jerry Wang
  • 这些经常被忽视的SQL错误用法,你踩过几个坑?

    Limit是分页查询是最常用的场景之一,但也通常也是最容易出问题的地方。比如对于下面简单的语句,一般我们觉得在type, name, create_time字段...

    章为忠
  • 企业云: 公有云厂商不靠谱,企业级应用何去何从?

    公有云厂商的黄历上今年注定不是一个太平的年份。八月份有四个国际级云计算大厂就宕机了六次(AWS、iCloud、Microsoft和Google),有人正在网上买...

    静一
  • 干货丨什么是CMS ,CMS 有哪些功能呢?

    随着知识付费与专业内容的生活占比加大,内容构造者在撰写与梳理内容时,渴求通过更为高效便捷的方式,完成对内容的管理,更系统的对文字系统建立组织逻辑,自此CMS应运...

    齿轮易创说互联网
  • 词向量游戏:梅西-阿根廷+葡萄牙=?

    自从把腾讯词向量对接到AINLP公众号后台后,发现相似词相关的查询需求是逐渐增大的,已经不止一次有非CS专业的同学通过后台查询相似词或者相似度来做课程设计,这让...

    AINLP

扫码关注云+社区

领取腾讯云代金券