自然语言处理学习笔记

学习笔记-word2vec

2020-04-23  本文已影响0人  Pluto_wl

在nlp的世界里,词向量占据了重要的位置,它分布式的表示了单词的语义信息,大幅度的提升了下游任务的效果。

Word2vec根据预测词的方式包括两种模型,skip gram是使用中心词预测上下文词,Cbow是使用上下文词预测中心词。

skip-gram

skip-gram的主要是通过中心词来预测上下文。下图是skip-gram的模型结构图。

skip-gram 假设有句子窗口大小设置为2,选取第t个词作为中心词,那么上下文词有。
其输入格式是将中心词与每一个上下文词结合,作为输入,上下文词作为目标,

skip-gram模型的目标是最大化中心词的上下文词的概率,即\text{maxmize} \ p(w_{t-2}|w_t)p(w_{t-1}|w_t)p(w_{t+1}|w_t)p(w_{t+2}|w_t) \tag 1
w_o表示上下文词,w_i表示中心词,那么概率由中心词预测上下文词的概率如下表示:p(w_o|w_i)=\frac{e^{U_o \cdot V_i}}{\sum_j{e^{U_j \cdot V_i}}} \tag 2
注意U和V的两种理解方式

  1. 论文V_i表示Embedding层矩阵里的词向量,也被称为w_i的input vector。U_j是softmax层矩阵里的行向量,也被称为w_i的output vector。
  2. 在代码实现中,有两个Embedding矩阵,分别是表示中心词的矩阵V和表示上下文词的矩阵U,很好理解为什么要分为两个矩阵,因为上下文词和中心词的作用肯定是不同,所以学习出来的矩阵也是不同的。

现在得到了输入向量V_i和输出向量U_o,使用两个向量的内积U_o \cdot V_i作为V_iU_o的相似度,可以这样理解,距离越近的词,所表示的意思越相近,所以相似度就会越高。
分母是将词表中所有词的输出向量U_j与输入向量V_i做内积,为什么调用所有词呢?理由是每次预测时候可能是词表中的任何一个词,所以要计算输入词向量与所有词的相似度。
最后使用softmax作为其概率。

Cbow

Cbow与skip-gram相反,它是根据上下文词预测中心词,模型结构如下图所示


cbow

它将上下文词当作输入,经过embedding层后将上下文词的向量加和取平均,然后再经过softmax来预测中心词

优化

我们可以看到上述的词向量模型直接对词典里的V个词计算相似度并归一化,显然是会花费大量时间。为了解决这个问题,提出了层次Softmax(Hierarchical Softmax)和负采样(Negative Sampling)两种优化方式。

层次softmax

层次softmax是将最后一层的softmax转变为一棵哈夫曼树,将计算softmax时间复杂度从词表大小|vocab|降到log|vocav|
具体的,首先根据词频建立哈夫曼树,叶子结点为单词。所有内部节点就类似之前神经网络隐藏层的神经元,其中,根节点的词向量对应我们的投影后的词向量,而所有叶子节点就类似于之前神经网络softmax输出层的神经元,叶子节点的个数就是词汇表的大小。在哈夫曼树中,隐藏层到输出层的softmax映射不是一下子完成的,而是沿着哈夫曼树一步步完成的,因此这种softmax取名为"Hierarchical Softmax",,此外,哈夫曼树的每一个内部结点都包含一个参数向量\theta,它与经过embedding得到的向量共同决定当前走哪一个方向。

下面这段话来自于参考问下[2]
为了便于我们后面一般化的描述,我们定义输入的词为w,其从输入层词向量求和平均后的哈夫曼树根节点词向量为x_w, 从根节点到w所在的叶子节点,包含的节点总数为l_w,w在哈夫曼树中从根节点开始,经过的第i个节点表示为p_{w_i},对应的哈夫曼编码为d_{w_i}\in { 0,1},其中i=2,3,...l_w。而该节点对应的模型参数表示为θ_{w_i}, 其中i=1,2,...l_{w−1},没有i=l_w是因为模型参数仅仅针对于哈夫曼树的内部节点。
定义w经过的哈夫曼树某一个节点j的逻辑回归概率为P(d_j^w|x_w, \theta_{j-1}^w),其表达式为:
P(d_j^w|x_w, \theta_{j-1}^w)= \begin{cases} \sigma(x_w^T\theta_{j-1}^w)& {d_j^w=0}\\ 1- \sigma(x_w^T\theta_{j-1}^w) & {d_j^w = 1} \end{cases} \tag 5
那么对于某一个目标输出词w,其最大似然为:
\prod_{j=2}^{l_w}P(d_j^w|x_w, \theta_{j-1}^w) = \prod_{j=2}^{l_w} [\sigma(x_w^T\theta_{j-1}^w)] ^{1-d_j^w}[1-\sigma(x_w^T\theta_{j-1}^w)]^{d_j^w} \tag 6
在word2vec中,由于使用的是随机梯度上升法,所以并没有把所有样本的似然乘起来得到真正的训练集最大似然,仅仅每次只用一个样本更新梯度,这样做的目的是减少梯度计算量。这样我们可以得到w的对数似然函数L如下:
L= log \prod_{j=2}^{l_w}P(d_j^w|x_w, \theta_{j-1}^w) = \sum\limits_{j=2}^{l_w} ((1-d_j^w) log [\sigma(x_w^T\theta_{j-1}^w)] + d_j^w log[1-\sigma(x_w^T\theta_{j-1}^w)]) \tag 7
最后对公式(7)求导,使用梯度下降法更新参数

  1. 使用哈夫曼树可以将时间复杂度降低到log|V|
  2. 哈夫曼树使高频词更靠近根结点,那么检索到高频词的时间就会大大缩短
  1. 对于低频词会导致路径过长

负采样

负采样计算

负采样是word2vec中一个重要的加速计算方式,具体是思路是有中心词w,那么其上下文词就是正样本,其他词就是负样本。选取负样本的过程叫做负采样。
设有\text{neg}个负样本,使用w_0表示正样本,w_1, w_2, ..., w_{neg}表示负样本,w_i表示中心词。
那么正样本的概率为p(w_0|w_i)=\sigma(w_0^Tw_i),y=1 \tag{8}
负样本的概率为p(w_j|w_i)=1-\sigma(w_j^T w_i),y=0,j=1,2,..neg \tag{9}
所以将公式(8)和公式(9)整合到一起后,可改写为
p(w_j|w_i)=\sigma(w_j|w_i)^{y_j} [1-sigma(w_j|w_i)]^{1-y_j},j=0,1,..,neg,y=\{0,1\} \tag{10}
知道了如何表示概率,那么损失函数可写为
L = \prod_{i=0}^{neg} \sigma(x_{w_0}^T\theta^{w_i})^{y_i}(1- \sigma(x_{w_0}^T\theta^{w_i}))^{1-y_i} \tag{11}
使用对数似函数
L = \sum\limits_{i=0}^{neg}y_i log(\sigma(x_{w_0}^T\theta^{w_i})) + (1-y_i) log(1- \sigma(x_{w_0}^T\theta^{w_i})) \tag{12}

负采样方式

通常的采样方式是这样的,词表大小为|V|,那么将长度为1的线段按照词频概率划分为不等长的|V|段。即每段的长度由以下公式决定:len(w) = \frac{count(w)}{\sum\limits_{u \in vocab} count(u)} \tag{13}

但在word2vec中,对每个单词的频率去了\frac{3}{4}次幂,即每段的长度变为了
len(w) = \frac{count(w)^{3/4}}{\sum\limits_{u \in vocab} count(u)^{3/4}} \tag{14}
但在采样前,先将线段划分为M个等长线段,此时M>>|V|,这样可以保证每个词对应的线段都会划分成对应的小块。而M份中的每一份都会落在某一个词对应的线段上。在采样的时候,我们只需要从M个位置中采样出neg个位置就行,此时采样到的每一个位置对应到的线段所属的词就是我们的负例词。下图展示了划分后的效果

word2vec参数详解

论文:word2vec Parameter Learning Explained
参考:https://blog.csdn.net/lanyu_01/article/details/80097350

参考文献

  1. https://www.cnblogs.com/guoyaohua/p/9240336.html (推荐)
  2. https://www.cnblogs.com/pinard/p/7243513.html (推荐)
  3. https://blog.csdn.net/itplus/article/details/37969979 (推荐)
上一篇下一篇

猜你喜欢

热点阅读