更别致的词向量模型(四):模型的求解
By 苏剑林 | 2017-11-19 | 51364位读者 |损失函数 #
现在,我们来定义loss,以便把各个词向量求解出来。用$\tilde{P}$表示$P$的频率估计值,那么我们可以直接以下式为loss
\[\sum_{w_i,w_j}\left(\langle \boldsymbol{v}_i, \boldsymbol{v}_j\rangle-\log\frac{\tilde{P}(w_i,w_j)}{\tilde{P}(w_i)\tilde{P}(w_j)}\right)^2\tag{16}\]
相比之下,无论在参数量还是模型形式上,这个做法都比glove要简单,因此称之为simpler glove。glove模型是
\[\sum_{w_i,w_j}\left(\langle \boldsymbol{v}_i, \boldsymbol{\hat{v}}_j\rangle+b_i+\hat{b}_j-\log X_{ij}\right)^2\tag{17}\]
在glove模型中,对中心词向量和上下文向量做了区分,然后最后模型建议输出的是两套词向量的求和,据说这效果会更好,这是一个比较勉强的trick,但也不是什么毛病。
\[\begin{aligned}&\sum_{w_i,w_j}\left(\langle \boldsymbol{v}_i, \boldsymbol{\hat{v}}_j\rangle+b_i+\hat{b}_j-\log \tilde{P}(w_i,w_j)\right)^2\\
=&\sum_{w_i,w_j}\left[\langle \boldsymbol{v}_i+\boldsymbol{c}, \boldsymbol{\hat{v}}_j+\boldsymbol{c}\rangle+\Big(b_i-\langle \boldsymbol{v}_i, \boldsymbol{c}\rangle - \frac{|\boldsymbol{c}|^2}{2}\Big)\right.\\
&\qquad\qquad\qquad\qquad\left.+\Big(\hat{b}_j-\langle \boldsymbol{\hat{v}}_j, \boldsymbol{c}\rangle - \frac{|\boldsymbol{c}|^2}{2}\Big)-\log X_{ij}\right]^2\end{aligned}\tag{18}\]
这就是说,如果你有了一组解,那么你将所有词向量加上任意一个常数向量后,它还是一组解!这个问题就严重了,我们无法预估得到的是哪组解,一旦加上的是一个非常大的常向量,那么各种度量都没意义了(比如任意两个词的cos值都接近1)。事实上,对glove生成的词向量进行验算就可以发现,glove生成的词向量,停用词的模长远大于一般词的模长,也就是说一堆词放在一起时,停用词的作用还明显些,这显然是不利用后续模型的优化的。(虽然从目前的关于glove的实验结果来看,是我强迫症了一些。)
互信息估算 #
为了求解模型,首先要解决的第一个问题就是$P(w_i,w_j),P(w_i),P(w_j)$该怎么算呢?$P(w_i),P(w_j)$简单,直接统计估计就行了,但$P(w_i,w_j)$呢?怎样的两个词才算是共现了?当然,事实上不同的用途可以有不同的方案,比如我们可以认为同出现在一篇文章的两个词就是碰过一次面了,这种方案通常会对主题分类很有帮助,不过这种方案计算量太大。更常用的方案是选定一个固定的整数,记为window,每个词前后的window个词,都认为是跟这个词碰过面的。
一个值得留意的细节是:中心词与自身的共现要不要算进去?窗口的定义应该是跟中心词距离不超过window的词,那么应该要把它算上的,但如果算上,那没什么预测意义,因为这一项总是存在,如果不算上,那么会降低了词与自身的互信息。所以我们采用了一个小trick:不算入相同的共现项,让模型自己把这个学出来。也就是说,哪怕上下文(除中心词外)也出现了中心词,也不算进loss中,因为数据量本身是远远大于参数量的,所以这一项总可以学习出来。
权重和降采样 #
glove模型定义了如下的权重公式:
\[\lambda_{ij}=\Big(\min\{x_{ij}/x_{max}, 1\}\Big)^{\alpha}\tag{19}\]
其中$x_{ij}$代表词对$(w_i,w_j)$的共现频数,$x_{max},\alpha$是固定的常数,通常取$x_{max}=100,\alpha=3/4$,也就是说,要对共现频数低的词对降权,它们更有可能是噪音,所以最后Golve的loss是
\[\sum_{w_i,w_j}\lambda_{ij}\left(\langle \boldsymbol{v}_i, \boldsymbol{v}_j\rangle+b_i+b_j-\log \tilde{P}(w_i,w_j)\right)^2\tag{20}\]
在文本的模型中,继续沿用这一权重,但有所选择。首先,对频数作$\alpha$次幂,相当于提高了低频项的权重,这跟word2vec的做法基本一致。值得思考的是$\min$这个截断操作,如果进行这个截断,那么相当于大大降低了高频词的权重,有点像word2vec中的对高频词进行降采样,能够提升低频词的学习效果,但可能带来的后果是:高频词的模长没学好。我们可以在《模长的含义》这一小节中看到这一点。总的来说,不同的场景有不同的需求,因此我们在最后发布的源码中,允许用户自定义是否截断这个权重。
Adagrad #
跟glove一样,我们同样使用Adagrad算法进行优化,使用Adagrad的原因是因为它大概是目前最简单的自适应学习率的算法。
但是,我发现glove源码中的Adagrad算法写法是错的!!我不知道glove那样写是刻意的改进,还是笔误(感觉也不大可能笔误吧?),总之,如果我毫不改动它的迭代过程,照搬到本文的simpler glove模型中,很容易就出现各种无解的nan!如果写成标准的Adagrad,nan就不会出现了。
选定一个词对$w_i,w_j$我们得到loss
\[L=\lambda_{ij}\left(\langle \boldsymbol{v}_i, \boldsymbol{v}_j\rangle-\log\frac{\tilde{P}(w_i,w_j)}{\tilde{P}(w_i)\tilde{P}(w_j)}\right)^2\tag{21}\]
它的梯度是
\[\begin{aligned}\nabla_{\boldsymbol{v}_i} L=\lambda_{ij}\left(\langle \boldsymbol{v}_i, \boldsymbol{v}_j\rangle-\log\frac{\tilde{P}(w_i,w_j)}{\tilde{P}(w_i)\tilde{P}(w_j)}\right)\boldsymbol{v}_j\\
\nabla_{\boldsymbol{v}_j} L=\lambda_{ij}\left(\langle \boldsymbol{v}_i, \boldsymbol{v}_j\rangle-\log\frac{\tilde{P}(w_i,w_j)}{\tilde{P}(w_i)\tilde{P}(w_j)}\right)\boldsymbol{v}_i
\end{aligned}\tag{22}\]
然后根据Adagrad算法的公式进行更新即可,默认的初始学习率选为$\eta=0.1$,迭代公式为
\[\left\{\begin{aligned}\boldsymbol{g}_{\gamma}^{(n)} =& \nabla_{\boldsymbol{v}_{\gamma}^{(n)}} L\\
\boldsymbol{G}_{\gamma}^{(n)} =& \boldsymbol{G}_{\gamma}^{(n-1)} + \boldsymbol{g}_{\gamma}^{(n)}\otimes \boldsymbol{g}_{\gamma}^{(n)}\\
\boldsymbol{v}_{\gamma}^{(n)} =& \boldsymbol{v}_{\gamma}^{(n-1)} - \frac{\boldsymbol{g}_{\gamma}^{(n)}}{\sqrt{\boldsymbol{G}_{\gamma}^{(n-1)}}}\eta
\end{aligned}\right.,\,\gamma=i,j
\tag{23}\]
根据公式可以看出,Adagrad算法基本上是对loss的缩放不敏感的,换句话说,将loss乘上10倍,最终的优化效果基本没什么变化,但如果在随机梯度下降中,将loss乘上10倍,就等价于将学习率乘以10了。
转载到请包括本文地址:https://www.spaces.ac.cn/archives/4675
更详细的转载事宜请参考:《科学空间FAQ》
如果您还有什么疑惑或建议,欢迎在下方评论区继续讨论。
如果您觉得本文还不错,欢迎分享/打赏本文。打赏并非要从中获得收益,而是希望知道科学空间获得了多少读者的真心关注。当然,如果你无视它,也不会影响你的阅读。再次表示欢迎和感谢!
如果您需要引用本文,请参考:
苏剑林. (Nov. 19, 2017). 《更别致的词向量模型(四):模型的求解 》[Blog post]. Retrieved from https://www.spaces.ac.cn/archives/4675
@online{kexuefm-4675,
title={更别致的词向量模型(四):模型的求解},
author={苏剑林},
year={2017},
month={Nov},
url={\url{https://www.spaces.ac.cn/archives/4675}},
}
November 29th, 2017
“所以我们采用了一个小trick:不算入相同的共现项,让模型自己把这个学出来。也就是说,哪怕上下文(除中心词外)也出现了中心词,也不算进loss中,因为数据量本身是远远大于参数量的,所以这一项总可以学习出来。”请问这里话里的学出来,具体怎样理解和在算法中怎样体现出来呢?
体现就是:在一般的足够多的语料下,我们统计出来的共现项大概有数十亿,也就是$10^9\sim 10^{10}$这个数量级,而如果我们保留30w的词语,每个词语用128维词向量,那么参数量不超过$10^8$,数据量差不多是参数量的100倍,就算不统计自身的共现项,那也就减少了30w的数据量,微不足道。
换个角度来讲,训练的过程就是依靠互信息把每个词的词向量“摆放”好,如果我们的模型是合理的,那么依靠别人的互信息就足够摆放好自己了。
December 3rd, 2017
请问基于16和17的两个模型实际效果有多大的差别?
May 7th, 2019
博主你好,最近在读word embedding相关的文章,读你的博客受到很大启发。关于GLOVE,我觉得文章出发点的直觉非常好,好的词向量应该满足条件概率的比例。个人认为,这种不对称的corpus statistics比对称的mutual information包含更多的信息。不过一直有个困惑想跟博主讨论下。GLOVE原文提到“Our final model should be invariant under this relabeling, but Eqn. (3) is not”。博主对于“invariant under this relabeling”怎么理解?
大概的意思是模型应该在变换$w \leftrightarrow \tilde{w}, X \leftrightarrow X^T$之下保持不变吧
July 15th, 2019
(23)的adagrad分母少了一个根号
谢谢指出,已经修正~
November 1st, 2020
batch选多大。。。
原生的glove和word2vec都是没有batch的概念,都是一个个样本地学的。