假设语料库中有这样一行句子:html
I love deep learning and NLPpython
中心词为deep,那么在计算梯度的时候则能够获得以下的梯度向量。函数
能够很明显地看到该向量很是稀疏。常见的解决办法有两种:一是使用稀疏矩阵更新运算来更新矩阵\(U,V\)的特定的列向量。二是使用哈希来更新,即key为word string,value是对应的列向量。优化
下图公式中的分子计算起来比较简单,而分母则比较困难了,由于须要想加的项太多,并且每一项的内积运算也是一个工做量。因此为了提升计算效率提出了 负采样(negative sampling)。lua
主要思路就是除了对中心词窗口大小附近的上下文词取样之外(即true pairs),还会随机抽取一些噪声和中心词配对(即noise pairs)进行计算,而不是遍历整个词库。spa
使用了负采样后的目标函数为
\[ \begin{align} J(\theta)&=\frac{1}{T}\sum_{t=1}^TJ_t(\theta) \\ J_t(\theta)&=log\,\sigma(u_o^Tv_c)+\sum_{j=1}^kE_{j\sim p(w)}[log \, \sigma(-u_j^Tv_c)] \end{align} \]3d
其中\(\sigma(x)=\frac{1}{1+e^{-x}}\)是sigmoid函数。code
公式(2)中第一项表示咱们但愿能同时出现的两个词的几率最大化。第二项的sigmoid函数中取了负号,因此其做用是最小化负采样获得的词与中心词共同出现的几率。视频
另外公式(2)中的第二项的\(j\sim p(w)\)表示每一个样本j以p(w)的几率进行采样。而这个p(w)能够根据须要自定义,可是通常是采用unigram分布,即根据某个词出现的频率进行抽样。htm
unigram 一元分词,把句子分红一个一个的汉字
bigram 二元分词,把句子从头至尾每两个字组成一个词语
trigram 三元分词,把句子从头至尾每三个字组成一个词语.
你可能会想万一随机抽样获得的词与第一项中的上下文词汇重复了怎么办?首先这个几率很低,由于词库很是的大;另外即便重复也不要紧,由于重复的几率很小,因此影响不是很大。k通常取10左右。
由上面总结的步骤能够观察到这种方式多多少少仍是缺少效率的。假如语料库有以下三个句子组成:
按照word2vec思路,假设窗口大小为2(即左右长度),那么若是要计算I和like同时出现的几率,就得移动窗口遍历,而后每一个窗口或者几个窗口都要进行一次参数更新。要知道,不少词串出现的频次是很高的。能不能遍历一遍语料,迅速获得结果呢?
其实在word2vec以前就有这么个方法了,这些方法是基于统计共现矩阵的方法。若是在窗口级别上统计词性和语义共现,能够获得类似的词。若是在文档级别上统计,则会获得类似的文档(潜在语义分析LSA)。使用该方法对上面三个句子进行统计的示例以下:
为方便说明,假设窗口大小为1,那么遍历一遍语料库后可获得以下表格(或共生矩阵):
这种方法简单易懂,可是实际上语料库很是庞大,这样获得的矩阵一样会很是大,且具备高稀疏性。另外每次须要添加新的word时,有须要从新计算一遍。
共生矩阵太大且稀疏,很天然的一个想法是将该矩阵降维,用更加稠密的矩阵进行信息存储。那么如何降维呢?咱们可使用奇异值分解(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])
上面使用SVD存在以下缺点:
下图给出了两种类型的方法总结,能够看到有两类,分别是count based(基于计数的方法) 和 direct prediction(直接预测的方法)
这些基于计数的方法在中小规模语料训练很快,有效地利用了统计信息。但用途受限于捕捉词语类似度,也没法拓展到大规模语料。
而NNLM, HLBL, RNN, Skip-gram/CBOW这类进行预测的模型必须遍历全部的窗口训练,也没法有效利用单词的全局统计信息。但它们显著地提升了上级NLP任务,其捕捉的不只限于词语类似度。
GloVe是将count based* 和 direct prediction**的优点结合起来提出的一种方法,其目标函数以下:
\[J(θ)=\frac{1}{2} ∑_{i,j=1}^W f(P_{ij})(u^T_iv_j −log \,P_{ij})^2\]
GloVe的优势是训练筷,可扩展到大规模语料,也适用于小规模的语料。
下图展现了GloVe的结果示例,能够看到与frog相近的词中含有不多见的词汇,也就是说它能在全局的范围内对词进行分类。
前面介绍了不少超参数,例如window size,vector size等等。那么咱们如何评估这些参数对模型带来的影响呢?
评测的方法分两类:Intrinsic(内部) vs. Extrinsic(外部)
一般指对特定的子任务或者中间任务进行评估,例如咱们会观察向量之间的差别性或类似性及向量内积与人类对于类似性的判断有多大关系。
该类方法的好处以下:
- 计算速度快
- 可以帮助咱们快速理解系统是如何工做的,咱们可以知道哪一类超参数可以对类似性度量产生影响。
固然有好处也就会有缺点:一般咱们不知道模型在实际应用中表现如何。也就是说也许这种评估方法是好的,可是在实际应用中表现却不好。好比有人花了几年时间提升了在某个数据集上的分数,当将其词向量用于真实任务时并无多少提升效果,想一想真悲哀。
常见的评估方法是词向量同义词。即若是已知单词a和单词b是类似词,那么单词c的类似词是什么?
a:b → c:?
计算公式以下:
\[d=\underset{i}{\operatorname{argmax}} \frac{(x_b-x_a+x_c)^Tx_i}{\|x_b-x_a+x_c\|}\]
举个栗子:假如已知man对woman,那king对应的单词是哪个呢?
上面公式中的\(x_b\)对应woman,\(x_a\)对应man,\(x_c\)对应king,须要作的就是遍历语料库找到使得cosine距离最大的单词(粗略地理解就是找到一个点i使得其与king组成的连线能与man和woman组成的连线尽量平行,这样就知足类似词的关系。)
除了找同义词还能够有其余做用:
下图展现了在GloVe即以前提出的方法的比较,其中Dim表示Dimension,Size表示数据大小,Sem表示semantic(语义),Syn表示Syntactic(句法),Tot表示total,即将前面两个指标取均值。
能够看到GloVe表现最为优秀,而且由最下面一部分表格能够看到并非维度越高越好,由于维度为300的时候要比1000表现更好;另外数据仍是礼多人不怪,越多越好。
下图展现了三个不一样超参数对最终结果的影响。
第一个是保持窗口对称,且窗口大小固定的状况下,向量维度对最终模型表现的影响。能够看到最初随着维度增长,模型表现也愈佳,可是当维度增长到300以上后,模型表现没有很明显的变化。虽然semantic评估有略微增加,可是维度增长,对资源的消耗也会增长,因此考虑到成本,通常会选择300做为最终的维度。
第二个是指保持窗口对称,维度固定的状况下,窗口大小对模型的影响。
第三个是指窗口不对称,也就是说只考虑前面或者后面的单词,维度固定的状况下,窗口大小对模型的影响。
下图表示对GloVe来说,迭代次数越多越小,效果很稳定:
维基百科语料上获得的效果比新闻语料要好:
经过对外部实际应用的效果提高来体现。缺点很明显就是耗时较长,另外在实际应用中可能会同时优化多个子系统,也许最终整个系统表现获得了提高,可是这样并不能知道是哪个子系统对系统起到了提高做用。这类评测中,每每会用pre-train的向量在外部任务的语料上retrain。
由下图也可看出GloVe与许多方法相比依旧表现出色。
PS:这一视频感受听得模模糊糊的,先后没什么关联。。。不少细节没有提到,看来仍是须要阅读其余的课外资料了。