Word2Vec导学第二部分 - 负采样

Word2Vec导学第二部分 - 负采样

在word2vec导学的第二部分,我将介绍一些在基础skip-gram模型上的额外改进,这些改进是非常重要的,他将使得模型变得可以被训练。

当你阅读word2vec中的skip-gram模型导学的时候,你会发现那个神经网络实在是太巨大了。

在我给的这个例子下面,每个词向量由300个元素组成,并且一个单词表中包含了10000个单词。回想神经网络中有两个权重矩阵——一个在隐藏层,一个在输出层。这两层都具有300 x 10000 = 3,000,000个权重!

使用梯度下降法在这种巨大的神经网络下面进行训练是很慢的。并且可能更糟糕的是,你需要大量的训练数据来调整这些权重来避免过拟合。上百万的权重乘以上十亿的训练样本,意味着这个模型将会是一个超级大怪兽!

word2vec的作者在第二篇论文中提出了这个问题。

在第二篇文章中有三个创新点:

  1. 对于常见的单词对或者短语,在模型中将他们视为单个的单词。
  2. 对常见单词进行二次采样来减少他们在训练样本中的数量。
  3. 使用所谓的“负采样”(negative sampling)来改进优化对象,这将造成每一个训练的样本只会更对模型权重的很小一个比例的更新。

对频率高的单词使用再抽样和使用负采样是非常值得的,这不仅会减少训练过程的计算负担,还将增加生成的词向量的质量。

词对和“短语”

作者指出了像“Boston Globe”(“波士顿环球报”,一种报纸)这样的单词对,在作为单独的“Boston”和“Globe”来进行看待的时候有着非常不同的含义。所以在将它作为一整个“Boston Globe”来说是非常有意义的,不论它出现在文中哪里,都将一整个当成一个单词来看待,并且有它自己的词向量。

你可以在他们公布的模型中看到这个结果,那个模型使用了1千亿个来自谷歌新闻数据集的单词来进行训练。额外增加的短语使得这个模型的单词尺寸缩减到了3百万个单词!

短语发现在他们论文中的“学习短语”这个部分中。他们分享了这个应用在word2phrase.c文件中。

我不认为短语的发现方法是论文中的一个关键,但是我将要分享一些关于这个的内容,因为这个也是十分简单的。

这个工具每次使用都仅仅关注两个单词的组合,但是实际上你可以多次使用这个工具,从而来获取更长的单词词组。比如说,我第一次使用获取了”New York”这个词组,然后再使用第二次,这次将获取到”New York City”这个词组来作为”New York”和”City”这两个词的组合。

这个工具从训练文章中计算出每两个单词组合同时出现的次数,并且在一个公式中使用这些计算出来的次数来决定哪些单词的组合能够转换成短语。这个公式是设计出来将多个经常一起出现的单词组合变成短语的。并且它还能够完成一些频率不高单词组成短语,和避免一写不正常的单词比如”and the”或者是”this is”来组成短语。

更多公式的细节在这里

高频词汇的二次采样

在本导学的第一部分,我介绍了训练样本是怎么样从源文件中创造出来的,但是这里,我将重复说一下。下面的例子向我们展示了从句子”The quick brown fox jumps over the lazy dog.”中找到一些训练样本(词对)。这里我之前使用了2这么小的词窗。下面单词被高亮为蓝色的就是我的输出单词。

这里对于经常使用的”the”这个单词有两个“问题”:

  1. 当我们关注与词对的时候,(”fox”, “the”)这个词对没有告诉我们任何关于”fox”的含义。”the”这个单词几乎和上下文的每一个单词都同时出现过。
  2. 我们将拥有比我们需要的(“the”, …)样本更多的个数,这些样本个数超过了将”the”这个单词变成一个好向量的个数。

Word2Vec使用了一个”二次采样”技术来处理这些问题。对于每一个我们在训练样本中遇到的单词,我们将有机会能够高效地将他们从文中进行删除。我们删除单词的概率跟单词出现的频率相关。

如果我们的窗大小为10,并且我们移除了我们文章中特定的”the”:

  1. 当我们训练剩下的单词时,”the”这个单词将不会出现在他们上下文的窗里。
  2. 我们将会在”the”作为输入函数单词的时候减少10个训练的样本。

采样率

word2vec的C代码中使用了一个公式来计算给出特定单词时候单词表中的单词出现的概率。

wi代表单词,z(wi)代表在总的语料库中的一个概率。比如说,如果单词”peanut”在1十亿的单词库中出现了1000次,那么z(‘peanut’) = 1e-6。

这也是代码中名为“采样”的一个来控制重采样频率的一个参数,它的默认值为0.001。更小的“采样”参数意味着单词被保存下来的几率更小。

负采样

训练一个神经网络意味着使用一个训练样本就要稍微调整一下所有的神经网络权重,这样才能够确保预测训练样本更加精确。换句话说,每个训练样本都会改变神经网络中的权重。

正如我们上面讨论的,单词表的大小意味着我们的skip-gram神经网络拥有非常庞大的权重数,所有权重都会被十亿个样本中的一个稍微地进行更新!

负采样通过使每一个训练样本仅仅改变一小部分的权重而不是所有权重,从而解决这个问题。下面介绍它是如何进行工作的。

当通过(”fox”, “quick”)词对来训练神经网络时,我们回想起这个神经网络的“标签”或者是“正确的输出”是一个one-hot向量。也就是说,对于神经网络中对应于”quick”这个单词的神经元对应为1,而其他上千个的输出神经元则对应为0。

使用负采样,我们通过随机选择一个较少数目(比如说5个)的“负”样本来更新对应的权重。(在这个条件下,“负”单词就是我们希望神经网络输出为0的神经元对应的单词)。并且我们仍然为我们的“正”单词更新对应的权重(也就是当前样本下”quick”对应的神经元)。

论文说选择5~20个单词对于较小的样本比较合适,而对于大样本,我们可以悬着2~5个单词。

回想一下,我们模型的输出层有大约300 x 10,000维度的权重矩阵。所以我们只需要更新正确的输出单词”quick”的权重,加上额外的5个其他应该输出为0的单词的权重。也就是总共6个输出神经元,和总共1800个的权重值。这些总共仅仅是输出层中3百万个权重中的0.06%。

在隐藏层中,只更新了输入单词对应的权重(不论你是否使用了复采样)。

选择负采样样本

“复采样样本”(也就是我们需要训练的五个输出为0单词)使用“一元分部”(“unigram distribution”)来进行选取。

从本质上来说,选择一个单词来作为负样本的概率取决于它出现频率,对于更经常出现的单词,我们将更倾向于选择它为负样本。

在使用C语言实现的词转向量(word2vec)中,你可以看到这个概率公式。每个单词都被给予一个等于它频率的权重(单词出现的数目)的3/4次方。选择某个单词的概率就是它的权重除以所有单词权重之和。

使用频率的3/4次方显然是根据经验来的;在他们的文章中,他们说到这个公式比其他函数的表现更为优秀。你可以通过在谷歌中输入: plot y = x^(3/4) and y = x并且调整焦距为x = [0, 1]范围。当我们增加数值一点点的时候它的图像有一点小弯曲。

使用C语言来实现这个样本选择的实现很有意思。他们有一个1亿元素大小的数组(每一个都相当于一个一元模型的表格)。表格中通过索引来多次记录每一个在单词表中出现的单词,在这里单词指标大小通过 P(wi) * table_size 来表达。其次,为了切实选择一个负样本,你仅仅只需要创造一个0到1亿的随机整数样本,并且使用这个数字在表格中索引的单词。由于更高概率的单词在表格中出现的次数会更多,所以你将更倾向于选择到它们。

你可能感兴趣的:(nlp)