共计 2488 个字符,预计需要花费 7 分钟才能阅读完成。
1. 背景介绍
CBOW(Continuous Bag of Words)模型是 Word2Vec 的两种经典实现之一,主要作用是通过上下文预测中心词来学习词向量表示。它的核心优势在于对高频词的处理效率和训练速度,特别适合处理大规模语料库。在实际应用中,CBOW 常用于文本分类、信息检索等需要稠密词向量的场景。

2. CBOW vs Skip-gram
- CBOW 特点:
- 用上下文词预测中心词
- 训练速度更快(尤其对高频词)
-
对小数据集表现更好
-
Skip-gram 特点:
- 用中心词预测上下文词
- 对低频词效果更好
- 适合大数据集
3. 核心实现
3.1 词嵌入矩阵初始化
词嵌入矩阵 W∈ℝ^(V×d)和上下文矩阵 W ’∈ℝ^(d×V)通常随机初始化:
import numpy as np
vocab_size = 10000 # 词汇表大小
embedding_dim = 300 # 词向量维度
# Xavier 初始化
W = np.random.uniform(-1/np.sqrt(embedding_dim),
1/np.sqrt(embedding_dim),
(vocab_size, embedding_dim))
W_prime = np.random.uniform(-1/np.sqrt(embedding_dim),
1/np.sqrt(embedding_dim),
(embedding_dim, vocab_size))
3.2 前向传播
- 将上下文词的 one-hot 向量与 W 相乘得到词向量
- 对上下文词向量求平均
- 与 W ’ 相乘得到输出分数
- 通过 softmax 得到概率分布
def forward(context_words_indices, W, W_prime):
# context_words_indices: 上下文词索引列表
h = np.mean(W[context_words_indices], axis=0)
u = np.dot(h, W_prime)
y_pred = softmax(u)
return h, u, y_pred
3.3 损失函数
使用交叉熵损失函数:
def cross_entropy(y_pred, y_true):
return -np.sum(y_true * np.log(y_pred + 1e-10))
3.4 反向传播
关键梯度计算:
def backward(context_indices, center_index, h, y_pred, W, W_prime, learning_rate):
# 计算梯度
e = y_pred.copy()
e[center_index] -= 1
# 更新 W'
dW_prime = np.outer(h, e)
W_prime -= learning_rate * dW_prime
# 更新 W
dh = np.dot(W_prime, e)
for i in context_indices:
W[i] -= learning_rate * dh / len(context_indices)
4. 完整实现代码
import numpy as np
from collections import defaultdict
class CBOW:
def __init__(self, vocab_size, embedding_dim):
self.vocab_size = vocab_size
self.embedding_dim = embedding_dim
# 初始化参数
self.W = np.random.uniform(-1/np.sqrt(embedding_dim),
1/np.sqrt(embedding_dim),
(vocab_size, embedding_dim))
self.W_prime = np.random.uniform(-1/np.sqrt(embedding_dim),
1/np.sqrt(embedding_dim),
(embedding_dim, vocab_size))
@staticmethod
def softmax(x):
exp_x = np.exp(x - np.max(x))
return exp_x / exp_x.sum()
def forward(self, context_indices):
h = np.mean(self.W[context_indices], axis=0)
u = np.dot(h, self.W_prime)
y_pred = self.softmax(u)
return h, u, y_pred
def train(self, context_indices, center_index, learning_rate=0.01):
# 前向传播
h, u, y_pred = self.forward(context_indices)
# 计算误差
e = y_pred.copy()
e[center_index] -= 1
# 反向传播
dW_prime = np.outer(h, e)
dh = np.dot(self.W_prime, e)
# 更新参数
self.W_prime -= learning_rate * dW_prime
for i in context_indices:
self.W[i] -= learning_rate * dh / len(context_indices)
# 返回损失
loss = -np.log(y_pred[center_index] + 1e-10)
return loss
5. 性能优化建议
- 负采样:用负采样替代 softmax,大幅减少计算量
- 层次 softmax:使用霍夫曼树加速 softmax 计算
- mini-batch 训练:批量处理数据提高并行效率
- 词频处理:对高频词进行下采样
6. 避坑指南
- 数值稳定性:
- 对 softmax 做 max 归一化
-
添加微小值 (1e-10) 防止 log(0)
-
学习率选择:
- 初始学习率 0.01-0.1
-
使用学习率衰减策略
-
评估方法:
- 相似词任务
- 类比推理任务(king – man + woman ≈ queen)
- 下游任务评估
7. 进阶思考
- 实际应用:
- 作为文本分类的特征输入
-
用于信息检索的 query 扩展
-
改进方向:
- 加入 subword 信息
- 结合上下文位置信息
- 多任务联合训练
通过这个完整实现,我们不仅掌握了 CBOW 的核心算法,还了解了词嵌入矩阵调整的关键技术。建议读者尝试在真实数据集上训练,并观察不同超参数对结果的影响。
正文完
