# 近似训练
🏷 sec_approx_train
回想一下我们在 :numref: sec_word2vec
中的讨论。跳元模型的主要思想是使用 softmax 运算来计算基于给定的中心词wc 生成上下文字wo 的条件概率(如 :eqref: eq_skip-gram-softmax
),对应的对数损失在 :eqref: eq_skip-gram-log
给出。
由于 softmax 操作的性质,上下文词可以是词表V 中的任意项, :eqref: eq_skip-gram-log
包含与整个词表大小一样多的项的求和。因此, :eqref: eq_skip-gram-grad
中跳元模型的梯度计算和 :eqref: eq_cbow-gradient
中的连续词袋模型的梯度计算都包含求和。不幸的是,在一个词典上(通常有几十万或数百万个单词)求和的梯度的计算成本是巨大的!
为了降低上述计算复杂度,本节将介绍两种近似训练方法:负采样和分层 softmax。
由于跳元模型和连续词袋模型的相似性,我们将以跳元模型为例来描述这两种近似训练方法。
# 负采样
🏷 subsec_negative-sampling
负采样修改了原目标函数。给定中心词wc 的上下文窗口,任意上下文词wo 来自该上下文窗口的被认为是由下式建模概率的事件:
P(D=1∣wc,wo)=σ(uo⊤vc),
其中σ 使用了 sigmoid 激活函数的定义:
σ(x)=1+exp(−x)1.
:eqlabel: eq_sigma-f
让我们从最大化文本序列中所有这些事件的联合概率开始训练词嵌入。具体而言,给定长度为T 的文本序列,以w(t) 表示时间步t 的词,并使上下文窗口为m,考虑最大化联合概率:
t=1∏T−m≤j≤m, j=0∏P(D=1∣w(t),w(t+j)).
:eqlabel: eq-negative-sample-pos
然而, :eqref: eq-negative-sample-pos
只考虑那些正样本的事件。仅当所有词向量都等于无穷大时, :eqref: eq-negative-sample-pos
中的联合概率才最大化为 1。当然,这样的结果毫无意义。为了使目标函数更有意义,负采样添加从预定义分布中采样的负样本。
用S 表示上下文词wo 来自中心词wc 的上下文窗口的事件。对于这个涉及wo 的事件,从预定义分布P(w) 中采样K 个不是来自这个上下文窗口噪声词。用Nk 表示噪声词wk(k=1,…,K)不是来自wc 的上下文窗口的事件。假设正例和负例S,N1,…,NK 的这些事件是相互独立的。负采样将 :eqref: eq-negative-sample-pos
中的联合概率(仅涉及正例)重写为
t=1∏T−m≤j≤m, j=0∏P(w(t+j)∣w(t)),
通过事件S,N1,…,NK 近似条件概率:
P(w(t+j)∣w(t))=P(D=1∣w(t),w(t+j))k=1, wk∼P(w)∏KP(D=0∣w(t),wk).
:eqlabel: eq-negative-sample-conditional-prob
分别用it 和hk 表示词w(t) 和噪声词wk 在文本序列的时间步t 处的索引。 :eqref: eq-negative-sample-conditional-prob
中关于条件概率的对数损失为:
−logP(w(t+j)∣w(t))===−logP(D=1∣w(t),w(t+j))−k=1, wk∼P(w)∑KlogP(D=0∣w(t),wk)−logσ(uit+j⊤vit)−k=1, wk∼P(w)∑Klog(1−σ(uhk⊤vit))−logσ(uit+j⊤vit)−k=1, wk∼P(w)∑Klogσ(−uhk⊤vit).
我们可以看到,现在每个训练步的梯度计算成本与词表大小无关,而是线性依赖于K。当将超参数K 设置为较小的值时,在负采样的每个训练步处的梯度的计算成本较小。
# 层序 Softmax
作为另一种近似训练方法,层序 Softmax(hierarchical softmax)使用二叉树( :numref: fig_hi_softmax
中说明的数据结构),其中树的每个叶节点表示词表V 中的一个词。
![用于近似训练的分层softmax,其中树的每个叶节点表示词表中的一个词]()
🏷 fig_hi_softmax
用L(w) 表示二叉树中表示字w 的从根节点到叶节点的路径上的节点数(包括两端)。设n(w,j) 为该路径上的jth 节点,其上下文字向量为un(w,j)。例如, :numref: fig_hi_softmax
中的L(w3)=4。分层 softmax 将 :eqref: eq_skip-gram-softmax
中的条件概率近似为
P(wo∣wc)=j=1∏L(wo)−1σ([[n(wo,j+1)=leftChild(n(wo,j))]]⋅un(wo,j)⊤vc),
其中函数σ 在 :eqref: eq_sigma-f
中定义,leftChild(n) 是节点n 的左子节点:如果x 为真,[[x]]=1; 否则[[x]]=−1。
为了说明,让我们计算 :numref: fig_hi_softmax
中给定词wc 生成词w3 的条件概率。这需要wc 的词向量vc 和从根到w3 的路径( :numref: fig_hi_softmax
中加粗的路径)上的非叶节点向量之间的点积,该路径依次向左、向右和向左遍历:
P(w3∣wc)=σ(un(w3,1)⊤vc)⋅σ(−un(w3,2)⊤vc)⋅σ(un(w3,3)⊤vc).
由σ(x)+σ(−x)=1,它认为基于任意词wc 生成词表V 中所有词的条件概率总和为 1:
w∈V∑P(w∣wc)=1.
:eqlabel: eq_hi-softmax-sum-one
幸运的是,由于二叉树结构,L(wo)−1 大约与O(log2∣V∣) 是一个数量级。当词表大小V 很大时,与没有近似训练的相比,使用分层 softmax 的每个训练步的计算代价显著降低。
# 小结
- 负采样通过考虑相互独立的事件来构造损失函数,这些事件同时涉及正例和负例。训练的计算量与每一步的噪声词数成线性关系。
- 分层 softmax 使用二叉树中从根节点到叶节点的路径构造损失函数。训练的计算成本取决于词表大小的对数。
# 练习
- 如何在负采样中对噪声词进行采样?
- 验证 :eqref:
eq_hi-softmax-sum-one
是否有效。 - 如何分别使用负采样和分层 softmax 训练连续词袋模型?
Discussions