word2vec作为神经概率语言模型的输入,其本身其实是神经概率模型的副产品,是为了通过神经网络学习某个语言模型而产生的中间结果。具体来说,“某个语言模型”指的是“CBOW”和“Skip-gram”。具体学习过程会用到两个降低复杂度的近似方法——Hierarchical Softmax或Negative Sampling。两个模型乘以两种方法,一共有四种实现。
一、获取样本
下图展示了如何从源文本获得训练样本:
有两个“问题”,常见的词是“ the”:
- 在查看单词对时,(“ fox”,“ the”)并不能告诉我们很多有关“ fox”的含义。“ the”出现在几乎每个单词的上下文中。
- 我们将有更多的(“ the”,…)样本,而不是需要学习一个“ the”的良好向量的样本。
Word2Vec实现了“subsampling”方案来解决此问题。对于我们在训练集中遇到的每个单词,都有可能有效地将其从文本中删除。我们删除单词的概率与单词的频率有关。
如果窗口大小为10,并且从文本中删除了“ the”的特定实例:
- 当我们训练其余单词时,“ the”将不会出现在它们的任何上下文窗口中。
- 我们将减少10个训练样本,其中“ the”是输入词。
请注意,这两种效果如何帮助解决上述两个问题。
1.Sampling rate
word2vec C代码实现了一个方程式,用于计算将给定单词保留在词汇表中的概率。 $w_i$是单词,$z(w_i)$是语料库中该单词占单词总数的比例。例如,如果单词“花生”在10亿个单词的语料库中出现了1000次,则$z(“花生”)= 1E-6$。代码中还有一个名为“ sample”的参数,用于控制发生多少次采样,默认值为0.001。较小的“样本”值表示保留单词的可能性较小。
$P(w_i) = (sqrt{frac{z(w_i)}{sample}} + 1) cdot frac{sample}{z(w_i)}$
任何单词都不应该占语料库的很大一部分,因此我们希望在x轴上查看很小的值。
Subsampling of frequent words 带点信息论的味道, 即最常使用的词, 能提供的信息量不如低频单词, 比如 France 与 Paris 的共用, 比 France 与 the 共用带来的信息量显然更大. 换个角度, 高频单词在多次迭代训练之后, 其向量不会再显著地改变.
对单词进行 subsampling, t 为阈值, f(wi) 为词频. 词频越高, 显然 P(wi) 就越大, 即高频单词会以更大的概率会剔除, 而词频小于 t 的单词则不会被剔除.
这是此函数中的一些有趣的要点(再次使用默认样本值0.001)。
- $P(w_i)=1.0,z(w_i)<=0.0026$,这意味着将仅对代表总单词的0.26%以上的单词进行子采样。
- $P(w_i)=0.5,z(w_i)=0.00746$(被保留的机会为50%)
- $P(w_i)=0.033,z(w_i)=1.0$(被保留的机会为3.3%)如果语料库完全由$w_i$一词组成,那当然是荒谬的。
代码实现:Word2Vec (skip-gram model): PART 2 — Implementation in TF0
二、CBOW
1.一个单词上下文
2.参数更新
3.多个单词上下文
三、Skip-gram
1.网络结构
2.参数更新
四、优化
原始的CBOW模型和Skip-Gram 模型的计算量太大,非常难以计算。
- 模型在计算网络输出的时候,需要计算误差 。对于CBOW 模型,需要计算V个误差(词汇表的大小),对于 Skip-Gram 模型,需要计算CV个误差。 另外,每个误差的计算需要用到 softmax 函数,该 softmax 函数涉及到O(V)复杂度的运算:$sum _{j=1} ^ V exp(u_j)$ 。
- 每次梯度更新都需要计算网络输出。 如果词汇表有 100万 单词,模型迭代 100 次,则计算量超过 1 亿次。
虽然输入向量的维度也很高,但是由于输入向量只有一位为 1,其它位均为 0,因此输入的总体计算复杂度较小。
word2vec 优化的主要思想是:限制输出单元的数量。
事实上在上百万的输出单元中,仅有少量的输出单元对于参数更新比较重要,大部分的输出单元对于参数更新没有贡献。
有两种优化策略:
- 通过分层softmax来高效计算softmax函数。
- 通过负采样来缩减输出单元的数量。
1.分层softmax
分层 softmax 是一种高效计算 softmax 函数的算法。 经过分层 softmax 之后,计算 softmax 函数的算法复杂度从O(V)降低到O(logV) ,但是仍然要计算V-1个内部节点的向量表达 。
(1)CBOW
(2)Skip-gram
2.负采样
在网络的输出层,真实的输出单词对应的输出单元作为正向单元,其它所有单词对应的输出单元为负向单元。
- 正向单元的数量为1,毋庸置疑,正向单元必须输出。
- 负向单元的数量为V-1,其中V为词表的大小,通常为上万甚至百万级别。如果计算所有负向单元的输出概率,则计算量非常庞大。可以从所有负向单元中随机采样一批负向单元,仅仅利用这批负向单元来更新。这称作负采样。
负采样的核心思想是:利用负采样后的输出分布来模拟真实的输出分布。
论文中指出对于较小的数据集,选择5到20个单词非常合适,而对于大型数据集,则只需选择2到5个单词。
$P(w_i) = frac{ f(w_i) }{sum_{j=0}^{n}left( f(w_j) ight) }$
$P(w_i) = frac{ {f(w_i)}^{3/4} }{sum_{j=0}^{n}left( {f(w_j)}^{3/4} ight) }$
该方程式倾向于增加不经常出现的单词的概率,而减少更频繁出现的单词的概率。
参考链接:
【1】word2vec原理(一) CBOW与Skip-Gram模型基础
【3】Hierarchical Softmax(层次Softmax) - 知乎
【4】词向量详解:从word2vec、glove、ELMo到BERT - 每日头条
【5】Word2Vec Tutorial Part 2 - Negative Sampling
【7】Word2Vec (skip-gram model): PART 2 — Implementation in TF0