Word2Vec模型学习和Word2Vec提取相似文本体验

文章目录

  • 说明
  • Word2Vec模型
    • 核心思想
    • 两种经典模型
    • 关键技术和算法流程
    • 优点和局限
    • 应用场景
  • Word2Vec提取相似文本
    • 完整源码
    • 执行结果

说明

  • 本文适用于初学者,体验Pytorch框架在自然语言处理中的使用。简单了解学习Word2Vec模型,体验其使用。

Word2Vec模型

  • Word2Vec 是一种广泛使用的 词嵌入(Word Embedding) 技术,由 Google 团队(Tomas Mikolov 等)于 2013 年提出。它通过将词语映射到低维稠密向量空间,捕捉词语之间的语义和语法关系,使得相似含义或用法的词在向量空间中距离更近。
  • Word2Vec模型使用一层神经网络将one-hot(独热编码)形式的词向量映射到分布式形式的词向量,使用了层次Softmax、负采样(Negative Sampling)等技巧进行训练速度上的优化。
  • Word2Vec模型的主要用途有两点:一是用于其他复杂的神经网络模型的初始化(预处理);二是把词与词之间的相似度用作某个模型的特征(分析)。

核心思想

  • Word2Vec 基于 “分布假说”(Distributional Hypothesis): “具有相似上下文的词语,其语义也相似。” 模型通过分析大量文本数据,学习词语的分布式表示(即向量)。

两种经典模型

  1. CBOW(Continuous Bag-of-Words)

    • 目标:通过上下文词语(窗口内的周围词)预测当前词。
    • 特点:适合小型数据集或高频词,训练速度较快。
    • 示例
      句子:"The cat sits on the mat"
      输入:["the", "cat", "on", "the"](上下文) → 输出预测:"sits"
  2. Skip-gram

    • 目标:通过当前词预测上下文词语。
    • 特点:适合大型数据集或低频词,能更好捕捉复杂模式。
    • 示例
      输入:"sits" → 输出预测:["the", "cat", "on", "the"]

关键技术和算法流程

  • 负采样(Negative Sampling):通过采样负例(非上下文词)加速训练,替代传统的 softmax 计算。
  • 层次 Softmax(Hierarchical Softmax):使用哈夫曼树减少计算复杂度,提升效率。
  • 滑动窗口(Window Size):控制上下文范围(通常 5~10 个词),影响语义捕捉的广度。

  • word2Vec实质上是一种降维操作,即将one-hot形式的词向量转换为Word2Vec形式。算法流程:
  1. one-hot形式的词向量输入单层神经网络中,其中输入层的神经元节点个数应该和one-hot形式的词向量维数相对应。
  2. 通过神经网络中的映射层中的激活函数计算目标单词与其他词汇的关联概率,在计算时使用了负采样的方式来提高其训练速度和正确率
  3. 通过使用随机梯度下降(SGD)优化算法计算损失。
  4. 通过反向传播算法对神经元的各个权重和偏置进行更新。

优点和局限

  1. 高效:比传统矩阵分解(如 LSA)更轻量。
  2. 可解释性:向量空间中的距离反映语义/语法相似性。
  3. 泛化能力:适用于多种下游任务(如文本分类、机器翻译)。

  1. 一词多义:无法处理多义词(如 "bank" 可能指河岸或银行)。
  2. 静态向量:每个词只有单一表示,无法根据上下文动态调整(后续模型如 BERT 解决了这一问题)。
  3. 依赖数据质量:需要大量语料才能训练出有效的向量。

应用场景

  • 文本相似度计算
  • 推荐系统(用户/物品的嵌入表示)
  • 机器翻译的前置处理
  • 命名实体识别(NER)、情感分析等 NLP 任务

Word2Vec提取相似文本

完整源码

import collections
import math
import random
import sys
import timeimport torch.utils.data as Data
import torch
from torch import nn
# Word2Vec提取相似文本
# 以只读方式打开文件 读取单词 存储在列表中
with open('HarryPotter.txt','r') as f:lines = f.readlines()raw_dataset=[st.split() for st in lines]"""
tk for st in raw_dataset for tk in st 等价于
result = []
for st in raw_dataset:        # 遍历每一条文本(每个子列表)for tk in st:             # 遍历文本中的每一个词(token)result.append(tk)     # 将词加入结果列表
"""
# tk是token的缩写
counter = collections.Counter([tk for st in raw_dataset for tk in st])
# 过滤低频词 只保留在数据集中至少出现5次的词
counter = dict(filter(lambda x: x[1] >= 5, counter.items()))
#  生成从索引到词的映射表 idx_to_token
"""
counter.items() 返回的是词频字典的所有键值对(词 + 出现次数)。
tk for tk, _ in counter.items() 遍历这些键值对,只取词(忽略频率),生成一个列表。
结果:idx_to_token 是一个列表,索引是词在列表中的位置,值是对应的词。
"""
idx_to_token = [tk for tk, _ in counter.items()]
# 生成从词到索引的映射表 token_to_idx
"""
使用 enumerate 遍历 idx_to_token 列表,得到每个词及其对应的索引。
构建一个字典,键是词(token),值是该词对应的索引(index)。
"""
token_to_idx = {tk: idx for idx, tk in enumerate(idx_to_token)}
# 将原始文本转换为索引表示 dataset raw_dataset中的单词在这一步被转换为对应的idx
"""
外层循环遍历每条原始文本 st(如句子或段落)。
内层循环遍历每个词 tk,如果这个词存在于 token_to_idx 中,则将其转换为对应的索引。
最终结果是一个二维列表,其中每个子列表是一条文本对应的词索引序列。
"""
dataset = [[token_to_idx[tk] for tk in st if tk in token_to_idx]for st in raw_dataset]
# 统计所有保留词的总数量 num_tokens
num_tokens = sum([len(st) for st in dataset])'''
二次采样操作
降频操作: 越高频率的词一般意义不大,根据公式高频词越容易被过滤。既不希望超高频被完全过滤,又希望减少高频词对训练的影响。
'''
def discard(idx):return random.uniform(0, 1) < 1 - math.sqrt(1e-4 / counter[idx_to_token[idx]] * num_tokens)
'''
提取中心词和背景词 将与中心词距离不超过背景窗口大小的词作为背景词
get_centers_and_contexts 函数提取所有的中心词和背景词
每次在整数1和max_window_size之间随机均匀采样一个整数作为背景窗口大小
'''
def get_centers_and_contexts(dataset, max_window_size):"""从给定的数据集中获取中心和上下文:param dataset: 数据集:param max_window_size: 最大背景窗口:return: 一个包含中心词和上下文的元组(centers, contexts)"""# 中心词和背景词列表centers, contexts = [], []# 遍历数据集中的每个字符串stfor st in dataset:# 跳过长度小于2的句子if len(st) < 2:continue# 将符合要求的单词添加到中心词列表中centers += st# 对于每个中心词for center_i in range(len(st)):# 随机选择一个背景窗口大小window_size = random.randint(1, max_window_size)# 生成一个包含中心词索引和周围索引的列表'''center_i:当前中心词在句子 st 中的索引位置。window_size:随机选择的窗口大小(范围为 1 到 max_window_size)。len(st):当前句子中词的总数量。1. center_i - window_size 计算窗口的起始索引(左边界),不能小于 0,所以用 max(0, ...) 来限制。2. center_i + 1 + window_size 计算窗口的结束索引(右边界),注意:加 1 是因为 Python 的 range(start, end) 是左闭右开区间;所以 center_i + 1 表示从中心词开始,至少包括它本身;再加上 window_size 就能取到右边最多 window_size 个词;使用 min(..., len(st)) 防止超出句子长度。3. range(...) + list(...) 把这个索引范围转换成一个整数列表,即所有可能的上下文词的位置。'''indices = list(range(max(0, center_i - window_size), min(len(st), center_i + 1 + window_size)))#  将中心词索引从列表中移除indices.remove(center_i)contexts.append([st[idx] for idx in indices])# 返回中心和上下文列表return centers, contexts# 假设最大背景窗口大小为5 提取中心词和背景词
all_centers, all_contexts = get_centers_and_contexts(dataset, 5)"""
负采样近似加快程序运行时间
对于一对中心词和背景词 随机采样5个噪声词
噪声词采样率P(w)设为w词频与总词频之比的0.75次方
"""
def get_negatives(all_contexts, sampling_weights, K):"""用于获取负样本:param all_contexts: 所有上下文的列表:param sampling_weights: 采样权重的列表:param K: 所需的负样本数量:return: all_negatives 包含负样本的列表"""all_negatives, neg_candidates, i = [], [], 0# 生成一个候选噪声词的列表,其中每个噪声词的采样权重与原始词的采样权重相同population = list(range(len(sampling_weights)))for contexts in all_contexts:# 初始化一个空列表用于存储负样本negatives = []# 当负样本数量小于上下文数量与k的乘积时,继续循环while len(negatives) < len(contexts) * K:# 如果i等于候选噪声词列表的长度,则重新生成候选噪声词列表if i == len(neg_candidates):i, neg_candidates = 0, random.choices(population, sampling_weights, k=int(1e5))# 获取下一个负样本和更新ineg, i = neg_candidates[i], i + 1# 如果负样本不在上下文中,则添加到负样本列表中if neg not in set(contexts):negatives.append(neg)# 将当前上下文的负样本添加到all_negatives列表中all_negatives.append(negatives)return all_negatives
# 计算采样权重 使用计数器中每个元素的0.75次方
sampling_weights = [counter[w] ** 0.75 for w in idx_to_token]
# 获取负样本
all_negatives = get_negatives(all_contexts, sampling_weights, 5)# 小批量读取函数batchify
"""
小批量输入data是一个列表 其中每个元素分别为中心词center、背景词context和噪声词negative
"""
def batchify(data):max_len = max(len(c) + len(n) for _, c, n in data)centers, contexts_negatives, masks, labels = [], [], [], []for center, context, negative in data:cur_len = len(context) + len(negative)centers += [center]contexts_negatives += [context + negative + [0] * (max_len - cur_len)]masks += [[1] * cur_len + [0] * (max_len - cur_len)]labels += [[1] * len(context) + [0] * (max_len - len(context))]batch = (torch.tensor(centers).view(-1, 1), torch.tensor(contexts_negatives),torch.tensor(masks), torch.tensor(labels))return batchclass MyDataset(torch.utils.data.Dataset):def __init__(self, centers, contexts, negatives):assert len(centers) == len(contexts) == len(negatives)self.centers = centersself.contexts = contextsself.negatives = negativesdef __getitem__(self, index):return (self.centers[index], self.contexts[index], self.negatives[index])def __len__(self):return len(self.centers)# 定义批次大小 并根据操作系统设置线程数
batch_size = 256
num_workers = 0 if sys.platform.startswith('win32') else -1
# 创建数据集
dataset = MyDataset(all_centers, all_contexts, all_negatives)
# 创建数据加载器
data_iter = Data.DataLoader(dataset, batch_size, shuffle=True,collate_fn=batchify,num_workers=num_workers)
# 遍历数据集
for batch in data_iter:for name, data in zip(['centers', 'contexts_negatives', 'masks', 'labels'], batch):print(name, 'shape:', data.shape)break# 搭建网络模型
#采用交叉熵损失函数
class SigmoidBinaryCrossEntropyLoss(nn.Module):def __init__(self):super(SigmoidBinaryCrossEntropyLoss, self).__init__()def forward(self, inputs, targets, mask=None):inputs, targets, mask = inputs.float(), targets.float(), mask.float()res = nn.functional.binary_cross_entropy_with_logits(inputs, targets, reduction="none", weight=mask)res = res.sum(dim=1) / mask.float().sum(dim=1)return resloss = SigmoidBinaryCrossEntropyLoss()# 定义sigmd函数
def sigmd(x):return - math.log(1 / (1 + math.exp(-x)))# 设置嵌入向量的大小
embed_size = 200
# 创建一个神经网络
"""
嵌入层 将输入的索引映射到嵌入向量 嵌入向量的维度为embed_size
nn.Embedding(num_embeddings=len(idx_to_token), embedding_dim=embed_size)
nn.Embedding(num_embeddings=len(idx_to_token), embedding_dim=embed_size)
"""
net = nn.Sequential(nn.Embedding(num_embeddings=len(idx_to_token), embedding_dim=embed_size),nn.Embedding(num_embeddings=len(idx_to_token), embedding_dim=embed_size))"""
center 中心词
contexts_and_negatives 上下文词和负样本 
embed_v 将输入映射到嵌入向量的函数
embed_u 将输入映射到嵌入向量的函数
"""
def skip_gram(center, contexts_and_negatives, embed_v, embed_u):v = embed_v(center)u = embed_u(contexts_and_negatives)pred = torch.bmm(v, u.permute(0, 2, 1))return pred"""
训练网络模型 
"""
def train(net, lr, num_epochs):device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')print("train on", device)net = net.to(device)optimizer = torch.optim.Adam(net.parameters(), lr=lr)for epoch in range(num_epochs):start, l_sum, n = time.time(), 0.0, 0for batch in data_iter:center, context_negative, mask, label = [d.to(device) for d in batch]pred = skip_gram(center, context_negative, net[0], net[1])l = loss(pred.view(label.shape), label, mask).mean()optimizer.zero_grad()l.backward()optimizer.step()l_sum += l.cpu().item()n += 1print('epoch %d, loss %.2f, time %.2fs'% (epoch + 1, l_sum / n, time.time() - start))train(net, 0.01, 5)# 定义函数用于获取给定查询令牌相似的令牌
def get_similar_tokens(query_token, k, embed):W = embed.weight.datax = W[token_to_idx[query_token]]cos = torch.matmul(W, x) / (torch.sum(W * W, dim=1) * torch.sum(x * x) + 1e-9).sqrt()_, topk = torch.topk(cos, k=k + 1)topk = topk.cpu().numpy()for i in topk[1:]:print('余弦相似度 = %.3f: %s' % (cos[i], (idx_to_token[i])))# 调用函数获取与'Dursley'最相似的5个令牌
get_similar_tokens('Dursley', 5, net[0])

执行结果

centers shape: torch.Size([256, 1])
contexts_negatives shape: torch.Size([256, 60])
masks shape: torch.Size([256, 60])
labels shape: torch.Size([256, 60])
train on cuda
epoch 1, loss 3.27, time 236.44s
epoch 2, loss 1.17, time 237.80s
epoch 3, loss 0.70, time 236.57s
epoch 4, loss 0.53, time 241.82s
epoch 5, loss 0.45, time 241.26s
余弦相似度 = 0.290: was
余弦相似度 = 0.285: one.
余弦相似度 = 0.282: tight
余弦相似度 = 0.278: moment,
余弦相似度 = 0.271: loudly,

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

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

相关文章

flutter 配置 安卓、Ios启动图

android 配置启动图 launch_background.xml <?xml version"1.0" encoding"utf-8"?> <!-- Modify this file to customize your launch splash screen --> <layer-list xmlns:android"http://schemas.android.com/apk/res/android&…

MCP(一)——QuickStart

目录 1. MCP简介2. MCP的优势3. MCP核心4. QuickStart For Server Developers(仅具参考)4.1 MCP核心概念4.2 构建MCP服务器的代码4.2.1 设置MCP服务器实例4.2.2 辅助函数4.2.3 实现工具执行4.2.4 在Cherry-Studio中添加MCP服务器4.2.5 演示4.2.5.1 测试工具get_alerts4.2.5.2 测…

Nginx网站功能

一.基于授权的访问控制 1.基于授权的访问控制简介 Nginx与Apahce 一样&#xff0c;可以实现基于用户授权的访问控制&#xff0c;当客户端想要访问相应网站或者目录时&#xff0c;要求用户输入用户名和密码才能正常访问&#xff0c;配置步骤与Apache基本一致。 2.基于授权的访…

海外盲盒系统开发:重构全球消费体验的科技引擎

当盲盒文化席卷全球&#xff0c;海外盲盒系统开发已成为重构消费体验的核心赛道。数据显示&#xff0c;2025年全球盲盒市场规模突破120亿&#xff0c;东南亚市场年增长率达4540。我们开发的海外盲盒系统&#xff0c;以技术创新为驱动&#xff0c;打造覆盖全链路的全球化解决方案…

数学建模初等模型应用

一、目的 掌握初等模型的建模方法,对简单的初等模型能借助Matlab工具软件进行辅助建模、求解和检验。 二、实验内容与设计思想&#xff08;设计思路、主要代码分析&#xff09; 1、预测鱼的质量 &#xff08;1&#xff09;设计思路&#xff1a;使用线性回归模型预测鱼的质量…

C 语言学习笔记(指针1)

内容提要 函数 变量的作用域变量的生命周期 指针 预备知识变量指针与指针变量 函数 变量的作用域 引入问题 我们在函数设计的过程中&#xff0c;经常要考虑对于参数的设计&#xff0c;换句话说&#xff0c;我们需要考虑函数需要几个参数&#xff0c;需要什么类型的参数&a…

【Linux】第二十二章 访问网络附加内存

1. NFS的主要功能是什么&#xff1f; NFS是由Linux、UNIX及类似操作系统使用的互联网标准协议&#xff0c;主要功能就是提供网络文件共享&#xff0c;允许不同的计算机系统之间通过网络共享文件&#xff0c;它使得网络上的计算机能够像访问本地文件系统一样访问远程计算机上的…

大模型时代,Python 近红外光谱与 Transformer 模型:学习的必要性探究

在当下大语言模型盛行的时代&#xff0c;各类新技术如潮水般不断涌现&#xff0c;让人应接不暇。身处这样的浪潮之中&#xff0c;不少人心中都会泛起疑问&#xff1a;Python 近红外光谱和 Transformer 模型还有学习的必要性吗&#xff1f;今天&#xff0c;就让我们深入探讨一番…

强化学习鱼书(7)——神经网络和Q学习

代码地址 书内附代码地址 https://github.com/oreilly-japan/deep-learning-from-scratch-4 环境搭建 0.建立虚拟环境 conda create -n env_test python3.10 conda activate env_test1.安装cuda 50系的显卡只支持torch的nightlycuda12.8版本&#xff0c;别的版本会显示no k…

数据建模与分析:从回归预测到特征聚类的全面探索(PyTorch)

文章目录 简介&#xff1a;数据建模简介回归分析回归分析简介回归分析建模判定系数估计标准差住房价格回归预测 聚类聚类简介聚类分析建模植物花卉特征聚类 主成分分析&#xff08;PCA&#xff09;主成分分析简介成分分析建模地区竞争力指标降维 简介&#xff1a; 在现代数据科…

uv 包管理工具使用教程

一、简介 uv 是一个基于 Rust 实现的超快 Python 包管理工具&#xff0c;旨在加速 Python 开发流程。它是 pip、pip-tools、virtualenv 和 venv 的现代替代品&#xff0c;支持更快的包解析、安装和虚拟环境创建。 主要特性包括&#xff1a; 极快的依赖解析与安装 自动创建和…

5分钟应急响应+99%达标率:AI智能监控重塑商业清洁新标准

一、方案整体架构 面对商业综合体日均10万客流量带来的管理挑战&#xff0c;传统保洁模式在人员监管、质量评估和应急响应方面存在显著瓶颈。本系统以全场景AI监控为核心&#xff0c;构建三级智能化管理体系&#xff1a; 1. 前端感知层&#xff1a;部署800万像素广角摄像…

裸金属服务器:解锁极致性能,拒绝虚拟化开销!

什么是裸金属服务器&#xff1f; 裸金属服务器&#xff08;Bare Metal Server&#xff09;是一种介于物理服务器和云服务器之间的新型计算服务形态。它既具备传统物理服务器的性能优势&#xff0c;又拥有云服务器的灵活性和便捷管理特性。与虚拟化云服务器不同&#xff0c;裸金…

[论文精读]Ward: Provable RAG Dataset Inference via LLM Watermarks

Ward: Provable RAG Dataset Inference via LLM Watermarks [2410.03537] Ward: Provable RAG Dataset Inference via LLM Watermarks ICLR 2025 Rebuttal&#xff1a;Ward: 可证明的 RAG 数据集推理通过 LLM 水印 | OpenReview --- Ward: Provable RAG Dataset Inference v…

【ffmpeg】ffprobe基本用法

ffprobe 是 FFmpeg 工具集中的一个强大命令行工具&#xff0c;主要用于分析多媒体文件&#xff08;如视频、音频等&#xff09;的格式和内容信息。它可以提取文件的元数据、编解码器信息、流详情、帧信息等&#xff0c;而无需对文件进行转码或修改。 基本用法 ffprobe [选项] …

有哪些GIF图片转换的开源工具

以下是关于GIF图片转换的开源工具的详细总结,涵盖功能特点、适用场景及用户评价: 1. FFmpeg 功能特点: 作为开源命令行工具,FFmpeg支持视频转GIF、调整帧率、分辨率、截取片段等操作,可通过脚本批量处理。适用场景: 适合开发者或技术用户进行高效批处理,常用于服务器端自…

js不同浏览器标签页、窗口或 iframe 之间可以相互通信

一、创建一个广播通道 // 创建一个名为 vue-apps-channel 的广播通道 const channel new BroadcastChannel(vue-apps-channel);二、发送消息 channel.postMessage({type: popup, message: false}); 三、接收消息&#xff08;也需要创建广播通道&#xff09; // 也创建一个…

【算法笔记day two】滑动窗口(不定长版)

前言 hello大家好&#xff0c;本期文章紧接着上期&#xff0c;讲述滑窗的下一个大分类——不定长。 定长滑窗请看我上期文章&#xff0c;有详细介绍。温馨提醒&#xff0c;代码大部分为手搓&#xff0c;答案方法不唯一。如果想要优雅的版本可以去找其他题解&#xff0c;我的…

Node.js Express 项目现代化打包部署全指南

Node.js Express 项目现代化打包部署全指南 一、项目准备阶段 1.1 依赖管理优化 # 生产依赖安装&#xff08;示例&#xff09; npm install express mongoose dotenv compression helmet# 开发依赖安装 npm install nodemon eslint types/node --save-dev1.2 环境变量配置 /…

Linux电源管理——PSCI初始化流程和多核启动流程

目录 一、PSCI 初始化流程 1、PSCI设备树节点 2、PSCI kernel初始化流程 get_set_conduit_method set_conduit psci_probe 二、CPU PSCI 操作初始化流程 1、CPU 设备树节点 2、 struct cpu_operations 3、kernel 流程 cpu_read_bootcpu_ops smp_init_cpus 三、CPU…