Word2Vec

1. Word2Vec 工具

定义:

  • \(\mathcal{V}\) :词表(dictionary)索引集合

    • \(V=|\mathcal{V}|\) 表示词表数量

    • 一般来说,语料(corpus)中在词典以外的词会被过滤掉(即删除)。一般用停词(stop word)来过滤

  • \(w_c\) :中心词(词典中的索引 \(c\)

    • 一般为单词的 one-hot 向量
  • \(w_o\) :生成的上下文词(词典中的索引 \(o\)

  • \(\boldsymbol{u}_c\) :中心词(center word)向量

  • \(\boldsymbol{v}_o\) :上下文词(context word)向量

    • 注意: 在训练中,一个词有两个词向量,上下文词向量和中心词向量,它们一般不同
  • \(m\) :上下文词窗口范围

  • \(T\) :文档长度

1.1 跳元模型(Skip-Gram)模型

1.1.1 Skip-Gram 的网络结构

  • 输入层\(\boldsymbol{x} \in \mathbb{R}^{1 \times V}\) 为 one-hot 的词向量(定义为行向量),其中 \(V\)

  • 隐藏层\(\boldsymbol{h} \in \mathbb{R}^{1 \times N}\) 为中心词向量 \(\boldsymbol{u}_c\),就是 word embedding 的结果,其中 \(N\) 表示 word embedding 的维度

    • 隐藏层训练参数为 \(\mathbf{W}_1 \in \mathbb{R}^{V \times N}\)

    • 即:\(\boldsymbol{u} = \boldsymbol{h} = \boldsymbol{x} \mathbf{W}_1\)

  • 输出层\(\boldsymbol{y} \in \mathbb{R}^{1 \times V}\),为 one-hot 向量,上下文词的词向量

    • 训练参数为:\(\mathbf{W}_2 \in \mathbb{R}^{N \times V}\)

      • 每一列向量可以表示为上下文词向量,\(\boldsymbol{v}_i = \mathbf{W}_2[:, i] \in \mathbb{R}^{1 \times N}\)
    • 即:\(\boldsymbol{y} = \boldsymbol{h} \mathbf{W}_2\)

    • 可以通过 softmax 函数激活,计算出现上下文词的概率

1.1.2 Skip-Gram 模型

给定中心词 \(w_c\),生成任何上下文词 \(w_o\) 的条件概率为

\[\Pr(w_o \mid w_c) = \frac{ \exp(\boldsymbol{u}_o^\top \boldsymbol{v}_c) }{ \sum \limits_{i \in \mathcal{V}} \exp(\boldsymbol{u}_i^\top \boldsymbol{v}_c) } \]

对于给定的上下文窗口 \(m\),跳元模型的似然函数是在给定任何中心词的情况下生成所有上下文词的概率:

\[\begin{aligned} & \prod_{t=1}^{T} \Pr(w^{(t-m)} \mid w^{(t)}) \Pr(w^{(t-m+1)} \mid w^{(t)}) \cdots \Pr(w^{(t-1)} \mid w^{(t)}) \Pr(w^{(t+1)} \mid w^{(t)}) \cdots \Pr(w^{(t+m-1)} \mid w^{(t)}) \Pr(w^{(t+m)} \mid w^{(t)}) \\ &= \prod_{t=1}^{T} \prod_{-m \leq j \leq m,\ j \neq 0} \Pr(w^{(t+j)} \mid w^{(t)}) \end{aligned} \]

在训练中,我们通过最大化似然函数(即极大似然估计)来学习模型参数。这相当于最小化以下损失函数(负对数似然函数):

\[- \sum_{t=1}^{T} \sum_{-m \leq j \leq m,\ j \neq 0} \ln \Pr (w^{(t+j)} \mid w^{(t)}). \]

涉及中心词 \(w_c\) 和上下文词 \(w_o\) 的对数条件概率为:

\[\ln \Pr(w_o \mid w_c) = \boldsymbol{u}_o^\top \boldsymbol{v}_c - \ln \left[\sum_{i \in \mathcal{V}} \exp(\boldsymbol{u}_i^\top \boldsymbol{v}_c)\right] \]

通过微分,我们可以获得其相对于中心词向量 \(\boldsymbol{v}_c\) 的梯度为

\[\begin{split} \frac{\partial \log \Pr(w_o \mid w_c)}{\partial \boldsymbol{v}_c} &= \boldsymbol{u}_o - \frac{\sum_{j \in \mathcal{V}} \exp(\mathbf{u}_j^\top \boldsymbol{v}_c)\boldsymbol{u}_j}{\sum_{i \in \mathcal{V}} \exp(\boldsymbol{u}_i^\top \boldsymbol{v}_c)} \\ &= \boldsymbol{u}_o - \sum_{j \in \mathcal{V}} \left[\frac{\text{exp}(\boldsymbol{u}_j^\top \boldsymbol{v}_c)}{ \sum_{i \in \mathcal{V}} \text{exp}(\boldsymbol{u}_i^\top \boldsymbol{v}_c)}\right] \boldsymbol{u}_j \\ &= \boldsymbol{u}_o - \sum_{j \in \mathcal{V}} \Pr(w_j \mid w_c) \boldsymbol{u}_j \end{split} \]

1.2 连续词袋(Continuous Bag of Words,CBOW)模型

由于连续词袋模型中存在多个上下文词,因此在计算条件概率时对这些上下文词向量进行平均。给定上下文词\(w_{o_1}, \ldots, w_{o_{2m}}\) (共 \(2m\) 个,中心词前后各 \(m\) 个) 生成任意中心词 \(w_c\) 的条件概率为:

\[\Pr(w_c \mid w_{o_1}, \ldots, w_{o_{2m}}) = \frac{ \exp\left[\dfrac{1}{2m}\boldsymbol{u}_c^\top (\boldsymbol{v}_{o_1} + \ldots, + \boldsymbol{v}_{o_{2m}}) \right] }{ \sum \limits_{i \in \mathcal{V}} \exp \left[\dfrac{1}{2m}\boldsymbol{u}_i^\top (\boldsymbol{v}_{o_1} + \ldots, + \boldsymbol{v}_{o_{2m}}) \right] } \]

定义 \(\boldsymbol{W}_o= \{w_{o_1}, \ldots, w_{o_{2m}} \}\) 以及 \(\bar{\boldsymbol{v}}_o = \left(\boldsymbol{v}_{o_1} + \ldots, + \boldsymbol{v}_{o_{2m}} \right)/(2m)\),则上式可以简化为:

\[\Pr(w_c \mid \boldsymbol{W}_o) = \frac{\exp\left(\boldsymbol{u}_c^\top \bar{\boldsymbol{v}}_o\right)}{\sum \limits_{i \in \mathcal{V}} \exp\left(\boldsymbol{u}_i^\top \bar{\boldsymbol{v}}_o\right)} \]

给定长度为 \(T\) 的文本序列,其中时间步 \(t\) 处的词表示为 \(w^{(t)}\)。对于上下文窗口 \(m\),连续词袋模型的似然函数是在给定其上下文词的情况下生成所有中心词的概率:

\[\prod_{t=1}^{T} \Pr(w^{(t)} \mid w^{(t-m)}, \ldots, w^{(t-1)}, w^{(t+1)}, \ldots, w^{(t+m)}) \]

连续词袋模型的最大似然估计等价于最小化以下损失函数:

\[-\sum_{t=1}^T \ln \Pr(w^{(t)} \mid w^{(t-m)}, \ldots, w^{(t-1)}, w^{(t+1)}, \ldots, w^{(t+m)}) \]

请注意,

\[\ln \Pr(w_c \mid \boldsymbol{W}_o) = \boldsymbol{u}_c^\top \bar{\boldsymbol{v}}_o - \ln \left[\sum_{i \in \mathcal{V}} \exp \left(\boldsymbol{u}_i^\top \bar{\boldsymbol{v}}_o\right)\right] \]

通过微分,我们可以获得其关于任意上下文词向量 \(\boldsymbol{v}_o \, (i = 1, \ldots, 2m)\) 的梯度,如下:

\[\frac{\partial \log\, P(w_c \mid \boldsymbol{W}_o) }{\partial \boldsymbol{v}_{o_i}} = \frac{1}{2m} \left[\boldsymbol{u}_c - \sum_{j \in \mathcal{V}} \frac{\exp(\boldsymbol{u}_j^\top \bar{\boldsymbol{v}}_o) \boldsymbol{u}_j }{ \sum \limits_{i \in \mathcal{V}} \exp(\boldsymbol{u}_i^\top \bar{\boldsymbol{v}}_o)} \right] = \frac{1}{2m} \left[\boldsymbol{u}_c - \sum_{j \in \mathcal{V}} \Pr(w_j \mid \boldsymbol{W}_o) \, \boldsymbol{u}_j \right] \]

可以看出计算复杂度为 \(\mathcal{O}(|\mathcal{V}|)\)

1.3 近似训练

1.3.1 负采样

定义:

  • \(w_k, k=1,2,\cdots,K\)\(K\) 预定义的个噪声词

  • \(\Pr_N(w)\)噪声词分布,为预定义的概率分布函数

  • \(S\):表示上下文词 \(w_o\) 来自中心词 \(w_c\) 的上下文窗口的事件

  • \(N_k\):噪声词 \(w_k\) 不是来自上下文窗口 \(w_c\) 的事件

  • 假设事件 \(S, N_1, \ldots, N_K\) 之间相互独立

负采样修改了原目标函数。给定中心词 \(w_c\) 的上下文窗口,任意上下文词 \(w_o\) 来自该上下文窗口的被认为是由下式建模概率的事件:

\[\Pr(D=1\mid w_c, w_o) = \sigma(\boldsymbol{u}_o^\top \boldsymbol{v}_c) = \frac{1}{1+\exp \left(-\boldsymbol{u}_o^\top \boldsymbol{v}_c \right)} \]

其中,\(\sigma(\cdot)\)为 sigmoid 激活函数。因此,对于给定长度为的文本序列 \(T\),用 \(w^{(t)}\) 表示时间步 \(t\) 的中心词,并设上下文窗口为 \(m\),考虑最大化联合概率:

\[\prod_{t=1}^{T} \prod_{-m \leq j \leq m,\ j \neq 0} \Pr(D=1\mid w^{(t)}, w^{(t+j)}) \]

负采样将上述的联合概率(仅涉及正例)重写为:

\[\prod_{t=1}^{T} \prod_{-m \leq j \leq m,\ j \neq 0} \Pr(w^{(t+j)} \mid w^{(t)}) \]

并通过事件 \(S, N_1, \ldots, N_K\) 近似条件概率:

\[\Pr(w^{(t+j)} \mid w^{(t)}) = \Pr(D=1\mid w^{(t)}, w^{(t+j)}) \prod_{k=1,\ w_k \sim \Pr_w(w)}^K \Pr(D=0\mid w^{(t)}, w_k). \]

则条件概率的对数损失为:

\[\begin{split} -\ln \Pr(w^{(t+j)} \mid w^{(t)}) =& -\ln \Pr(D=1\mid w^{(t)}, w^{(t+j)}) - \sum_{k=1,\ w_k \sim \Pr_N(w)}^K \ln \Pr(D=0\mid w^{(t)}, w_k) \\ =&-\ln \sigma\left(\boldsymbol{u}_{i_{t+j}}^\top \boldsymbol{v}_{i_t}\right) - \sum_{k=1,\ w_k \sim \Pr_N(w)}^K \ln \left[1-\sigma\left(\boldsymbol{u}_{h_k}^\top \boldsymbol{v}_{i_t}\right)\right] \\ =&-\ln \sigma\left(\boldsymbol{u}_{i_{t+j}}^\top \boldsymbol{v}_{i_t}\right) - \sum_{k=1,\ w_k \sim \Pr_N(w)}^K \ln \sigma\left(-\boldsymbol{u}_{h_k}^\top \boldsymbol{v}_{i_t}\right) \end{split} \]

可以看出计算复杂度从 \(\mathcal{O}(|\mathcal{V}|)\) 降低到 \(\mathcal{O}(K)\)

1.3.2 层序 Softmax (hierarchical softmax)

定义:

  • \(L(w)\):表示二叉树中表示字的从根节点到叶节点的路径上的节点数(包括两端)
  • \(n(w,j)\) 为该路径上的 \(j\text{ th}\) 节点
  • \(\boldsymbol{u}_{n(w, j)}\) 为节点 \(n(w,j)\) 的上下文字向量

层序 Softmax 使用二叉树,其中树的每个叶节点表示词表 \(\mathcal{V}\) 中的一个词 \(w_i\)。分层softmax将条件概率近似为:

\[\Pr(w_o \mid w_c) = \prod_{j=1}^{L(w_o)-1} \sigma \left[ [\![ n(w_o, j+1) = \text{leftChild} \left(n(w_o, j) \right) ]\!] \cdot \boldsymbol{u}_{n(w_o, j)}^\top \boldsymbol{v}_c \right] \]

其中,\(\text{leftChild}(n)\) 表示节点 \(n\) 的左子节点;\([\![ x ]\!]\) 函数表示:如果为 \(x\) 真,则 \([\![ x ]\!]=1\);否则,\([\![ x ]\!]=-1\)

如:在图14.2.1 中,给定中心词 \(w_c\) 生成词 \(w_3\)的条件概率。这需要 \(w_c\) 的词向量 \(\boldsymbol{v}_c\) 和从根到 \(w_3\) 的路径上的非叶节点向量之间的点积,该路径依次向左、向右和向左遍历:

\[\Pr(w_3 \mid w_c) = \sigma \left( \boldsymbol{u}_{n(w_3, 1)}^\top \boldsymbol{v}_c \right) \cdot \sigma \left(-\boldsymbol{u}_{n(w_3, 2)}^\top \boldsymbol{v}_c \right) \cdot \sigma \left(\boldsymbol{u}_{n(w_3, 3)}^\top \boldsymbol{v}_c \right) \]

\(\sigma(x)+\sigma(-x)=1\),它认为基于任意词 \(w_c\) 生成词表 \(\mathcal{V}\) 中所有词的条件概率总和为1:

\[\sum_{w \in \mathcal{V}} \Pr(w \mid w_c) = 1 \]

可以看出训练发复杂度约为 \(\mathcal{O}(\text{log}_2|\mathcal{V}|)\)

2. pytorch 实现

2.1 Embedding 层

Embedding 层将词编码(注意是类别编码,不是 one-hot 编码)转化为密集(Dense)向量

  • 主要参数:

    • num_embeddings:int 类型;词典大小
    • embedding_dim:int 类型;Embedding 向量的维度
    • padding_idx: 词典中用于 padding 的词的索引,padding 词的 Embedding 向量始终被设为 0,并且不会被训练
    • max_norm:float 类型;对于 Embedding 向量,若其范数(norm)超过 max_norm 值,则该向量会被规则化到 max_norm 值
    • norm_type:p-范数 的 p 值,用于规范化范数超过 max_norm 的 Embedding 向量
  • 输入于输出

    • 输入:词编码(索引);输入的数值不能超过词典大小,即 num_embeddings
    • 输出:\((*,H)\);Embedding 向量,最后一维 \(H\) 表示 Embedding 向量维度

实例:

import torch.nn as nn
word_to_ix = {"apple": 0, "banana": 1, "orange": 2}  # 建立一个含有3个词的字典
embed_layer = nn.Embedding(3, 5)    # 3 words in vocab, 5 dimensional embeddings
lookup_tensor = torch.tensor([0, 1, 2], dtype=torch.long)
# 0, 1, 2 分别表示字典中所对应的三个词。注意:如果输入的数值超过 3,则会报错

embed_vector1 = embed_layer(lookup_tensor)  # embedding 向量
embed_vector2 = embed_layer.weight          # Embedding Layer 的 weight 也是 embedding 向量,二者等价
print(embed_vector.size(), embed_vector1, embed_vector2 ) 

参考文献

第14章 自然语言处理:预训练, 动手学深度学习 第二版, website

Word2Vec: 一种词向量的训练方法, PaddlePaddle 飞桨, website

Angel Hair, Word2Vec的PyTorch实现(中文数据)(参考版), website

mathor, PyTorch实现Word2Vec, website

posted @ 2024-04-02 12:21  veager  阅读(72)  评论(0)    收藏  举报