基于 PyTorch 手动实现 CBOW 词向量训练详解

自然语言处理是人工智能领域的核心分支之一,而词向量(Word2Vec)作为 NLP 任务的基础表征技术,解决了传统独热编码高维稀疏、无法表达语义关联的痛点。Word2Vec 包含两种经典模型:跳元模型(Skip-Gram)与连续词袋模型(CBOW)。本文将结合完整可运行的 PyTorch 代码,从原理剖析、数据集构建、网络搭建、模型训练到结果保存,全方位讲解CBOW 模型的手动实现流程,同时解析代码细节与踩坑优化技巧,帮助零基础读者彻底理解词向量的训练逻辑,全文结合实战代码,兼具理论深度与工程落地性。

一、研究背景与理论基础

1.1 词向量的发展痛点

在早期自然语言处理任务中,研究者常使用One-Hot 独热编码表征单词。假设词汇表包含 1000 个单词,每个单词会被编码为长度 1000 的向量,仅对应索引位置为 1,其余全为 0。这种编码方式存在两大致命缺陷:第一,维度灾难。词汇量越大,向量维度越高,计算成本呈指数级增长;第二,语义隔离。任意两个单词的独热向量内积恒为 0,无法体现 "computer" 与 "program" 这类语义相近单词的关联关系。

为解决上述问题,Word2Vec 词嵌入技术应运而生。它通过神经网络训练,将单词映射到低维稠密向量空间,语义相似的单词在向量空间中距离更近,完美实现语义量化表达。

1.2 CBOW 模型核心原理

Word2Vec 两大模型中,CBOW(Continuous Bag of Words,连续词袋模型) 的核心逻辑是:通过上下文单词预测中心单词 。本文代码中设置CONTEXT_SIZE = 2,代表中心词左右各取 2 个单词作为上下文窗口,单个样本共 4 个上下文词汇。模型训练时,输入上下文单词的向量表征,经过嵌入层映射、全连接层特征提取后,输出词汇表中每个单词的概率分布,不断缩小预测概率与真实中心词的误差,最终收敛得到稳定的词嵌入矩阵。

对比 Skip-Gram 模型(中心词预测上下文),CBOW 训练速度更快,适合小型语料训练,非常适合入门学习词向量原理,也是本文实战实现的核心模型。

1.3 CBOW 网络结构拆解

标准简易 CBOW 网络分为三层:

  1. 嵌入层 Embedding:将单词索引转换为低维稠密向量,是词向量存储的核心层;
  2. 隐藏全连接层:聚合上下文向量特征,通过激活函数增强非线性表达能力;
  3. 输出分类层:映射到词汇表维度,经 Log Softmax 输出单词预测概率,配合 NLLLoss 损失函数完成训练优化。

二、数据集预处理完整流程

2.1 原始语料定义

本文采用一段英文科普文本作为小型训练语料,涵盖计算机基础概念短句,语料长度适中,适合轻量化模型快速收敛训练:

python 复制代码
raw_text = """We are about to study the idea of a computational process,
Computational processes are abstract beings that inhabit computers.
As they evolve, processes manipulate other abstract things called data.
The evolution of a process is directed by a pattern of rules
called a program. People create programs to direct processes. In effect,
We conjure the spirits of the computer with our spells."""

小型封闭语料可以避免生僻词干扰,降低模型训练难度,方便初学者观察损失下降与词向量收敛过程。

2.2 词汇表与索引映射构建

首先提取语料中所有独立单词构建词汇表,再建立单词→索引索引→单词双向映射字典,这是深度学习文本任务的标准预处理步骤:

python 复制代码
vocab = set(raw_text)
vocab_size = len(vocab)
word_to_idx = {word: i for i, word in enumerate(vocab)}
idx_to_word = {i: word for i in enumerate(vocab)}

集合去重保证词汇唯一性,双向字典方便后续编码转换与预测结果还原,是 CBOW 数据输入的基础铺垫。

2.3 上下文与中心词样本构建

设置上下文窗口大小CONTEXT_SIZE = 2,遍历整个文本序列,逐个提取中心词与对应上下文:

python 复制代码
data = []
for i in range(CONTEXT_SIZE, len(raw_text) - CONTEXT_SIZE):
    context =(
        [raw_text[i - (2-j)] for j in range(CONTEXT_SIZE)]
        + [raw_text[i + j + 1] for j in range(CONTEXT_SIZE)]
    )
    target = raw_text[i]
    data.append((context, target))

遍历范围规避首尾边界(无完整上下文),每个样本格式为(上下文列表, 中心词),批量构建训练数据集,为后续迭代训练提供样本支撑。

2.4 上下文向量编码优化函数

自定义make_context_vector函数,将上下文单词转换为模型可识别的张量索引,同时加入工程优化:小写统一转换 + 未知词兜底:

python 复制代码
def make_context_vector(context, word_to_ix):
    idxs = [word_to_ix.get(w.lower(), 0) for w in context]
    return torch.tensor(idxs, dtype=torch.long)

原生代码仅简单索引映射,优化后通过get方法设置默认索引 0,避免陌生单词导致键值报错;小写统一消除大小写差异干扰,提升数据集鲁棒性,是实战开发中必备的容错技巧。

三、设备配置与 CBOW 网络模型搭建

3.1 自适应训练设备选择

深度学习训练优先使用 GPU 加速,代码自动兼容 CUDA、Apple MPS 与 CPU 三类设备,跨平台适配性极强:

python 复制代码
device = 'cuda' if torch.cuda.is_available() else 'mps' if torch.backends.mps.is_available() else 'cpu'
print(device)

NVIDIA 显卡自动启用 CUDA 加速,Mac 苹果芯片调用 MPS 框架,无加速设备则默认 CPU 运行,兼顾不同运行环境的兼容性。

3.2 CBOW 神经网络类定义

基于 PyTorch 的 nn.Module 自定义 CBOW 模型,严格遵循三层结构设计:

python 复制代码
class CBOW(nn.Module):
    def __init__(self, vocab_size, embedding_dim):
        super(CBOW, self).__init__()
        self.embeddings = nn.Embedding(vocab_size, embedding_dim)
        self.proj = nn.Linear(embedding_dim, 128)
        self.output = nn.Linear(128, vocab_size)

    def forward(self, inputs):
        embeds = sum(self.embeddings(inputs)).view(1, -1)
        out = F.relu(self.proj(embeds))
        out = self.output(out)
        nll_prob = F.log_softmax(out, dim=-1)
        return nll_prob
网络层详解:
  1. 嵌入层 nn.Embedding:输入词汇总量与词向量维度(本文设置 10 维),自动初始化词嵌入权重矩阵,是训练后词向量的存储载体;
  2. 特征投影层 Linear:将聚合后的上下文向量映射到 128 维隐藏空间,ReLU 激活函数引入非线性特征;
  3. 输出分类层:映射回词汇表维度,Log Softmax 归一化输出概率分布,适配 NLLLoss 损失函数计算误差。
前向传播逻辑:

上下文多个单词嵌入向量求和聚合,重塑维度后逐层前向计算,最终输出中心词预测对数概率,完全贴合 CBOW 上下文预测中心词的核心逻辑。

四、模型训练全过程解析

4.1 初始化模型、优化器与损失函数

python 复制代码
model = CBOW(vocab_size, 10).to(device)
optimizer = optim.Adam(model.parameters(), lr=0.001)
loss_function = nn.NLLLoss()
losses = []
  1. 模型实例化:词汇总量 + 10 维词向量,迁移至训练设备;
  2. 优化器选择 Adam:自适应学习率,收敛速度优于 SGD,适合小型模型快速训练;
  3. 损失函数 NLLLoss:配合网络末端的 Log Softmax,是分类任务经典组合;
  4. 损失列表:记录每轮总损失,用于观察模型收敛趋势。

4.2 迭代训练核心循环

设置 200 轮训练 epoch,搭配 tqdm 进度条可视化训练过程,逐样本梯度更新:

python 复制代码
model.train()
for epoch in tqdm(range(200)):
    total_loss = 0
    for context, target in data:
        # 数据预处理与设备迁移
        context_vector = make_context_vector(context, word_to_idx).to(device)
        target = torch.tensor([word_to_idx[target]]).to(device)
        # 前向传播预测
        train_predict = model(context_vector)
        loss = loss_function(train_predict, target)
        # 反向传播与参数更新
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        total_loss += loss.item()
    losses.append(total_loss)
    print(losses)
训练关键步骤拆解:
  1. 训练模式锁定 model.train ():启用 Dropout、BN 等训练专用层(本文模型轻量化,为规范写法保留);
  2. 梯度清零:每轮样本必须执行zero_grad(),避免梯度累积干扰参数更新;
  3. 损失反向传播:loss.backward()自动计算所有权重梯度;
  4. 参数迭代:优化器 step () 根据梯度更新嵌入层与全连接层权重;
  5. 损失累加:统计每 epoch 总损失,打印观察模型是否稳步收敛。

随着训练轮次增加,总损失会持续下降并逐渐趋于平稳,代表模型学习到上下文与中心词的语义关联,词向量权重逐步优化完成。

五、模型推理与词向量结果保存

5.1 自定义上下文推理预测

训练完成后输入自定义上下文['People', 'create', 'to', 'direct'],预测最可能的中心单词:

python 复制代码
context = ['People', 'create', 'to', 'direct']
context_vector = make_context_vector(context, word_to_idx).to(device)
model.eval()
predict = model(context_vector)
max_idx = predict.argmax(1)

切换model.eval()推理模式,关闭梯度计算与训练专用层,通过 argmax 取概率最大值索引,还原预测中心词,验证模型语义学习效果。

5.2 提取并查看词嵌入权重

嵌入层权重矩阵就是最终训练完成的 Word2Vec 词向量,直接提取解析:

python 复制代码
print("CBOW embeddings'weight=", model.embeddings.weight)
W = model.embeddings.weight.cpu().detach().numpy()
print(W)

将 GPU 张量迁移至 CPU,脱离计算图转换为 numpy 数组,方便后续离线存储与数据分析,权重矩阵形状为[词汇总数, 10],每行对应一个单词的 10 维稠密向量。

5.3 构建单词 - 向量映射字典

封装所有单词与对应词向量,方便后续快速查询调用:

python 复制代码
word_2_vec = {}
for word in word_to_idx.keys():
    word_2_vec[word] = W[word_to_idx[word], :]

字典结构化存储,实现输入单词快速检索对应向量,适配下游 NLP 任务调用需求。

5.4 词向量离线持久化保存

通过 numpy 压缩保存训练好的词向量文件,实现模型结果复用:

python 复制代码
np.savez('word2vec实现.npz', file_1=W)
data = np.load('word2vec实现.npz')
print(data.files)

保存为 npz 压缩格式,体积小巧读取便捷,后续无需重新训练,直接加载文件即可调用训练好的词向量,提升工程复用效率。

六、总结

本文基于 PyTorch 完整实现了 CBOW 词向量训练全流程,从理论原理、语料预处理、网络搭建、迭代训练到结果保存,层层拆解代码逻辑。CBOW 通过上下文预测中心词的训练方式,让神经网络自动学习单词的语义关联,将离散单词映射为低维稠密向量,解决了传统独热编码的语义缺陷。

全套代码轻量化易运行,适配入门级深度学习硬件,同时加入工程容错优化,兼顾学习理解与实战落地。通过 200 轮迭代训练,损失稳步收敛,最终提取并离线保存词嵌入矩阵,完成 Word2Vec 核心功能实现。掌握 CBOW 手动实现原理,不仅能深入理解词嵌入训练机制,也为后续 Transformer、大语言模型等进阶 NLP 学习打下坚实基础。

相关推荐
大学有意思2 小时前
2026深度解析广西英华国际职业学院新能源汽车技术专业
人工智能·机器人
踩着两条虫2 小时前
AI驱动的Vue3应用开发平台深入探究(十八):扩展与定制之集成第三方库
vue.js·人工智能·低代码·重构·架构
词元Max2 小时前
2.5 Python 类型注解与运行时类型检查
开发语言·python
沪漂阿龙2 小时前
深度解析Pandas数据组合:从concat到merge,打通你的数据处理任督二脉
python·数据分析·pandas
恋猫de小郭2 小时前
Claude Code 源码里有意思设定:伪造、投毒、卧底、封号
前端·人工智能·ai编程
kailp2 小时前
无需本地显卡!跑GPT-SoVITS-V2Pro完整教程
人工智能·gpt·ai·大模型·云计算
饼干哥哥2 小时前
n8n已死!我用Kimi跑通了Claude Skills,直接替代工作流
人工智能
童园管理札记2 小时前
2026实测|GPT-4.5+Agent智能体:3小时搭建企业级客服系统,附完整源码与部署教程(一)
经验分享·python·深度学习·重构·学习方法
爱写代码的汤二狗2 小时前
第4章 载体选择:网站、小程序还是App?
人工智能·驱动开发·创业创新