Continuous Bag of Words (CBOW) - 自然语言处理 | 莫烦Python
切换视频源:

Continuous Bag of Words (CBOW)

作者: 莫烦 编辑: 莫烦 2020-07-20

学习资料:

怎么了

之前我们在介绍搜索引擎的时候,提到过TF-IDF算法, 这种算法是通过一种统计学的方式来用文章中的词的重要程度,转化成向量来表示一篇文章的。 向量化思维在机器学习中也非常常见,我们可以认为,一张图片是一个向量,一篇文章是一个向量,一句话也可以是一个向量。 这样的向量化表示优点也很明显,就是能被计算机计算,是计算机能够理解的模式。

那么我们还能更加细化能被向量化的东西吗?比如说有没有词的向量呢?词的向量有怎么得到呢? 这里的短片简介将会清楚的阐述这样的过程。

w2v

什么是CBOW

CBOW 是 Continuous Bag-of-Word 的简称,同篇论文中, 还有另外一个一起提出的,十分相似的模型,Skip-Gram, 我们会在下一节内容中继续阐述Skip-Gram. 那么这个CBOW是什么个东西呢?用一句话概述:挑一个要预测的词,来学习这个词前后文中词语和预测词的关系

举个例子吧,有这样一句话。

我爱莫烦Python,莫烦Python通俗易懂。

模型在做的事情如图中所示,将这句话拆成输入和输出,用前后文的词向量来预测句中的某个词。

cbow illustration

那么这个模型的输入输出可以是:

# 1
# 输入:[我,爱] + [烦,Python]
# 输出:莫

# 2
# 输入:[爱,莫] + [Python, ,]
# 输出:烦

# 3
# 输入:[莫,烦] + [,,莫]
# 输出:Python

# 4
# 输入:[烦,Python] + [莫,烦]
# 输出:,

通过在大数据量的短语或文章中学习这样的词语关系,这个模型就能理解要预测的词前后文的关系。而图中彩色的词向量就是这种训练过程的一个副产品。

词向量的应用

词向量的几种典型应用:

  • 把这些对词语理解的向量通过特定方法组合起来,就可以有对某句话的理解了;
  • 可以在向量空间中找寻同义词,因为同义词表达的意思相近,往往在空间中距离也非常近;
  • 词语的距离换算。

词语距离计算这个比较有意思,比如可以拿词语做加减法。公猫 - 母猫 就约等于 男人 - 女人。 如果我哪天想知道 莫烦Python 的友商有哪些,我可以做一下这样的计算

友商 = 莫烦Python - (腾讯 - 阿里)

秀代码

为了做一个有区分力的词向量,我做了一些假数据,想让计算机学会这些假词向量的正确向量空间。 如果你习惯直接看所有源码,那么源码在这里

我将训练的句子人工分为两派(数字派,字母派),虽然都是文本,但是期望模型能自动区分出在空间上,数字和字母是有差别的。因为数字总是和数字一同出现, 而字母总是和字母一同出现。并且我还在字母中安排了一个数字卧底,这个卧底的任务就是把字母那边的情报向数字通风报信。 所以期望的样子就是数字 9 不但靠近数字,而且也靠近字母。

这就是最终的实验结果。可以看到内奸9已经被暴露啦~

CBOW w2v result

我们就开始写模型吧,这个模型还相对比较简单。tensorflow 2.0 版本之后,我比较推荐使用keras来编写模型。如果对这一套还不是很熟悉的朋友, 可以参考一下我写的一些简易 TF2.+ 的代码, 如果你会 TF1.+,或者 Pytorch,那么你可能只需要10分钟的入门时间。

下面就是CBOW中的词向量组件了,最为核心的就是 self.embeddings,词向量就存在于这里里面。之后我们会将它可视化

接下来就是模型的预测是如何进行的了,我们用classcall功能定义模型的前向预测部分。说白了,其实也就是把预测时的embedding词向量给拿出来, 然后求一个词向量平均,这样输出就够了。在用这个平均的向量预测一下目标值。

在求loss的时候我们稍微做一些手脚,这样可以在训练拥有庞大词汇的模型上有好处。使用nce_loss能够大大加速softmax求loss的方式,它不关心所有词汇loss, 而是抽样选取几个词汇用来传递loss,因为如果考虑所有词汇,那么当词汇量大的时候,会很慢。

这就完成了整个模型的搭建啦。我加上我写好的处理数据组件,就能直接开始训练啦。

值得注意的是,在数据处理方面,我没在代码中特别强调,但是可以看出,process_w2v_data() 这个功能需要确定我们的skip_window这个参数, 这个参数的作用就是,在我们要预测的词周围,我们要选取多少个词作为他的输入。如果skip_window=1则意味着我们选取这个词前后各1个词作为网络的输入, 如果skip_window=2则意味着我们选取这个词前后各2个词,以此类推。具体代码可以看到我写在 utils.py 当中的代码。

最后如果将学到的embedding向量结果进行可视化,就有了我们之前在文章前面看到的那个样子,观看一下字母和数字的距离,我们也能知道CBOW学会了这些词之间的内在联系。

思考括展

我们已经能成功的训练出这些词向量了,除了可视化展示他们,我们还能怎么使用这些向量呢?在这里我举一个例子。

句子是由词语组成的,那么有一种理解句子的方式,就是将这个句子中所有词语的词向量都加起来,然后就变成了句子的理解。 不过这种空间上的向量相加,从直观上理解,就不是特别成立,因为它加出来以后,还是在这个词汇空间中的某个点, 你说它是句向量吧,好像也不行,说它是一个词的理解吧,好像也不对。

所以更常用的方式是将这些训练好的词向量当做预训练模型,然后放入另一个神经网络(比如RNN)当成输入,使用另一个神经网络加工后,训练句向量。

总结

词向量是词语的向量表示,我们的计算机最擅长使用这种数字化向量表示来计算和理解词语。所以词向量对于理解词语甚至是句子都有很强的适用性。 下一节我们来见识一下另一种词向量训练方法Skip-Gram,我个人更喜欢后者, 因为后者没有我觉得说不太通的词向量相加过程。


降低知识传递的门槛

莫烦很常从互联网上学习知识,开源分享的人是我学习的榜样。 他们的行为也改变了我对教育的态度: 降低知识传递的门槛免费 奉献我的所学正是受这种态度的影响。 通过 【赞助莫烦】 能让我感到认同,我也更有理由坚持下去。