目录
一、关于word2vec
1、什么是word2vec
2、常用训练算法
1)CBOW
2)SkipGram
二、关于npy、npz文件
1、npy文件
1)定义
2)特性
3)用途
4)保存及读取
运行结果:
运行结果:
2、npz文件
1)定义
2)用途
3)保存及读取
运行结果:
运行结果:
三、CBOW案例解析
1、获取训练集数据
调试结果:
2、生成one-hot
运行结果:
3、创建CBOW类
4、cuda、优化器
5、开始训练
运行结果:
6、测试
运行结果:
7、获取词向量矩阵
运行结果:
8、生成词嵌入字典
9、保存为npz文件
运行结果:
一、关于word2vec
1、什么是word2vec
Word2Vec是一种用于将单词表示为连续向量的技术。它是一种浅层、双层的神经网络模型,用于训练单词的分布式表示。
Word2Vec模型将单词映射到一个低维向量空间中,使得具有相似含义的单词在向量空间中距离较近。这种表示方法有助于在自然语言处理任务中更好地捕捉和理解单词之间的语义关系。
2、常用训练算法
1)CBOW
以上下文词汇预测当前词,前后两个单词预测当前词,这里的两个单词是自定义个数的
2)SkipGram
以当前词预测其上下文词汇,即当前词预测前后两个单词,这里的两个单词也是自定义个数的
二、关于npy、npz文件
1、npy文件
1)定义
npy文件是NumPy库中用于保存数组数据的二进制文件格式。
2)特性
二进制存储:npy文件以二进制形式存储数据,比文本文件(如CSV)更加高效地保存大型数组数据。二进制格式允许直接映射到内存,从而加快了读写速度。
数据完整性:npy文件不仅保存数组的数据,还包含了数组的形状(维度)、数据类型以及其他必要的元数据信息。这确保了数据的完整性,使得在加载数据时可以完全重现保存时的数组,而无需任何额外的转换或解析。
跨平台性:npy文件的格式是跨平台的,可以在不同的操作系统和硬件环境中进行加载和使用。
3)用途
npy文件的设计目的是为了在数据分析和科学计算领域中,提供一种高效的存储和读取NumPy数组数据的方式。
4)保存及读取
"""保存为npy文件"""
a = np.random.randint(5,size=(2,4))
np.save('test.npy',a)
运行结果:
"""读取npy文件"""
b = np.load('test.npy')
print(b)
运行结果:
2、npz文件
1)定义
npz文件是NumPy用于存储数值数据的压缩格式。它实际上是一个压缩存档文件,可以包含一个或多个NumPy数组。
2)用途
npz文件通常用于存储和传输大量的数值数据,特别是在科学计算和数据分析领域。
3)保存及读取
"""保存为npz文件"""
a = np.random.randint(0,10,(3,),dtype='int')
b = np.random.randint(0,10,(3,),dtype='int')
c = np.random.randint(0,10,(3,),dtype='int')
np.savez('test.npz',file1=a,file2=b,file3=c) # 压缩储存数组,并给数组 分别命名
运行结果:
"""读取npz文件"""
data = np.load('test.npz')
print(data.files) # 读取其内文件名
aa = data[data.files[0]] # 读取文件内容
bb = data[data.files[1]]
cc = data[data.files[2]]
print('read:',aa,bb,cc) # 打印文件内容
运行结果:
三、CBOW案例解析
1、获取训练集数据
import torch
import torch.nn as nn # 神经网络
import torch.nn.functional as F
import torch.optim as optim
from tqdm import tqdm,trange # 显示进度条函数
import numpy as npCONTEX_SIZE = 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() # 语料库# 中文的语句,你可以选择分词,也可以选择分字
vocab = set(raw_text) # 利用集合的唯一性,建立词库,集合内元素不重复
vocab_size = len(vocab) # 打印词库长度# enumerate返回一个可迭代对象的元素内容及其索引
word_to_idx = {word:i for i,word in enumerate(vocab)} # for循环的复合写法,第1次循环,i得到的索引号,word 第1个单词
idx_to_word = {i:word for i,word in enumerate(vocab)}data = [] # 用于存放分割出来的元组,元组内有两个元素,一个数前后对应的四个单词,另一个是中间的词
for i in range(CONTEX_SIZE,len(raw_text)-CONTEX_SIZE): # 遍历值为上述设置的左右两边词长度2到文章总次数-2,i从2开始context = ([raw_text[i-(2-j)] for j in range(CONTEX_SIZE)] # 获取前两个单词+ [raw_text[i+j+1] for j in range(CONTEX_SIZE)] # 获取后两个单词) # 获取上下文词,第一组为(['we''are''to''study'])target = raw_text[i] # 获取目标词,第一个词为aboutdata.append((context,target)) # 将上下文词和目标词保存到data中,第一组格式为((['we','are''to''study']),'about')
调试结果:
2、生成one-hot
def make_context_vector(context,word_to_idx): # 将上下文词转换为one-hotidxs = [word_to_idx[w] for w in context] # 遍历四个词,返回四个词对应的索引,将索引存入列表return torch.tensor(idxs,dtype=torch.long) # 返回创建的一个torch张量,内容为词在词库中对应的索引# 上述函数的示例
print(make_context_vector(data[0][0],word_to_idx)) # 将前后两组单词以及上述定义的字典传入自定义函数,返回其在词库中的索引
运行结果:
3、创建CBOW类
class CBOW(nn.Module): # 定义一个CBOW的类,其继承nn.Module,nn.Module是PyTorch中所有神经网络模块的基类,提供了模型构建所需的基本功能。def __init__(self,vocab_size,embedding_dim): # 初始化super(CBOW,self).__init__()self.embeddings = nn.Embedding(vocab_size,embedding_dim) # 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) # 将索引传入上述的Embedding词嵌入层进行处理,然后对结果求和,最后调整形状为1,embedding_dim,-1表示根据张量的大小自动计算该位置上的维度out = F.relu(self.proj(embeds)) # 将词嵌入的结果进行线性变换,然后再进行relu激活函数处理,即小于0的变为0,大于0的不变out = self.output(out) # 输出层nll_prob = F.log_softmax(out,dim=-1) # 使用softmax激活函数将原始输出值转换为概率分布的对数形式,dim=-1 指定了对最后一个维度进行计算,return nll_prob
4、cuda、优化器
# m模型在cuda训练
device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
print(device)
model = CBOW(vocab_size,10).to(device) # 将词库长度和每个单词嵌入的维度大小传入模型,然后放入GPU进行运算optimizer = optim.Adam(model.parameters(),lr=0.001) # 创建一个Adam优化器,对模型的参数进行优化
# model.parameters()返回模型中所有可训练参数的迭代器,lr表示学习率
5、开始训练
losses = [] # 存储损失的集合
loss_function = nn.NLLLoss() # NLLLoss损失函数(当分类列表非常多的情况),将多个类别分别分成0、1两个类别。
for epoch in tqdm(range(200)): # 开始训练,tqdm表示展示一个进度条,200表示循环展示200次total_loss = 0 # 用于储存当前epoch的总损失,每轮将总损失增加到列表for context,target in data: # 遍历元组中的左右四个词,以及中间的一个词context_vecter = make_context_vector(context,word_to_idx).to(device) # 通过遍历将所有的四个词以及词组对应的字典传入函数,返回对应的索引,然后传入GPUtarget = torch.tensor([word_to_idx[target]]).to(device) # 返回中间的词对应的索引,然后转换为torch张量传入GPUtrain_predict = model(context_vecter) # 将每一组数据的四个索引传入模型进行前向传播,model.forward可以不写forward# print(train_predict) # 打印返回的每一个数对应的概率值对数形式loss = loss_function(train_predict,target) # 将上述模型返回的预测结果与真实值传入负对数似然损失函数进行计算得到损失值optimizer.zero_grad() # 梯度清零loss.backward() # 反向传播计算得到每个参数梯度值optimizer.step() # 根据梯度更新网络参数total_loss += loss.item() # 叠加损失值losses.append(total_loss)
print(losses)
运行结果:
6、测试
# 测试
context = ['People','create','to','direct']
context_vector = make_context_vector(context,word_to_idx).to(device)# 预测的值
model.eval() # 进入测试模式
predict = model(context_vector)
max_idx = predict.argmax(1).item() # dim=1表示每一行中的最大值对应的索引号,dim=0表示每一列中最大值对应的索引号
print(f"{','.join(context)}中间的单词为:",idx_to_word[max_idx])
运行结果:
7、获取词向量矩阵
W = model.embeddings.weight.cpu().detach().numpy() # 获取词嵌入层的权重,因为模型在GPU训练,先将其传入CPU,detach()表示分理处张量,然后将其转变为numpy数组类型
print(W) # 打印模型的词嵌入矩阵
运行结果:
8、生成词嵌入字典
word_2_vec = {}
for word in word_to_idx.keys():# 词向量矩阵中某个词的索引对应的那一列即为该词的词向量word_2_vec[word] = W[word_to_idx[word],:]
print('结束')
9、保存为npz文件
np.savez('word2vec实现.npz',file_1=W)
data = np.load('word2vec实现.npz')
print(data.files)