共计 1752 个字符,预计需要花费 5 分钟才能阅读完成。
背景介绍
CBOW(Continuous Bag of Words)是 Word2Vec 的两种主要模型之一,它通过上下文预测当前词来学习词向量。在自然语言处理(NLP)中,词嵌入技术将词语映射到低维连续向量空间,使得语义相似的词在向量空间中也相近。CBOW 因其训练速度快、适合处理高频词等优点,被广泛应用于文本分类、信息检索和机器翻译等任务。

CBOW vs Skip-gram
- CBOW:用上下文词预测目标词,适合小型数据集和高频词,训练速度较快
- Skip-gram:用中心词预测上下文词,适合大型数据集和低频词,对罕见词表现更好
CBOW 的数学原理
模型架构
CBOW 包含三层:
1. 输入层:上下文词的 one-hot 向量(维度 =V,词汇表大小)
2. 隐藏层:求上下文词向量的平均值(维度 =N,词向量维度)
3. 输出层:通过 softmax 计算目标词概率(维度 =V)
关键公式
-
隐藏层计算:
$$ h = \frac{1}{C} \sum_{c=1}^C W_{in}^T x_c $$
其中 C 是上下文窗口大小 -
Softmax 输出:
$$ p(w_o|w_{c}) = \frac{\exp(v_{w_o}^T h)}{\sum_{i=1}^V \exp(v_{w_i}^T h)} $$ -
交叉熵损失:
$$ L = -\log p(w_o|w_{c}) $$
手算示例
以句子 ”the quick brown fox” 为例,设:
– 上下文窗口 =2
– 词向量维度 =3
– 当前目标词 =”brown”
- 构建词汇表:{“the”:0, “quick”:1, “brown”:2, “fox”:3}
- 初始化随机权重矩阵(示例值):
W_in = [[0.1, 0.2, 0.3], # the [0.4, 0.5, 0.6], # quick [0.7, 0.8, 0.9], # brown [1.0, 1.1, 1.2]] # fox - 计算隐藏层:
上下文词 ”the”(0) 和 ”quick”(1) 的平均向量:
([0.1,0.2,0.3] + [0.4,0.5,0.6] ) / 2 = [0.25, 0.35, 0.45]
Python 实现
import numpy as np
# 超参数设置
V = 10000 # 词汇表大小
N = 300 # 词向量维度
learning_rate = 0.01
# 初始化权重
W_in = np.random.rand(V, N) # 输入到隐藏层
W_out = np.random.rand(N, V) # 隐藏层到输出
# CBOW 前向传播
def forward(context_words):
h = np.mean([W_in[word] for word in context_words], axis=0)
scores = np.dot(h, W_out)
probs = np.exp(scores) / np.sum(np.exp(scores))
return probs, h
# 训练过程
for epoch in range(100):
for context, target in training_data:
# 前向传播
probs, h = forward(context)
# 计算梯度
grad_out = np.outer(h, probs)
grad_out[:, target] -= h
# 更新权重
W_out -= learning_rate * grad_out
for word in context:
W_in[word] -= learning_rate * grad_out[target] / len(context)
性能优化
负采样技术
用以下公式替代 softmax:
$$ \log \sigma(v_{w_o}^T h) + \sum_{k=1}^K \log \sigma(-v_{w_k}^T h) $$
其中 K 是负样本数量(通常 5 -20)
矩阵运算优化
- 使用 numpy 的向量化操作
- 对高频词进行下采样
- 使用多线程处理批量数据
避坑指南
- 参数设置 :
- 词向量维度通常选择 50-300
- 学习率从 0.025 开始线性衰减
-
上下文窗口大小:简单任务用 2 -5,语义任务用 5 -10
-
过拟合问题 :
- 对小数据集使用早停法
- 增加负采样数量
- 添加 L2 正则化
思考题
如何将 CBOW 应用于医疗领域文本?可以考虑:
1. 使用领域特定语料预训练
2. 调整上下文窗口捕获医学术语关系
3. 结合领域知识设计特殊 token(如药品、病症代码)
通过这个完整流程,相信你已经掌握了 CBOW 的核心原理和实现方法。建议尝试在自己的数据集上运行代码,观察不同参数对结果的影响。
