从 NLP 入手
n-gram
语言模型(language model)就是假设一门语言所有可能的句子服从一个概率分布,每个句子出现的概率加起来是1,那么语言模型的任务就是预测每个句子在语言中出现的概率。如果把句子 \(s\) 看成单词 \(w\) 的序列 \(s=\{w_1,w_2,...,w_m\}\) ,那么语言模型就是建模一个 \(p(w_1,w_2,...,w_m)\) 来计算这个句子 \(s\) 出现的概率,直观上我们要得到这个语言模型,基于链式法则可以表示为每个单词出现的条件概率的乘积,我们将条件概率的条件 \((w_1,w_2,...,w_{i-1})\) 称为单词 \(w_i\) 的上下文,用 \(c_i\) 表示。
\[\begin{aligned} p\left(w_{1}, w_{2}, \ldots, w_{m}\right)&=p\left(w_{1}\right) * p\left(w_{2} \mid w_{1}\right) * p\left(w_{3} \mid w_{1}, w_{2}\right) \ldots p\left(w_{m} \mid w_{1}, \ldots, w_{m-1}\right) \\ &=\prod_{i=1}^{m} p\left(w_{i} \mid w_{1}, w_{2}, \ldots, w_{i-1}\right) \\ &=\prod_{i=1}^{m} p\left(w_{i} \mid c_i\right) \end{aligned} \tag{1} \]
可以看到,language model 就是条件概率 \(p(w|c)\) 的集合,但是直接计算每个 \(w\) 在语料库中的条件概率是需要很大计算量的。因此在统计语言模型中,引入了马尔可夫假设,即“一个词出现的概率只与它前面出现的有限的一个或者 n 个词有关”,将这 \(n\) 个词称为一个 gram,这就是著名的 n-gram 模型,因此可以将模型简化为:
\[p\left(w_{1}, w_{2}, w_{3}, \ldots, w_{m}\right)=\prod_{i=1}^{m} p\left(w_{i} \mid w_{i-n+1}, \ldots, w_{i-1}\right) \tag{2}\]
最大似然估计
上面的 n-gram 构建语言模型的方法实际上就是,将一个训练语料库中的每个 \(w_i\) 和它的 \(c_i\) (也就是由前面\(n\)个 \(w\) 构成)的条件概率计算出来并储存(实际操作上是统计每个gram出现的次数),然后下一次计算某个句子的出现的概率时,即 (2)式,就在存储中找到这个句子中出现的 \(w\) 和 \(c\) 的条件概率,然后乘起来即可。
因此,我们是否可以不事先计算并存储每个 \(w\) 和 \(c\) 条件概率,而是建立一个模型(或者说函数),给这个模型一组 \(w\) 和 \(c\) 就能输出它们的条件概率。
在机器学习领域有一个方法是:对所要考虑的问题建模后为其构造一个目标函数,然后对这个目标函数进行优化,从而求得一组最优的参数,最后利用这组最优参数对应的模型进行预测,也就是最大似然估计。
在建模统计语言模型时,利用最大似然估计,根据(1)式目标函数,我们可以写出其对数似然函数如下:
\[\mathcal{L}_{MLE}= \sum_{w_i \in s} \log p_{\theta}(w_i\mid c_i) \tag 3\]
然后最大化对数似然函数 \(\mathcal{L}_{MLE}\) ,实际上这样就是将 \(p(w|c)\) 看成 \(w\) 和 \(c\) 的函数, \(\theta\) 为待定参数集:
\[p_{\theta}(w|c)=F(w,c;\theta) \tag 4\]
这样一旦最优参数集 \(\theta^{*}\) 可以确定,函数 \(F\) 就被唯一确定,那么对于任何概率 \(p(w|c)\) 都可以用函数 \(F(w,c;{\theta}^{*})\) 来计算了。
神经概率语言模型
上面的方法似然看起来很美好,但其中有两个问题:
- 如何构造一个好的函数 \(F\) 。
- 最大似然估计虽然理论上简单可行,但对于某些模型,在实际计算时可能需要很大的计算量,因此未必容易。
首先来看第一个问题,这也就是我们为什么引入神经网络,因为神经网络理论上可以表示任何函数,那么通过训练,肯定能找到这个合适的 \(F\) ,因此 Bengio 等人在 2003 年 A Neural Probabilistic Language Model 中提出了神经概率语言模型(NPLM)。其不在受限于 gram 的大小,可以在包含任意大小上下文的情况下建模 \(w\) 的条件概率。
具体来看,它把语言模型的建立当作一个多分类问题,我们用 \(V=\{ v_1,v_2,...,v_{|V|} \}\) 表示一个包含所有单词的单词库,其大小为 \(|V|\) ,将 \((w,c)\) 当成一对训练样本(实际上 \(w\) 会转换成词向量,这里不做详解),通过神经网络后和 softmax 后,输出一个向量 \(\hat{y}=\left[\hat{y}_{i,1},\hat{y}_{i,2},...,\hat{y}_{i,|V|}\right]\) , 其中每一维 \(\hat{y}_{i,j}=p(v_j|c_i)\) 表示上下文为 \(c_i \) 时 第 \(i\) 个单词 \(w_i\) 是单词库中第 \(j\) 个单词 \(v_j\) 的概率,训练过程要求最后单词库中概率最大的单词就是训练样本对中的 \(w_i\) 。这样训练结束后,给神经网络一个上下文 \(c_l=(w_1,w_2,...,w_{l-1})\) ,神经网络就能预测在当前上下文 \(c_l\) 时,下一个 单词 \(w_l\) 是单词库中的各个词的概率 \(p(w_l|c_l)\) ,通过这个我们也就可以构建语言模型。
我们知道,这种方法本质上就是拟合一个 \(w\) 和 \(c\) 的函数 \(F\) ,或者说建立一个参数集为 \(\theta\) 条件概率分布 \(p_{\theta}(w|c)\) ,只要给出当前上下文 \(c\) ,我们就能够直接计算下一个单词 \(w\) 的概率。
假设输入到 softmax 前的结果用 \(s_{\theta}(w,c)\) 表示,实际上 \(s_{\theta}(w,c)\) 是有含义的,它是一个 socring function ,输出的分数用来量化 \(w\) 在上下文 \(c\) 中匹配性,那么 \(w\) 条件概率可以表示为以下形式:
\[\begin{aligned} p_{\theta}(w|c)&= \frac{exp(s_{\theta}(w,c))}{\sum_{w^\prime \in V}exp(s_{\theta}(w,c))} \\ &= \frac{u_{\theta}(w,c)}{Z(c)} \end{aligned} \tag{5}\]
式中, \(u_{\theta}(w,c)=exp(s_{\theta}(w,c))\) 表示下一个单词是这个 \(w\) 在单词库中的概率;令 \(Z(c) = \sum_{w^\prime \in V}exp(s_{\theta}(w,c))\) 表示当前单词库中所有单词的概率的累和,通常将这一项叫做“配分函数”或“归一化因子”。一般来说,单词库 \(|V|\) 的数量是非常巨大的,因此计算 \(Z(c)\) 是非常昂贵、耗时的一件事,这也就是 NCE 要解决的问题。(见附录1)
如果我们不考虑 \(s_{\theta}(w,c)\) 的具体形式,那么 (5) 式实际上就可以当作我们在 (4) 式中所构造的函数 \(F\) 的表达式, 既然如此,那我们接着用上节提到的最大似然估计的方式来试着求解 \(F\) 的参数 \(\theta\) 。我们将从句子 \(s\) 中取样的 \(w\) 看成经验分布(数据分布) \(\tilde{p}(w|c)\) , (3) 式中的 \(\mathcal{L}_{MLE}\) 可以写成:
\[\begin{aligned} \arg\max \mathcal{L}_{MLE} &= \arg\max \sum_{w \sim \tilde{p}(w|c)} \log p_{\theta}(w \mid c) \\ &=\arg\max \mathbb E_{w \sim \tilde{p}(w|c)} \log{\frac{u_{\theta}(w,c)}{Z(c)}} \end{aligned} \tag{6}\]
现在要最大化 \(\mathcal{L}_{MLE}\) ,那么将其关于 \( \theta\) 求导:
\[\begin{aligned} \frac{\partial}{\partial \theta}\mathcal{L}_{\mathrm{MLE}}&=\mathbb E_{w \sim \tilde{p}(w|c)} \frac{\partial}{\partial \theta}\log{\frac{u_{\theta}(w,c)}{Z(c)}} \\ &=\mathbb E_{w \sim \tilde{p}(w|c)} \left[ \frac{\partial}{\partial \theta} \log{u_{\theta}(w,c)}- \frac{\partial}{\partial \theta}\log{Z(c)} \right] \\ &=\mathbb E_{w \sim \tilde{p}(w|c)} \frac{\partial}{\partial \theta} \log{u_{\theta}(w,c)} - \frac{\partial}{\partial \theta} \log{Z(c)} \end{aligned} \tag{7}\]
这里解释一下上面到最后一步的转换,因为 \(Z(c)=\sum_{w^\prime \in V}exp(s_{\theta}(w,c))\) ,其中 \(w^{\prime}\) 为单词库 \(V\) 中所有的单词,而单词库其中每个单词的概率由 \(p_{\theta}(w|c)\) 产生,因此 \(w^{\prime} \sim p_{\theta}(w|c)\) ,与经验分布 \(w \sim \tilde{p}(w|c)\) 不相关,所以可以把期望 \(\mathbb E_{w \sim \tilde{p}(w|c)}\) 去掉。
(7) 式结果中的 \(\frac{\partial}{\partial \theta} \log{Z(c)}\) 计算如下:
\[\begin{aligned} \frac{\partial}{\partial \theta}\log{Z(c)}&=\frac{1}{Z(c)} \frac{\partial}{\partial \theta}Z(c) \\ &=\frac{1}{Z(c)}\frac{\partial}{\partial \theta} \sum_{w^\prime \in V}u_{\theta}(w,c) \\ &=\frac{1}{Z(c)} \frac{\partial}{\partial \theta} \sum_{w^\prime \in V} {exp(s_{\theta}(w,c))} \\ &=\sum_{w^\prime \in V} \frac{1}{Z(c)} exp(s_{\theta}(w,c)) \frac{\partial}{\partial \theta} s_{\theta}(w,c) \\ &=\sum_{w^\prime \in V} p_{\theta}(w|c) \frac{\partial}{\partial \theta} s_{\theta}(w,c) \\ &=\mathbb{E}_{w \sim p_{\theta}(w|c)} \frac{\partial}{\partial \theta} s_{\theta}(w,c) \\ &=\mathbb{E}_{w \sim p_{\theta}(w|c)} \frac{\partial}{\partial \theta} logu_{\theta}(w,c) \end{aligned} \tag{8}\]
将 (8) 式结果带回 (7) 式中得:
\[\begin{aligned} \frac{\partial}{\partial \theta}\mathcal{L}_{\mathrm{MLE}} &=\mathbb E_{w \sim \tilde{p}(w|c)} \frac{\partial}{\partial \theta} \log{u_{\theta}(w,c)} - \frac{\partial}{\partial \theta} \log{Z(c)} \\ &=\mathbb E_{w \sim \tilde{p}(w|c)} \frac{\partial}{\partial \theta} \log{u_{\theta}(w,c)} - \mathbb{E}_{w \sim p_{\theta}(w|c)} \frac{\partial}{\partial \theta} logu_{\theta}(w,c) \\ &=\sum_w{\tilde{p}(w|c) \frac{\partial}{\partial \theta} \log{u_{\theta}(w,c)}} - \sum_w {p_{\theta}(w|c) \frac{\partial}{\partial \theta} logu_{\theta}(w,c)} \\ &=\sum_w{\left[ \tilde{p}(w|c) \frac{\partial}{\partial \theta} \log{u_{\theta}(w,c)} - p_{\theta}(w|c) \frac{\partial}{\partial \theta} logu_{\theta}(w,c) \right]} \\ &=\sum_w{\left[\left(\tilde{p}(w|c)- p_{\theta}(w|c)\right)\frac{\partial}{\partial \theta} logu_{\theta}(w,c)\right]} \end{aligned} \tag{9}\]
最大似然好像很容易,但是实际上还是绕不开对“归一化常数”的计算,所以就需要 NCE 登场了。
NCE (Noise Contrastive Estimation)
上一节中说明了计算 \(Z(c)\) 非常昂贵这个问题需要解决,一个简单的思路是将 \(Z(c)\) 也看成模型的一个参数 \(z_c\) 来进行训练,但是这种方法不适合于上面提到的最大似然估计,因为由 (6) 式可以看出来,它会直接将 \(z_c\) 趋于 \(0\) 来获得最大似然。因此,有人提利用这个思想提出了一些不定义 \(Z(c)\) ,直接用 \(u_{\theta}(w,c)\) 估计模型的方法,如 contrastive divergence (Hinton, 2002)和 score matching (Hyvarinen, 2005)。(见附录2)
而 NCE 不同于上面两种方法,它是通过最大化同一个目标函数来估计模型参数 \(\theta\) 和归一化常数,NCE 的核心思想就是通过学习数据分布样本和噪声分布样本之间的区别,从而发现数据中的一些特性,因为这个方法需要依靠与噪声数据进行对比,所以称为“噪声对比估计(Noise Contrastive Estimation)”。更具体来说,NCE 将问题转换成了一个二分类问题,分类器能够对数据样本和噪声样本进行二分类,而这个分类器的参数 \(\theta \) 就等价于上节中我们想要得到 \(\theta\) 。(见附录3)
现在假设一个特定上下文 \(c\) 的数据分布为 \(\tilde{p}(w|c)\) ,我们称从它里面取出的样本为正样本,令类别 \(D=1\) ;而另一个与 \(c\) 无关的噪声分布为 \(q(w)\) ,我们称从里面取出的样本为负样本,令类别为 \(D=0\) 。遵循 Gutmann and Hyvrinen (2012) 中的设置,假设现在取出了 \(k_d\) 个正样本和 \(k_n\) 个负样本,将这些正负样本混合形成一个混合分布 \(p(w|c)\) 。
我们得到下面这些概率:
\[\begin{aligned} p(D=1)=\frac{k_d}{k_d+k_n} \\ p(D=0)=\frac{k_n}{k_d+k_n} \\ p(w|D=1,c)= \tilde{p}(w|c) \\ p(w|D=0,c)=q(w) \end{aligned} \tag{10}\]
所以可以计算后验概率:
\[\begin{aligned} p(D=0|w,c) &=\frac{p(D=0)p(w|D=0,c)}{p(D=0)p(w|D=0,c)+p(D=1)p(w|D=1,c)} \\ &=\frac{\frac{k_n}{k_d+k_n} \times q(w)}{\frac{k_d}{k_d+k_n} \times \tilde{p}(w \mid c)+\frac{k_n}{k_d+k_n} \times q(w)} \\ &=\frac{\frac{k_n}{k_d} \times q(w)}{\tilde{p}(w \mid c)+\frac{k_n}{k_d} \times q(w)} \\ \\ p(D=1|w,c)&= \frac{p(D=1)p(w|D=1,c)}{p(D=0)p(w|D=0,c)+p(D=1)p(w|D=1,c)} \\ &=\frac{\frac{k_d}{k_d+k_n} \times \tilde{p}(w|c)}{\frac{k_d}{k_d+k_n} \times \tilde{p}(w \mid c)+\frac{k_n}{k_d+k_n} \times q(w)} \\ &=\frac{\tilde{p}(w \mid c)}{\tilde{p}(w \mid c)+\frac{k_n}{k_d} \times q(w)} \end{aligned} \tag{11}\]
我们令负样本和正样本的比例为: \(k=\frac{k_n}{k_d}\) ,则有:
\[\begin{aligned} p(D=0|w,c) &=\frac{k \times q(w)}{\tilde{p}(w \mid c)+k \times q(w)} \\ \\ p(D=1|w,c) &=\frac{\tilde{p}(w \mid c)}{\tilde{p}(w \mid c)+k \times q(w)} \end{aligned} \tag{12}\]
现在我们观察 (12) 式,NCE 所做的事情就是将式中的经验分布 \(\tilde{p}(w|c)\) 替换成概率模型 \(p_{\theta}(w|c)\) ,使后验概率成为参数为 \(\theta\) 的函数。但问题是这样现在这样的形式还是需要计算 \(Z(c)\) ,我们只是将原来问题进行了一定的转换从而引入了噪声分布。为了解决这个问题,NCE 做了两个设定:
- 一个就是前面提到的,将 \(Z(c)\) 作为一个参数 \(z_c\) 来进行估计,相当于引进了一个新的参数。
- 第二个是,事实证明(Mnih and Teh, 2012),对于参数很多的神经网络来说,我们将 \(z_c\) 固定为 1 对每个 \(c\) 仍是有效的。
第二个设定,即减少了参数的数量,又使模型的输出符合”归一化“的性质(即 \(Z(c)≈1\) ),是很合理的,如果 \(Z(c)≈1\) ,由 (5) 式可以得到 \(p_{\theta}(w|c)=u_{\theta}(w|c)\) , 那么 (12) 式可以写成如下形式,即具有参数 \(\theta\) 的后验概率:
\[\begin{array}{l} p_{\theta}(D=0|w,c)=\frac{k \times q(w)}{u_{\theta}(w, c)+k \times q(w)} \\ p_{\theta}(D=1|w,c)=\frac{u_{\theta}(w, c)}{u_{\theta}(w, c)+k \times q(w)} \end{array} \tag{13}\]
现在我们有了参数为 \(\theta\) 的二元分类问题,假设标签 \(D_t\) 为伯努利分布,那么很容易写出他的条件对数似然 \( \mathcal{L}_{NCE}^c\) 如下,实际上在它前面加上负号后, \(-\mathcal{L}_{NCE}^c\) 也就等价于 logistics 分类里的 log loss,或者说交叉熵损失函数:
\[\begin{aligned} \mathcal{L}^c_{\mathrm{NCE}} &=\sum_{t=1}^{k_d+k_n} \left[ D_t \log P(D=1|w_t,c) +(1-D_t) \log P(D=0|w_t,c) \right] \\ &=\sum_{t=1}^{k_d}\log P(D=1|w_t,c) + \sum_{t=1}^{k_n} \log P(D=0|w_t,c) \\ &=\sum_{t=1}^{k_d}\log\frac{u_{\theta}(w, c)}{u_{\theta}(w, c)+k \times q(w)} + \sum_{t=1}^{k_n} \log\frac{k \times q(w)}{u_{\theta}(w, c)+k \times q(w)} \\ \end{aligned} \tag{14}\]
而 NCE 的目标函数还需要在 (14) 式的基础上除以正样本的数量 \(k_d\) ,即
\[\begin{aligned} J^c_{NCE} &=\frac{1}{k_d}\left[\sum_{t=1}^{k_d} \log\frac{u_{\theta}(w, c)}{u_{\theta}(w, c)+k \times q(w)} + \sum_{t=1}^{k_n} \log\frac{k \times q(w)}{u_{\theta}(w, c)+k \times q(w)}\right] \\ &=\frac{1}{k_d}\sum_{t=1}^{k_d}\log\frac{u_{\theta}(w, c)}{u_{\theta}(w, c)+k \times q(w)} + \frac{1}{k_d} \sum_{t=1}^{k_n} \log\frac{k \times q(w)}{u_{\theta}(w, c)+k \times q(w)} \\ &=\frac{1}{k_d}\sum_{t=1}^{k_d}\log\frac{u_{\theta}(w, c)}{u_{\theta}(w, c)+k \times q(w)} + \frac{k}{k_n} \sum_{t=1}^{k_n} \log \frac{k \times q(w)}{u_{\theta}(w, c)+k \times q(w)} \end{aligned} \tag{15}\]
当数据数量很大时,根据大数定律,上式也可以写成:
\[\begin{aligned} J^c_{NCE} &=\frac{1}{k_d}\sum_{t=1}^{k_d}\log\frac{u_{\theta}(w, c)}{u_{\theta}(w, c)+k \times q(w)} + \frac{k}{k_n} \sum_{t=1}^{k_n} \log \frac{k \times q(w)}{u_{\theta}(w, c)+k \times q(w)} \\ &=\mathbb{E}_{w \sim \tilde{p}(w|c)} \log\frac{u_{\theta}(w, c)}{u_{\theta}(w, c)+k \times q(w)} + k \mathbb{E}_{w \sim q(w)} \log \frac{k \times q(w)}{u_{\theta}(w, c)+k \times q(w)} \end{aligned} \tag{16}\]
要最大化上述对数似然函数,也就是最大化如下目标函数:
\[\begin{aligned} J^c_{NCE}&= \mathbb{E}_{w \sim \tilde{p}(w|c)}{\log{\frac{u_{\theta}(w, c)}{u_{\theta}(w, c)+k \times q(w)}}} + k\mathbb{E}_{w \sim q(w)} {\log{\frac{k \times q(w)}{u_{\theta}(w, c)+k \times q(w)}}} \\ \end{aligned} \tag{17}\]
NCE 目标函数中的 \(k\) 实际上就是在设置“二分类问题”时,选取的负样本与正样本的比例,通常的做法会默认正样本数量为 1 ,然后将负样本的数量 \(k\) 作为一个手动输入的参数,从而确定这个比例 \(k\) 。在 TensorFlow 的相关源码 中,正样本的数量 num_true 默认值为1,如果设置大于 1,那么会进行一个 1 / num_ture 的归一化。
可以看到实际上这个比例 \(k\) 对我们的 NCE 优化是有影响的,所以 NCE 的作者也考虑了什么样的比例 \(k\) 是最好的,我这里就直接说结论了,有兴趣的可以看详细看下这篇论文 Gutmann and Hyvrinen (2012) 。
结论是:对于设置的噪声分布 \(q(w)\) ,我们实际上是希望它尽量接近数据分布 \(\tilde{p}(w|c)\) ,否则这个二分类任务就过于简单了,也就无法很好的学到数据特性。而作者通过实验和推导证明(我在第三节中也会简单的证明),当负样本和正样本数量之比 \(k\) 越大,那么我们的 NCE 对于噪声分布好坏的依赖程度也就越小。换句话说,作者建议我们在计算能力运行的条件下,尽可能的增大比值 \(k\) 。也许这也就是大家都默认将正样本数量设置为 1 的原因:正样本至少取要 1 个,所以最大化比值 \(k\) ,也就是尽可能取更多负样本的同时,将正样本数量取最小值 1。
另外,如果我们希望目标函数不是只针对一个特定的上下文 \(c\) ,而是使不同的上下文可以共享参数,也就是设置一批上下文的全局目标函数:
\[\begin{aligned} J_{NCE} &=\sum_c P(c) J^c_{NCE} \\ \end{aligned} \tag{18}\]
到这,NCE 的构建就完成了,总结一下就是:从上下文 \(c\) 中取出单词作为正样本,从噪声分布中取出单词作为负样本,正负样本数量比为 \(1:k\) ,然后训练一个二分类器,通过一个类似于交叉熵损失函数的目标函数进行训练(如果取正样本数量为 1,那么 (14) 式与 (15) 式等价,NCE 目标函数就等价于交叉熵损失函数)。
NCE 的原理
上面虽然推导了那么多公式,但实际只是按照 NCE 的思想进行问题的转换,那么这样做究竟是否正确呢?根据附录 3 的描述,直觉上看好像是没有问题的。
我们再看回 (17) 式,我们对它关于 \(\theta\) 进行求导:
\[\begin{aligned} \frac{\partial}{\partial \theta} J^c_{NCE}(\theta)&= \frac{\partial}{\partial \theta} \left[\mathbb{E}_{w \sim \tilde{p}(w|c)}{\log{\frac{u_{\theta}(w, c)}{u_{\theta}(w, c)+k \times q(w)}}} + k\mathbb{E}_{w \sim q(w)} {\log{\frac{k \times q(w)}{u_{\theta}(w, c)+k \times q(w)}}} \right] \\ &=\frac{\partial}{\partial \theta} \sum_{w} \tilde{p}(w|c) \log{\frac{u_{\theta}(w, c)}{u_{\theta}(w, c)+k \times q(w)}} + \frac{\partial}{\partial \theta} k\sum_{w}q(w) \log{\frac{k \times q(w)}{u_{\theta}(w, c)+k \times q(w)}} \\ &=\sum_{w} \tilde{p}(w|c)\frac{\partial}{\partial \theta} \log{\frac{u_{\theta}(w, c)}{u_{\theta}(w, c)+k \times q(w)}} + k\sum_{w}q(w) \frac{\partial}{\partial \theta} \log{\frac{k \times q(w)}{u_{\theta}(w, c)+k \times q(w)}} \\ \end{aligned} \tag{19}\]
分布对上面的两项进行求导:
\[\begin{aligned} \frac{\partial}{\partial \theta} log{\frac{u_{\theta}(w, c)}{u_{\theta}(w, c)+k \times q({w})}} &= -\frac{\partial}{\partial \theta}log{(1+\frac{k \times q(w)}{u_{\theta}(w,c)})} \\ &=-\frac{1}{1+\frac{k \times q(w)}{u_{\theta}(w,c)}}\frac{\partial}{\partial \theta}\frac{k \times q(w)}{u_{\theta}(w,c)} \\ &=-\frac{1}{1+\frac{k \times q({w})}{u_{\theta}(w,c)}} (k \times q(w)) \frac{-1} {[u_{\theta}(w,c)]^2} \frac{\partial}{\partial \theta} \frac{1}{u_{\theta}(w, c)} \\ &=\frac{k \times q(w)}{u_{\theta}(w, c)+k \times q(w)} \frac{1}{u_{\theta}(w,c)} \frac{\partial}{\partial \theta} \frac{1}{u_{\theta}(w,c)} \\ &=\frac{k \times q(w)}{u_{\theta}(w, c)+k \times q(w)} \frac{\partial}{\partial \theta} log{u_{\theta}(w,c)} \end{aligned} \tag{20}\]
\[\begin{aligned} \frac{\partial}{\partial \theta} log{\frac{k \times q(w)}{u_{\theta}(w, c)+k \times q(w)}} &=-\frac{\partial}{\partial \theta}log{(1+\frac{u_{\theta}(w,c)}{k \times q(w)})} \\ &=-\frac{1}{1+\frac{u_{\theta}(w,c)}{k \times q(w)}}\frac{\partial}{\partial \theta}\frac{u_{\theta}(w,c)}{k \times q(w)} \\ &=-\frac{1}{1+\frac{u_{\theta}(w,c)}{k \times q(w)}} \frac{1}{k \times q(w)} \frac{\partial}{\partial \theta}u_{\theta}(w,c) \\ &=-\frac{1}{u_{\theta}(w,c) + k \times q(w)} \frac{\partial}{\partial \theta}u_{\theta}(w,c) \\ &=-\frac{u_{\theta}(w,c)}{u_{\theta}(w,c) + k \times q(w)} \frac{1}{u_{\theta}(w,c)} \frac{\partial}{\partial \theta}u_{\theta}(w,c) \\ &=-\frac{u_{\theta}(w,c)}{u_{\theta}(w,c) + k \times q(w)} \frac{\partial}{\partial \theta}log{u_{\theta}(w,c)} \\ \end{aligned} \tag{21}\]
将上面两个结果再带回 (19) 式中,并根据前面 \(Z(c)\approx1\) 的设定,也就是 \(p_{\theta}(w,c)=u_{\theta}(w,c)\) :
\[\begin{aligned} \frac{\partial}{\partial \theta} J^c_{NCE}(\theta) &=\sum_{w} \tilde{p}(w|c)\frac{\partial}{\partial \theta} \log{\frac{u_{\theta}(w, c)}{u_{\theta}(w, c)+k \times q(w)}} + k\sum_{w}q(w) \frac{\partial}{\partial \theta} \log{\frac{k \times q(w)}{u_{\theta}(w, c)+k \times q(w)}} \\ &=\sum_{w} \tilde{p}(w|c) \frac{k \times q(w)}{u_{\theta}(w, c)+k \times q(w)} \frac{\partial}{\partial \theta} \log{u_{\theta}(w,c)} - k\sum_{w}q(w) \frac{u_{\theta}(w,c)}{u_{\theta}(w,c) + k \times q(w)} \frac{\partial}{\partial \theta}\log{u_{\theta}(w,c)} \\ &=\sum_{w} \tilde{p}(w|c) \frac{k \times q(w)}{u_{\theta}(w, c)+k \times q(w)} \frac{\partial}{\partial \theta} \log{u_{\theta}(w,c)} - \sum_{w} u_{\theta}(w,c) \frac{k \times q(w)}{u_{\theta}(w,c) + k \times q(w)} \frac{\partial}{\partial \theta}\log{u_{\theta}(w,c)} \\ &=\sum_w{\left[\frac{k \times q(w)}{u_{\theta}(w, c)+k \times q(w)} \left(\tilde{p}(w|c)- u_{\theta}(w,c)\right)\frac{\partial}{\partial \theta}log u_{\theta}(w,c)\right]} \end{aligned} \tag{22}\]
上一节中我们设定了 \(Z(c)\approx1\) ,也就是 \(p_{\theta}(w|c)=u_{\theta}(w,c)\) ,因此:
\[\begin{aligned} \frac{\partial}{\partial \theta} J^c_{NCE}(\theta) &=\sum_w{\left[\frac{k \times q(w)}{p_{\theta}(w|c)+k \times q(w)} \left(\tilde{p}(w|c)- p_{\theta}(w|c)\right)\frac{\partial}{\partial \theta}log u_{\theta}(w,c)\right]} \end{aligned} \tag{23}\]
这里的参数 \(k\) 依然指的是负样本与正样本数量的比例,如果我们令 \(k\to\infty\) 的话,那么:
\[\begin{aligned} \lim_{k \to \infty} \frac{\partial}{\partial \theta} J^c_{NCE}(\theta) &=\lim_{k \to \infty} \sum_w{\left[\frac{q(w)}{ \frac{p_{\theta}(w|c)}{k}+q(w)} \left(\tilde{p}(w|c)- p_{\theta}(w|c)\right)\frac{\partial}{\partial \theta}log u_{\theta}(w,c)\right]} \\ &= \sum_w{\left[\left(\tilde{p}(w|c)- p_{\theta}(w|c)\right)\frac{\partial}{\partial \theta}log u_{\theta}(w,c)\right]} \end{aligned} \tag{24}\]
可以看到,当 \(k\) 趋于无穷时, (24) 式中 NCE 目标函数的梯度和 (9) 式中 MLE 对数似然函数梯度是等价的,也就是说我们通过 NCE 转换后的优化目标,本质上就是对极大似然估计方法的一种近似,并且随着负样本和正样本数量比 \(k\) 的增大,这种近似越精确,这也解释了为什么作者建议我们将 \(k\) 设置的越大越好。
从 NCE 到 InfoNCE
到目前为止,应该对 NCE 的来龙去脉比较清楚了
InfoNCE 是在 Representation Learning with Contrastive Predictive Coding 这篇论文中提出的,这里不会具体介绍 CPC ,而是着重说明如何借鉴 NCE 的思想提出 InfoNCE 并用于 CPC 中的
简单来说,CPC(对比预测编码) 就是一种通过无监督任务来学习(编码)高维数据的特征表示(representation),而通常采取的无监督策略就是根据上下文预测未来或者缺失的信息,NLP 中已经利用这种思想来学习 word 的 representation。
要构建这样的预测任务,一个方法是直接建模条件生成模型 \(p(x_{t+k}|c_t)\) 根据当前上下文 \(c_t\) 预测 \(k\) 个时刻后的数据 \(x_{t+k}\) (假设是像文本、语音中那样的序列数据);但作者觉得这样的方法过于针对细节进行重建,并不是很好,于是引入了互信息的思想,认为我们可以通过最大化当前上下文 \(c_t\) 和要未来的数据 \(x_{t+k}\) 之间的互信息来构建预测任务,互信息的表示如下:
\[\begin{aligned} I(x_{t+k} ; c_t)=\sum_{x, c} p(x_{t+k}, c_t) \log \frac{p(x_{t+k} \mid c_t)}{p(x_{t+k})} \end{aligned} \tag{25}\]
我们没办法知道 \(x_{t+k}\) 和 \(c_t\) 之间的联合分布 \(p(x_{t+k},c_t)\) ,因此要最大化 \(I(x_{t+k} ; c_t)\) ,就需要从 \(\frac{p(x_{t+k} \mid c_t)}{p(x_{t+k})}\) 入手,即最大化 \(\frac{p(x_{t+k} \mid c_t)}{p(x_{t+k})}\) 。
那么如何训练 \(\frac{p(x_{t+k} \mid c_t)}{p(x_{t+k})}\) 呢?我们可以把这个比例定义为密度比,那么根据附录 3中的思想,分子 \(p(x_{t+k}|c_t)\) 就相当于 \(p_d\) ,是我们想得到的目标函数;分母 \(p(x_{t+k})\) 就相当于 \(p_n\) ,是用来进行对比的参考分布(噪声)。因此,我们就可以根据 NCE 中提供的思路,将问题转换为一个二分类的问题,更具体来解释:
- 从条件 \(p(x_{t+k} \mid c_t)\) 中取出数据称为“正样本”,它是根据上下文 \(c_t\) 所做出的预测数据,将它和这个上下文一起组成“正样本对”,类别标签设为 1。
- 将从 \(p(x_{t+k})\) 中取出的样本称为“负样本”,它是与当前上下文 \(c_t\) 没有必然关系的随机数据,将它和这个上下文 \(c_t\) 一起组成“负样本对”,类别标签设为 0。
- 正样本也就是与 \(c_t\) 间隔固定步长 \(k\) 的数据,根据 NCE 中说明的设定,正样本选取 1 个;因为在 NCE 中证明了噪声分布与数据分布越接近越好,所以负样本就直接在当前序列中随机选取(只要不是那一个正样本就行),负样本数量越多越好。
所以要做的就是训练一个 logistics 分类模型,来区分这两个正负样本对。问题转换后,训练的模型能够“成功分辨出每个正负样本的能力”就等价于“根据 \(c_t\) 预测 \(x_{t+k}\) 的能力”。
根据 NCE 中的设置,现在假设给出一组大小为 \(N\) 的 \(X=\{x_1,\dots,x_N\}\) ,其中包含 \(1\) 个从 \(p(x_{t+k}|c_t)\) 中取样正样本和 \(N-1\) 从一个指定分布(用于对比的噪声分布) \(p(x_{t+k})\) ,假设第 \(x_i\) 是正样本,且 \(i=t+k\) ,上下文 \(c_t\) 表示 \(t\) 之前的数据,那么能够正确的同时找到那一个正样本 \(x_{t+k}\) 和 \(N-1\) 个负样本的情况可以写成如下形式:
\[\begin{aligned} p\left(d=i \mid X, c_{t}\right)&=p(x_{t+k}|c_t)\\ &=\frac{p\left(x_{t+k} \mid c_{t}\right) \prod_{l \neq t+k} p\left(x_{l}\right)}{\sum_{j=1}^{N} p\left(x_{j} \mid c_{t}\right) \prod_{l \neq j} p\left(x_{l}\right)} \\ &=\frac{\frac{p\left(x_{t+k} \mid c_{t}\right)}{p\left(x_{t+k}\right)}}{\sum_{j=1}^{N} \frac{p\left(x_{j} \mid c_{t}\right)}{p\left(x_{j}\right)}} \end{aligned} \tag{26}\]
我们最大化上面这个式子,即最大化模型“成功分辨出每个正负样本的能力”,也就是最大化我们定义的密度比,也就是最大化 \(c_t\) 与 \(x_{t+k}\) 的互信息。
参考 (5) 式,可以写出根据 \(c_t\) 预测 \(x_{t+k}\) 的形式:
\[\begin{aligned} p(x_{t+k}|c_t)&= \frac{exp(s_{\theta}(x_{t+k},c_t))}{\sum_{x_j \in X}exp(s_{\theta}(x_{j},c_t))} \\ \end{aligned} \tag{27}\]
在上式中,我们知道 \(s_{\theta}(x,c)\) 是一个 socring function ,输出的分数用来量化 \(x\) 在上下文 \(c\) 中匹配性;放在这里 \(s_{\theta}(x_{t+k},c_t)\) 也就是量化对 \(x_{t+k}\) 预测的结果和真实结果的相似程度,CPC 文章中用余弦相似度来量化,并且将 \(exp(s_{\theta}(x_{t+k},c_t))\) 定义为 \( f_k(x_{t+k},c_t)\) ,也就是:
\[\begin{aligned} p(x_{t+k}|c_t)&= \frac{f_k(x_{t+k},c_t)}{\sum_{x_j \in X}f_k(x_{j},c_t)} \\ \end{aligned} \tag{28}\]
现在对比 (26) (28)两个式子,这两个式子的目标是一致的,也就意味着 \(f_k(x_{t+k},c_t)\) 实际上就可以作为密度比 \(\frac{p(x_{t+k} \mid c_t)}{p(x_{t+k})}\) 的一种表示形式,它们之间虽不直接等价,但是含义上是正相关的,即:
\[\begin{aligned} f_k(x_{t+k},c_t)\propto\frac{p(x_{t+k}|c_t)}{p(x_{t+k})} \end{aligned} \tag{29}\]
现在我们的优化目标就是使 (26) 或 (28) 的结果最大,所以可以写出对应形式的交叉熵损失如下:
\[\begin{aligned} \mathcal{L}_{N}&=-\sum_{X}\left[p(x,c)\log \frac{f_{k}\left(x_{t+k}, c_{t}\right)}{\sum_{x_{j} \in X} f_{k}\left(x_{j}, c_{t}\right)}\right] \\ &=-\mathbb{E}_X\left[\log \frac{f_{k}\left(x_{t+k}, c_{t}\right)}{\sum_{x_{j} \in X} f_{k}\left(x_{j}, c_{t}\right)}\right] \\ \end{aligned} \tag{30}\]
上式就是最终得到的 InfoNCE 损失函数了,并且最小化 InfoNCE,也就等价于最大化 \(x_{t+k}\) 和 \(c_t\) 之间互信息的下限,从而做到了我们所要求的最大化 \(I\left(x_{t+k};c_{t}\right)\) ,证明如下,
\[\begin{aligned} \mathcal{L}_{\mathrm{N}}^{\mathrm{opt}} &=-\underset{X}{\mathbb{E}} \log \left[\frac{\frac{p\left(x_{t+k} \mid c_{t}\right)}{p\left(x_{t+k}\right)}}{\frac{p\left(x_{t+k} \mid c_{t}\right)}{p\left(x_{t+k}\right)}+\sum_{x_{j} \in X_{\mathrm{neg}}} \frac{p\left(x_{j} \mid c_{t}\right)}{p\left(x_{j}\right)}}\right] \\ &=\underset{X}{\mathbb{E}} \log \left[1+\frac{p\left(x_{t+k}\right)}{p\left(x_{t+k} \mid c_{t}\right)} \sum_{x_{j} \in X_{\mathrm{neg}}} \frac{p\left(x_{j} \mid c_{t}\right)}{p\left(x_{j}\right)}\right] \\ & \approx \underset{X}{\mathbb{E}} \log \left[1+\frac{p\left(x_{t+k}\right)}{p\left(x_{t+k} \mid c_{t}\right)}(N-1) \underset{x_{j}}{\mathbb{E}} \frac{p\left(x_{j} \mid c_{t}\right)}{p\left(x_{j}\right)}\right] \\ &=\underset{X}{\mathbb{E}} \log \left[1+\frac{p\left(x_{t+k}\right)}{p\left(x_{t+k} \mid c_{t}\right)}(N-1)\right] \\ & \geq \underset{X}{\mathbb{E}} \log \left[\frac{p\left(x_{t+k}\right)}{p\left(x_{t+k} \mid c_{t}\right)} N\right] \\ &=-I\left(x_{t+k}, c_{t}\right)+\log (N) \end{aligned} \tag{31}\]
到底为止,如何从由 NCE 结合互信息的思想构建 (30) 式中的 InfoNCE 也清楚了,现在 InfoNCE 主要用在自监督学习中作为一个对比损失函数,实际上 InfoNCE 的这个思想也是可以作为互信息的一个估计器,在论文中也有证明它和另一个互信息估计器 MINE 之间的关系,这里就不再详细说明了。
在使用 InfoNCE 时把它当作一个对比损失,那么分子上的 \( (x_{t+k},c_t)\) 表示正样本对, 分母上的\((x_j,c_t)\) 表示负样本对,我们只要构建好正负样本对,然后利用 InfoNCE 的优化过程,就可以做到使正样本对之间的互信息最大,使负样本对之间的互信息最小这件事情了:
\[\begin{aligned} \mathcal{L}_{N}^{InfoNCE} &=-\mathbb{E}_X\left[\log \frac{f_{k}\left(x_{t+k}, c_{t}\right)}{\sum_{x_{j} \in X} f_{k}\left(x_{j}, c_{t}\right)}\right] \\ \end{aligned} \tag{32}\]
后记
附录 1——NCE 要解决的问题
实际上NCE 要解决的是归一化参数密度估计问题。
假设现在有一组观测样本 \(X=\{x_1,x_2,\dots,x_n\}\) ,它遵循一个未知的参数化概率密度函数 \(p_d(.;\theta)\) ,参数密度估计问题就是根据观测样本 \(X\) 找到一组最优参数 \(\theta\) ,通常使用极大似然估计的方法。对于这个密度函数 \(p_m(.;\theta)\) 的估计还需要满足下面两个约束条件:
- \(\int p(x;\theta)dx=1\)
- \(p_m(.;\theta) ≥ 0\)
如果同时满足上面两个约束条件,那么称建模的密度函数是归一化的;如果只满足第 2 个正约束条件,那么称其未归一化。
语言模型中说的 \(Z(c)\) 在 NCE 实际上指的就是 partition function,这里用 \(Z(\theta)\) 表示,假设 \(p_m^0(.;\theta)\) 为估计的未归一化模型,则 \(Z(\theta)=\int p_m^0(x;\theta)dx\) ,而将模型归一化的方式就是: \(\frac{p_m^0(.;\theta)}{Z(\theta)}\) 。而对于 \(Z(\theta)\) ,除非 \(p_m^0(.;\theta)\) 的形式特别简单,否则是没办法写出积分的解析解形式的,只能通过数值积分的方法来近似。这种数值积分对于低维问题是有较高的精度的,但是对于实际应用中的很多高维问题,在计算上就是非常昂贵甚至不可接受的。
附录 2——将归一化常数作为参数
这里解释一下为什么可以将归一化常数作为一个附加的参数。
附录1中提到可以通过 \(\frac{p_m^0(.;\theta)}{Z(\theta)}\) 来对 \(p_m^0(.;\theta)\) 进行归一化,实际上可以看作对 \(p_m^0(.;\theta)\) 进行了一定的缩放,假设归一化后的密度函数为 \(p_m(.;\theta)\) ,则:
\[\begin{aligned} \log p_m(.;\theta) &= \log \frac{p_m^0(.;\theta)}{Z(\theta)}\\ &=\log p_m^0(.;\theta)-\log Z(c) \end{aligned}\]
因此我们可以把 \(\log Z(c)\) 当成一个参数 \(c\) ,也就是:
\[\begin{aligned} \log p_m(.;\theta) &=\log p_m^0(.;\theta)-c \end{aligned}\]
也就是学习一个参数 \(c\) ,来对未归一化的 \(p_m^0(.;\theta)\) 进行大小为 \(c\) 的缩放,最终达到归一化的效果。
附录 3——用噪声进行对比的直觉
这里解释一下用噪声的分布进行对比的直觉。
按照 Gutmann and Hyvrinen(2012)中的解释(如果真的想弄懂 NCE,强烈推荐阅读一下这篇论文),估计数据的密度函数 \(p(x)\) 实际上是确定观测数据 \(X\) 的属性,而这种属性一般需要相对于另一些参考数据(噪声) \(Y\) 的属性来体现(描述)出来的。如果我们参考(噪声)数据 \(Y\) 是从概率密度函数为 \(p_n\) 的分布中独立同分布采样出来的 ,\(X\) 相对于 \(Y\) 的属性用它们的密度比 \(p_d/p_n\) 来描述。那么如果相对数据 \(Y\) 的分布 \(p_n\) 已知,也就能通过 \(p_d/p_n\) 获得 \(X\) 的密度函数 \(p_d\) 。话句话说,如果我们知道 \(Y\) 的属性,也知道了 \(X\) 和 \(Y\) 之间的差异,那么我们也就知道了 \(X\) 的属性。
所以 NCE 中通过训练一个二分类器来对 \(X\) 和 \(Y\) 中的数据进行比较,为了区分出这两个数据,分类器就会比较它们属性的不同,换句话说,这个二分类也就学到了 \(X\) 和 \(Y\) 之间的差异,而这个差异根据 (14) (15)的推导,也确实符合 \(p_d/p_n\) 的形式的,实际上也就是训练了 logistic 分类器。
Reference
Noise Contrastive Estimation 前世今生——从 NCE 到 InfoNCE