Word2Vec
在上节你已经见到了如何学习一个神经语言模型来得到更好的词嵌入,在本节中你会见到 Word2Vec算法,这是一种简单而且计算时更加高效的方式来学习这种类型的嵌入,让我们来看看。
本节中的大多数的想法来源于Tomas Mikolov,Kai Chen,Greg Corrado 和 Jeff Dean。
(Mikolov T, Chen K, Corrado G, et al. Efficient Estimation of Word Representations in Vector Space[J]. Computer Science, 2013.)
假设在训练集中给定了一个这样的句子:“I want a glass of orange juice to go along with my cereal.”,在Skip-Gram模型中,我们要做的是抽取上下文和目标词配对,来构造一个监督学习问题。
上下文不一定总是目标单词之前离得最近的四个单词,或最近的n个单词。我们要的做的是随机选一个词作为上下文词,比如选orange这个词,然后我们要做的是随机在一定词距内选另一个词,比如在上下文词前后5个词内或者前后10个词内,我们就在这个范围内选择目标词。可能你正好选到了juice作为目标词,正好是下一个词(表示orange的下一个词),也有可能你选到了前面第二个词,所以另一种配对目标词可以是glass,还可能正好选到了单词my作为目标词。
于是我们将构造一个监督学习问题,它给定上下文词,要求你预测在这个词正负10个词距或者正负5个词距内随机选择的某个目标词。显然,这不是个非常简单的学习问题,因为在单词orange的正负10个词距之间,可能会有很多不同的单词。但是构造这个监督学习问题的目标并不是想要解决这个监督学习问题本身,而是想要使用这个学习问题来学到一个好的词嵌入模型。
接下来说说模型的细节,我们继续假设使用一个10,000词的词汇表,有时训练使用的词汇表会超过一百万词。但我们要解决的基本的监督学习问题是学习一种映射关系,从上下文c,比如单词orange,到某个目标词,记为t,可能是单词juice或者单词glass或者单词my。延续上一张幻灯片的例子,在我们的词汇表中,orange是第6257个单词,juice是10,000个单词中的第4834个,这就是你想要的映射到输出y的输入x。
为了表示输入,比如单词orange,你可以先从one-hot向量开始,我们将其写作O_c,这就是上下文词的one-hot向量(上图编号1所示)。然后和你在上节中看到的类似,你可以拿嵌入矩阵E乘以向量O_c,然后得到了输入的上下文词的嵌入向量,于是这里e_c=EO_c。
在这个神经网络中(上图编号2所示),我们将把向量e_c喂入一个softmax单元。我通常把softmax单元画成神经网络中的一个节点(上图编号3所示),这不是字母O,而是softmax单元,softmax单元要做的就是输出^y。然后我们再写出模型的细节,这是softmax模型(上图编号4所示),预测不同目标词的概率:
这里θ_t是一个与输出t有关的参数,即某个词t和标签相符的概率是多少。我省略了softmax中的偏差项,想要加上的话也可以加上。
最终softmax的损失函数就会像之前一样,我们用y表示目标词,我们这里用的y和^y都是用one-hot表示的,于是损失函数就会是:
这是常用的softmax损失函数,y 就是只有一个1其他都是0的one-hot向量,如果目标词是juice,那么第4834个元素就是1,其余是0(上图编号5所示)。类似的^y是一个从softmax单元输出的10,000维的向量,这个向量是所有可能目标词的概率。
总结一下,这大体上就是一个可以找到词嵌入的简化模型和神经网络(上图编号2所示),其实就是个softmax单元。矩阵E将会有很多参数,所以矩阵E有对应所有嵌入向量e_c的参数(上图编号6所示),softmax单元也有θ_t的参数(上图编号3所示)。
如果优化这个关于所有这些参数的损失函数,你就会得到一个较好的嵌入向量集,这个就叫做Skip-Gram模型。它把一个像orange这样的词作为输入,并预测这个输入词,从左数或从右数的某个词,预测上下文词的前面一些或者后面一些是什么词。
实际上使用这个算法会遇到一些问题,首要的问题就是计算速度。尤其是在softmax模型中,每次你想要计算这个概率,你需要对你词汇表中的所有10,000个词做求和计算,可能10,000个词的情况还不算太差。如果你用了一个大小为100,000或1,000,000的词汇表,那么这个分母的求和操作是相当慢的,实际上10,000已经是相当慢的了,所以扩大词汇表就更加困难了。
这里有一些解决方案,如分级(hierarchical)的softmax分类器和负采样(Negative Sampling)。
在文献中你会看到的方法是使用一个分级(hierarchical)的softmax分类器,意思就是说不是一下子就确定到底是属于10,000类中的哪一类。
想象如果你有一个分类器(上图编号1所示),它告诉你目标词是在词汇表的前5000个中还是在词汇表的后5000个词中,假如这个二分类器告诉你这个词在前5000个词中(上图编号2所示),然后第二个分类器会告诉你这个词在词汇表的前2500个词中,或者在词汇表的第二组2500个词中,诸如此类,直到最终你找到一个词准确所在的分类器(上图编号3所示),那么就是这棵树的一个叶子节点。
像这样有一个树形的分类器,意味着树上内部的每一个节点都可以是一个二分类器,比如逻辑回归分类器,所以你不需要再为单次分类,对词汇表中所有的10,000个词求和了。实际上用这样的分类树,计算成本与词汇表大小的对数成正比(上图编号4所示),而不是词汇表大小的线性函数,这个就叫做分级softmax分类器。
我要提一下,在实践中分级softmax分类器不会使用一棵完美平衡的分类树或者说一棵左边和右边分支的词数相同的对称树(上图编号1所示的分类树)。实际上,分级的softmax分类器会被构造成常用词在顶部,然而不常用的词像durian会在树的更深处(上图编号2所示的分类树),因为你想更常见的词会更频繁,所以你可能只需要少量检索就可以获得常用单词像the和of。然而你更少见到的词比如durian就更合适在树的较深处,因为你一般不需要到那样的深处,所以有不同的经验法则可以帮助构造分类树形成分级softmax分类器。
所以这是你能在文献中见到的一个加速softmax分类的方法,但是我不会再花太多时间在这上面了,你可以从我在第一张幻灯片中提到的Tomas Mikolov等人的论文中参阅更多的细节,所以我不会再花更多时间讲这个了。因为在下节中,我们会讲到另一个方法叫做负采样,我感觉这个会更简单一点,对于加速softmax和解决需要在分母中对整个词汇表求和的问题也很有作用,下节中你会看到更多的细节。
但是在进入下个视频前,我想要你理解一个东西,那就是怎么对上下文c进行采样,一旦你对上下文c进行采样,那么目标词t就会在上下文c的正负10个词距内进行采样。
但是你要如何选择上下文c?
一种选择是你可以就对语料库均匀且随机地采样,如果你那么做,你会发现有一些词,像the、of、a、and、to诸如此类是出现得相当频繁的,于是你那么做的话,你会发现你的上下文到目标词的映射会相当频繁地得到这些种类的词,但是其他词,像orange、apple或durian就不会那么频繁地出现了。你可能不会想要你的训练集都是这些出现得很频繁的词,因为这会导致你花大部分的力气来更新这些频繁出现的单词的e_c(上图编号1所示),但你想要的是花时间来更新像durian这些更少出现的词的嵌入,即e_durian。实际上词p(c)的分布并不是单纯的在训练集语料库上均匀且随机的采样得到的,而是采用了不同的分级来平衡更常见的词和不那么常见的词。
这就是Word2Vec的Skip-Gram模型,如果你读过我之前提到的论文原文,你会发现那篇论文实际上有两个不同版本的Word2Vec模型,Skip-Gram只是其中的一个,另一个叫做CBOW,即连续词袋模型(Continuous Bag-Of-Words Model),它获得中间词两边的的上下文,然后用周围的词去预测中间的词,这个模型也很有效,也有一些优点和缺点。
(上图左边为CBOW,下面为Skip-Gram)
CBOW对小型数据库比较合适,而Skip-Gram在大型语料中表现更好。
总结下:
CBOW是从原始语句推测目标字词;而Skip-Gram正好相反,是从目标字词推测出原始语句。
而刚才讲的Skip-Gram模型,关键问题在于softmax这个步骤的计算成本非常昂贵,因为它需要在分母里对词汇表中所有词求和。通常情况下,Skip-Gram模型用到更多点。
在下个笔记中,我会展示给你一个算法,它修改了训练目标使其可以运行得更有效,因此它可以让你应用在一个更大的训练集上面,也可以学到更好的词嵌入。