大家好,又见面了,我是你们的朋友全栈君。
词向量模型
one-hot Vector
one-hot vector
最简单的编码方式:假设我们的词库总共有n个词,那我们开一个1*n的高维向量,而每个词都会在某个索引index下取到1,其余位置全部都取值为0。
问题
这种词向量编码方式简单粗暴,我们将每一个词作为一个完全独立的个体来表达。遗憾的是,这种方式下,我们的词向量没办法给我们任何形式的词组相似性权衡。因为你开了一个极高维度的空间,然后每个词语都会占据一个维度,因此没有办法在空间中关联起来。
解决方案
可以把词向量的维度降低一些,在这样一个子空间中,可能原本没有关联的词就关联起来了。
基于 SVD 的方法
SVD
这是一种构造词嵌入(即词向量)的方法,我们首先会遍历所有的文本数据集,然后统计词出现的次数,接着用一个矩阵 X 来表示所有的次数情况,紧接着对X进行奇异值分解得到一个 USVT 的分解。然后用 U 的行(rows)作为所有词表中词的词向量。对于矩阵 X ,有2种选择:全文或者窗口长度。
-
词-文档矩阵
建立一个词组文档矩阵 X,具体是这么做的:遍历海量的文件,每次词组 i 出现在文件 j 中时,将 Xij 的值加1。不过大家可想而知,这会是个很大的矩阵R|V|×M,而且矩阵大小还和文档个数M有关系。所以咱们最好想办法处理和优化一下。word-document的共现矩阵最终会得到泛化的主题(例如体育类词汇会有相似的标记),这就是浅层语义分析(LSA, Latent Semantic Analysis) -
基于窗口的共现矩阵 X
把矩阵X记录的词频变成一个相关性矩阵,对 X 做奇异值分解,观察奇异值(矩阵的对角元素),并根据我们期待保留的百分比来进行截断(只保留前k个维度),把子矩阵 U1:|V|,1:k 视作我们的词嵌入矩阵。也就是说,对于词表中的每一个词,我们都用一个 k 维的向量来表达了。窗口长度容易捕获语法(POS)和语义信息
对共现矩阵X进行奇异值分解
特征值分解与奇异值分解
特征值分解只适用于方阵。当矩阵是高维的情况下,那么这个矩阵就是高维空间下的一个线性变换,一个矩阵乘以一个向量后得到的向量,其实就相当于将这个向量进行了线性变换。我们通过特征值分解得到的前N个特征向量,对应了这个矩阵最主要的N个变化方向。利用这前N个变化方向,可以近似这个矩阵(变换)。也就是 – 提取这个矩阵最重要的特征。总结一下,特征值分解可以得到特征值与特征向量,特征值表示的是这个特征到底有多重要,而特征向量表示这个特征是什么,可以将每一个特征向量理解为一个线性的子空间,我们可以利用这些线性的子空间干很多的事情。
奇异值分解是一个能适用于任意的矩阵的一种分解的方法,可以通过求特征值得到。
问题
- 矩阵的维度会经常变化(新的词语经常会增加,语料库的大小也会随时变化)。
- 矩阵是非常稀疏的,因为大多数词并不同时出现。
- 矩阵的维度通常非常高(≈106×106),需要大量的存储
- 训练需要O(n2)的复杂度
- 对于新词或者新的文档很难及时更新
- 需要专门对矩阵X进行特殊处理,以应对词组频率的极度不平衡的状况
解决方案:直接学习低维度的词向量
idea: 将最重要的信息存储在固定的,低维度的向量里:密集向量(dense vector),维数通常是25-1000
然而,如何降维?
基于迭代的方法
创建一个模型,它能够一步步迭代地进行学习,并最终得出每个单词基于其上下文的条件概率。
n-gram
基本思想: 一个词出现的概率只与它前面固定数目的词相关。
主要工作是在预料中统计各种词串出现的次数以及平滑化处理,概率值计算号之后就存储起来,下次需要计算一个句子的概率时,只需找到相关的概率参数,将它们连乘起来就好了。
建立一个概率模型,它包含已知和未知参数。每增加一个训练样本,它就能从模型的输入、输出和期望输出(标签),多学到一点点未知参数的信息。
在每次迭代过程中,这个模型都能够评估其误差,并按照一定的更新规则,惩罚那些导致误差的参数。(误差“反向传播”法)。
CBOW
以 {“The”, “cat”, “over”, “the”, “puddle”} 为上下文,能够预测或产生它们中心的词语”jumped”。模型输入为 x(c),模型输出为 y,y 就是中心词 ‘jumped’。对于每个词语 wi 学习了两个向量。
连续词袋模型(CBOW)中的各个记号:
- WiWi:单词表 V 中的第 i 个单词, one-hot 向量
- v∈Rn∗|V|v∈Rn∗|V|:输入词矩阵
- vivi:V的第i列,n 维 WiWi 的输入向量
- U∈R|V|∗nU∈R|V|∗n:输出词矩阵
- UiUi:U 的第 i 行,n 维 WiWi 的输出向量
把整个过程拆分成以下几步:
- 对于 m 个词长度的输入上下文,我们产生它们的 one-hot 向量 (xc−m,⋯,xc−1,xc+1,⋯,xc+m)(xc−m,⋯,xc−1,xc+1,⋯,xc+m),作为模型输入。
- 我们得到上下文的嵌入词向量 (vc−m+1=Vxc−m+1,⋯,vc+m=Vxc+m)(vc−m+1=Vxc−m+1,⋯,vc+m=Vxc+m)
- 将这些向量取平均 vˆ=Vc−m+Vc−m+1+⋯+Vc+m2mv^=Vc−m+Vc−m+1+⋯+Vc+m2m
- 产生一个得分向量 z=Uvˆz=Uv^
- 将得分向量转换成概率分布形式 yˆ=softmax(z)y^=softmax(z)
- 我们希望我们产生的概率分布 ,与真实概率分布 yˆy^ 相匹配。而 y 刚好也就是我们期望的真实词语的one-hot向量。
怎样找到矩阵U、V?
目标函数选交叉熵,用梯度下降法去更新每一个相关的词向量 UcUc 和 VjVj.
当我们试图从已知概率学习一个新的概率时,最常见的是从信息论的角度寻找方法来评估两个概率分布的差距。其中广受好评又广泛应用的一个评估差异/损失的函数是交叉熵:
H(yˆ,y)=−∑|V|j=1yjlog(yˆj)H(y^,y)=−∑j=1|V|yjlog(y^j)
结合我们当下的例子,y 只是一个one-hot向量,于是上面的损失函数就可以简化为:
H(yˆ,y)=−yjlog(yˆj)H(y^,y)=−yjlog(y^j)
我们用 c 表示 y 这个 one-hot 向量取值为 1 的那个维度的下标。所以在我们预测为准确值的情况下 yˆc=1y^c=1。于是损失为 −1 log(1) = 0。所以对于一个理想的预测值,因为预测得到的概率分布和真实概率分布完全一样,因此损失为0。相反,当我们的预测结果非常不理想, yˆc=0.01y^c=0.01。计算得到的损失为−1 log(0.01) ≈ 4.605,损失非常大,原本这才是标准结果,可是你给了一个非常低的概率,因此会拿到一个非常大的loss。最终的优化函数为:
Skip-Gram
与上面提到的模型对应的另一种思路,是以中心的词语 ”jumped” 为输入,能够预测或产生它周围的词语 ”The”, “cat”, “over”, “the”, “puddle” 等。这里我们叫 ”jumped” 为上下文。我们把它叫做Skip-Gram 模型。
这个模型的建立与连续词袋模型(CBOW)非常相似,但本质上是交换了输入和输出的位置。我们令输入的 one-hot 向量(中心词)为 x(因为它只有一个),输出向量为 y(j)。U 和 V 的定义与连续词袋模型一样。看一下网络结构图:
举个例子,假设现在的数据集如下:
the quick brown fox jumped over the lazy dog
这个数据集中包含了词语及其上下文信息。上下文信息(Context)是一个比较宽泛的概念,有多种不同的理解:例如,词语周边的句法结构,词语的左边部分的若干个词语信息,对应的右半部分等。这里,我们使用最原始和基本的定义,即认为词语左右相邻的若干个词汇是该词对应的上下文信息。例如,取左右的词窗口为1,下面是数据集中的(上下文信息,对应的词)的pairs:
([the, brown], quick), ([quick, fox], brown), ([brown, jumped], fox), ...
Skip-Gram模型是通过输入的目标词来预测其对应的上下文信息,所以目标是通过[quick]来预测[the]和[brown],通过[brown]来预测[quick]和[fox]… 将上面的pair转换为(inpUt, output)的形式如下:
(quick, the), (quick, brown), (brown, quick), (brown, fox), ...
对应到上面部分,我们可以把 Skip-Gram 模型的运作方式拆分成以下几步:
- 生成 one-hot 输入向量 x。
- 得到上下文的嵌入词向量 VcVc=VxVx。
- 因为这里不需要取平均值的操作,所以直接是vˆ=vcv^=vc。
- 通过U=UVcU=UVc产生 2m 个得分向量 Uc−m,⋯,Uc−1,Uc+1,⋯,Uc+mUc−m,⋯,Uc−1,Uc+1,⋯,Uc+m,如果上下文各取一个词,就是 Uc−1Uc−1, Uc+1Uc+1
- 将得分向量转换成概率分布形式 y=softmax(u)y=softmax(u)。
- 我们希望我们产生的概率分布与真实概率分布 yc−m,⋯,yc−1,,yc+1⋯,yc+myc−m,⋯,yc−1,,yc+1⋯,yc+m 相匹配,也就是我们真实输出结果的 one-hot 向量。
为模型设定一个目标/损失函数。不过不同的地方是我们这里需要引入朴素贝叶斯假设来将联合概率拆分成独立概率相乘。只要给出了中心词,所有的输出词是完全独立的。使用随机梯度下降算法(SGD)来进行最优化求解,并且使用mini-batch方法 (通常batch_size在16到512之间)。可以用随机梯度下降法去更新未知参数的梯度。
对应的优化函数是
这里值得一提的是,skipgram 和 PMI 之间是有联系的,Levy and Goldberg(2014) 提到过,skip-gram 在矩阵成为 PMI 的一个 shifted version 时(WW‘T=MPMI−logkWW‘T=MPMI−logk),得到最优解,也就是说,
Skip-gram is implicitly factoring a shifted version of the PMI matrix into the two embedding matrices.
我们再次观察一下目标函数,注意到对整个单词表|V|求和的计算量是非常巨大的,任何一个对目标函数的更新和求值操作都会有O(|V|)的时间复杂度。我们需要一个思路去简化一下,我们想办法去求它的近似,可以参照负面采样(Negative Sampling)
why skip-gram
在NLP中,语料的选取是一个相当重要的问题。
首先,语料必须充分。一方面词典的词量要足够大,另一方面尽可能地包含反映词语之间关系的句子,如“鱼在水中游”这种句式在语料中尽可能地多,模型才能学习到该句中的语义和语法关系,这和人类学习自然语言是一个道理,重复次数多了,也就会模型了。
其次,语料必须准确。所选取的语料能够正确反映该语言的语义和语法关系。如中文的《人民日报》比较准确。但更多时候不是语料选取引发准确性问题,而是处理的方法。
由于窗口大小的限制,这会导致超出窗口的词语与当前词之间的关系不能正确地反映到模型中,如果单纯扩大窗口大小会增加训练的复杂度。Skip-gram模型的提出很好解决了这些问题。
我们来看看 skip-gram 的定义。
Skip-gram 实际上的定义很简单,就是允许跳几个字的意思。依照原论文里的定义,这个句子:
Insurgents killed in ongoing fighting.
在 bi-grams 的时候是拆成:
{ insurgents killed, killed in, in ongoing, ongoing fighting }
在 2-skip-bi-grams 的时候拆成:
{ insurgents killed, insurgents in, insurgents ongoing, killed in, killed ongoing, killed fighting, in ongoing, in fighting, ongoing fighting }
在 tri-grams 的时候是:
{ insurgents killed in, killed in ongoing, in ongoing fighting }
在 2-skip-tri-grams 的时候是:
{ insurgents killed in, insurgents killed ongoing, insurgents killed fighting, insurgentsin ongoing, insurgents in fighting, insurgents ongoing fighting, killed in ongoing, killed in fighting, killed ongoing fighting, in ongoing fighting }
这样就有办法在整篇文章都是用“台湾大学”的情况下以“台大”找到文章,解决一些“同义词”想要解决的问题。Skip-gram 一方面反映了句子的真实意思,另一方面还扩大了语料,2元词组由原来的4个扩展到了9个,3元词组由原来的3个扩展到了10个。
Word2Vec
Word2Vec 是一个典型的预测模型,用于高效地学习Word Embedding,实现的模型就是上面提到的两种:连续词袋模型(CBOW)和Skip-Gram模型。算法上这两个模型是相似的
- CBOW 从输入的上下文信息来预测目标词
- Skip-gram 模型则是相反的,从目标词来预测上下文信息
一般而言,这种方式上的区别使得 CBOW 模型更适合应用在小规模的数据集上,能够对很多的分布式信息进行平滑处理;而 Skip-Gram 模型则比较适合用于大规模的数据集上。
向量空间模型(Vector space models, VSMs)
将词语表示为一个连续的词向量,并且语义接近的词语对应的词向量在空间上也是接近的。
分布式假说理论: 该假说的思想是如果两个词的上下文(context)相同,那么这两个词所表达的语义也是一样的;换言之,两个词的语义是否相同或相似,取决于两个词的上下文内容,上下文相同表示两个词是可以等价替换的。
词向量生成方法主要分两大类:
- 计数法(count-based methods, e.g. Latent Semantic Analysis)
在大型语料中统计词语及邻近的词的共现频率,然后将之为每个词都映射为一个稠密的向量表示; - 预测法(predictive methods, e.g. neural probabilistic language models)。
直接利用词语的邻近词信息来得到预测词的词向量(词向量通常作为模型的训练参数)。
词向量任务评价
内部任务评价
内部任务评价的特点如下:
- 一般是在一个特定的子任务中进行评测
- 计算很快
- 有助于理解相关的系统
- 在实际的NLP任务中表现好坏,可能需要外部关联实际应用
方法:词向量类比
我们先输入一组不完整的类比 a:b::c:? 内部任务评价系统找出最大化余弦相似度的词向量
理想情况下,我们想得到xb−xa=xd−xc(例如,王后–国王 = 女演员 – 男演员)。于是xb−xa+xc=xd, 所以我们只需要找出一个与xb−xa+xc的标准化内积(比如余弦相似度)取最大值的词向量就可以了。
类比语料示例:
首都城市1 : 国家1 : : 首都城市2 : 国家2 Beijing:China::Astana Kazakhstan Beijing:China::Asmara Eritrea ... 比较级 bad:worst::big biggest bad:worst::easy easiest ... 时态 dancing:danced::decreased decreased dancing:danced::falling fell ...
方法:相关性评价
另外一个评测词向量质量的简单方法是人为对两个词的相似度在一个固定区间内打分(比如说 0-10),再跟对应向量的余弦相适度进行对比。
评测语料
考虑参数
- 词向量的维度
- 资料库的大小
- 资料源/类型
- 上下文窗口的大小
- 上下文的对称性
一般而言,
- 精度和使用的模型高度相关,因为这些生成词向量的方法所依据的特性是完全不同的(如同时出现的次数,奇异向量等。)
- 文集量越大,精度越高,因为例子越多,生成的系统学习到的经验就更丰富。比如在完成词汇类比的例子中,系统如果之前没有接触测试词,就可能会生成错误的结果。
- 如果维度特别低或特别高,精度就会比较低。低维度词向量无法捕捉文集中不同词语的不同意义。这可以视为我们模型复杂度过低而导致的高偏差。比如 “king”, “queen”, “man”, “woman” 这几个词,我们需要至少2个维度像”gender” 如 “leadership” 来把它们编译成 2-字节 词向量。 过低的维度将无法捕捉四个词之间的语义差别,而过高的维度将捕捉到一些对泛化能力没有用的噪音– 即高方差的问题。
外部任务评价
外部任务评价的特点如下:
- 在一个实际任务中进行评测
- 需要花很长的时间来计算精度
- 不太清楚是否是某个子系统或者其他子系统,又或是几个子系统互相作用引起的问题
- 如果替换原有的子系统后获得精度提升,则说明替换很可能是有效的
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/140729.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...