共计 1784 个字符,预计需要花费 5 分钟才能阅读完成。
CBOW 模型与反向传播的必要性
CBOW(Continuous Bag of Words)是 Word2Vec 中的经典模型,通过上下文词预测中心词来学习词向量。它的核心优势在于对高频词处理更高效,适合大规模语料训练。反向传播算法则是训练神经网络的关键,通过计算损失函数对模型参数的梯度来更新权重。理解 CBOW 的反向传播过程,不仅能帮助调试模型,还能为后续优化(如负采样、层次 softmax)打下基础。

数学推导:从损失函数到梯度计算
1. 损失函数定义
CBOW 的损失函数采用交叉熵,对于单个训练样本:
$$ J = -\sum_{w \in V} y_w \log(\hat{y}w) $$
其中 $y_w$ 是真实标签(one-hot 向量),$\hat{y}_w$ 是预测概率(softmax 输出):
$$ \hat{y}_w = \frac{\exp(z_w)}{\sum $$} \exp(z_{w’})
2. 输出层梯度计算
首先求损失对输出层得分 $z_j$ 的偏导:
$$ \frac{\partial J}{\partial z_j} = \hat{y}j – y_j $$
然后通过链式法则得到输出层权重 $W$ 的梯度:
$$ \frac{\partial J}{\partial W_{ij}} = (\hat{y}_j – y_j) \cdot h_i $$
其中 $h_i$ 是隐藏层第 $i$ 维的输出。
3. 隐藏层梯度传播
隐藏层的梯度是所有输出神经元梯度的加权和:
$$ \frac{\partial J}{\partial h_i} = \sum_{j \in V} (\hat{y}j – y_j) \cdot W $$
Python 实现与优化
基础实现(向量化版本)
import numpy as np
# 初始化参数
vocab_size = 10000
embed_dim = 300
W1 = np.random.randn(vocab_size, embed_dim) * 0.01 # 输入层到隐藏层
W2 = np.random.randn(embed_dim, vocab_size) * 0.01 # 隐藏层到输出层
# 前向传播
def forward(context_ids):
h = np.mean(W1[context_ids], axis=0) # 平均上下文词向量
z = np.dot(h, W2)
y_hat = np.exp(z) / np.sum(np.exp(z))
return h, y_hat
# 反向传播
def backward(context_ids, target_id, h, y_hat, learning_rate=0.01):
# 计算梯度
y = np.zeros(vocab_size)
y[target_id] = 1
dz = y_hat - y
# 更新输出层权重
dW2 = np.outer(h, dz)
W2 -= learning_rate * dW2
# 传播到隐藏层并更新输入层权重
dh = np.dot(W2, dz)
for word_id in context_ids:
W1[word_id] -= learning_rate * dh / len(context_ids)
性能对比测试
# 非向量化实现(对比用)def slow_backward(context_ids, target_id, h, y_hat):
# 此处省略实现细节
# 实测在 vocab_size=10000 时比向量化版本慢约 50 倍
pass
实践避坑指南
梯度爆炸处理
- 现象:损失值突然变为 NaN
- 解决:梯度裁剪(添加
np.clip(grad, -1, 1))或权重初始化缩小 10 倍
学习率设置
- 推荐初始值:0.025(随迭代线性递减到 0.001)
- 监控指标:每 1000 词损失下降幅度应在 5%~15% 之间
稀疏矩阵优化
- 使用
scipy.sparse存储词频矩阵 - 对高频词进行下采样(概率 $1-\sqrt{t/f(w)}$)
- 采用负采样替代全词表 softmax
思考题
- 如何修改代码支持负采样优化?
-
提示:只需采样少量负例,修改损失函数为 sigmoid 交叉熵
-
对比 Skip-gram 的反向传播差异
-
提示:Skip-gram 是中心词预测上下文,梯度会反向传播到多个输出节点
-
在大语料下的分布式训练方案
- 提示:考虑参数服务器架构或使用 Horovod 框架
总结
通过本文的推导和代码实践,我们拆解了 CBOW 反向传播的 ” 黑箱 ” 过程。建议读者尝试在小型语料(如 IMDB 数据集)上从头实现,逐步添加负采样等优化。理解这些基础原理后,学习更复杂的词嵌入模型(如 GloVe、BERT)会轻松许多。
