I. 复习word2vec的核心思路
1. Skip-gram 模型示意图:
2.word vectors的随机梯度
假设语料库中有这样一行句子:
I love deep learning and NLP
中心词为deep,那么在计算梯度的时候则可以得到如下的梯度向量。
可以很明显地看到该向量非常稀疏。常见的解决办法有两种:一是使用稀疏矩阵更新运算来更新矩阵(U,V)的特定的列向量。二是使用哈希来更新,即key为word string,value是对应的列向量。
II. 近似
1. 负采样
下图公式中的分子计算起来比较简单,而分母则比较困难了,因为需要想加的项太多,而且每一项的内积运算也是一个工作量。所以为了提高计算效率提出了 负采样(negative sampling)。
主要思路就是除了对中心词窗口大小附近的上下文词取样以外(即true pairs),还会随机抽取一些噪声和中心词配对(即noise pairs)进行计算,而不是遍历整个词库。
2. 目标函数
使用了负采样后的目标函数为
其中(sigma(x)=frac{1}{1+e^{-x}})是sigmoid函数。
公式(2)中第一项表示我们希望能同时出现的两个词的概率最大化。第二项的sigmoid函数中取了负号,所以其作用是最小化负采样得到的词与中心词共同出现的概率。
另外公式(2)中的第二项的(jsim p(w))表示每个样本j以p(w)的概率进行采样。而这个p(w)可以根据需要自定义,但是一般是采用unigram分布,即根据某个词出现的频率进行抽样。
unigram 一元分词,把句子分成一个一个的汉字
bigram 二元分词,把句子从头到尾每两个字组成一个词语
trigram 三元分词,把句子从头到尾每三个字组成一个词语.
你可能会想万一随机抽样得到的词与第一项中的上下文词汇重复了怎么办?首先这个概率很低,因为词库非常的大;另外即使重复也没关系,因为重复的概率很小,所以影响不是很大。k一般取10左右。
3. word2vec总结
- 遍历语料库中的每个词
- 预测每个词的上下文
- 在每个窗口中计算梯度并做随机梯度下降。
III. 改进word2vec方法
1. 基于窗口的共生矩阵(co-occurrence matrix)
由上面总结的步骤可以观察到这种方式多多少少还是缺乏效率的。假如语料库有如下三个句子组成:
- I like deep learning.
- I like NLP.
- I enjoy flying.
按照word2vec思路,假设窗口大小为2(即左右长度),那么如果要计算I和like同时出现的概率,就得移动窗口遍历,然后每个窗口或者几个窗口都要进行一次参数更新。要知道,很多词串出现的频次是很高的。能不能遍历一遍语料,迅速得到结果呢?
其实在word2vec之前就有这么个方法了,这些方法是基于统计共现矩阵的方法。如果在窗口级别上统计词性和语义共现,可以得到相似的词。如果在文档级别上统计,则会得到相似的文档(潜在语义分析LSA)。使用该方法对上面三个句子进行统计的示例如下:
为方便说明,假设窗口大小为1,那么遍历一遍语料库后可得到如下表格(或共生矩阵):
这种方法简单易懂,但是实际上语料库非常庞大,这样得到的矩阵同样会非常大,且具有高稀疏性。另外每次需要添加新的word时,有需要重新计算一遍。
2. 共生矩阵太大且稀疏的解决办法:SVD
共生矩阵太大且稀疏,很自然的一个想法是将该矩阵降维,用更加稠密的矩阵进行信息存储。那么如何降维呢?我们可以使用奇异值分解(SVD),示意图如下。
奇异值分解可阅读之前做的笔记:
import numpy as np
import matplotlib.pyplot as plt
la = np.linalg
words = ['I', 'like', 'enjoy', 'deep', 'learnig', 'NLP', 'flying', '.']
X = np.array([
[0,2,1,0,0,0,0,0],
[2,0,0,1,0,1,0,0],
[0,1,0,0,1,0,0,0],
[0,1,0,0,0,0,0,1],
[0,0,1,0,0,0,0,1]])
U, s, Vh = la.svd(X, full_matrices=False)
for i in range(len(words)):
plt.text(U[i,0], U[i,1], words[i])
3. SVD缺点
上面使用SVD存在如下缺点:
- 计算复杂度高:对n×m的矩阵是复杂度为(O(mn^2))
- 不方便处理新词或新文档
- 与其他DL模型训练套路不同
其他方法分类
下图给出了两种类型的方法总结,可以看到有两类,分别是count based(基于计数的方法) 和 direct prediction(直接预测的方法)
这些基于计数的方法在中小规模语料训练很快,有效地利用了统计信息。但用途受限于捕捉词语相似度,也无法拓展到大规模语料。
而NNLM, HLBL, RNN, Skip-gram/CBOW这类进行预测的模型必须遍历所有的窗口训练,也无法有效利用单词的全局统计信息。但它们显著地提高了上级NLP任务,其捕捉的不仅限于词语相似度。
IV. GloVe
GloVe是将**count based* 和 direct prediction的优势结合起来提出的一种方法,其目标函数如下:
- (P_{ij})表示词i和词j共同出现的频次
- f是如下图示的一个函数
GloVe的优点是训练筷,可扩展到大规模语料,也适用于小规模的语料。
下图展示了GloVe的结果示例,可以看到与frog相近的词中含有很少见的词汇,也就是说它能在全局的范围内对词进行分类。
V. 评估word vectors
前面介绍了很多超参数,例如window size,vector size等等。那么我们如何评估这些参数对模型带来的影响呢?
评测的方法分两类:Intrinsic(内部) vs. Extrinsic(外部)
1. Intrinsic word vector evaluation
通常指对特定的子任务或者中间任务进行评估,例如我们会观察向量之间的差异性或相似性及向量内积与人类对于相似性的判断有多大关系。
该类方法的好处如下:
- 计算速度快
- 能够帮助我们快速理解系统是如何工作的,我们能够知道哪一类超参数能够对相似性度量产生影响。
当然有好处也就会有缺点:通常我们不知道模型在实际应用中表现如何。也就是说也许这种评估方法是好的,但是在实际应用中表现却很差。比如有人花了几年时间提高了在某个数据集上的分数,当将其词向量用于真实任务时并没有多少提高效果,想想真悲哀。
常见的评估方法是词向量同义词。即如果已知单词a和单词b是相似词,那么单词c的相似词是什么?
a:b → c:?
计算公式如下:
举个栗子:假如已知man对woman,那king对应的单词是哪一个呢?
上面公式中的(x_b)对应woman,(x_a)对应man,(x_c)对应king,需要做的就是遍历语料库找到使得cosine距离最大的单词(粗略地理解就是找到一个点i使得其与king组成的连线能与man和woman组成的连线尽可能平行,这样就满足相似词的关系。)
除了找同义词还可以有其他作用:
- Analogy(相似)
- 公司名与CEO
- 原型,比较级,最高级(superlative)
方法比较
下图展示了在GloVe即之前提出的方法的比较,其中Dim表示Dimension,Size表示数据大小,Sem表示semantic(语义),Syn表示Syntactic(句法),Tot表示total,即将前面两个指标取均值。
可以看到GloVe表现最为优秀,并且由最下面一部分表格可以看到并不是维度越高越好,因为维度为300的时候要比1000表现更好;另外数据还是礼多人不怪,越多越好。
Analogy evaluation and hyperparameters
下图展示了三个不同超参数对最终结果的影响。
第一个是保持窗口对称,且窗口大小固定的情况下,向量维度对最终模型表现的影响。可以看到最初随着维度增加,模型表现也愈佳,但是当维度增加到300以上后,模型表现没有很明显的变化。虽然semantic评估有略微增长,但是维度增加,对资源的消耗也会增加,所以考虑到成本,一般会选择300作为最终的维度。
第二个是指保持窗口对称,维度固定的情况下,窗口大小对模型的影响。
第三个是指窗口不对称,也就是说只考虑前面或者后面的单词,维度固定的情况下,窗口大小对模型的影响。
下图表示对GloVe来讲,迭代次数越多越小,效果很稳定:
维基百科语料上得到的效果比新闻语料要好:
2. Extrinsic
通过对外部实际应用的效果提升来体现。缺点很明显就是耗时较长,另外在实际应用中可能会同时优化多个子系统,也许最终整个系统表现得到了提升,但是这样并不能知道是哪一个子系统对系统起到了提升作用。这类评测中,往往会用pre-train的向量在外部任务的语料上retrain。
由下图也可看出GloVe与许多方法相比依旧表现出色。
PS:这一视频感觉听得模模糊糊的,前后没什么关联。。。很多细节没有提到,看来还是需要阅读其他的课外资料了。