自然语言处理【NLP】—— 使用CBOW模型进行词预测
连续词袋模型(Continuous Bag-of-Words, CBOW)是一种用于学习词嵌入的神经网络模型。与Skip-gram模型不同,CBOW通过上下文单词来预测目标单词。输入是上下文单词(通常取目标单词前后各n个单词)输出是预测的目标单词训练目标是最大化正确预测目标单词的概率理解词嵌入的基本概念学习如何使用PyTorch构建神经网络模型掌握自然语言处理中的上下文预测方法CBOW模型虽然简单
·
引言
自然语言处理(NLP)是现代人工智能的重要领域之一,而词嵌入(word embedding)是NLP的基础技术。本文将介绍如何使用PyTorch实现连续词袋模型(CBOW)来预测文本中的单词。
一、什么是CBOW模型?
连续词袋模型(Continuous Bag-of-Words, CBOW)是一种用于学习词嵌入的神经网络模型。与Skip-gram模型不同,CBOW通过上下文单词来预测目标单词。它的特点是:
- 输入是上下文单词(通常取目标单词前后各n个单词)
- 输出是预测的目标单词
- 训练目标是最大化正确预测目标单词的概率
二、代码实现
1. 准备数据
首先我们需要准备语料库并构建词汇表:
CONTEXT_SIZE = 2 # 设置词左边和右边选择的个数
raw_text = """We are about to study the idea of a computational process...""".split()
vocab = set(raw_text) # 构建词汇表
vocab_size = len(vocab)
# 创建单词到索引的映射
word_to_idx = {word:i for i,word in enumerate(vocab)}
idx_to_word = {i:word for i,word in enumerate(vocab)}
2. 构建训练数据
我们需要将原始文本转换为模型可以理解的训练数据:
data = [] # 存储训练数据
for i in range(CONTEXT_SIZE, len(raw_text) - CONTEXT_SIZE):
context = (
[raw_text[i - (2-j)] for j in range(CONTEXT_SIZE)] +
[raw_text[i + j + 1] for j in range(CONTEXT_SIZE)]
)
target = raw_text[i] # 目标词
data.append((context, target))
3. 定义CBOW模型
我们使用PyTorch的nn.Module来定义CBOW模型:
class CBOW(nn.Module):
def __init__(self, vocab_size, embedding_dim):
super(CBOW, self).__init__()
self.embeddings = nn.Embedding(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)
out = F.relu(self.proj(embeds))
out = self.output(out)
nll_prob = F.log_softmax(out, dim=-1)
return nll_prob
4. 训练模型
设置好优化器和损失函数后,我们就可以开始训练模型了:
model = CBOW(vocab_size, 10).to(device)
optimizer = optim.Adam(model.parameters(), lr=0.001)
loss_function = nn.NLLLoss()
for epoch in tqdm(range(200)):
total_loss = 0
for context, target in data:
context_vector = make_context_vector(context, word_to_idx).to(device)
target = torch.tensor([word_to_idx[target]]).to(device)
# 前向传播
train_predict = model(context_vector)
loss = loss_function(train_predict, target)
# 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_loss += loss.item()
losses.append(total_loss)
5. 使用模型进行预测
训练完成后,我们可以使用模型来预测单词:
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)
predicted_word = idx_to_word[max_idx.item()]
print(f"根据这些词:{context}")
print(f"预测到下一个词是: {predicted_word}")
- 预测结果如下:
三、完整代码
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 np
#任务:已经有了语料库,1、构造训练数据集,(单词,词库)
#真实的单词模型,每一个单词的词性,你训练大量的输入文本
CONTEXT_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)
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(CONTEXT_SIZE,len(raw_text) - CONTEXT_SIZE): #(2,60)
context = (
[raw_text[i - (2-j)] for j in range(CONTEXT_SIZE)]
+ [raw_text[i + j + 1] for j in range(CONTEXT_SIZE)]
#获取上下文词(['we','are','to','study'])
)
target = raw_text[i] #获取目标词'about'
data.append((context,target))#将上下文词和目标词保存到data中
def make_context_vector(context,word_tp_ix):#将上下文词转换为one-hot
idxs = [word_tp_ix[w] for w in context]
return torch.tensor(idxs,dtype=torch.long)
print(make_context_vector(data[0][0],word_to_idx))
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)
out = F.relu(self.proj(embeds))
out = self.output(out)
nll_prob = F.log_softmax(out,dim=-1)
return nll_prob
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(),lr=0.001)
losses = [] #存储损失的集合
loss_function = nn.NLLLoss() #NLLLoss损失函数(当分类列表非常多的情况),将多个类别分成0、1两个类别
model.train()
for epoch in tqdm(range(200)):#开始训练
total_loss = 0
for context,target in data:
context_vector = make_context_vector(context,word_to_idx).to(device)
target = torch.tensor([word_to_idx[target]]).to(device)
# 开始前向传播
train_predict = model(context_vector)
loss = loss_function(train_predict,target)
# 反向传播
optimizer.zero_grad() # 梯度值清零
loss.backward() # 反向传播计算得到每个参数的梯度值
optimizer.step() #根据梯度更新网络参数
total_loss += loss.item()
losses.append(total_loss)
print(losses)
#测试
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) #dim=1表示每一行中的最大值对应的索引号,dim=0表示每一列中的最大值对应的索引号
predicted_word = idx_to_word[max_idx.item()] # 用 .item() 从张量中提取标量值
print(f"根据这些词:{context}")
print(f"预测到下一个词是: {predicted_word}")
四、总结
通过这个简单的CBOW模型实现,我们能够:
- 理解词嵌入的基本概念
- 学习如何使用PyTorch构建神经网络模型
- 掌握自然语言处理中的上下文预测方法
CBOW模型虽然简单,但它是理解现代NLP技术的重要基础。在实际应用中,我们可以通过调整上下文窗口大小、嵌入维度等参数,或者使用更大的语料库来获得更好的效果。
希望这篇博客能帮助你理解CBOW模型的原理和实现方法!
更多推荐
所有评论(0)