skip-gram 理论部分见:NLP 笔记:Skip-gram_刘文巾的博客-CSDN博客

1 导入库

import numpy as np
import torch
from torch import nn, optim
import random
from collections import Counter
import matplotlib.pyplot as plt

2 数据集部分

2.1 训练数据

#训练数据
text ='I like dog i like cat i like \
animal dog cat animal apple \
cat dog like dog fish milk like dog \
cat eyes like i like apple apple \
i hate apple i movie book music like \
cat dog hate cat dog like he is man she\
is woman king is man queen is woman'

2.2 参数设置

#参数设置
EMBEDDING_DIM = 2 #词向量维度
PRINT_EVERY = 1000 #可视化频率
EPOCHS = 1000 #训练的轮数
BATCH_SIZE = 5 #每一批训练数据大小
N_SAMPLES = 3 #负样本大小
WINDOW_SIZE = 5 #最大背景词窗口大小
FREQ = 0 #词汇出现频率,低于这个的词汇将被删除
DELETE_WORDS = False #是否删除部分高频词(是否二次采样)

2.3 文本预处理

2.3.1 保留一定数目以上词频的词汇

#文本预处理
def preprocess(text, FREQ):text = text.lower()words = text.split()word_counts = Counter(words)#计算每个词出现的次数trimmed_words = []for word in words :if word_counts[word] > FREQ:trimmed_words.append(word)return trimmed_words
words = preprocess(text, FREQ)
#保留下词汇出现频率大于等于FREQ的词

2.3.2 构建word<->num的字典

#构建词典 word<->num;num<->word
vocab = set(words)
vocab2int = {}
int2vocab = {}
for c, w in enumerate(vocab):vocab2int[w]=cint2vocab[c]=w
vocab2int,int2vocab

2.3.3 将words中的词汇id化

#将文本转化为数值
int_words = []
for w in words:int_words.append(vocab2int[w])

2.3.4 计算词频

#计算单词频次
int_word_counts = Counter(int_words)
total_count = len(int_words)
word_freqs={}
for w, c in int_word_counts.items():word_freqs[w]=c/total_count

2.3.5 二次采样(去除出现频率过高的词汇)

#二次采样:去除出现频次高的词汇
if DELETE_WORDS:t = 1e-5prob_drop = {}for w in int_word_counts:prob_drop[w]=1-np.sqrt(t/word_freqs[w])#每个word的丢弃概率train_words=[]for w in int_words:if(random.random()<(1-prob_drop[w])):train_words.append(w)
else:train_words = int_words

2.3.6 选作负样本的概率

word_freqs = np.array(list(word_freqs.values()))
noise_dist = torch.from_numpy(word_freqs ** (0.75) / np.sum(word_freqs ** (0.75)))noise_dist
'''
tensor([0.0969, 0.1314, 0.1088, 0.0969, 0.0425, 0.0715, 0.0253, 0.0253, 0.0253,0.0425, 0.0253, 0.0253, 0.0253, 0.0253, 0.0715, 0.0425, 0.0253, 0.0425,0.0253, 0.0253], dtype=torch.float64)
'''

2.3.7 获取中心词周围的背景词

#获取目标词汇(中心词的背景词)
def get_target(words, idx, WINDOW_SIZE):target_window = np.random.randint(1, WINDOW_SIZE+1)#当前窗口的大小,窗口大大小可以灵活调整,这样训练得到的效果会更好if (idx-target_window)>0:start_point = idx-target_window#预测窗口的第一个下标else:start_point=0if(idx+target_window<len(words)):end_point = idx+target_window#预测窗口的最后一个下标else:end_point=len(words)-1targets = set(words[start_point:idx]+words[idx+1:end_point+1])#预测窗口区间中不同的单词return list(targets)
#得到的就是以idx下标处的单词为中心词,一定窗口大小的背景词

2.3.8 生成一个一个batch

#批次化数据
def get_batch(words, BATCH_SIZE, WINDOW_SIZE):n_batches = len(words)//BATCH_SIZE#我们的单词一共需要划分成几个batchwords = words[:n_batches*BATCH_SIZE]#这里我们是把最后多出来的几个词剔除掉了for idx in range(0, len(words), BATCH_SIZE):batch_x, batch_y = [],[]batch = words[idx:idx+BATCH_SIZE]
#当前batch所涉及的单词for i in range(len(batch)):x = batch[i]y = get_target(batch, i, WINDOW_SIZE)
我们记y返回的窗口size为k_i(一个batch里面不同的i可能窗口的size是不一样的)batch_x.extend([x]*len(y))
#batch_x:[k_i]batch_y.extend(y)
#batch_y:[k_i]yield batch_x, batch_y#每次输出当前的这一组batch_x和batch_y,待下一次调用的时候,生成下一组
#batch_x:[sigma{k_i}]
#batch_y:[sigma{k_i}]

3 定义模型

class SkipGramNeg(nn.Module):def __init__(self, n_vocab, n_embed, noise_dist):super().__init__()self.n_vocab = n_vocab#输入的单词数量(len(vocab2int))self.n_embed = n_embed#中间词向量的维度(EMBEDDING_DIM)self.noise_dist = noise_dist#定义词向量层(每个词被选成负样本的概率)#noise_dist [n_vocab]self.in_embed = nn.Embedding(n_vocab, n_embed)#中心词对应的权重矩阵
#维度 n_vocab->n_embedself.out_embed = nn.Embedding(n_vocab, n_embed)#背景词对应的权重矩阵
#维度 n_vocab->n_embed #词向量层参数初始化self.in_embed.weight.data.uniform_(-1, 1)self.out_embed.weight.data.uniform_(-1, 1)#将参数的范围限定在(-1,1)#输入词的前向过程(对应 input->hidden)def forward_input(self, input_words):
#k_i表示一个batch每个i的窗口大小
#input_words [sigma{k_i}]input_vectors = self.in_embed(input_words)return input_vectors
#input_vectors [sigma{k_i},n_embed]#目标词的前向过程(在中心词窗口内的背景词的编码)def forward_output(self, output_words):
#output_words [sigma{k_i}]output_vectors = self.out_embed(output_words)return output_vectors
#output_vectors [sigma{k_i},n_embed]#负样本词的前向过程def forward_noise(self, size, N_SAMPLES):noise_dist = self.noise_dist#从词汇分布中采样负样本noise_words = torch.multinomial(noise_dist,size * N_SAMPLES,replacement=True)noise_vectors = self.out_embed(noise_words).view(size, N_SAMPLES, self.n_embed)return noise_vectors#noise_vectors [sigma{k_i},N_SAMPLES,n_embed]

4 定义损失函数

负采样见NLP 笔记:Skip-gram_刘文巾的博客-CSDN博客

class NegativeSamplingLoss(nn.Module):def __init__(self):super().__init__()def forward(self, input_vectors, output_vectors, noise_vectors):#k_i表示一个batch每个i的窗口大小#input_vectors [sigma{k_i},n_embed]#output_vectors [sigma{k_i},n_embed]#noise_vectors [sigma{k_i},N_SAMPLES,n_embed]BATCH_SIZE, embed_size = input_vectors.shape#将输入词向量与目标词向量作维度转化处理        input_vectors = input_vectors.view(BATCH_SIZE, embed_size, 1)#input_vectors [sigma{k_i},n_embed,1]output_vectors = output_vectors.view(BATCH_SIZE, 1, embed_size)#output_vectors [sigma{k_i},1,n_embed]test = torch.bmm(output_vectors, input_vectors)
#test [sigma{k_i},1,1]#也就是中心词和背景词的条件概率,即u_o^T v_c#目标词的lossout_loss = torch.bmm(output_vectors, input_vectors).sigmoid().log()
#out_loss [sigma{k_i},1,1]out_loss = out_loss.squeeze()
#out_loss [sigma{k_i}]#负样本损失noise_loss = torch.bmm(noise_vectors.neg(), input_vectors).sigmoid().log()
#noise_loss [sigma{k_i},N_SAMPLES,1]noise_loss = noise_loss.squeeze().sum(1)
#noise_loss [sigma{k_i},1]#综合计算两类损失#目标是让正样本概率大,负样本概率小,也就是两个loss的和越大越好
#但损失函数是要最小化, 所以前面要加一个-return -(out_loss + noise_loss).mean()

5 模型的声明、损失函数和优化函数的定义

model = SkipGramNeg(len(vocab2int),EMBEDDING_DIM, noise_dist=noise_dist)
criterion = NegativeSamplingLoss()
optimizer = optim.Adam(model.parameters(), lr=0.003)

6 模型的训练

#训练
steps = 0
for e in range(EPOCHS):#获取输入词以及目标词for input_words, target_words in get_batch(train_words, BATCH_SIZE, WINDOW_SIZE):
#input_words [sigma{k_i}]
#target_words [sigma{k_i}]steps += 1inputs, targets = torch.LongTensor(input_words), torch.LongTensor(target_words)#输入、输出以及负样本向量input_vectors = model.forward_input(inputs)
#k_i表示一个batch每个i的窗口大小
#input_vectors [sigma{k_i},n_embed]output_vectors = model.forward_output(targets)
#output_vectors [sigma{k_i},n_embed]size, _ = input_vectors.shape
#size:sigma{k_i}noise_vectors = model.forward_noise(size, N_SAMPLES)
#noise_vectors [sigma{k_i},N_SAMPLES,n_embed]#计算损失loss = criterion(input_vectors, output_vectors, noise_vectors)#打印损失if steps%PRINT_EVERY == 0:print("loss:",loss)#梯度回传optimizer.zero_grad()loss.backward()optimizer.step()'''
loss: tensor(2.3455, grad_fn=<NegBackward>)
loss: tensor(1.6729, grad_fn=<NegBackward>)
loss: tensor(1.6398, grad_fn=<NegBackward>)
loss: tensor(1.5920, grad_fn=<NegBackward>)
loss: tensor(1.4348, grad_fn=<NegBackward>)
loss: tensor(1.5463, grad_fn=<NegBackward>)
loss: tensor(1.4360, grad_fn=<NegBackward>)
loss: tensor(1.6348, grad_fn=<NegBackward>)
loss: tensor(1.4676, grad_fn=<NegBackward>)
loss: tensor(1.6141, grad_fn=<NegBackward>)
'''

7 结果可视化

如NLP 笔记:Skip-gram_刘文巾的博客-CSDN博客 第4条第3)小条所言,权重矩阵的每一行对应的是一个点在稠密空间上的编码

plt.figure(figsize=(20,10))
for i, w in int2vocab.items():vectors = model.state_dict()["in_embed.weight"]x,y = float(vectors[i][0]),float(vectors[i][1])plt.scatter(x,y)plt.annotate(w, xy=(x, y), xytext=(5, 2), textcoords='offset points', ha='right', va='bottom')plt.show()

pytorch笔记: 搭建Skip—gram相关推荐

  1. 李沐《动手学深度学习》第二版 pytorch笔记1 环境搭建

    李沐<动手学深度学习>第二版pytorch笔记1 搭建环境 文章目录 李沐<动手学深度学习>第二版pytorch笔记1 搭建环境 此时尚有耐心 虚拟环境搭建 创建虚拟环境 查看 ...

  2. pytorch 笔记:torchsummary

    作用:打印神经网络的结构 以pytorch笔记:搭建简易CNN_UQI-LIUWJ的博客-CSDN博客 中搭建的CNN为例 import torch from torchsummary import ...

  3. Pytorch笔记:风格迁移

    Pytorch笔记:风格迁移 训练模型:风格迁移网络+VGG16网络 生成网络:风格迁移网络 代码如下(根据陈云<深度学习框架:Pytorch入门与实践>的代码改动) main.py im ...

  4. (d2l-ai/d2l-zh)《动手学深度学习》pytorch 笔记(4)线性神经网络(暂停)

    开源项目地址:d2l-ai/d2l-zh 教材官网:https://zh.d2l.ai/ 书介绍:https://zh-v2.d2l.ai/ 笔记基于2021年7月26日发布的版本,书及代码下载地址在 ...

  5. 《自然语言处理学习之路》02 词向量模型Word2Vec,CBOW,Skip Gram

    本文主要是学习参考莫烦老师的教学,对老师课程的学习,记忆笔记. 原文链接 文章目录 书山有路勤为径,学海无涯苦作舟. 零.吃水不忘挖井人 一.计算机如何实现对于词语的理解 1.1 万物数字化 1.2 ...

  6. pytorch 笔记:使用Tune 进行调参

    自动进行调参,我们以pytorch笔记:搭建简易CNN_UQI-LIUWJ的博客-CSDN博客的代码为基础,进行output_channel和learning rate的调参 1 导入库 from f ...

  7. Introduction to PyTorch 笔记

    文章目录 Introduction to PyTorch 笔记 Part 1 - Tensors in PyTorch (Solution).ipynb Part 2 - Neural Network ...

  8. PYTORCH笔记 actor-critic (A2C)

    理论知识见:强化学习笔记:Actor-critic_UQI-LIUWJ的博客-CSDN博客 由于actor-critic是policy gradient和DQN的结合,所以同时很多部分和policy ...

  9. pytorch笔记:policy gradient

    本文参考了 策略梯度PG( Policy Gradient) 的pytorch代码实现示例 cart-pole游戏_李莹斌XJTU的博客-CSDN博客_策略梯度pytorch 在其基础上添加了注释和自 ...

最新文章

  1. Android 游戏开发必备的基础知识
  2. 「CameraCalibration」传感器(相机、激光雷达、其他传感器)标定笔记
  3. MySQL——在Linux下安装和卸载MySQL
  4. 晨哥真有料丨你太容易被得到了!
  5. Linux 新漏洞曝光,居然又双叒是提升权限漏洞!
  6. java低层源码_Java线程池及其底层源码实现分析
  7. 天聪公司研发成功第三代声纹识别算法
  8. 分治法--二分查找、乘方、斐波那契数
  9. Javascript中相同Function使用多个名称
  10. 公文写作神器 v2.8.1.20 去更新去广告版
  11. 啊D注入工具是一种主要用于SQL的注入工具
  12. 在Docker里部署ReviewBoard4.0-RC
  13. 论文笔记Doubly Stochastic Variational Inference for Deep Gaussian Processes深度高斯过程的双重随机变分推理
  14. 【解决U盘无法访问】
  15. 【Docker系列】 Docker secrets
  16. Drug Target Review | 人工智能(AI)在基因组学中的作用
  17. Chrome之“无法访问此网站 找不到服务器IP地址“解决方案
  18. Linux启动流程详解
  19. 学习笔记:CentOS7学习之十六:LVM管理和ssm存储管理器使用
  20. 2022-2028年全球及中国光纤布拉格光栅(FBG)加速度计行业投资前景分析

热门文章

  1. HBase 6、用Phoenix Java api操作HBase
  2. java中c/s模式传送数据
  3. 微软中国发布“IE8浏览器性能解密”,为金山网盾辟谣
  4. 学科网站建设的尝试与思考
  5. Leetcode1704判断字符串的两半是否相似(C++题解)
  6. kattis ones简单题取模运算+枚举
  7. echarts搭配MySQL_Echarts连接Mysql使用心得
  8. 四级计算机基础知识,全国计算机等级考试四级通关攻略
  9. liu四声拼音怎么读_拼音是99%的西安孩子幼升小必备知识!附:幼小拼音学习计划...
  10. html5up ui开源框架,ZUI-HTML5前端 UI 框架