NLP with DL Stanford – 2.Word2Vec Tutorial

来源:互联网 发布:淘宝苹果手机联保 编辑:程序博客网 时间:2024/05/07 00:09

NLP with DL Stanford – 2.Word2Vec Tutorial - The Skip-Gram Model

  • NLP with DL Stanford 2Word2Vec Tutorial - The Skip-Gram Model
    • 模型概述 Model Overview
    • 模型细节 Model Details
    • 隐藏层 The Hidden Layer
    • 输出层 The Output Layer
    • 直觉 Intuition
    • 模型改进 Model Improvement
      • Word Pairs and Phrases
      • Subsampling Frequent Words
      • Sampling rate
      • Negative Sampling
        • Selecting Negative Samples
    • 参考

该文主要翻译了参考的前两个网页,有增有减,同时依照论文(Distributed Representations of Words and Phrases and their Composition)做了一定的修改。

模型概述 Model Overview

首先忽略模型的细节,我们将从整体了解在此过程中我们究竟做了什么。Word2Vec使用了一个在机器学习中也许会遇到的技巧。训练一个带有单层隐藏层的简单神经网络,但实际上我们不会使用训练出的神经网络。相反,训练的目标实际上只是为了学习隐藏层的权重,这些权重实际上就是我们试图学习的“词向量”。
我们将训练神经网络来做以下事情。 给定在句子中的特定单词(即输入单词),查看附近的单词并随机选择一个(即附近词)。 神经网络将告诉我们在词汇表中的每个词成为所谓“附近词”的概率。也就是说,输出概率与每个单词出现在输入单词附近的可能性相关。 例如,如果你给训练的网络输入单词 “Soviet” ,输出概率对于像 “Union” 和 “Russia” 与此相关联的词比像”watermelon” 和 “kangaroo” 等不相关的词要高得多。

值得注意的是,“附近”的概念实际上有一个“窗口大小”(Window size)的参数。典型的窗口大小可以是5,意味着输入单词的后面5个字和前面5个字(总共10个)。

下面是一个例子,蓝色为输出单词,用黑框框起来的是附近词,窗口大小为2。

这里写图片描述

很明显,神经网络将从每个配对的统计次数中学习,学习到的次数越高,输出概率就越高

模型细节 Model Details

假设我们有10,000个单词。

首先,我们不能把一个词直接以字符串的形式输入,而是表示成one-hot vector(参见上节)作为输入。而网络的输出是单个向量(也具有10,000个分量),包含词汇表中所有词成为输入单词(随机选择的)附近单词的概率。

以下为我们神经网络的架构:

这里写图片描述
注意到隐藏层神经元上并没有激活函数,但是输出神经元使用了Softmax,这部分稍后再谈。

当训练该网络时,输入是表示输入单词的one-hot vector(”Soviet” )训练输出也是表示输出单词的one-hot vector。 但是当你对一个输入字评估训练的网络时,输出向量实际上是一个概率分布(即一串浮点值,而不是一个one-hot vector)。

隐藏层 The Hidden Layer

之前提到,训练的目标实际上只是为了学习隐藏层的权重。在上面的例子中,我们正在学习具有300个特征的单词向量。 因此,隐藏层将由具有10,000行(每一行代表词汇表中的一个单词)和300列(每一列代表一个隐藏的神经元)的权重矩阵表示。

不难理解,权重矩阵的每一行,实际上就是我们需要的字向量!

这里写图片描述
现在你可能会问自己:“一个 one-hot vector 几乎都是零,这有什么效果呢?” 如果你将一个1×10,000的one-hot vector乘以一个10,000×300的矩阵,它将只选择矩阵行对应于“1”位置的特定行。 这里有一个小例子:

这里写图片描述

这意味着这个模型的隐藏层实际上类似于一张查找表,隐藏层的输出是输入单词的“词向量”。

输出层 The Output Layer

当”ants”1×300的词向量被送到输出层的时候,实际遇到的是一个Softmax回归分类器。 它的要点是每个输出神经元将产生0和1之间的输出(代表概率),并且所有这些输出值的总和相加等于1。

具体来说,每个输出神经元具有与来自隐藏层的词矢量相乘的权重向量,然后将函数exp(x)应用于结果。 最后,为了得到输出总和为1,我们将这个结果除以来自所有10,000个输出节点的数值总和。

一个例子来计算单词“car”的输出神经元的结果。

这里写图片描述

值得注意的是,神经网络本身并不知道输出单词相对于输入单词的偏移量。它不学习输入单词之前与之后不同的概率集合。比如,”New” 每一次都出现在 “York” 之前,至少根据训练数据,”New” 出现在 “York” 附近是100%的概率。 但是,如果我们取”York”附近的10个单词,随机选择其中一个,它是 “New” 的概率不会是100%; 你可能选择了附近的其他单词。

直觉 Intuition

我们已经初步了解了模型,但是你没有考虑过里面一些令人兴奋的意义呢?

如果两个不同的词具有非常相似的上下文(Contexts,即什么词可能出现在它们周围),则我们的模型需要对这两个词输出非常相似的结果。 而预测神经网络为这两个词的输出是否相似的一种方式是判断词向量是否相似。 因此,如果两个词具有相似的上下文,那么我们的网络应该有能力学到这两个词的相似词向量!

两个单词具有相似的上下文意味着什么? 你可以想象 “intelligent” 和 “smart” 这一对同义词将有非常相似的上下文。 或者相关的词,如 “engine” 和 “transmission”,也可能具有类似的上下文。

这也可以为你处理词干。例如网络可能会为 “ant” 和 “ants” 学习到类似的单词向量,因为它们应该有类似的上下文。

模型改进 Model Improvement

你可能已经注意到Skip-Gram神经网络包含大量的权重。对于300个特征和一个10000词汇量的例子,在隐藏层和输出层将各自产生3M的权重数! 在一个如此巨大的神经网络上使用梯度下降将是非常缓慢的。 更糟糕的是,你需要大量的训练数据来调整许多权重,以避免过度拟合。 数百万的权重乘以数十亿的训练样本意味着训练这个模型将是一个灾难。

Word2Vec的作者们在他们第二篇论文里提出了三个创新点:
1. 在他们的模型中将常见词组或短语都视为“单词”。
2. 对频繁词进行二次采样以减少训练示例的数量。
3. 使用被称为“负取样”(Negative Sampling)的技巧修正优化目标,使得每个训练样本仅更新模型的一小部分权重。

对频繁项的二次抽样和负取样不仅减轻了训练过程的负担,也提升了最终词向量的质量。

Word Pairs and “Phrases”

这个技巧不难理解,但是主要的问题是我们应该怎么找到这些词组/短语呢?
论文中并没有给出细节,虽然存在很多的方法能够实现目的,但是各个方法之间的比较超出了该论文的范畴。论文使用了简单的data-driven方法,通过对一对词的词频计算得到一个分数来做判断,公式也不难理解:

score(wi,wj)=count(wiwj)δcount(wi)×count(wj)

其中δ是一个舍弃系数,防止过多的由频次低的单词组合成的短语(分母小产生的分数可能会非常大)。

当然,也可以对维基百科的词条进行提取。

Subsampling Frequent Words

以这张图为例:

这里写图片描述

对于像 “the” 这样常见词存在两个“问题”:
1. 对于像(“fox”, “the”)的单词对,并没有告诉我们很多关于fox的信息。”the” 可以出现在几乎所有有类似上下文的词汇前。
2. (“the”,…) 此类的样本太多会导致无法训练出令人满意的 “the” 的词向量。

二次采样机制用来解决以上问题。 对于在训练文本中遇到的每个单词,我们有机会从文本中有效地删除它。 当然,我们删去单词的概率与单词的频率有关。

假如窗口大小为10,则从文本中删除 “the” 一个特定的实例:
1. 当我们训练剩下的单词时,”the”不会出现在他们任何一个的上下文窗口中。
2. 我们将减少10个训练样本,其中”the”是输入字。

Sampling rate

论文中定义了以下的方程计算抛弃一个特定词的概率。wi是一个单词,t是一个阈值,一般设为105f(wi)是该词出现在语料库里的次数:

P(wi)=1tf(wi)

Negative Sampling

负采样的要点在于每次训练样本仅能修正一小部分的权重,而不是所有权重。

前面提到过,比如当我们用单词对( ” fox ” , ” quick “)训练神经网络的时候,输出是one-hot vector,即对于输出神经元对应于”quick”会输出1,其余输出神经元为0。我们把输出神经元为0对应的单词成为“负”单词( Negative Word ),输出为1的单词称为“正”单词( Positive Word )。

在负采样的时候,我们仅选取一部分”负“单词更新权重(假设为5个)和我们的”正“单词(例子中的” quick “)。因此我们只需要更新6个单词对应的权重,即1800个权重值,对于输出层3M个权重值来说只占了0.06%!

当然,在隐藏层,只有输入单词的权重才会被更新(不管有没有负采样)。

论文里提出对于小的数据集选取5-20个单词更新取得的效果比较好,而对于大型数据集2-5个单词即可。

Selecting Negative Samples

需要指出的是,选取一个词作为负样本的概率与它的频率正相关,频率越高越有可能被选作负样本。

在Word2Vec C实现中,有如下计算概率的等式。每个词被赋予一个权重,等价于词频的3/4次幂。而概率等于该词的权重除以所有权重之和。

P(wi)=f(wi)3/4nj=0(f(wj)3/4)

C代码具体实现非常有趣。他们有一个100M的数组(被称为 unigram table),他们会把每一个词的序号多次填入数组中,次数由P(wi)×table_size确定。然后每次生成1到100M的随机数,挑出随机数对应的负样本。当单词的概率越大,在表格中出现的次数就越多,则更有可能被挑选中。

参考

  1. http://mccormickml.com/2016/04/19/word2vec-tutorial-the-skip-gram-model/
  2. http://mccormickml.com/2017/01/11/word2vec-tutorial-part-2-negative-sampling/
  3. Google’s trained Word2Vec model in Python
  4. 论文 Distributed Representations of Words and Phrases and their Composition
  5. 其他资源
0 0