深入解析CBOW模型中的反向传播算法:从数学推导到代码实现

1次阅读
没有评论

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

image.webp

CBOW 模型与反向传播的重要性

CBOW(Continuous Bag-of-Words)是 Word2Vec 中的经典模型,它通过上下文词预测中心词来学习词向量。反向传播算法在这个过程中起到了关键作用,它负责根据预测误差调整模型参数,使得词向量能够更好地捕捉语义信息。对于 NLP 初学者来说,理解 CBOW 的反向传播不仅有助于掌握词向量技术,还能为后续学习更复杂的神经网络模型打下基础。

深入解析 CBOW 模型中的反向传播算法:从数学推导到代码实现

数学推导

1. 损失函数与 Softmax 推导

CBOW 模型的输出层使用 Softmax 函数计算每个词的概率分布。给定隐藏层输出 (h) 和输出层权重矩阵 (W),中心词 (w_O) 的概率为:

[P(w_O|w_{c}) = \frac{\exp(u_{w_O}^T h)}{\sum_{i=1}^{V} \exp(u_i^T h)} ]

其中 (u_i) 是输出层权重矩阵的第 (i) 列,(V) 是词汇表大小。损失函数通常采用交叉熵:

[J = -\log P(w_O|w_{c}) ]

2. 输出层权重的偏导计算

为了更新输出层权重,我们需要计算损失函数对 (u_j) 的偏导数。对于目标词 (w_O) 和非目标词 (w_j)((j \neq O)),偏导分别为:

[\frac{\partial J}{\partial u_j} = (P(w_j|w_{c}) – \mathbb{1}(j=O)) \cdot h ]

其中 (\mathbb{1}(j=O)) 是指示函数,当 (j=O) 时为 1,否则为 0。

3. 隐藏层到输出层的梯度传播

通过链式法则,损失函数对隐藏层输出 (h) 的梯度为:

[\frac{\partial J}{\partial h} = \sum_{j=1}^{V} (P(w_j|w_{c}) – \mathbb{1}(j=O)) \cdot u_j ]

这一梯度将用于更新输入层到隐藏层的权重。

代码实现

以下是使用 Python 和 NumPy 实现的 CBOW 反向传播关键步骤:

import numpy as np

# 假设词汇表大小为 V,隐藏层维度为 N
V = 10000
N = 300

# 初始化权重矩阵
W_input = np.random.randn(V, N)  # 输入层到隐藏层
W_output = np.random.randn(N, V)  # 隐藏层到输出层

# 假设输入上下文词的 one-hot 编码(实际中可能是多个词的均值)x = np.zeros(V)
x[[1, 3, 5]] = 1  # 假设上下文词索引为 1,3,5
x = x / 3  # 取平均

# 前向传播
h = np.dot(W_input.T, x)  # 隐藏层输出

# 计算输出层得分(未归一化)u = np.dot(W_output.T, h)

# Softmax 计算
exp_u = np.exp(u - np.max(u))  # 数值稳定性处理
probs = exp_u / np.sum(exp_u)

# 假设目标词索引为 2
target = 2

# 计算梯度
grad_output = probs.copy()
grad_output[target] -= 1

grad_output = grad_output.reshape(-1, 1)  # 转为列向量
h = h.reshape(-1, 1)  # 转为列向量

# 输出层权重梯度
dW_output = np.dot(h, grad_output.T)

# 隐藏层梯度
dh = np.dot(W_output, grad_output)

# 输入层权重梯度
dW_input = np.dot(x.reshape(-1, 1), dh.T)

# 更新权重
learning_rate = 0.01
W_output -= learning_rate * dW_output
W_input -= learning_rate * dW_input

性能对比

  • For 循环实现 :计算每个词的梯度时需要遍历整个词汇表,时间复杂度为 (O(V)),在大词汇表下非常慢。
  • 向量化实现 :利用矩阵运算一次性计算所有梯度,时间复杂度仍为 (O(V)),但常数项大大降低,实际速度快很多。

避坑指南

1. 梯度爆炸问题

  • 识别 :如果梯度值突然变得极大(如超过 1e6),可能是梯度爆炸。
  • 解决 :使用梯度裁剪(gradient clipping),限制梯度的最大值。
grad_norm = np.linalg.norm(grad_output)
if grad_norm > 1.0:
    grad_output = grad_output / grad_norm

2. 学习率设置

  • 经验值范围:通常从 (0.01) 开始尝试,逐步调整。
  • 学习率衰减:随着训练进行,可以逐步降低学习率(如每轮乘以 (0.99))。

3. 稀疏矩阵优化

  • 输入层 :由于输入是 one-hot 或少量词的均值,可以使用稀疏矩阵存储和计算。
  • 输出层 :对于负采样或分层 Softmax 优化,可以避免计算全部词汇的梯度。

思考题

  1. 如何修改代码支持负采样优化?
  2. 提示:只需采样少量负样本,而非计算全部词汇的梯度。

  3. 对比 Skip-gram 的反向传播差异?

  4. 提示:Skip-gram 是中心词预测上下文,梯度传播方向相反。

  5. 在大语料下的分布式训练方案?

  6. 提示:考虑使用 Hogwild! 异步更新或模型并行。

总结

通过本文的推导和代码实现,相信大家对 CBOW 的反向传播有了更清晰的认识。实际应用中,可以进一步结合负采样或分层 Softmax 来提升训练效率。希望这些内容能帮助你在 NLP 学习中少走弯路!

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