深入解析CBOW模型的词嵌入矩阵生成原理与实现

1次阅读
没有评论

共计 2071 个字符,预计需要花费 6 分钟才能阅读完成。

image.webp

CBOW 模型架构回顾

CBOW(Continuous Bag-of-Words)是 Word2Vec 的两种经典模型之一,其核心思想是通过上下文词预测目标词。模型结构分为三层:

深入解析 CBOW 模型的词嵌入矩阵生成原理与实现

  • 输入层 :接收上下文词的 one-hot 编码。例如窗口大小为 2 时,会同时输入目标词前后各 2 个词的 one-hot 向量
  • 投影层(隐藏层):将多个上下文词的 one-hot 向量通过共享的嵌入矩阵转换为词向量,并取平均作为隐藏层输出
  • 输出层 :通过另一个词向量矩阵将隐藏层表示映射到词汇表空间,最终通过 softmax 得到预测概率

词嵌入矩阵的数学表示

词嵌入矩阵本质上是模型训练过程中学习到的参数矩阵:

  1. 输入矩阵 W :维度为 [V×N],V 是词汇表大小,N 是嵌入维度。每一行对应一个词的输入向量表示
  2. 输出矩阵 W ’:维度为 [N×V],用于将隐藏层输出转换为词汇表空间

初始化通常采用随机小数值,如从均匀分布 U(-0.5/N, 0.5/N) 中采样。

词向量更新公式推导

核心是通过梯度下降更新矩阵参数:

  1. 前向传播:
    $$ h = \frac{1}{C} \sum_{c=1}^C W^T x_c $$
    $$ u = W’^T h $$
    $$ y = \text{softmax}(u) $$

  2. 损失函数(交叉熵):
    $$ L = -\log P(w_O|w_{I,1},…,w_{I,C}) $$

  3. 反向传播时,通过链式法则计算梯度并更新参数:
    $$ \frac{\partial L}{\partial W’} = \sum_{j=1}^V (y_j – t_j)h $$
    $$ \frac{\partial L}{\partial W} = \frac{1}{C} \sum_{c=1}^C x_c (y – t) W’ $$

Python 实现示例

import numpy as np
from collections import defaultdict

class CBOW:
    def __init__(self, vocab_size, embedding_dim):
        # 初始化权重矩阵
        self.W1 = np.random.uniform(-0.5/embedding_dim, 0.5/embedding_dim, 
                                   (vocab_size, embedding_dim))
        self.W2 = np.random.uniform(-0.5/embedding_dim, 0.5/embedding_dim,
                                   (embedding_dim, vocab_size))

    def forward(self, context_indices):
        # 上下文词向量的均值作为隐藏层输出
        h = np.mean(self.W1[context_indices], axis=0)
        u = np.dot(self.W2.T, h)
        y_pred = self._softmax(u)
        return h, y_pred

    def _softmax(self, x):
        e_x = np.exp(x - np.max(x))
        return e_x / e_x.sum()

    def train(self, context_indices, target_index, lr=0.01):
        # 前向传播
        h, y_pred = self.forward(context_indices)

        # 计算梯度
        t = np.zeros_like(y_pred)
        t[target_index] = 1
        delta = y_pred - t

        # 反向传播更新参数
        dW2 = np.outer(h, delta)
        dW1 = np.zeros_like(self.W1)
        for i in context_indices:
            dW1[i] += np.dot(self.W2, delta) / len(context_indices)

        self.W1 -= lr * dW1
        self.W2 -= lr * dW2

优化技术分析

  • 负采样 :将 softmax 计算简化为对少量负样本的二元分类,大幅提升训练效率
  • 采样概率:$$ P(w_i) = \frac{f(w_i)^{3/4}}{\sum_j f(w_j)^{3/4}} $$
  • 目标函数变为:$$ \log \sigma(v’{w_O}^T h) + \sum}^k \mathbb{E{w_i} [\log \sigma(-v’^T h)] $$

  • 层次 softmax:使用霍夫曼树将计算复杂度从 O(V) 降到 O(logV)

  • 每个节点表示二分类概率:$$ P(d_j|w_j,\theta_j) = [\sigma(\theta_j^T h)]^{1-d_j} [1-\sigma(\theta_j^T h)]^{d_j} $$

生产环境最佳实践

  1. 维度选择
  2. 一般任务:50-300 维
  3. 专业领域:需更大的维度捕捉细微语义

  4. 训练数据量

  5. 至少需要千万级别的 token
  6. 专业领域建议领域内数据 + 通用语料混合

  7. 超参数调优

  8. 学习率:初始 0.025,线性衰减到 0.0001
  9. 窗口大小:简单任务用 3 -5,短语识别用 5 -10
  10. 负采样:5-20 个负样本,大数据集可减少

开放性问题

在不同应用场景下(如推荐系统、机器翻译、情感分析),CBOW 与 Skip-gram 哪种表现更好?为什么在某些场景下预训练词嵌入(如 GloVe)可能比 Word2Vec 更合适?这涉及到词嵌入方法对词频分布、语义组合等特性的捕捉差异。

正文完
 0
评论(没有评论)