(二)通俗易懂理解——Skip-gram和CBOW算法原理

什么是Word2Vec和Embeddings?

Word2Vec是从大量文本语料中以无监督的方式学习语义知识的一种模型,它被大量地用在自然语言处理(NLP)中。那么它是如何帮助我们做自然语言处理呢?Word2Vec其实就是通过学习文本来用词向量的方式表征词的语义信息,即通过一个嵌入空间使得语义上相似的单词在该空间内距离很近。Embedding其实就是一个映射,将单词从原先所属的空间映射到新的多维空间中,也就是把原先词所在空间嵌入到一个新的空间中去。

我们从直观角度上来理解一下,cat这个单词和kitten属于语义上很相近的词,而dog和kitten则不是那么相近,iphone这个单词和kitten的语义就差的更远了。通过对词汇表中单词进行这种数值表示方式的学习(也就是将单词转换为词向量),能够让我们基于这样的数值进行向量化的操作从而得到一些有趣的结论。比如说,如果我们对词向量kitten、cat以及dog执行这样的操作:kitten - cat + dog,那么最终得到的嵌入向量(embedded vector)将与puppy这个词向量十分相近。

模型

Word2Vec模型中,主要有Skip-Gram和CBOW两种模型,从直观上理解,Skip-Gram是给定input word来预测上下文。而CBOW是给定上下文,来预测input word。

skip-gram模型的输入是一个单词W1,它的输出是W1的上Wo1,...,Woc,上下文的窗口大小为C。举个例子,这里有个句子“I drive my car to the store”。我们如果把”car”作为训练输入数据,单词组{“I”, “drive”, “my”, “to”, “the”, “store”}就是输出。所有这些单词,我们会进行one-hot编码。


假如我们有一个句子“The dog barked at the mailman”。

  • 首先我们选句子中间的一个词作为我们的输入词,例如我们选取“dog”作为input word;
  • 有了input word以后,我们再定义一个叫做skip_window的参数,它代表着我们从当前input word的一侧(左边或右边)选取词的数量。如果我们设置skip\_window=2,那么我们最终获得窗口中的词(包括input word在内)就是['The', 'dog','barked', 'at']skip\_window=2代表着选取左input word左侧2个词和右侧2个词进入我们的窗口,所以整个窗口大小span=2\times 2=4。另一个参数叫num_skips,它代表着我们从整个窗口中选取多少个不同的词作为我们的output word,当skip\_window=2num\_skips=2时,我们将会得到两组 (input word, output word) 形式的训练数据,即 ('dog', 'barked'),('dog', 'the')
  • 神经网络基于这些训练数据将会输出一个概率分布,这个概率代表着我们的词典中的每个词是output word的可能性。这句话有点绕,我们来看个栗子。第二步中我们在设置skip_window和num_skips=2的情况下获得了两组训练数据。假如我们先拿一组数据 ('dog', 'barked') 来训练神经网络,那么模型通过学习这个训练样本,会告诉我们词汇表中每个单词是“barked”的概率大小。


下面这个例子展示了从“The quick brown fox jumps over the lazy dog.“ 中找到的一些词对. 我使用了window size=2,而蓝色标出的词为输入词。

模型细节

我们如何来表示这些单词呢?

首先,我们都知道神经网络只能接受数值输入,我们不可能把一个单词字符串作为输入,因此我们得想个办法来表示这些单词。最常用的办法就是基于训练文档来构建我们自己的词汇表(vocabulary)再对单词进行one-hot编码。

假设从我们的训练文档中抽取出10000个唯一不重复的单词组成词汇表。我们对这10000个单词进行one-hot编码,得到的每个单词都是一个10000维的向量,向量每个维度的值只有0或者1,假如单词ants在词汇表中的出现位置为第3个,那么ants的向量就是一个第三维度取值为1,其他维都为0的10000维的向量(ants=[0, 0, 1, 0, ..., 0])。


模型的输入如果为一个10000维的向量,那么输出也是一个10000维度(词汇表的大小)的向量,它包含了10000个概率,每一个概率代表着当前词是输入样本中output word的概率大小。


重点内容

其实在阅读各种博客的时候,我最想知道的就是怎么输入怎么输出,对于很多原理介绍不是特别关心,不过由于写的算是一篇技术贴,就copy他人的内容作为一些基础介绍。接下来谈谈自己的理解。

以“The quick brown fox jumps over the lazy dog.“为例。

首先输入就是一个one-hot向量,假设我们语料中有10000个词,那输入一个1*10000的one-hot矩阵来表示brown,接下来我们的隐藏层设置为300个神经单元,这个300个神经单元就是我们要的维度,如果你想要设置成100维的词向量,那么这个神经元就设置成100.

那么在输入和隐藏层之间就会产生一个10000*300的权重矩阵,而这个矩阵就是我们需要的词向量。这个词向量怎么来的,那么要看接下去的连接。

在隐藏层后面将再接一层,这一层具有10000个神经元,这10000个神经元代表的是总共的词汇量10000个,而至于这层形成的权重矩阵不用管,虽然权重矩阵为300*10000.

这时候我们得到10000个输出,这10000个输出将代入softmax转化为10000个概率,这10000个概率值加总和为1.

这就是整个skip-gram的网络层。我们以brown为例,将形成四组训练数据(brown,The)、(brown,quick)、(brown,fox)、(brown,jumps)。

如何进行权重优化呢?拿(brown,fox)来说,brown的输出为10000个概率,形式为1*10000,而fox为1*10000的one-hot形式,我们的代价函数就是可以最小化这两个矩阵的交叉熵,也可以求这两个矩阵的差平方,即损失值。

经过不断的迭代,最终输入层和隐藏层形成了一个10000*300的权重矩阵,那么这个权重矩阵将一一对应输入层当中词汇向量,至于为何可以这样,暂时没有搞明白。

另外,我们如果按照一般的神经网络训练,那输入跟隐藏层之间的权重将无比巨大,导致计算缓慢,假设我们有320000个词汇,那将有320000*300个权值需要训练。这时候就会根据one-hot的特点进行权值索引,解决这个难题。这也是为何把这个层也叫做投影层,不做运算只是投影。

如下图所示,输入的是一个one-hot,经过权值矩阵运算,相当于是对其进行索引,输入在第4列,那么输出就是第4行,这样避免了计算。

到此,skip-gram算法原理介绍结束,至于训练过程中的一些加快训练方法可以参考相关博客,如负采样的运用等。


CBOW模型

CBOW模型跟skip-gram的原理是一样的,只不过在输入的时候是该词周围的词向量加总作为输入。

现在有这样一句话:今天我和小明去北京玩

今天:[1, 0, 0, 0, 0, 0, 0, 0, 0, 0] 记为x1

我 :[0, 1, 0, 0, 0, 0, 0, 0, 0, 0] 记为x2

和 :[0, 0, 0, 0, 0, 0, 0, 0, 1, 0] 记为x3

去 :[0, 0, 0, 0, 0, 0, 0, 1, 0, 0] 记为x4

北京:[0, 0, 0, 0, 0, 0, 1, 0, 0, 0] 记为x5

玩 :[0, 0, 0, 0, 0, 0, 1, 0, 0, 0] 记为x6

小明的向量表示为:

小明 :[0, 0, 0, 0, 1, 0, 0, 0, 0, 0]


我们的输入就是:

X = x1 + x2 + x3 + x4 + x5 + x6 = [1, 1, 0, 0, 0, 1, 1, 1, 1, 0]

这个输入是把‘小明’这个词的上下文全部作为输入,而如果我们只是要前后的一个,那就只要加总‘和’‘去’。其他的就跟skip-gram是一样的。


本文基于对其他博客的解读,如有错误,欢迎指正。

参考作者:天雨粟:理解 Word2Vec 之 Skip-Gram 模型

blog.csdn.net/u01173414

mccormickml.com/2016/04

编辑于 2018-07-13 16:41

文章被以下专栏收录