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

pytorch实现基于Word2Vec的词嵌入

PyTorch 实现 Word2Vec(Skip-gram 模型) 的完整代码,使用 中文语料 进行训练,包括数据预处理、模型定义、训练和测试


1. 主要特点

支持中文数据,基于 jieba 进行分词
使用 Skip-gram 进行训练,适用于小数据集
支持负采样,提升训练效率
使用 cosine similarity 计算相似单词

完整代码:

import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import random
import jieba
from collections import Counter
from sklearn.metrics.pairwise import cosine_similarity

# ========== 1. 数据预处理 ==========
corpus = [
    "我们 喜欢 深度 学习",
    "自然 语言 处理 是 有趣 的",
    "人工智能 改变 了 世界",
    "深度 学习 是 人工智能 的 重要 组成部分"
]

# 超参数
window_size = 2      # 窗口大小
embedding_dim = 10   # 词向量维度
num_epochs = 100     # 训练轮数
learning_rate = 0.01 # 学习率
batch_size = 4       # 批大小
neg_samples = 5      # 负采样个数

# 分词 & 构建词汇表
tokenized_corpus = [list(jieba.cut(sentence)) for sentence in corpus]
vocab = set(word for sentence in tokenized_corpus for word in sentence)
word2idx = {word: idx for idx, word in enumerate(vocab)}
idx2word = {idx: word for word, idx in word2idx.items()}

# 统计词频
word_counts = Counter([word for sentence in tokenized_corpus for word in sentence])
total_words = sum(word_counts.values())

# 计算负采样概率
word_freqs = {word: count / total_words for word, count in word_counts.items()}
word_powers = {word: freq ** 0.75 for word, freq in word_freqs.items()}
Z = sum(word_powers.values())
word_distribution = {word: prob / Z for word, prob in word_powers.items()}

# 负采样函数
def negative_sampling(positive_word, num_samples=5):
    words = list(word_distribution.keys())
    probabilities = list(word_distribution.values())
    negatives = []
    while len(negatives) < num_samples:
        neg = np.random.choice(words, p=probabilities)
        if neg != positive_word:
            negatives.append(neg)
    return negatives

# 生成 Skip-gram 训练数据
data = []
for sentence in tokenized_corpus:
    indices = [word2idx[word] for word in sentence]
    for center_idx in range(len(indices)):
        center_word = indices[center_idx]
        for offset in range(-window_size, window_size + 1):
            context_idx = center_idx + offset
            if 0 <= context_idx < len(indices) and context_idx != center_idx:
                context_word = indices[context_idx]
                data.append((center_word, context_word))

# 转换为 PyTorch 张量
data = [(torch.tensor(center), torch.tensor(context)) for center, context in data]

# ========== 2. 定义 Word2Vec (Skip-gram) 模型 ==========
class Word2Vec(nn.Module):
    def __init__(self, vocab_size, embedding_dim):
        super(Word2Vec, self).__init__()
        self.embedding = nn.Embedding(vocab_size, embedding_dim)
        self.output_layer = nn.Linear(embedding_dim, vocab_size)

    def forward(self, center_word):
        embed = self.embedding(center_word)  # 获取中心词向量
        out = self.output_layer(embed)       # 计算词分布
        return out

# 初始化模型
model = Word2Vec(len(vocab), embedding_dim)

# ========== 3. 训练 Word2Vec ==========
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=learning_rate)

for epoch in range(num_epochs):
    total_loss = 0
    random.shuffle(data)  # 每轮打乱数据
    for center_word, context_word in data:
        optimizer.zero_grad()
        output = model(center_word.unsqueeze(0))  # 预测词分布
        loss = criterion(output, context_word.unsqueeze(0))  # 计算损失
        loss.backward()
        optimizer.step()
        total_loss += loss.item()
    
    if (epoch + 1) % 10 == 0:
        print(f"Epoch [{epoch+1}/{num_epochs}], Loss: {total_loss:.4f}")

# ========== 4. 测试词向量 ==========
word_vectors = model.embedding.weight.data.numpy()

# 计算单词相似度
def most_similar(word, top_n=3):
    if word not in word2idx:
        return "单词不在词汇表中"
    
    word_vec = word_vectors[word2idx[word]].reshape(1, -1)
    similarities = cosine_similarity(word_vec, word_vectors)[0]
    
    # 获取相似度最高的 top_n 个单词(排除自身)
    similar_idx = similarities.argsort()[::-1][1:top_n+1]
    return [(idx2word[idx], similarities[idx]) for idx in similar_idx]

# 测试相似词
test_words = ["深度", "学习", "人工智能"]
for word in test_words:
    print(f"【{word}】的相似单词:", most_similar(word))

数据预处理
  • 使用 jieba.cut() 进行分词
  • 创建 word2idxidx2word
  • 使用滑动窗口生成 (中心词, 上下文词) 训练样本
  • 实现 negative_sampling() 提高训练效率
模型
  • Embedding 学习词向量
  • Linear 计算单词的概率分布
  • CrossEntropyLoss 计算目标词与预测词的匹配度
  • 使用 Adam 进行梯度更新
计算词相似度
  • 使用 cosine_similarity 计算词向量相似度
  • 找出 top_n 个最相似的单词

 5. 可优化点

 使用更大的中文语料库(如 THUCNews
 使用 t-SNE 进行词向量可视化
增加负采样,提升模型训练效率


http://www.kler.cn/a/527463.html

相关文章:

  • Rust 条件语句
  • 前端八股CSS:盒模型、CSS权重、+与~选择器、z-index、水平垂直居中、左侧固定,右侧自适应、三栏均分布局
  • HarmonyOS简介:HarmonyOS核心技术理念
  • Xposed-Hook
  • AI大模型开发原理篇-1:语言模型雏形之N-Gram模型
  • 数据分析系列--⑤RapidMiner进行关联分析(中文数据案例)
  • 记一次将Java web服务部署上云的全过程
  • 安卓自用am命令记录
  • Python3 【装饰器】避坑指南:常见错误解析
  • [EAI-023] FAST,机器人动作专用的Tokenizer,提高VLA模型的能力和训练效率
  • 如何在 ACP 中建模复合罐
  • GCC, Makefile, make, CMake, CMakeLists.txt
  • 分布式微服务系统架构第89集:kafka消费者
  • 吴恩达深度学习——有效运作神经网络
  • 【LLM】Ollama框架入门指北
  • jEasyUI 创建 CRUD 应用
  • 安卓安全访问配置说明network-security-config —未来之窗跨平台操作
  • 【搞定offer】远程医疗:健康科技领域,搞定医疗offer
  • 2501,编写dll
  • 大语言模型(LLM)模拟金融市场参与者行为
  • 离线大模型-通义千问
  • 栈和队列特别篇:栈和队列的经典算法问题
  • ### 2024 江西省赛题解(A,C,D,G,H,J,K,L) BEFI待补
  • qt-Quick3D笔记之官方例程Runtimeloader Example运行笔记
  • 合并2个排序的链表
  • DeepSeek是什么,最近到底经历了什么?它能干什么?