从零实现Word2Vec之CBOW模型:理解词向量的核心原理

在自然语言处理(NLP)领域,词向量(Word Embedding)是连接自然语言与机器学习模型的桥梁,而Word2Vec无疑是词向量技术中最经典的代表。Word2Vec包含两种核心模型:CBOW(Continuous Bag-of-Words,连续词袋模型)和Skip-gram。本文将从原理入手,基于PyTorch框架从零实现CBOW模型,帮助大家理解词向量的生成过程。

一、CBOW模型核心原理

CBOW模型的核心思想是通过上下文预测中心词:给定一个目标词的上下文(左右相邻的若干个词),模型学习输出这个目标词的概率分布,最终通过模型训练得到的嵌入层权重,即为我们所需的词向量。

举个简单例子:句子"We are about to study"中,若以"about"为中心词,上下文窗口设为2(即左右各2个词),则上下文是["We","are","to","study"],CBOW模型要做的就是用这4个词预测中心词"about"。

CBOW模型的核心流程:

  1. 将上下文词汇转换为索引,再通过嵌入层(Embedding)映射为低维稠密向量;

  2. 对所有上下文词向量做平均/求和操作;

  3. 通过全连接层将词向量映射到词汇表维度;

  4. 用Softmax激活函数输出词汇表中每个词作为中心词的概率;

  5. 以负对数似然损失(NLLLoss)优化模型,最终得到词向量。

二、代码实现:从零构建CBOW模型

1. 数据预处理:构建语料库与词汇映射

首先我们需要准备语料,并完成基础的数据预处理:构建词汇表、词汇-索引映射、生成训练数据(上下文-中心词对)。

python 复制代码
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from tqdm import tqdm
import numpy as np

# 1. 配置参数与原始语料
CONTEXT_SIZE = 2  # 上下文窗口大小:左右各2个词
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.""".split()

# 2. 构建词汇表与映射关系
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, word in enumerate(vocab)}  # 索引→词

# 3. 生成训练数据:(上下文, 中心词) 对
data = []
for i in range(CONTEXT_SIZE, len(raw_text) - CONTEXT_SIZE):
    # 拼接左上下文(前2个词)和右上下文(后2个词)
    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))

# 4. 工具函数:将上下文转换为索引张量
def make_context_vector(context, word_to_ix):
    idxs = [word_to_ix[w] for w in context]
    return torch.tensor(idxs, dtype=torch.long)

# 测试数据预处理结果
print("示例上下文索引:", make_context_vector(data[0][0], word_to_idx))
2. 定义CBOW模型结构

基于PyTorch的nn.Module自定义CBOW模型,核心包含三层:

• 嵌入层(Embedding):将词索引映射为低维词向量;

• 投影层(Linear):对词向量做线性变换;• 输出层(Linear):映射回词汇表维度,输出概率分布。

python 复制代码
# 设备配置:优先使用GPU/MPS,否则用CPU
device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
print(f"Using {device} device")

class CBOW(nn.Module):
    def __init__(self, vocab_size, embedding_dim):
        super(CBOW, self).__init__()
        # 嵌入层:vocab_size个词,每个词映射为embedding_dim维向量
        self.embeddings = nn.Embedding(vocab_size, embedding_dim)
        # 投影层:将词向量映射到128维
        self.proj = nn.Linear(embedding_dim, 128)
        # 输出层:映射回词汇表维度,用于预测中心词
        self.output = nn.Linear(128, vocab_size)

    def forward(self, input):
        # 1. 嵌入层:获取上下文词向量并求和
        embeds = sum(self.embeddings(input)).view(1, -1)
        # 2. 投影层 + ReLU激活
        out = F.relu(self.proj(embeds))
        # 3. 输出层 + 对数Softmax(适配NLLLoss)
        out = self.output(out)
        nll_prob = F.log_softmax(out, dim=-1)
        return nll_prob
3. 模型训练

配置优化器、损失函数,迭代训练模型,并记录损失变化:

python 复制代码
# 初始化模型、优化器、损失函数
model = CBOW(vocab_size, 10).to(device)  # 词向量维度设为10
optimizer = optim.Adam(model.parameters(), lr=0.001)
loss_function = nn.NLLLoss()  # 负对数似然损失(适配log_softmax输出)
losses = []

# 训练模式
model.train()
# 迭代训练200轮
for epoch in tqdm(range(200), desc="Training"):
    total_loss = 0
    for context, target in data:
        # 1. 准备数据:上下文张量 + 目标词张量
        context_vector = make_context_vector(context, word_to_idx).to(device)
        target = torch.tensor([word_to_idx[target]]).to(device)
        
        # 2. 前向传播
        predict = model(context_vector)
        loss = loss_function(predict, target)
        
        # 3. 反向传播 + 优化
        optimizer.zero_grad()  # 清空梯度
        loss.backward()        # 反向传播
        optimizer.step()       # 更新参数
        
        # 累计损失
        total_loss += loss.item()
    losses.append(total_loss)
    # 打印每轮损失(可选)
    # print(f"Epoch {epoch+1}, Loss: {total_loss:.4f}")

print("训练完成,损失变化:", losses[:5], "...")  # 打印前5轮损失
4. 模型测试与词向量提取

训练完成后,我们可以用自定义上下文测试模型预测效果,并提取最终的词向量:

python 复制代码
# 测试模型:自定义上下文预测中心词
context = ['People','create','to','direct']
context_vector = make_context_vector(context, word_to_idx).to(device)

# 评估模式(关闭Dropout等)
model.eval()
with torch.no_grad():  # 禁用梯度计算
    predict = model(context_vector)
    max_idx = predict.argmax(1)  # 取概率最大的索引
    print("预测中心词:", idx_to_word[max_idx.item()])

# 提取词向量:嵌入层权重即为词向量
print("\n嵌入层权重(词向量矩阵):", model.embeddings.weight)
# 转换为CPU上的numpy数组(方便后续使用)
W = model.embeddings.weight.cpu().detach().numpy()

# 构建词→词向量的映射字典
word_2_vec = {}
for word in word_to_idx.keys():
    word_2_vec[word] = W[word_to_idx[word], :]

# 保存词向量到文件
np.savez('cbow_word2vec.npz', word_vectors=W)
# 加载验证
data = np.load('cbow_word2vec.npz')
print("\n保存的词向量文件:", data.files)
print("示例词向量(process):", word_2_vec["process"])

三、结果分析与拓展

1. 损失变化解读

训练过程中,损失值应逐步下降并趋于稳定,这说明模型正在学习到上下文与中心词的关联规律。如果损失下降缓慢,可尝试调整学习率、词向量维度、上下文窗口大小或训练轮数。

2. 词向量的应用

提取到的词向量可用于:

• 词汇相似度计算:通过余弦相似度衡量两个词的语义相似性;

• 文本分类/情感分析:将词向量作为模型输入特征;

• 词汇类比推理:如"国王-男人+女人=女王"的经典推理任务。

3. 模型优化方向

本文实现的是基础版CBOW,可从以下方向优化:

• 替换求和为平均:上下文词向量求和改为平均,减少长上下文的数值偏差;

• 增大语料库:本文语料较小,实际应用需用大规模语料训练;

• 加入负采样(Negative Sampling):替代全量Softmax,提升训练效率;

• 调整超参数:词向量维度(如100/200/300)、上下文窗口、学习率等。

四、总结

本文从原理到代码,完整实现了基于CBOW的Word2Vec模型,核心要点:

  1. CBOW通过"上下文预测中心词"学习词向量,是Word2Vec的核心模型之一;

  2. 嵌入层的权重即为词向量,这是NLP中词向量的核心来源;

  3. PyTorch的nn.Embedding层是实现词向量的关键,结合全连接层可快速搭建CBOW模型。

通过本文的实现,相信大家对词向量的生成逻辑有了更直观的理解。在此基础上,可进一步探索Skip-gram模型、负采样优化等内容,深入掌握Word2Vec的精髓。

相关推荐
Flying pigs~~2 小时前
基于Bert的模型迁移文本分类项目
人工智能·深度学习·算法·大模型·nlp·bert
新加坡内哥谈技术2 小时前
AI代理可能会让自由软件再次变得重要
人工智能·ai编程
风象南2 小时前
学了 100 个 AI 工具,不如把 1 个用到极致
人工智能
Datacarts2 小时前
AI大模型时代:1688商品数据API如何重构电商智能决策
大数据·人工智能·重构
呆呆敲代码的小Y2 小时前
【Unity-AI开发篇】| 游戏中接入DeepSeek实现AI对话,完整详细步骤
人工智能·游戏·unity·ai·游戏引擎·u3d·deepseek
nancy_princess10 小时前
clip实验
人工智能·深度学习
飞哥数智坊10 小时前
TRAE Friends@济南第4次活动:100+极客集结,2小时极限编程燃爆全场!
人工智能
AI自动化工坊10 小时前
ProofShot实战:给AI编码助手添加可视化验证,提升前端开发效率3倍
人工智能·ai·开源·github
飞哥数智坊10 小时前
一场直播涨粉 2 万的背后!OpenClaw + 飞书,正在重塑软件交付的方式
人工智能