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

相关文章

YOLO v3 训练速度慢的问题

一天一夜出了两个模型,仅仅迭代了200次   原因:编译之前没有将Makefile 文件里的GPU设置为1,编译的是CPU版本,必须训练慢   解决方案: make clean  vim Makefile make   再次训练 速度快了,5分钟迭代了500次

将一维机械振动信号构造为训练集和测试集(Python)

从如下链接中下载轴承数据集。 https://www.sciencedirect.com/science/article/pii/S2352340918314124 import numpy as npimport scipy.io as sioimport matplotlib.pyplot as pltimport statistics as statsimport pandas

6月21日训练 (东北林业大学)(个人题解)

前言:   这次训练是大一大二一起参加的训练,总体来说难度是有的,我和队友在比赛时间内就写出了四道题,之后陆陆续续又补了了三道题,还有一道题看了学长题解后感觉有点超出我的能力范围了,就留给以后的自己吧。话不多说,上正文。 正文:   Problem:A 幸运数字: #include <bits/stdc++.h>using namespace std;int sum,ans;in

国产AI算力训练大模型技术实践

&nbsp;&nbsp; ChatGPT引领AI大模型热潮,国内外模型如雨后春笋,掀起新一轮科技浪潮。然而,国内大模型研发推广亦面临不小挑战。面对机遇与挑战,我们需保持清醒,持续推进技术创新与应用落地。 为应对挑战,我们需从战略高度全面规划大模型的研发与运营,利用我们的制度优势,集中资源攻坚克难。通过加强顶层设计,统一规划,并加大政策与资源的扶持,我们必将推动中国人工智能实现从追赶者到

预训练是什么?

预训练是什么? 图像领域的预训练 在介绍图像领域的预训练之前,我们首先介绍下卷积神经网络(CNN),CNN 一般用于图片分类任务,并且CNN 由多个层级结构组成,不同层学到的图像特征也不同,越浅的层学到的特征越通用(横竖撇捺),越深的层学到的特征和具体任务的关联性越强(人脸-人脸轮廓、汽车-汽车轮廓) 由此,当领导给我们一个任务:阿猫、阿狗、阿虎的图片各十张,然后让我们设计一个深度神经网

面试:关于word2vec的相关知识点Hierarchical Softmax和NegativeSampling

1、为什么需要Hierarchical Softmax和Negative Sampling 从输入层到隐含层需要一个维度为N×K的权重矩阵,从隐含层到输出层又需要一个维度为K×N的权重矩阵,学习权重可以用反向传播算法实现,每次迭代时将权重沿梯度更优的方向进行一小步更新。但是由于Softmax激活函数中存在归一化项的缘故,推导出来的迭代公式需要对词汇表中的所有单词进行遍历,使得每次迭代过程非常缓慢

使用matlab的大坑,复数向量转置!!!!!变量区“转置变量“功能(共轭转置)、矩阵转置(默认也是共轭转置)、点转置

近期用verilog去做FFT相关的项目,需要用到matlab进行仿真然后和verilog出来的结果来做对比,然后计算误差。近期使用matlab犯了一个错误,极大的拖慢了项目进展,给我人都整emo了,因为怎么做仿真结果都不对,还好整体的代码都是我来写的,慢慢往下找就找到了问题的来源,全网没有看到多少人把这个愚蠢的错误写出来,我来引入一下。 代码错误的表现:复数向量的虚部被取反,正数变成负数,负数

本地离线模型搭建指南-LLaMA-Factory训练框架及工具

搭建一个本地中文大语言模型(LLM)涉及多个关键步骤,从选择模型底座,到运行机器和框架,再到具体的架构实现和训练方式。以下是一个详细的指南,帮助你从零开始构建和运行一个中文大语言模型。 本地离线模型搭建指南将按照以下四个部分展开 中文大语言模型底座选择依据本地运行显卡选择RAG架构实现LLaMA-Factory训练框架及工具 4 训练架构及工具 4.1 为什么要使用LLaMA-Factor

ChatGPT原理和训练【 ChatGPT是由OpenAI开发】

本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:王文峰哦) ChatGPT原理和训练【 ChatGPT是由OpenAI开发】 学习教程(传送门)1.概述2

发表在SIGMOD 2024上的高维向量检索/向量数据库/ANNS相关论文

前言 SIGMOD 2024会议最近刚在智利圣地亚哥结束,有关高维向量检索/向量数据库/ANNS的论文主要有5篇,涉及混合查询(带属性或范围过滤的向量检索)优化、severless向量数据库优化、量化编码优化、磁盘图索引优化。此外,也有一些其它相关论文,比如FedKNN: Secure Federated k-Nearest Neighbor Search。 下面对这些论文进行一个简单汇总介绍