
一、根据上下文预测当前词继续上文对CBOW自然语言处理的过程分析。上文https://blog.csdn.net/2201_75573294/article/details/157554148?fromshareblogdetailsharetypeblogdetailsharerId157554148sharereferPCsharesource2201_75573294sharefromfrom_link一个函数将上下文文本转化为pytorch张量def make_context_vector(context, word_to_idx): idxs [word_to_idx[w] for w in context] return torch.tensor(idxs, dtypetorch.long) # 强制类型的转换将列表转换为张量搭建神经网络模型nn.embeddings是一个网络层构建49x10的一个矩阵全连接层[4x49]*[49x10][4x10][1x10]全连接128个神经元这里leninputs就是4其实就是求平均确保最后只有一行输出。这里的relu不是一个网络层。log_softmax提前现在这里做一个交叉熵函数(可以把大的值变得越大小的越小拉大之间的差距方便后面对比),其实就是把交叉熵损失函数拆成两部分进行。class CBOW(nn.Module): # 神经网络 def __init__(self, vocab_size, embedding_dim): super(CBOW, self).__init__() # 父类的初始化 self.embeddings nn.Embedding(vocab_size, embedding_dim) # vocab_size词嵌入的one-hot大小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)/len(inputs) # 对嵌入向量求和 out F.relu(self.proj(embeds)) # nn.relu激活层 out self.output(out) nll_prob F.log_softmax(out, dim-1) # softmax交叉熵 return nll_prob设备使用输入词表的大小49和词向量的维度也就是embedding层的维度10。原来是49*49压缩为49*10# 模型在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) # 语料库中一共有49个单词 optimizer optim.Adam(model.parameters(), lr0.001) # 优化器1.训练这里使用的二分类损失函数和上面我们提到的交叉熵函数共同作用就是交叉熵损失函数。tqdm添加一个进度条只要有for循环就可以使用进度条target对应的编码转化为张量前向传播进入神经网络模型forwardcontext_vector就是我们传入的参数对应input在下面内容展示中我们知道context_vector的内容其实就是目标词上下文词张量矩阵losses [] # 存储损失的集合 loss_function nn.NLLLoss() # NLLLoss损失函数当分类类别非常多的情形这里和Log_softmax合在一起就是交叉熵损失 model.train() # 设置模型为训练模式 for epoch in tqdm(range(200)): # 开始训练 total_loss 0 for context, target in data: #遍历每个训练样本这里的data就是我们上文分析过的上下文和预测词组合的元组 context_vector make_context_vector(context, word_to_idx).to(device) target torch.tensor([word_to_idx[target]]).to(device) # 开始前向传播进入forward train_prediction model(context_vector) # 可以不写forward, torch的内置功能 loss loss_function(train_prediction, target) # 计算真实值和预测值之间的差距 # 反向传播 optimizer.zero_grad() # 梯度清零 loss.backward() # 反向传播计算得到每个参数的梯度值 optimizer.step() # 根据梯度更新网络参数 total_loss loss.item() losses.append(total_loss) print(losses)data内容word_to_idx内容每一次运行的编码都是不一样的根据word_to_idx编号把data中每一组上下文此列表转化为张量例如target也就是我们目标要预测的那个词也根据word_to_idx编号转为张量about编码是31inputs是四个词的索引embeddings把他转化为10维的向量2.测试# 测试 context [People, create, to, direct] # People create programs to direct context_vector make_context_vector(context, word_to_idx).to(device) # 预测的值 model.eval() # 进入测试模式 predict model(context_vector) max_idx predict.argmax(1) # dim1表示每一行中的最大值对应的索引号dim0表示每一列中的最大值对应的索引号 print(f测试上下文: {context}) print(f预测结果索引: {max_idx.item()}) print(f预测的单词: {idx_to_word[max_idx.item()]})3.输出权重datach转化为numpy矩阵拿回cpu中w权重就是我们需要保存下来的权重矩阵w所有词的向量表。为我们下面词嵌入字典的保存做准备。# 获取词向量这个Embedding就是我们需要的问题向量。他只是一个模型的一个中间过程 print(CBOW embedding weight, model.embeddings.weight) # GPU W model.embeddings.weight.cpu().detach().numpy() # .detach(): 这个方法会创建一个新的Tensor它和原来的Tensor共享数据 # 但不会参与梯度的反向传播这对于防止在计算梯度时意外修改某些参数很有用 # print(W)4.生成词嵌入字典词嵌入字典是不是就相当于人类的字典一样这个字典是给机器使用的方面以后机器进行理解词义的时候使用尤其是压缩词的时候。对于人来说字典就是词义对于机器来说他的‘字典’就是词向量。这里词向量其实就是上面我们获得的w权重矩阵。# 生成词嵌入字典即[单词1:词向量1, 单词2:词向量2...]的格式 word_2_vec {} for word in word_to_idx.keys(): word_2_vec[word]W[word_to_idx[word],:] print(over) np.savez(word2vec实现.npz,file1W) datanp.load(word2vec实现.npz) print(data.files) adata[data.files[0]] print(a)词嵌入字典文件保存后缀通常为npz或者npy二、numpy进行保存和读取词嵌入字典文件有两种保存方法和对应的读取方法import numpy as np1.第一种保存#第一种 a np.random.randint(5, size(2, 4)) #随机生成2行4列的数据数据值为0~5之间 np.save(test.npy, a)读取b np.load(test.npy) print(b)结果2.第二种保存a np.random.randint(0, 10, (3,), dtypeint) b np.random.randint(0, 10, (3,), dtypeint) c np.random.randint(0, 10, (3,), dtypeint) np.savez(test.npz, file1 a, file2 b, file3 c) #压缩存储数组并给数组分别命名读取data np.load(test.npz) print(data.files)结果读取具体内容data np.load(test.npz) aa data[data.files[0]] print(aa)结果三、拓展其实我们使用的输入法当我们输入一个词后后面后陆续出来我们可能会用到的词。输入法原理也是一样的只不过是输入法不是上下文而是根据前文预测下一个词自然语言联想系统。实际上换汤不换药基本原理都是一样的学要修改的最重要的地方就是data这里因为我们要获取的是前文。data [] # 获取上下文词将上下文词作为输入目标词作为输出。构建训练数据集。 for i in range(len(raw_text) - CONTEXT_SIZE):#(2,60),从第三个值开始预测 context raw_text[i:i CONTEXT_SIZE] # 前CONTEXT_SIZE个词 target raw_text[i CONTEXT_SIZE] # 下一个词 data.append((context, target))