0%

Word2Vec Tutorial Part 2 - Negative Sampling

  在word2vec教程的第2部分(第一部分链接)中,我将介绍对基本Skip-gram模型的一些其他修改,这些修改对训练可行性非常重要。

  当你阅读有关Word2Vec中的skip-gram模型的教程时,可能会意识到一些问题——它是一个巨大的神经网络!

  在我给出的示例中,我们有包含300个成分的单词向量和10,000个单词的词汇。回想一下,神经网络有两个权重矩阵——隐藏层的权重矩阵和输出层的权重矩阵,每个矩阵的权重数量为三百万!在较大的神经网络上运行梯度下降会很慢,更糟的是,您需要大量的训练数据才足以训练这么多的权重并避免过拟合,数百万的权重乘以数十亿的训练样本意味着训练这种模型十分困难。

  Word2Vec的作者在第二篇论文中通过以下两项创新解决了这些问题:

  1. 对频繁的单词进行二次采样以减少训练示例的数量。
  2. 他们使用称为“负采样”的技术来修改优化目标,该技术可使每个训练样本仅更新模型权重的一小部分。

  值得注意的是,对频繁出现的单词进行二次采样和应用负采样不仅减轻了训练过程的计算负担,而且还改善了其产生的单词向量的质量。

二次采样常见词

  在本教程的第1部分中,我展示了如何从源文本创建训练样本,但是在这里我再描述一次。下面的示例显示了一些从句子“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”为中心词的训练数据。

  这两个效果能够有助于解决上文提到的两个问题。

采样率

  word2vec C代码实现了一个方程式,用于计算将给定单词保留在词汇表中的概率。

  是一个词语,是语料库中该单词占单词总数的比例。例如,如果单词“peanut”在大小为10亿个单词的语料库中出现了1000次,则z(“peanut”)= 1E-6。

  代码中还有一个名为“sample”的参数,用于控制发生多少次采样,默认值为0.001。较小的“sample”值表示保留单词的可能性较小。

  表示保留该词的概率:

该函数的形状如下图:

任何单词都不应该占语料库的很大一部分,因此我们希望查看在x轴上很小的值。

  这是此函数中的一些有趣的要点(再次使用默认样本值0.001)。

  • 时,.
    • 这意味着将仅对在语料中出现次数达到总单词的0.26%以上的单词进行子采样。
  • 时,,即单词有50%的概率被保留。
  • 时,
    • 这是整个语料库都只由一个单词构成的情况,是不合理的情况。

您可能会注意到,本文对该函数的定义与C代码中实现的定义略有不同,但是我认为C实现是更具权威性的版本。

负采样

  训练神经网络的过程为取一组训练样本,略微调整所有神经元的权重,以使其更准确地预测训练样本。换句话说,每个训练样本都会调整神经网络中的所有权重。

  正如我们上面所讨论的,词汇集的大小意味着我们的skip-gram神经网络具有大量的权重,我们数十亿的训练样本中的每一个都会对这些权重进行小幅更新。

  负采样通过让每个训练样本仅修改一小部分权重而不是全部权重来解决此问题,运作方式如下。

  在使用单词对(“fox”,“quick”)训练网络时,网络的“标签”或“正确输出”是一个one-hot向量。 也就是说,与“quick”相对应的输出神经元输出1,所有其他数千个输出神经元输出0。

  在采用负采样的情况下,我们将随机选择少量“负”词(例如5个)来更新权重。(“负”词指的是输出向量中为0的分量所对应的词),当然“正”字(在当前示例中为“quick”)的权重也需要更新。

论文中提到,在小数据集上选择5-20个负词就能够有不错的表现,在大的数据集上可选2-5个负词。

  回顾一下,我们模型的输出层的权重矩阵为300x10,000。因此,我们将更新正词(“quick”)的权重,再加上要输出0的5个其他词的权重。总共6个输出神经元,1,800个权重值,这仅占输出层3M权重的0.06%!

  在隐藏层中,无论是否使用负采样,仅更新输入单词的权重。

选择负样本

  使用“unigram distribution”选择“负样本”,其中更频繁的词更有可能被选为负样本。

  例如,假设你把整个训练语料库看作一个单词列表,并且您从列表中随机选择了5个词作为负样本。在这种情况下,选择“ couch”一词的概率等于“couch”在语料库中出现的次数除以语料库中单词词库的总数,由以下等式表示:

作者在论文中指出,他们对该等式进行了多种尝试,其中效果最好的是使用词语计数的3/4次幂:

对一些样本值进行探索后你会发现,与原始的等式相比,该等式倾向于增加不经常出现的单词的概率,而减少频繁出现的单词的概率。

  用C代码实现此选择的方式很有趣。代码中有一个包含100M个元素的大型数组(被称为unigram表),他们用词汇表中每个单词的索引多次填充该表,那么单词索引在表中出现的次数就等于*表大小。然后,要需要选择一个负样本时,只需生成一个介于0到100M之间的随机整数,然后使用表中该索引处的单词即可。因为概率较高的单词在表格中出现的次数更多,所以更有可能选择这些单词。

单词对和“短语”

  word2vec的第二篇论文还包括另一项值得讨论的创新。作者指出,像“Boston Globe”(报纸)这样的词对与单独的“Boston”和“Globe”具有不同的含义。因此,可以将“Boston Globe”视为一个单独的词并用其特有的词向量表示。

  您可以在他们发布的模型中查看结果,该模型已经过Google新闻数据集中1000亿个单词的训练。在模型中增加了短语,使词汇量扩充到300万个单词!
如果你对他们的训练结果感兴趣,可以查看我的这篇文章,也可以在这里浏览他们的词汇。

  短语检测在其论文的“Learning Phrases”章节中进行了介绍。他们在word2phrase.c中共享了其实现。我在这里共享了此代码的带注释的版本。

  我认为词组检测方法不是他们的文章的主要贡献,但我还是会分享一下,因为它比较直观。

  他们工具的每次遍历仅查看2个单词的组合,但是您可以多次运行以获取更长的短语,因此,第一遍将选取短语“New_York”,然后再次运行将选取“ New_York_City”,作为“ New_York”和“ City”的组合。

  该工具会对两个单词的每个组合出现在训练文本中的次数进行计数,然后将这些计数用于一个公式中,以确定哪些单词组合可以转换为短语。该公式通过比较某个词语组合与组合中单个词的出现次数来辨别出短语。它还偏向由不常用词组成的词组,以避免将常见词(例如“and the”或“this is”)认作词组。

您可以在我的代码注释中查看有关它们的公式的更多详细信息。