当前位置: 首页 > news >正文

Word2Vec模型详解:CBOW与Skip-gram

Word2Vec模型详解:CBOW与Skip-gram

目录

  1. 模型概述
  2. 理论基础
  3. CBOW模型详解
  4. Skip-gram模型详解
  5. 模型对比
  6. 代码实现详解
  7. 训练过程分析
  8. 应用场景
  9. 实验结果
  10. 总结

模型概述

Word2Vec是一种用于生成词向量的神经网络模型,由Google在2013年提出。它包含两种主要架构:

  • CBOW (Continuous Bag of Words): 根据上下文词汇预测目标词
  • Skip-gram: 根据目标词预测上下文词汇

这两种模型都能将词汇转换为高维密集向量,使得语义相近的词在向量空间中距离较近。

理论基础

基本假设

Word2Vec基于分布式假设:在相似上下文中出现的词汇具有相似的语义。

核心思想

通过神经网络学习词汇的分布式表示,使得:

  1. 语义相似的词汇在向量空间中距离较近
  2. 词汇间的语义关系通过向量运算体现
  3. 支持词汇类比推理(如:国王-男人+女人=皇后)

CBOW模型详解

模型架构

上下文词汇 → 嵌入层 → 平均池化 → 线性层 → 目标词概率

CBOW模型通过上下文词汇的平均嵌入来预测中心词汇。

代码实现

1. 模型定义
# 定义CBOW模型类,继承自PyTorch的神经网络模块
class CBOWModel(nn.Module):def __init__(self, vocab_size, embedding_dim):# 调用父类构造函数super(CBOWModel, self).__init__()# 创建词嵌入层,将词汇索引映射到密集向量self.embedding = nn.Embedding(vocab_size, embedding_dim)# 创建线性层,将嵌入向量映射到词汇表大小的输出self.linear = nn.Linear(embedding_dim, vocab_size)def forward(self, context_words):# 前向传播函数,context_words形状: [batch_size, context_size]# 获取上下文词汇的嵌入向量embeds = self.embedding(context_words)  # 形状: [batch_size, context_size, embedding_dim]# 计算上下文词汇嵌入的平均值mean_embed = torch.mean(embeds, dim=1)  # 形状: [batch_size, embedding_dim]# 通过线性层得到最终输出out = self.linear(mean_embed)  # 形状: [batch_size, vocab_size]return out

关键特点

  • 单一嵌入层:所有词汇共享同一个嵌入空间
  • 平均池化:对上下文词汇嵌入求平均
  • 分类任务:输出目标词汇的概率分布
2. 数据集创建
def create_cbow_dataset(corpus, window_size=2):"""创建CBOW训练数据集"""# 初始化数据列表data = []# 遍历语料库,跳过边界位置for i in range(window_size, len(corpus) - window_size):# 初始化上下文词汇列表context = []# 当前位置的词汇作为目标词target = corpus[i]# 收集目标词周围的上下文词汇for j in range(i - window_size, i + window_size + 1):# 跳过目标词本身if j != i:# 添加上下文词汇到列表context.append(corpus[j])# 将上下文和目标词作为训练样本data.append((context, target))# 返回训练数据集return data

数据格式:每个样本为 ([上下文词汇列表], 目标词)

3. 完形填空功能
def cloze_test(model, sentence, mask_position, word_to_id, id_to_word, window_size=2, top_k=5):"""完形填空函数"""# 将句子分割成词汇列表words = sentence.lower().replace('.', ' .').split()# 检查mask位置是否有效if mask_position >= len(words) or mask_position < 0:print(f"无效的mask位置: {mask_position}")return None# 保存被遮掩的真实词汇true_word = words[mask_position]print(f"被遮掩的词汇: '{true_word}'")# 提取上下文词汇(排除mask位置)context_words = []for i in range(max(0, mask_position - window_size), min(len(words), mask_position + window_size + 1)):if i != mask_position and words[i] in word_to_id:context_words.append(word_to_id[words[i]])# 进行预测with torch.no_grad():context_tensor = torch.tensor(context_words, dtype=torch.long).unsqueeze(0)output = model(context_tensor)probabilities = F.softmax(output, dim=1)# 获取top-k预测结果top_probs, top_indices = torch.topk(probabilities, top_k, dim=1)# 显示预测结果predictions = []for i in range(top_k):word_idx = top_indices[0][i].item()prob = top_probs[0][i].item()predicted_word = id_to_word[word_idx]predictions.append((predicted_word, prob))print(f"{predicted_word}\t\t{prob:.4f}")return predictions

完形填空原理:CBOW天然适合完形填空,因为它就是根据上下文预测目标词。


Skip-gram模型详解

模型架构

目标词 → 目标嵌入层 ↘→ 相似度计算 → 上下文词概率
上下文词 → 上下文嵌入层 ↗

Skip-gram使用两个独立的嵌入层,通过负采样进行训练。

代码实现

1. 模型定义
# 定义Skip-gram模型类,继承自PyTorch的神经网络模块
class SkipGramModel(nn.Module):def __init__(self, vocab_size, embedding_dim):# 调用父类构造函数super(SkipGramModel, self).__init__()# 创建输入词嵌入层,将目标词索引映射到密集向量self.target_embedding = nn.Embedding(vocab_size, embedding_dim)# 创建输出词嵌入层,用于预测上下文词self.context_embedding = nn.Embedding(vocab_size, embedding_dim)def forward(self, target_word, context_words):# 前向传播函数# target_word: [batch_size] - 目标词索引# context_words: [batch_size] - 上下文词索引# 获取目标词的嵌入向量target_embed = self.target_embedding(target_word)  # [batch_size, embedding_dim]# 获取上下文词的嵌入向量context_embed = self.context_embedding(context_words)  # [batch_size, embedding_dim]# 计算目标词和上下文词的相似度得分score = torch.sum(target_embed * context_embed, dim=1)  # [batch_size]return score

关键特点

  • 双嵌入层:目标词和上下文词有不同的嵌入空间
  • 点积相似度:计算目标词和上下文词嵌入的内积
  • 回归任务:输出相似度得分
2. 负采样训练
def negative_sampling(vocab_size, num_negatives=5):"""负采样:随机选择负样本词汇"""# 随机生成负样本词汇索引negative_samples = torch.randint(0, vocab_size, (num_negatives,))return negative_samplesdef train_skipgram(model, train_data, vocab_size, epochs=100, learning_rate=0.01, num_negatives=5):"""训练Skip-gram模型(使用负采样)"""# 定义二元交叉熵损失函数criterion = nn.BCEWithLogitsLoss()# 定义Adam优化器optimizer = optim.Adam(model.parameters(), lr=learning_rate)for epoch in range(epochs):total_loss = 0for target, context in train_data:# 正样本训练target_tensor = torch.tensor([target], dtype=torch.long)context_tensor = torch.tensor([context], dtype=torch.long)positive_label = torch.tensor([1.0], dtype=torch.float)positive_score = model(target_tensor, context_tensor)positive_loss = criterion(positive_score, positive_label)# 负样本训练negative_samples = negative_sampling(vocab_size, num_negatives)negative_labels = torch.zeros(num_negatives, dtype=torch.float)target_repeated = target_tensor.repeat(num_negatives)negative_scores = model(target_repeated, negative_samples)negative_loss = criterion(negative_scores, negative_labels)# 总损失total_sample_loss = positive_loss + negative_loss# 反向传播和参数更新optimizer.zero_grad()total_sample_loss.backward()optimizer.step()total_loss += total_sample_loss.item()return losses

负采样原理

  • 正样本:真实的(目标词, 上下文词)对,标签为1
  • 负样本:随机的(目标词, 非上下文词)对,标签为0
  • 避免计算整个词汇表的softmax,提高训练效率
3. 上下文预测功能
def predict_context_words(model, target_word, word_to_id, id_to_word, top_k=5):"""预测给定目标词的上下文词汇"""target_idx = word_to_id[target_word]target_tensor = torch.tensor([target_idx], dtype=torch.long)model.eval()with torch.no_grad():# 计算目标词与所有词汇的相似度得分scores = []vocab_size = len(word_to_id)for word_idx in range(vocab_size):context_tensor = torch.tensor([word_idx], dtype=torch.long)score = model(target_tensor, context_tensor)scores.append((word_idx, score.item()))# 按得分降序排序并返回top-k结果scores.sort(key=lambda x: x[1], reverse=True)predictions = []for i in range(min(top_k, len(scores))):word_idx, score = scores[i]predicted_word = id_to_word[word_idx]if predicted_word != target_word:predictions.append((predicted_word, score))return predictions

上下文预测原理:Skip-gram擅长预测给定词汇的可能上下文,适用于词汇扩展和同义词发现。


模型对比

特性CBOWSkip-gram
输入上下文词汇目标词
输出目标词概率上下文词得分
嵌入层单一共享嵌入双独立嵌入
训练数据量较少较多
计算复杂度较低较高
适用场景完形填空、语言模型词汇扩展、相似词发现
对频率的敏感性对高频词效果好对低频词效果好

数学表示

CBOW目标函数

maximize Σ log P(w_t | context(w_t))

Skip-gram目标函数

maximize Σ Σ log P(w_c | w_t)

其中:

  • w_t: 目标词
  • w_c: 上下文词
  • context(w_t): 目标词的上下文窗口

代码实现详解

共享组件

1. 数据预处理
def preprocess(text):"""文本预处理函数"""# 转换为小写并分割单词word = text.lower().replace('.', ' .').split(' ')# 创建词汇到ID的映射word_to_id = {}id_to_word = {}for w in word:if w not in word_to_id:tmp = len(word_to_id)word_to_id[w] = tmpid_to_word[tmp] = w# 获得ID列表corpus = [word_to_id[w] for w in word]return corpus, word_to_id, id_to_word
2. 相似度计算
def cos_similarity(x, y, eps=1e-8):"""计算余弦相似度"""nx = x / (np.sqrt(np.sum(x ** 2)) + eps)ny = y / (np.sqrt(np.sum(y ** 2)) + eps)return np.dot(nx, ny)
3. 词向量可视化
def visualize_embeddings(word_vectors, word_to_id, max_words=50):"""可视化词向量(使用PCA降维到2D)"""from sklearn.decomposition import PCAwords = list(word_vectors.keys())[:max_words]vectors = [word_vectors[word] for word in words]pca = PCA(n_components=2)vectors_2d = pca.fit_transform(vectors)plt.figure(figsize=(12, 8))plt.scatter(vectors_2d[:, 0], vectors_2d[:, 1], alpha=0.7)for i, word in enumerate(words):plt.annotate(word, (vectors_2d[i, 0], vectors_2d[i, 1]))plt.title('Word Embeddings Visualization (PCA)')plt.show()

训练流程对比

CBOW训练流程
  1. 提取上下文词汇窗口
  2. 计算上下文词汇嵌入的平均值
  3. 通过线性层预测目标词
  4. 使用交叉熵损失进行优化
Skip-gram训练流程
  1. 选择目标词和一个上下文词
  2. 计算正样本得分和损失
  3. 进行负采样,计算负样本损失
  4. 使用二元交叉熵损失进行优化

训练过程分析

超参数设置

# 共同超参数
window_size = 2        # 上下文窗口大小
embedding_dim = 100    # 词向量维度
epochs = 100          # 训练轮数
learning_rate = 0.01  # 学习率# Skip-gram特有参数
num_negatives = 5     # 负采样数量

训练数据量对比

以示例文本为例:

  • CBOW: 15个训练样本(每个位置一个样本)
  • Skip-gram: 60个训练样本(每个(目标词,上下文词)对一个样本)

损失函数分析

CBOW损失曲线特点

  • 初始损失较高(约3.0)
  • 快速收敛到接近0
  • 曲线较为平滑

Skip-gram损失曲线特点

  • 初始损失很高(约7.6)
  • 收敛较慢,存在波动
  • 最终损失相对较高(约1.3)

应用场景

CBOW适用场景

  1. 完形填空任务

    # 例:根据"you say ___ and I"预测"goodbye"
    cloze_test(model, "you say goodbye and I say hello", 2, word_to_id, id_to_word)
    
  2. 语言模型构建

    • 文本生成
    • 语法检查
    • 自动补全
  3. 高频词处理

    • 对常见词汇效果更好
    • 适合处理语法功能词

Skip-gram适用场景

  1. 词汇扩展和发现

    # 例:根据"love"找到相关词汇
    predict_context_words(model, "love", word_to_id, id_to_word)
    
  2. 同义词挖掘

    • 发现语义相似词汇
    • 构建同义词词典
  3. 低频词处理

    • 对罕见词汇效果更好
    • 适合处理专业术语
  4. 词汇类比推理

    # 概念上的:king - man + woman ≈ queen
    

实验结果

训练效果对比

测试文本: “you say goodbye and I say hello. what are you talking about? I love natural language processing.”

CBOW结果
相似词查找:
- "you" 的相似词: are, language, goodbye, i, about?
- "say" 的相似词: goodbye, what, natural, love, talking
- "hello" 的相似词: and, love, are, goodbye, about?完形填空准确性: 中等
收敛速度: 快
Skip-gram结果
相似词查找:
- "you" 的相似词: say, language, natural, love, hello
- "say" 的相似词: talking, hello, you, language, i
- "hello" 的相似词: goodbye, ., say, language, about?上下文预测能力: 强
词汇发现能力: 强

性能分析

指标CBOWSkip-gram
训练速度
内存消耗
收敛稳定性中等
词汇发现能力中等
语法理解能力中等

代码使用指南

运行CBOW模型

cd nlp
python cbow_pytorch.py

功能包括

  • 模型训练和损失可视化
  • 相似词查找
  • 批量完形填空测试
  • 交互式完形填空
  • 词向量可视化

运行Skip-gram模型

cd nlp
python skipgram_pytorch.py

功能包括

  • 负采样训练
  • 相似词查找
  • 上下文词预测
  • 词向量可视化

自定义使用

# 导入模型
from cbow_pytorch import CBOWModel, train_cbow
from skipgram_pytorch import SkipGramModel, train_skipgram# 准备数据
text = "your custom text here"
corpus, word_to_id, id_to_word = preprocess(text)# 训练CBOW
cbow_model = CBOWModel(len(word_to_id), 100)
cbow_data = create_cbow_dataset(corpus)
train_cbow(cbow_model, cbow_data)# 训练Skip-gram
skipgram_model = SkipGramModel(len(word_to_id), 100)
skipgram_data = create_skipgram_dataset(corpus)
train_skipgram(skipgram_model, skipgram_data, len(word_to_id))

优化建议

模型改进方向

  1. 层次化Softmax

    • 替代负采样,提高大词汇表训练效率
    • 基于词频构建二叉树结构
  2. 子词信息

    • 引入字符级或子词级信息
    • 处理未登录词和形态变化
  3. 动态窗口

    • 根据距离调整上下文权重
    • 更好捕捉长距离依赖

工程优化

  1. 批处理训练

    # 当前实现是单样本训练,可以改为批处理
    batch_size = 32
    
  2. 数据并行

    # 使用PyTorch的DataParallel进行多GPU训练
    model = nn.DataParallel(model)
    
  3. 内存优化

    • 使用gradient checkpointing
    • 动态词汇表

总结

核心要点

  1. CBOW与Skip-gram是互补的

    • CBOW:上下文→目标词,适合完形填空
    • Skip-gram:目标词→上下文,适合词汇发现
  2. 训练策略不同

    • CBOW:使用交叉熵损失,直接优化
    • Skip-gram:使用负采样,避免昂贵的softmax
  3. 应用场景各异

    • CBOW:语言建模、语法任务
    • Skip-gram:语义分析、词汇扩展

选择建议

  • 小数据集:选择CBOW,训练更稳定
  • 大数据集:选择Skip-gram,效果更好
  • 完形填空:使用CBOW
  • 词汇发现:使用Skip-gram
  • 平衡考虑:可以同时训练两个模型并集成

扩展方向

  1. FastText: 加入子词信息
  2. GloVe: 结合全局统计信息
  3. ELMo: 上下文相关的词向量
  4. BERT: 双向Transformer编码器

这两个模型为现代NLP奠定了重要基础,理解它们的原理和实现对深入学习词嵌入技术具有重要意义。

http://www.dtcms.com/a/270027.html

相关文章:

  • 结构化数据格式解析:JSON 与 XML 的技术应用与实践
  • Serverless 数据库来了?无服务器数据库 vs 传统数据库有何不同?
  • MySQL索引面试问题梳理
  • 华为eNSP防火墙实验(包含详细步骤)
  • Spring AI:检索增强生成(RAG)
  • SystemVerilog 断言重复操作符和序列操作符
  • 用 Spring Boot + Redis 实现哔哩哔哩弹幕系统(上篇博客改进版)
  • 2025年INS SCI2区,灵活交叉变异灰狼算法GWO_C/M+集群任务调度,深度解析+性能实测
  • 短视频电商APP源码开发技术栈解析:音视频、商品链路与互动设计
  • Web前端:not(否定伪类选择器)
  • 高效学习之一篇搞定分布式管理系统Git !
  • 编译安装Python 3.9(Linux Centos 7)
  • 淘宝直播与开源链动2+1模式AI智能名片S2B2C商城小程序的融合发展研究
  • Spring中Bean的实例化(xml)
  • 【docker】linux CentOS docker 安装流程
  • CSS知识复习5
  • CKS认证 | Day5 供应链安全 Trivy、kubesec、Webhook
  • 【Linux】基础开发工具(3)
  • 云归子批量混剪软件批量剪辑软件批量分割视频更新记录
  • 关于 scrapy框架 详解
  • Spring AI 基本组件详解 —— ChatClient、Prompt、Memory
  • 装修水电改造需要注意什么?水电改造有哪些注意事项?
  • C++ 的 copy and swap 惯用法
  • 05每日简报20250708
  • Kafka消息倾斜
  • 机器学习(西瓜书) 第三章 线性模型
  • Java 面向对象三大特性详解:封装、继承与多态,掌握OOP核心思想
  • OSPFv3和v2区别(续)
  • 数字人分身 + 矩阵系统聚合 + 碰一碰发视频:源码搭建 支持 OEM
  • 【网络协议安全】任务14:路由器DHCP_AAA_TELNET配置