word2vec模型案例

代码实现:

import torch.optim as optim
from tqdm import tqdm, trange
import numpy as np
import torch
from torch import nn
import torch.nn.functional as FCONTEXT_SIZE = 2raw_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()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)}data = []
for i in range(CONTEXT_SIZE, len(raw_text) - CONTEXT_SIZE):  # (2, 60)context = ([raw_text[i - (2-j)] for j in range(CONTEXT_SIZE)]          # [we,are]+ [raw_text[i + j + 1] for j in range(CONTEXT_SIZE)]       # [to,study])target = raw_text[i]  # 目标词data.append((context, target))def make_context_vector(context,word_to_idx):idxs = [word_to_idx[x] for x in context]return torch.tensor(idxs,dtype=torch.long)
print(make_context_vector(data[0][0],word_to_idx))device = 'cuda' if torch.cuda.is_available() else 'mps' if torch.backends.mps.is_available() else 'cpu'
print(device)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)null_plob = F.log_softmax(out,dim=-1)return null_plobmodel = CBOW(vocab_size,10).to(device)
optimizer = optim.Adam(model.parameters(),lr=0.001)
losses = []
loss_function = nn.NLLLoss()
model.train()
for epoch in tqdm(range(200)):total_loss = 0size = 0for 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()size += 1avg_loss = total_loss / sizeprint(avg_loss)context = ['People', 'create', 'to', 'direct']  # People create programs to direct
context_vector = make_context_vector(context, word_to_idx).to(device)# 预测的值
model.eval()  # 进入到测试模式
predict = model(context_vector)
max_idx = predict.argmax(1)  # dim=1表示每一行中的最大值对应的索引号,dim=0表示每一列中的最大值对应的索引号# 获取词向量,这个Embedding就是我们需要的词向量,他只是一个模型的一个中间过程
print("CBOW embedding weight=", model.embeddings.weight)  # GPU
W = model.embeddings.weight.cpu().detach().numpy()  # .detach(): 这个方法会创建一个新的Tensor,它和原来的Tensor共享# 这意味着这个新的Tensor不会参与梯度的反向传播,这对于防止在计算梯度时意外修改某些参数很有用。
print(W)# 生成词嵌入字典,即{单词1:词向量1,单词2:词向量2...}的格式
word_2_vec = {}
for word in word_to_idx.keys():# 词向量矩阵中某个词的索引所对应的那一列即为该词的词向量word_2_vec[word] = W[word_to_idx[word], :]
print('jiesu')# 保存训练后的词向量为npz文件,numpy处理矩阵的速度非常快,方便后期其他操作
np.savez('word2vec实现.npz', file_1=W)
data = np.load('word2vec实现.npz')
print(data.files)

这段代码是一个基于 PyTorch 实现的CBOW(连续词袋模型) 示例,用于训练词向量(类似 Word2Vec 的核心功能)。下面逐步分析代码:

一、核心功能概述

代码通过一段示例文本训练 CBOW 模型,最终得到每个单词的低维向量表示(词嵌入)。CBOW 的核心思想是:用一个单词的上下文(周围单词)预测该单词本身,通过这个过程让模型学习到单词的语义向量。

二、代码分步解析

1. 导入依赖库
import torch.optim as optim  # PyTorch优化器
from tqdm import tqdm, trange  # 进度条工具
import numpy as np  # 数值计算
import torch
from torch import nn  # 神经网络模块
import torch.nn.functional as F  # 神经网络函数(如激活函数、softmax等)

这些是 PyTorch 深度学习和数据处理的基础库,tqdm用于显示训练进度,提高可视化体验。

2. 数据预处理
(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()

CONTEXT_SIZE=2表示:对于每个目标词,取其前面 2 个词 + 后面 2 个词作为上下文(共 4 个词)。

(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)]  # 前面2个词(如i=2时,取i-2, i-1)+ [raw_text[i + j + 1] for j in range(CONTEXT_SIZE)]  # 后面2个词(如i=2时,取i+1, i+2))target = raw_text[i]  # 目标词(当前位置的词)data.append((context, target))

例如,对于句子片段We are about to study

  • 当目标词是about(索引 = 2)时,上下文是前面的We, are和后面的to, study,即(["We", "are", "to", "study"], "about")

data最终是一个列表,每个元素是(上下文单词列表, 目标词)的元组,用于模型训练。

(4)上下文转向量函数
def make_context_vector(context, word_to_idx):# 将上下文单词转为对应的索引,再封装成PyTorch张量idxs = [word_to_idx[x] for x in context]return torch.tensor(idxs, dtype=torch.long)

将上下文的单词列表(如["We", "are", "to", "study"])转为索引张量(如[10, 5, 3, 8]),作为模型的输入。

3. 设备配置
device = 'cuda' if torch.cuda.is_available() else 'mps' if torch.backends.mps.is_available() else 'cpu'
print(device)

自动选择训练设备:优先用 NVIDIA GPU(cuda),其次 Apple GPU(mps),最后用 CPU,以加速训练。

4. CBOW 模型定义
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)# 输出层:将128维向量映射到词汇表大小(预测目标词)self.output = nn.Linear(128, vocab_size)def forward(self, inputs):# 1. 上下文嵌入:获取输入的每个单词的嵌入向量,求和(上下文向量的平均/求和代表上下文语义)embeds = sum(self.embeddings(inputs)).view(1, -1)  # 形状:(1, embedding_dim)# 2. 投影层+激活函数out = F.relu(self.proj(embeds))  # 形状:(1, 128)# 3. 输出层+log_softmax(将输出转为概率分布的对数)out = self.output(out)  # 形状:(1, vocab_size)log_probs = F.log_softmax(out, dim=-1)  # 沿最后一维计算softmax并取对数return log_probs

模型核心逻辑:

嵌入层(embeddings):是训练的核心,其权重就是最终的词向量(每个单词对应一行向量)。

前向传播:将上下文单词的嵌入向量求和(代表上下文的整体语义),通过两层线性网络,最终输出对目标词的概率分布(对数形式)。

5. 模型训练
# 初始化模型(词汇表大小,嵌入维度10),并移动到指定设备
model = CBOW(vocab_size, 10).to(device)
# 优化器:Adam(常用的自适应学习率优化器)
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 损失函数:NLLLoss(负对数似然损失,配合log_softmax使用,等价于交叉熵损失)
loss_function = nn.NLLLoss()losses = []  # 记录损失
model.train()  # 切换到训练模式# 训练200个epoch
for epoch in tqdm(range(200)):total_loss = 0  # 总损失size = 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)# 3. 计算损失loss = loss_function(predict, target)# 4. 反向传播+参数更新optimizer.zero_grad()  # 清空梯度loss.backward()  # 计算梯度optimizer.step()  # 更新参数total_loss += loss.item()  # 累加损失(转为Python数值)size += 1# 计算并打印每个epoch的平均损失avg_loss = total_loss / sizeprint(f"Epoch {epoch+1}, Average Loss: {avg_loss}")losses.append(avg_loss)

训练过程流程:

每个 epoch 遍历所有训练样本(上下文 - 目标词对)。

对每个样本,模型根据上下文预测目标词,计算预测值与真实值的损失。

通过反向传播更新模型参数(尤其是嵌入层的权重,即词向量)。

随着训练进行,损失逐渐下降,说明模型越来越能通过上下文准确预测目标词。

6. 模型预测与词向量提取
(1)测试预测效果
# 测试上下文:"People", "create", "to", "direct"(对应原句"People create programs to direct processes")
context = ['People', 'create', 'to', 'direct']
context_vector = make_context_vector(context, word_to_idx).to(device)model.eval()  # 切换到评估模式(关闭 dropout 等训练特有的操作)
predict = model(context_vector)
max_idx = predict.argmax(1)  # 取概率最大的索引(预测的目标词)
print("预测的目标词:", idx_to_word[max_idx.item()])  # 理论上应输出"programs"

用训练好的模型测试:给定上下文People create ... to direct,模型应能预测出中间的目标词programs

(2)提取词向量
# 嵌入层的权重就是词向量(vocab_size × embedding_dim 的矩阵)
print("CBOW嵌入层权重(词向量矩阵):", model.embeddings.weight)# 将词向量矩阵从GPU移到CPU,并转为numpy数组(脱离计算图,不参与梯度计算)
W = model.embeddings.weight.cpu().detach().numpy()

CBOW 模型的核心输出是嵌入层的权重,每个单词对应的行向量就是该单词的语义向量(维度为 10,在初始化时指定)。

(3)构建词 - 向量字典并保存
# 构建{单词: 词向量}字典
word_2_vec = {}
for word in word_to_idx.keys():# 词向量矩阵中,单词索引对应的行即为该词的向量word_2_vec[word] = W[word_to_idx[word], :]# 保存词向量为npz文件(方便后续复用)
np.savez('word2vec实现.npz', word_vectors=W)
# 测试加载
data = np.load('word2vec实现.npz')
print("保存的词向量键名:", data.files)  # 输出 ['word_vectors']

将词向量整理为字典,并保存为 numpy 格式,方便后续用于语义相似度计算、文本分类等任务。

三、核心总结

  1. 数据层面:通过滑动窗口从文本中提取 “上下文 - 目标词” 对,作为训练样本。
  2. 模型层面:CBOW 模型通过嵌入层将单词转为向量,用上下文向量的总和预测目标词,最终学习到的嵌入层权重就是词向量。
  3. 训练目标:通过优化预测损失,让语义相近的词(如 “process” 和 “processes”)的向量更接近。
  4. 输出:得到每个单词的低维向量表示,可用于后续 NLP 任务(如语义相似度计算、文本分类等)。

这段代码是 Word2Vec 中 CBOW 模型的简化实现,核心思想与原始 Word2Vec 一致,适合理解词向量的训练原理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/96082.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/96082.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

< 自用文 OS 有关 > (续)发现正在被攻击 后的自救 Fail2ban + IPset + UFW 工作流程详解

继上编:< 自用文 主机 USC 记录:> 发现正在被攻击 后的自救-CSDN博客 环境: 改进: 以下是把代码,懒得写,扔给了 AI ,让它出的: Fail2ban IPset UFW 工作…

Linux —— 虚拟进程地址空间

🎁个人主页:工藤新一 🔍系列专栏:C面向对象(类和对象篇) 🌟心中的天空之城,终会照亮我前方的路 🎉欢迎大家点赞👍评论📝收藏⭐文章 文章目录虚…

简单聊一聊js

JavaScript 是一种高级的、解释型的编程语言。它是现代 Web 开发的三大核心基石之一,与 HTML 和 CSS 并列。​HTML​:负责网页的结构和内容​(如标题、段落、图片)。​CSS​:负责网页的样式和布局​(如颜色…

造粒机cad+设计说明书

摘要 随着现代化工业的快速发展,生产出大量的固体废弃物。这些废弃物对环境造成了很大的污染,因此需要采取有效的措施进行处理。机械强压式造粒机就是一种非常有效的处理工具,它可以将废渣、废料、饲料和化肥等材料通过机械强力挤压&#xff…

第五课 C#语言基本元素概览,初始类型,变量与方法,算法简介

熟悉C#语言要求:对构成C#语言的基本元素,随便拿出一个你都认识,对于常见基本元素,都能正确使用它 精通C#语言要求:对于构成C#语言的基本元素,随便拿出一个都会使用,对于常用基本元素&#xff0…

LLM学习:大模型基础——视觉大模型以及autodl使用

1、常见的VLM 在大模型中,VLM 是视觉语言模型(Vision-Language Model)的缩写,是一种多模态、生成式 AI 模型,能够理解和处理视频、图像和文本。 VLM 通过将大语言模型(LLM)与视觉编码器相结合构建而成,使 LLM 具有 “看” 的能力,从而可以处理并提供对提示中的…

Vue—路由配置中设置了meta.title,但页面标题仍然显示为“Vite App“?【让我来看看~】

路由配置中明明设置了meta.title,但是页面标题仍然显示为"Vite App"?这是因为仅仅在路由配置中设置meta.title是不够的,还需要在路由守卫中动态设置页面标题。需要做以下几件事来正确设置页面标题:1.首先更新HTML文件的…

【机器学习】综合实训(二)

项目五 电影评分预测【教学内容】使用 MovieLens 数据集,训练一个模型预测用户对电影的评分。主要有以下几个知识点:(1)数据加载与探索性分析(EDA)。(2)处理稀疏数据(如用…

STM32 UART + DMA + 空闲中断使用中的帧错误(FE)问题及解决方案

STM32 UART + DMA + IDLE中断使用中的帧错误(FE)问题及解决方案 在我调试STM32H7串口空闲中断DMA接受时遇到了一个bug,这个现象发生在系统刚上电时,有个串口由于帧错误FE挂起了中断,之后在HAL_UART_IRQHandler这个全局中断处理函数结束后,所有的中断使能标志位都被清除了,经过…

TDengine 选择函数 BOTTOM() 用户手册

BOTTOM() 函数用户手册 函数定义 BOTTOM(expr, k)功能说明 BOTTOM() 函数统计表/超级表中某列的值最小 k 个非 NULL 值。如果多条数据取值一样,全部取用又会超出 k 条限制时,系统会从相同值中随机选取符合要求的数量返回。 返回值 数据类型: 同应用…

西门子 S7-200 SMART PLC 实现星三角降压启动控制:原理、案例与完整程序

在工业控制场景中,中型异步电机直接启动时会产生远超额定电流的冲击电流(通常为额定电流的 5-7 倍),不仅会影响电网稳定性,还可能对机械设备造成损伤。星三角(Y-Δ)降压启动是解决这一问题的经典…

【Android】View 的基础知识

【Android】View 的基础知识 1. 什么是 View? View 是 Android 中所有UI组件的基础类。它表示屏幕上的一个矩形区域,负责绘制内容和处理用户交互事件。所有的 UI 组件(如按钮、文本框等)都是 View 的子类,而 ViewGroup…

西门子 S7-200 SMART PLC 实现电机点动与连续运行综合控制

在工业生产中,电机控制并非单一模式:调试设备时需要 “按动即转、松开即停” 的点动功能,正常生产时则需要 “一键启动、持续运行” 的连续控制。本文以西门子 S7-200 SMART PLC 为载体,详细讲解电机点动控制原理,并设…

如何解决pip安装报错ModuleNotFoundError: No module named ‘sphinx-rtd-theme’问题

【Python系列Bug修复PyCharm控制台pip install报错】如何解决pip安装报错ModuleNotFoundError: No module named ‘sphinx-rtd-theme’问题 摘要 在使用 PyCharm 开发 Python 项目时,pip install 报错是常见痛点。特别是在构建文档或引入第三方库时,开…

HakcMyVM-Literal

目录信息搜集漏洞利用权限提升信息搜集 主机发现 ┌──(kali㉿kali)-[~] └─$ nmap -sn 192.168.21.0/24 Nmap scan report for 192.168.21.5端口扫描 ┌──(kali㉿kali)-[~] └─$ nmap -sS -sV -O -p- 192.168.21.5 Starting Nmap 7.95 ( https://nmap.org ) a…

0904 类的继承

Part 1.梳理思维导图一.继承中的特殊成员函数1.构造函数父类的构造函数会被继承到子类中&#xff0c;在构造的顺序中&#xff0c;是先构造父类&#xff0c;再构造子类#include <iostream>using namespace std;class Father { public:string name; protected:int *age; pr…

PDF教程|如何把想要的网页保存下来?

前段时间有个小伙伴咨询了小白&#xff1a;领导想要某个网页的整个页面&#xff0c;有没有比较好的方法把它保存下来&#xff1f; 在他找到小白之前&#xff0c;这种事情他已经接到好几次了&#xff0c;每次都是怎么解决的呢&#xff1f;其实很简单&#xff0c;就是打开Word&a…

【bash】命令查看当前目录下文件个数

要用 ls 查看当前目录下的文件个数&#xff0c;可以结合 wc -l 来统计行数&#xff1a; ls -1 | wc -l说明&#xff1a; ls -1&#xff1a;以一行一个文件的方式列出。wc -l&#xff1a;统计行数&#xff0c;也就是文件/目录的数量。 ⚠️ 需要注意&#xff1a; 这个方法会把文…

「日拱一码」081 机器学习——梯度增强特征选择GBFS

目录 什么是梯度增强特征选择&#xff08;GBFS&#xff09; 为什么 GBM 适合做特征选择 GBFS 的一般步骤 代码示例 什么是梯度增强特征选择&#xff08;GBFS&#xff09; GBFS 并非一个像 Lasso 或随机森林那样有严格标准定义的独立算法&#xff0c;而是一种基于梯度提升机…

解构汇编, 万物起源

汇编的诞生汇编全景图核心主干: CPU架构主要分支: 语法和工具共同的地貌: 核心概念延伸: 跨平台 & 跨架构跨平台跨架构总结以 GAS vs. NASM 为例NASM 不支持跨架构 ≠ 无法在ARM架构上的系统安装汇编的诞生 机器语言的困境 早期的程序员直接使用机器语言进行编程机器语言由…