Word2vec之skip-gram训练词向量

2024-03-11 05:58
文章标签 训练 向量 word2vec gram skip

本文主要是介绍Word2vec之skip-gram训练词向量,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

参考自哈工大车万翔等老师编写的《自然语言处理-基于预训练模型的方法》

# coding: utf-8
# Name:     tesst2
# Author:   dell
# Data:     2021/10/12# 基于负采样的skip-garm模型
import torch
import torch.nn.functional as F
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader
from collections import defaultdict
from tqdm import tqdm
import torch.optim as optimBOS_TOKEN = "<bos>"
EOS_TOKEN = "<eos>"
PAD_TOKEN = "<pad>"def load_reuters():# 从NLTK中导入Reuters数据处理模块from nltk.corpus import reuters# 获取Reuters数据中的所有句子(已完成标记解析)text = reuters.sents()# (可选)将预料中的词转换为小写text = [[word.lower() for word in sentence] for sentence in text]# 构建词表,并传入预留标记vocab = Vocab.build(text, reserved_tokens=[PAD_TOKEN, BOS_TOKEN, EOS_TOKEN])# 利用词表将文本数据转换为id表示corpus = [vocab.convert_tokens_to_ids(sentence) for sentence in text]return corpus, vocabclass Vocab:def __init__(self, tokens=None):self.idx_to_token = list()self.token_to_idx = dict()if tokens is not None:if "<unk>" not in tokens:tokens = tokens + ["<unk>"]for token in tokens:self.idx_to_token.append(token)self.token_to_idx[token] = len(self.idx_to_token) - 1self.unk = self.token_to_idx["<unk>"]@classmethoddef build(cls, text, min_freq=1, reserved_tokens=None):token_freqs = defaultdict(int)for sentence in text:for token in sentence:token_freqs[token] += 1uniq_tokens = ["<unk>"] + (reserved_tokens if reserved_tokens else [])uniq_tokens += [token for token, freq in token_freqs.items() if freq >= min_freq and token != "<unk>"]return cls(uniq_tokens)def __len__(self):# 返回词表的大小,即词表中有多少个互不相同的标记return len(self.idx_to_token)def __getitem__(self, token):# 查找输入标记对应的索引值,如果该标记不存在,返回<unk>对应的索引值return self.token_to_idx.get(token, self.unk)def convert_tokens_to_ids(self, tokens):# 查找一系列输入标记对应的索引值,此处直接使用self即可,会调用__getitem__得到idreturn [self[token] for token in tokens]# 或者是# return [self.token_to_idx[token] for token in tokens]def convert_ids_to_tokens(self, indices):# 查找一系列索引值对应的标记return [self.idx_to_token[index] for index in indices]class SGNSDataset(Dataset):def __init__(self, corpus, vocab, context_size=2, n_negatives=5, ns_dist=None):self.data = []self.bos = vocab[BOS_TOKEN]self.eos = vocab[EOS_TOKEN]self.pad = vocab[PAD_TOKEN]for sentence in tqdm(corpus, desc="Dataset Construction"):sentence = [self.bos] + sentence + [self.eos]for i in range(1, len(sentence)-1):# 模型输入: (w, context)w = sentence[i]left_context_index = max(0, i-context_size)right_context_index = min(len(sentence), i+context_size)context = sentence[left_context_index:i] + sentence[i+1:right_context_index+1]context += [self.pad] * (2*context_size - len(context_size))self.data.append((w, context))# 负采样数量self.n_negatives = n_negatives# 负采样分布:若参数ns_dist为None,则使用均匀分布(从词表中均匀采样)self.ns_dist = ns_dist if ns_dist else torch.ones(len(vocab))def __len__(self):return len(self.data)def __getitem__(self, i):return self.data[i]def collate_fn(self, examples):words = torch.tensor([ex[0] for ex in examples], dtype=torch.long)contexts = torch.tensor([ex[1] for ex in examples], dtype=torch.long)batch_size, context_size = contexts.shapeneg_contexts = []# 对批次内的样本分别进行负采样for i in range(batch_size):# 保证负样本不包含当前样本中的contextns_dist = self.ns_dist.index_fill(0, contexts[i], .0)   # dim=0, 需要填充的tensor的索引-contexts[i], vale=.0# torch.multinomial--对ns_dist中的值,有放回(replacement=True)地抽取self.n_negatives * context_sizeneg_contexts.append(torch.multinomial(ns_dist, self.n_negatives * context_size, replacement=True))neg_contexts = torch.stack(neg_contexts, dim=0)return words, contexts, neg_contextsclass SGNSModel(nn.Module):def __init__(self, vocab_size, embedding_dim):super(SGNSModel, self).__init__()# 词向量self.w_embeddings = nn.Embedding(vocab_size, embedding_dim)# 上下文向量self.c_embeddings = nn.Embedding(vocab_size, embedding_dim)def forward_w(self, words):w_embeds = self.w_embeddings(words)return w_embedsdef forward_c(self, contexts):c_embeds = self.c_embeddings(contexts)return c_embedsdef get_unigram_distribution(corpus, vocab_size):# 从给定的语料中计算Unigram概率分布token_counts = torch.tensor([0]*vocab_size)total_count = 0for sentence in corpus:total_count += len(sentence)for token in sentence:token_counts[token] += 1unigram_dist = torch.div(token_counts.float(), total_count)return unigram_distdef save_pretrained(vocab, embeds, save_path):with open(save_path, "w") as writer:# 记录词向量大小writer.write(f"{embeds.shape[0]} {embeds.shape[1]}\n")for idx, token in enumerate(vocab.idx_to_token):vec = " ".join([f"{x}" for x in embeds[idx]])# 每一行对应一个单词以及由空格分隔的词向量writer.write(f"{token} {vec}\n")def main():# 设置超参数embedding_dim = 128context_size = 3batch_size = 1024n_negatives = 5         # 负样本数量num_epoch = 10# 读取文本数据corpus, vocab = load_reuters()# 计算Unigram概率分布unigram_dist = get_unigram_distribution(corpus, len(vocab))# 根据Unigram概率分布计算负采样分布: p(w)**0.75# 为了防止低频单词被忽略-->通过取 0.75 次方,低频单词的概率将稍微变大。negative_sampling_dist = unigram_dist ** 0.75negative_sampling_dist /= negative_sampling_dist.sum()# 构建SGNS训练数据集dataset = SGNSDataset(corpus, vocab, context_size=context_size, n_negatives=n_negatives, ns_dist=negative_sampling_dist)# data_loader = get_loader(dataset, batch_size)data_loader = DataLoader(dataset, batch_size)model = SGNSModel(len(vocab), embedding_dim)device = "cuda" if torch.cuda.is_available() else "cpu"model.to(device)optimizer = optim.Adam(model.parameters(), lr=0.001)model.train()for epoch in range(num_epoch):total_loss = 0for batch in tqdm(data_loader, desc=f"Training Epoch {epoch}"):words, contexts, neg_contexts = [x.to(device) for x in batch]optimizer.zero_grad()batch_size = words.shape[0]# 分贝提取batch内词、上下文和负样本的向量表示word_embeds = model.forward_w(words).unsqueeze(dim=2)       # [batch_size, word_embedding, 1]context_embeds = model.forward_c(contexts)                  # [batch_size, context_num, context_word_embedding]neg_context_embeds = model.forward_c(neg_contexts)          # [batch_size, neg_context_word_embedding]# 正样本的分类(对数)似然context_loss = F.logsigmoid(torch.bmm(context_embeds, word_embeds).seqeeze(dim=2))   # [batch_size, context_num]-->预测上下文的词context_loss = context_loss.mean(dim=1)# 负样本的分类(对数)似然# torch.neg()--->按元素取负-->output = -1 * inputneg_context_loss = F.logsigmoid(torch.bmm(neg_context_embeds, word_embeds).squeeze(dim=2).neg())neg_context_loss = neg_context_loss.view(batch_size, -1, n_negatives).sum(2)        # [batch_size, context_size, n_negatives]neg_context_loss = neg_context_loss.mean(dim=1)# 总体损失loss = -(context_loss + neg_context_loss).mean()loss.backward()optimizer.step()total_loss += loss.item()print(f"Loss: {total_loss:.2f}")# 合并词向量矩阵与上下文向量矩阵,作为最终的预训练词向量combined_embeds = model.w_embeddings.weight + model.c_embeddings.weight# 将词向量保存至sgns,vec文件save_pretrained(vocab, combined_embeds.data, "sgns.vec")if __name__ == "__main__":main()

这篇关于Word2vec之skip-gram训练词向量的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/796877

相关文章

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

MiniGPT-3D, 首个高效的3D点云大语言模型,仅需一张RTX3090显卡,训练一天时间,已开源

项目主页:https://tangyuan96.github.io/minigpt_3d_project_page/ 代码:https://github.com/TangYuan96/MiniGPT-3D 论文:https://arxiv.org/pdf/2405.01413 MiniGPT-3D在多个任务上取得了SoTA,被ACM MM2024接收,只拥有47.8M的可训练参数,在一张RTX

Spark MLlib模型训练—聚类算法 PIC(Power Iteration Clustering)

Spark MLlib模型训练—聚类算法 PIC(Power Iteration Clustering) Power Iteration Clustering (PIC) 是一种基于图的聚类算法,用于在大规模数据集上进行高效的社区检测。PIC 算法的核心思想是通过迭代图的幂运算来发现数据中的潜在簇。该算法适用于处理大规模图数据,特别是在社交网络分析、推荐系统和生物信息学等领域具有广泛应用。Spa

Vector3 三维向量

Vector3 三维向量 Struct Representation of 3D vectors and points. 表示3D的向量和点。 This structure is used throughout Unity to pass 3D positions and directions around. It also contains functions for doin

SigLIP——采用sigmoid损失的图文预训练方式

SigLIP——采用sigmoid损失的图文预训练方式 FesianXu 20240825 at Wechat Search Team 前言 CLIP中的infoNCE损失是一种对比性损失,在SigLIP这个工作中,作者提出采用非对比性的sigmoid损失,能够更高效地进行图文预训练,本文进行介绍。如有谬误请见谅并联系指出,本文遵守CC 4.0 BY-SA版权协议,转载请联系作者并注

8. 自然语言处理中的深度学习:从词向量到BERT

引言 深度学习在自然语言处理(NLP)领域的应用极大地推动了语言理解和生成技术的发展。通过从词向量到预训练模型(如BERT)的演进,NLP技术在机器翻译、情感分析、问答系统等任务中取得了显著成果。本篇博文将探讨深度学习在NLP中的核心技术,包括词向量、序列模型(如RNN、LSTM),以及BERT等预训练模型的崛起及其实际应用。 1. 词向量的生成与应用 词向量(Word Embedding)

Detectorn2预训练模型复现:数据准备、训练命令、日志分析与输出目录

Detectorn2预训练模型复现:数据准备、训练命令、日志分析与输出目录 在深度学习项目中,目标检测是一项重要的任务。本文将详细介绍如何使用Detectron2进行目标检测模型的复现训练,涵盖训练数据准备、训练命令、训练日志分析、训练指标以及训练输出目录的各个文件及其作用。特别地,我们将演示在训练过程中出现中断后,如何使用 resume 功能继续训练,并将我们复现的模型与Model Zoo中的

用Python实现时间序列模型实战——Day 14: 向量自回归模型 (VAR) 与向量误差修正模型 (VECM)

一、学习内容 1. 向量自回归模型 (VAR) 的基本概念与应用 向量自回归模型 (VAR) 是多元时间序列分析中的一种模型,用于捕捉多个变量之间的相互依赖关系。与单变量自回归模型不同,VAR 模型将多个时间序列作为向量输入,同时对这些变量进行回归分析。 VAR 模型的一般形式为: 其中: ​ 是时间  的变量向量。 是常数向量。​ 是每个时间滞后的回归系数矩阵。​ 是误差项向量,假

多云架构下大模型训练的存储稳定性探索

一、多云架构与大模型训练的融合 (一)多云架构的优势与挑战 多云架构为大模型训练带来了诸多优势。首先,资源灵活性显著提高,不同的云平台可以提供不同类型的计算资源和存储服务,满足大模型训练在不同阶段的需求。例如,某些云平台可能在 GPU 计算资源上具有优势,而另一些则在存储成本或性能上表现出色,企业可以根据实际情况进行选择和组合。其次,扩展性得以增强,当大模型的规模不断扩大时,单一云平

基于Python的自然语言处理系列(1):Word2Vec

在自然语言处理(NLP)领域,Word2Vec是一种广泛使用的词向量表示方法。它通过将词汇映射到连续的向量空间中,使得计算机可以更好地理解和处理文本数据。本系列的第一篇文章将详细介绍Word2Vec模型的原理、实现方法及应用场景。 1. Word2Vec 原理         Word2Vec模型由Google的Tomas Mikolov等人在2013年提出,主要有两种训练方式