【深度学习-模型系列】word2vec

简介

单词在计算机看来只是个符号而已,如何让计算机理解词义?

为什么要学习word embedding

图像和音频处理系统使用丰富的高维数据集,这些数据集被编码为图像数据的单个原始像素强度的向量,或者音频数据的功率谱密度系数。
对于物体或语音识别这一类的任务,我们所需的全部信息已经都存储在原始数据中(显然人类本身就是依赖原始数据进行日常的物体或语音识别的)。

然而,NLP通常将单词视为离散的原子符号(atomic symbol),因此“cat”可以表示为Id537,“dog”表示为Id143。这些编码是任意的,并且没有为系统提供关于个别符号之间可能存在的关系的有用信息。这意味着,当该模型处理有关“狗”的数据(比如它们既是动物、四条腿的、宠物等)时,它对“猫”的了解很少。将单词表示为惟一的、离散的id会导致数据稀疏,这通常意味着我们可能需要更多的数据来成功地训练统计模型。使用向量表示可以克服其中一些障碍。

向量空间模型(VSMs)表示连续向量空间中的词(嵌入),其中语义相似的词映射到附近的点(“彼此嵌入在一起”)。VSMs在NLP领域有着悠久而丰富的历史,但所有的方法都以某种方式依赖于分布假设,即出现在相同上下文中的单词具有相同的语义。利用这一原理的不同方法可以分为两类:

  • 基于计数的方法
    • 基于计数的方法计算某个单词与相邻单词在大型文本语料库中共存的频率的统计数据,然后将这些统计数据映射到每个单词的一个小而密集的向量。
    • 即对one-hot的降维
    • 如潜在语义分析、LDA、PCA,等传统降维方法
      • lda中的p(w|z)跟softmax什么关系?
  • 基于预测的方法(如神经概率语言模型)
    • 预测模型直接尝试根据学习到的小而密集的嵌入向量(考虑到模型的参数)来预测邻居的单词

以上参考tensorflow tutorial

简而言之,就是one-hot编码不能体现语义,单词间相似度是0

embedding可以看成sparse one-hot的降维,也可以看成id的升维。我觉得视为前者更好。

分布式假设

词向量的模型和求解都是基于同一种假设,Distributional Hypothesis (D.H.) (Harris, 1954):
“words are characterised by the company that they keep”

基于以上假设可以得出,上下文相似的词所表达的词义也是相似的

D.H. : the meaning of “cat” is captured by the probability
distribution P(|cat).

word2vec只是利用分布式假设的方法之一。

word2vec的起源

word2vec builds on existing research
architecture is essentially that of Minh and Hinton’s log-bilinear
model
change of focus: vectorization, not language modelling.

模型

skipgram VS cbow

字面意思呢?

  • skipgram: 重在skip这个词,并非连续的,而是跳跃的(predict the target using a random close‑by word)
  • cbow: continuous‑bag‑of‑words,重在continuous

优化目标

分类。词典大小是N,那么就是N分类。

弊端:

  • 【策略一】转化为二叉树,多个二分类。即Hierarchical Softmax
  • 【策略二】直接视为二分类:中心词w和context(w)相关,是正例,其他word都是负例
    • 负例太多,所以采用Negative Sampling

FS、 HS、 NCE

full softmax

神经网络语言模型通常采用极大似然估计(MLE)的方式,会采用softmax来计算$P(w_t | h) $。

$$\begin{align}
P(w_t | h) &= \text{softmax} (\text{score} (w_t, h)) \
&= \frac{\exp { \text{score} (w_t, h) } }
{\sum_\text{Word w’ in Vocab} \exp { \text{score} (w’, h) } }
\end{align}$$

其中$\text{score} (w_t, h)$

log似然,要最大化以下的函数
$$\begin{align}
J_\text{ML} &= \log P(w_t | h) \
&= \text{score} (w_t, h) -
\log \left( \sum_\text{Word w’ in Vocab} \exp { \text{score} (w’, h) } \right).
\end{align}$$

但是这里的第二项(full probabilistic model)计算量较大。

在word2vec,并不需要计算full probabilistic model。
CBOW and skip-gram 是采用二分类

$$J_\text{NEG} = \log Q_\theta(D=1 |w_t, h) +
k \mathop{\mathbb{E}}{\tilde w \sim P\text{noise}}
\left[ \log Q_\theta(D = 0 |\tilde w, h) \right]$$

HS

1
2
3
4
5
// 默认采用cbow模型
cbow = 1;

// 默认不用`Hierarchical Softmax`
int hs = 0, negative = 5;

Use Hierarchical Softmax; default is 0 (not used)

为什么层次 SoftMax 能加速?

  • Softmax 大部分的计算量在于分母部分,它需要求出所有分量的和
  • 而层次 SoftMax 每次只需要计算两个分量,因此极大的提升了速度

NCE

Noise-Contrastive Training

Negative Sampling

层次 Softmax 还不够简单,于是提出了基于负采样的方法进一步提升性能
负采样(Negative Sampling)是 NCE(Noise Contrastive Estimation) 的简化版本

比如我们有一个训练样本,中心词是w,它周围上下文共有2c个词,记为context(w)。由于这个中心词w,的确和context(w)相关存在,因此它是一个真实的正例。通过Negative Sampling采样,我们得到neg个和w不同的中心词wi,i=1,2,..neg,这样context(w)和$$w_i$就组成了neg个并不真实存在的负例。利用这一个正例和neg个负例,我们进行二元逻辑回归,得到负采样对应每个词$w_i$对应的模型参数$\theta_{i}$,和每个词的词向量。

Negative Sampling由于没有采用霍夫曼树,每次只是通过采样neg个不同的中心词做负例,就可以训练模型,因此整个过程要比Hierarchical Softmax简单。

Negative Sampling可否也用霍夫曼树?貌似还真不能?HS和NS貌似是冲突的。

负采样算法 - Negative Sampling

assigns high probabilities to the real words, and low probabilities to noise words

计算复杂度大大减小(注意分母,也就是log的第二项)。

scales only with the number of noise words that we select (k), and not all words in the vocabulary (V).

损失函数采用noise-contrastive estimation (NCE) loss tf.nn.nce_loss()

  • 负采样算法,即对给定的 w ,生成相应负样本的方法
  • 最简单的方法是随机采样,但这会产生一点问题,词表中的词出现频率并不相同
    • 如果不是从词表中采样,而是从语料中采样;显然,那些高频词被选为负样本的概率要大于低频词
    • 在词表中采样时也应该遵循这个
  • 因此,负采样算法实际上就是一个带权采样过程

这里还有很多细节,参考imhuay的github

一些源码细节

σ(x) 的近似计算,类似带权采样的策略,用查表来代替计算。

具体计算公式如下

$$\sigma(x)=\left {\begin{array}{ll} 0, &x<-6 \\="" \sigma(x_k),="" &x\in="" [-6,6]="" 1,="" &x="">6 \end{array}\right.$$

因为 σ(x) 函数的饱和性,当 x < -6 || x > 6 时,函数值基本不变了

低频词的处理

对于低频词,会设置阈值(默认 5),对于出现频次低于该阈值的词会直接舍弃,同时训练集中也会被删除

高频词的处理

  • 高频词提供的信息相对较少,为了提高低频词的词向量质量,有必要对高频词进行限制
  • 高频词对应的词向量在训练时,不会发生明显的变化,因此在训练是可以减少对这些词的训练,从而提升速度

Sub-sampling 技巧

  • 源码中使用 Sub-sampling 技巧来解决高频词的问题,能带来 2~10 倍的训练速度提升,同时提高低频词的词向量精度
  • 给定一个词频阈值 t,将 w 以 p(w) 的概率舍弃,p(w) 的计算如下

$$\begin{aligned} &p(w)=1-\sqrt\frac{t}{\mathrm{len}(w)}\ \text{where}\quad\ &\mathrm{len}(w)=\frac{\mathrm{count}(w)}{\sum_{u\in V}\mathrm{count}(u)} \end{aligned}$$

Word2Vec 中的Sub-sampling

  • 显然,Sub-Sampling 只会针对 出现频次大于 t 的词
  • 特别的,Word2Vec 使用如下公式计算 p(w),效果是类似的

$$p(w)=1-\left ( \sqrt\frac{t}{\mathrm{len}(w)} + \frac{t}{\mathrm{len}(w)} \right )$$

自适应学习率

  • 预先设置一个初始的学习率 η_0(默认 0.025),每处理完 M(默认 10000)个词,就根据以下公式调整学习率
  • 随着训练的进行,学习率会主键减小,并趋向于 0
  • 为了方式学习率过小,Word2Vec 设置了一个阈值 η_min(默认 0.0001 * η_0);当学习率小于 η_min,则固定为 η_min。

参数初始化

  • 词向量服从均匀分布 [-0.5/m, 0.5/m],其中 m 为词向量的维度
  • 所有网络参数初始化为 0

word2vec的不足

  • 基于上文的分布式假设,会出现“好”和“不好”相似度很高(因为这两个词的上下文大部份都是一样的)
    • “好”和”不好”更多的是相似,差异的细微的,人们认为它们是反义词。word2vec认为它俩相近是正常的,反而人是不客观的。
    • 要想学出它俩的区别来,需要用到情感分类的标签
  • HS树的构建
    • 采用的是平衡二叉树。n叉树呢?
      • 二叉树,是较多二分类,不适宜GPU。所以word2vec的相关代码都是采用的cpu,(google官方源码、fastText、gensim)
    • 树的深度,霍夫曼的最优性?
  • NCE的采样数目
    • 可以同时采样多个负样本,这样就适合GPU了吧?
  • 长依赖?需要这个东西吗?
  • 多义词
    • 每个词学多个vector(word2tensor): Improving Word Representations via Global Context and Multiple Word Prototypes; A Scalable Probabilistic Model for Learning Multi-Prototype Word Embeddings
  • oov

FAQ

  • Is “embedding” an action or a thing? Both
    • embedding words in a vector space (action)
    • producing word embeddings (things).
  • 为什么层次 SoftMax 能加速?
  • 为什么叫CBOW( Continuous Bag-Of-Words,即连续的词袋模型) 和 Skip-Gram?

参考

live demo

https://demo.eson.org/projector

TODO:扩展demo

  • word2vec的可视化
    • 给定word1 出word2
    • 显示vector向量
    • 一个word与一组word的相似度。用attention可视化。
    • 向量计算,比如king - man + woman = queen