自然语言处理:word2vec 之Skip-Gram模型(第二篇)
本文翻译自《Word2Vec Tutorial Part 2 - Negative Sampling》
在word2vec 第二篇(第一篇),将会涉及对基础的skip-gram模型进行一些额外调整,使其的训练在实际中可行
在读word2vec第一篇时,也许已经意识到:它是一个巨型网络;在文中的案例,每个词向量有300个元素,词典有偶10000个单词,神经网络有两个权重矩阵(隐层和输出层),各自都有300 x 10,000 = 3 百万个权重。
在如此大的网络计算梯度下降将会很慢,更糟糕的是,需要大量训练样本来使其避免过拟合。百万级权重乘上十亿级别的样本,将会是可怕的模型。
word2vec的作者在他们第二篇论文paper 中提出了两种创新来解决此问题:
- 对样本中高频词做二次采样以减少样本数.
- 用“负采样”的技巧来修改模型优化的目标函数,使得每个样本只需更新部分权重
值得注意的是,对高频词二次采样和负采样不仅仅减少了训练的计算压力,也改善了词向量的结果
对高频词二次采样
在 第一篇 中讲述了如何从源文本中提取训练样本,这里重温下,以下例子展示了从句子 “The quick brown fox jumps over the lazy dog.” 中提取的部分样本(词对)。这里使用的窗口大小为1,输入的单词蓝色高亮显示。
对于高频词如“the”有两个问题:
- 当搜索词对时, (“fox”, “the”) 并没有关于fox含义的信息,因为 “the” 在很多次的上下文中出现a
- 会产生很多如 (“the”, …) 的样本,对于产生“the” 词向量所需而言太冗余了.
Word2Vec 使用二次采样来解决此问题. 对文本中的每个词,施加一定的删除概率,词概率与词的频数有关
若窗口大小为10,并删除了文本中部分the:
- 在剩余单词的训练中, “the” 不会再每个词上下文中出现了
- 当单词the作为输入词,训练样本将减少10个.
采样率
word2vec 的C 代码实现了对保留一个单词的概率的计算。
wi表示单词,z(wi)表示该词在所有词中的比例。例如“peanut”在十亿个单词中出现了1000 次,那么z(‘peanut’) = 1E-6.
还有一个参数‘sample’控制着二次采样,默认值为0.001,越小表示单词被保留的几率越小
P(wi) 是单词保留的几率:
此公式的曲线为:
没有哪个词会在文本中占超大比重,所以这里看下x轴的较小值。
图中有些有意思的地方:
- 当 (wi)<=0.0026.,P(wi)=1.0 (100% 概率被保留)
- 意味着只有出现比例超过 0.26%的会被二次采样.
- 当 z(wi)=0.00746 ,P(wi)=0.5(50% 的机会被保留) .
- 当 z(wi)=1.0,P(wi)=0.033 (3.3% 的机会被保留) .
- 如果全文都是单词wi,这太荒谬了.
文中此函数的定义和C代码实现有些不同,但是C的实现是更权威的版本
负采样
训练神经网络意味着使用一个样本然后对所有神经元的权重进行调整,使得该样本的估计更加准确。换句话说,每个训练样本都会对所有权重进行调整
正如上述所说,词典的大小意味着skipgram网络有大量的权重参数,每个都会被10亿中的一个样本所修改。
负采样解决了此问题,使得每个训练样本只更新少部分权重参数,而不是所有。
当训练网络时,遇到词对 (“fox”, “quick”),网络输出的“label”或称之为“correct output”是独热向量,意识是,quick对应的神经元输出为1,其他神经元输出为0
负采样时,我们随机选取少量负样本词(例如5个)来更新他们权重,在这里,负样本对应网络的输出是0.同样对于正样本词如quick,也会更新他的权重。
文章说到选择5-20个词对于小数据集而言效果不错。对于大数据集,可以尝试2-5个词
输出层的权重矩阵300 x 10,000,但这里只需更新正样本词quick对应的权重,和5个负样本词对应的权重使其输出为0,共6个神经元,1800个权重参数。只有原来3M个参数的0.06%
在隐层,只有输入单词的权重需要更新(是否负采样都一样的)
负样本的选择
负样本(5个要把对应输出训练成0的词)通过unigram分布来选取(高频词更容易选为负样本)
例如将整个训练的语料库的单词组成列表,从中随机选取5个词,选到单词couch的概率等于couch出现的次数厨艺语料库的总词数。见以下公式:
文章的作者说他们尝试过对公式不同的变换,最好的形式是对词频加上3/4的幂
如果对样本做些实验,将会发现,这种形式有增加低频词的选中概率并减少高频词选中概率的倾向
它的C代码实现也有意思,准备了100M个元素的数组(称之为unigram表)。首先对表多次插入每个词的索引,插入的次数等于 P(wi)* 表大小(100M),然后选择负样本,只需随机选取0到100M的一个数,并作为数组下标。因为高频词出现多次,所以更容易被选中。
词对与 “短语”
第二篇word2vec的文章也涉及了值得探讨的创新。作者指出了一个词对例如:“Boston Globe”(一份报纸)与两个独立单词的含义有很大不同。所以将“Boston Globe”作为一个单词出现更有意义。
可以在文中看到该模型结果,从google新闻数据集的1000亿个单词训练的,短语的加入使得词典词数增加到3百万。
若对他们的词典有兴趣,我提取了部分放在here,或者在here浏览
短语检测在paper的 “Learning Phrases”部分,实现放在了 word2phrase.c,我添加了一份注释版here
我不觉得短语检测是这篇文章的关键贡献,但是很直观,所以这里分享下:
这个工具(word2phrase.c)每次处理都只涉及2个词的组合,但是可以运行多次以获得更长的短语。例如第一次跑得到短语 “New_York”,再跑就会得到“New_York_City”
工具会统计每两个词组合出现的次数,然后使用一个公式计算将那种组合作为一个短语,例如组合出现的次数相对单词独立出现次数较多的。工具也更倾向于将低频词组合为短语,从而避免生成类似“and the”或 “this is” 的短语
公式详见here.
我对短语检测的一个想法是,所有维基百科的标题加入到词典中。
其他资源
若你对C熟悉,我发布了原版word2vec C代码的带注释版本here
另一方面,word2vec 模型也可用于非文本数据用于推荐系统和广告定向(用户特征向量、物品特征向量,万物皆可embedding)
可以从用户的一系列行为中学习向量,更多详见:here
电子书 & 示例代码
word2vec是一个优美且强大的算法,迄今为止为了解它的原理做了大量工作
也许还有一些疑问:
- 对于模型权重是如何更新的更深的解释
- 想知道Skip-gram 和CBOW 技术和应用的差别。
- word2vec 的主要作者 Mikolov,在word2vec基础上做了更深入的工作,在 Facebook 的fastText库中
- 想看word2vec核心组件的 Python 实现
以上内容都在 The Inner Workings of word2vec - Pro Edition.看看会有不少收获