CBOW模型算法实战:从词嵌入矩阵到手算示例详解

1次阅读
没有评论

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

image.webp

词嵌入(Word Embedding)是自然语言处理(NLP)领域的一项基础技术,它将词语映射到低维连续向量空间,使得语义相似的词在向量空间中距离相近。CBOW(Continuous Bag-of-Words)模型是词嵌入技术中的一种经典算法,由 Mikolov 等人在 2013 年提出。与 Skip-gram 模型不同,CBOW 模型通过上下文词预测中心词,适合处理大规模语料库且训练速度较快。

CBOW 模型算法实战:从词嵌入矩阵到手算示例详解

1. CBOW 模型算法原理

CBOW 模型的核心思想是利用上下文词来预测当前词。假设我们有一个句子 ”I love natural language processing”,窗口大小为 2,那么对于中心词 ”natural”,其上下文词为 [“I”, “love”, “language”, “processing”]。

1.1 模型结构

CBOW 模型包含三层结构:

  1. 输入层 :将上下文词的 one-hot 向量作为输入。假设词汇表大小为 V,则每个词的 one-hot 向量维度为 V。

  2. 投影层 :将上下文词的 one-hot 向量与词嵌入矩阵 W 相乘,得到词向量表示。词嵌入矩阵 W 的维度为 V×N,其中 N 是词向量的维度。

  3. 输出层 :将投影层的输出(上下文词向量的平均值)与另一个矩阵 W ’ 相乘,得到输出向量,再通过 softmax 函数计算每个词作为中心词的概率。矩阵 W ’ 的维度为 N×V。

1.2 数学表达

  • 输入层:上下文词的 one-hot 向量 x₁, x₂, …, x_C,其中 C 是上下文词的数量。
  • 投影层:词向量 v_i = W^T x_i,上下文词向量的平均值为 v_avg = (v₁ + v₂ + … + v_C) / C。
  • 输出层:输出向量 u = W’^T v_avg,概率分布 y = softmax(u)。

2. 手算示例

假设词汇表包含三个词:”I”, “love”, “NLP”,词向量维度 N =2。词嵌入矩阵 W 和 W ’ 如下:

W = [[0.1, 0.2], [0.3, 0.4], [0.5, 0.6]]
W' = [[0.7, 0.8, 0.9], [0.1, 0.2, 0.3]]

以中心词 ”love” 为例,其上下文词为 ”I” 和 ”NLP”。计算过程如下:

  1. 将 ”I” 和 ”NLP” 的 one-hot 向量与 W 相乘,得到词向量:
  2. v_I = W^T x_I = [0.1, 0.2]
  3. v_NLP = W^T x_NLP = [0.5, 0.6]
  4. 计算平均向量:v_avg = ([0.1, 0.2] + [0.5, 0.6]) / 2 = [0.3, 0.4]
  5. 计算输出向量:u = W’^T v_avg = [0.70.3 + 0.10.4, 0.80.3 + 0.20.4, 0.90.3 + 0.30.4] = [0.25, 0.32, 0.39]
  6. 计算概率分布:y = softmax(u) ≈ [0.31, 0.34, 0.35]

3. Python 实现

以下是使用 NumPy 实现 CBOW 模型的代码:

import numpy as np

# 定义词汇表和词向量维度
vocab = ["I", "love", "NLP"]
vocab_size = len(vocab)
embedding_dim = 2

# 初始化词嵌入矩阵 W 和 W'
W = np.random.rand(vocab_size, embedding_dim)
W_prime = np.random.rand(embedding_dim, vocab_size)

# 定义 one-hot 编码函数
def one_hot(word, vocab):
    vec = np.zeros(len(vocab))
    vec[vocab.index(word)] = 1
    return vec

# 定义 softmax 函数
def softmax(x):
    e_x = np.exp(x - np.max(x))
    return e_x / e_x.sum()

# 定义 CBOW 模型
def cbow(context_words, center_word, vocab, W, W_prime, learning_rate=0.01):
    # 将上下文词转换为 one-hot 向量
    context_vecs = [one_hot(word, vocab) for word in context_words]

    # 计算投影层输出(平均向量)v_avg = np.mean([np.dot(W.T, vec) for vec in context_vecs], axis=0)

    # 计算输出层
    u = np.dot(W_prime.T, v_avg)
    y = softmax(u)

    # 计算损失(交叉熵)target = one_hot(center_word, vocab)
    loss = -np.sum(target * np.log(y))

    # 反向传播更新参数
    grad = y - target
    dW_prime = np.outer(v_avg, grad)
    dW = np.zeros_like(W)
    for vec in context_vecs:
        dW += np.outer(vec, np.dot(W_prime, grad)) / len(context_words)

    W -= learning_rate * dW
    W_prime -= learning_rate * dW_prime

    return loss, W, W_prime

# 示例训练
context_words = ["I", "NLP"]
center_word = "love"
loss, W, W_prime = cbow(context_words, center_word, vocab, W, W_prime)
print("Loss:", loss)
print("Updated W:", W)
print("Updated W':", W_prime)

4. 性能优化建议

  1. 大规模语料处理
  2. 使用负采样(Negative Sampling)替代 softmax,减少计算量。
  3. 采用分层 softmax(Hierarchical Softmax)加速训练。
  4. 使用多线程或 GPU 加速矩阵运算。

  5. 内存优化

  6. 对词频低的词进行截断(Subsampling)。
  7. 使用稀疏矩阵存储 one-hot 向量。
  8. 分批训练(Mini-batch)减少内存占用。

5. 避坑指南

  1. 常见错误
  2. 词向量维度设置不合理:维度太小会导致信息丢失,太大会增加计算量。
  3. 学习率过高或过低:建议使用自适应学习率算法(如 Adam)。

  4. 超参数调优

  5. 窗口大小:通常设置为 5 -10。
  6. 词向量维度:常用值为 100-300。
  7. 学习率:初始值设为 0.01,根据训练效果调整。

6. 思考题

如何将 CBOW 模型扩展到更大规模的语料处理?可以考虑以下方向:

  1. 分布式训练:将语料库分割到多台机器上并行训练。
  2. 增量训练:逐步增加语料库规模,避免重新训练。
  3. 模型压缩:对词嵌入矩阵进行量化或剪枝,减少存储和计算开销。

通过本文的详细解析和代码实现,读者可以深入理解 CBOW 模型的原理和实现细节,为进一步探索 NLP 领域打下坚实基础。

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