CBOW(파이토치 연습의 예로 txt 텍스트 소설을 사용함)
오늘 블로거가 좋은 실험을 했는데, 많은 친구들이 그로부터 뭔가를 배울 수 있을 것 같아요.
먼저 이 실험과 제가 한 일에 대해 이야기하겠습니다. 이 실험에서 블로거는 txt 파일에서 처음부터 시작하여 이 파일에 있는 중국어 단어를 분할하고 원-핫 인코딩을 수행합니다. 데이터를 처리한 후 또한 구축합니다. cbow 네트워크. 그 후 우리는 자체 모델을 학습시켰고 이를 기반으로 모델에 대한 검증, 즉 우리가 얻은 임베딩 단어 벡터를 통해 특정 단어와 가장 가까운 k 단어를 계산했습니다. 데이터 세트의 품질이 매우 낮은 것으로 나타났지만 검증 후에도 모델은 여전히 일정한 효과를 나타냈습니다.
먼저 데이터 세트 처리 및 모델 교육에 사용할 수 있는 코드를 살펴보겠습니다.
#coding=gbk
import os
import jieba
import torch
from torch import nn, optim
from torch.autograd import Variable
import torch.nn.functional as F
path="E:\\data\\dataz.txt"
def read_file(path):
fp=open(path,encoding='utf8')
text=fp.readlines()
fp.close()
return text
def cut_words(text):
dict_index={
}
index=0
words_list=[]
for line in text:
line=line.replace('"','')
line=line.replace('“','')
line=line.replace('”','')
line=line.replace('。','')
line=line.replace('\n','')
line=line.replace(' ','')
words_cut=line.split(',')
for i in words_cut:
words_l=jieba.lcut(i)
for word in words_l:
if word not in dict_index.keys():
dict_index[word]=index
index=index+1
if len(words_l)>0:
words_list.append(words_l)
return words_list,dict_index
def get_data_corpus(words_list,window_size):
data_corpus=[]
for words in words_list:
if len(words)<2:
continue
else:
for index in range(len(words)):
l=[]
target=words[index]
l.append(target)
try:
l.append(words[index+1])
l.append(words[index+2])
except:
pass
try:
l.append(words[index-1])
l.append(words[index-2])
except:
pass
data_corpus.append(l)
return data_corpus
text=read_file(path)
words_list,dict_index=cut_words(text)
#print(words_list,dict_index)
data_corpus=get_data_corpus(words_list,2)
#print(data_corpus)
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, vocab_size)
self.output = nn.Linear(embedding_dim, vocab_size)
def forward(self, inputs):
embeds = sum(self.embeddings(inputs)).view(1, -1)
# out = F.relu(self.proj(embeds))
out = self.output(embeds)
nll_prob = F.log_softmax(out, dim=-1)
return nll_prob
length=len(dict_index.keys())
data_final=[]
for words in data_corpus[0:10000]:
target_vector=torch.zeros(length)
context_id=[]
if len(words)==5:
target_vector[dict_index[words[0]]]=1
for i in words[1:]:
context_id.append(dict_index[i])
data_final.append([target_vector,context_id])
#print(data_final)
epochs=5
model=CBOW(length,100)
loss_function=nn.NLLLoss()
optimizer=optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
losses=[]
for epoch in range(epochs):
total_loss = 0
for data in data_final:
target=data[0]
context=data[1]
# context_vector = make_context_vector(context, word_to_idx).to(device) # 把训练集的上下文和标签都放到cpu中
target = torch.tensor(target).type(dtype=torch.long)
context=torch.tensor(context)
model.zero_grad() # 梯度清零
train_predict = model(context) # 开始前向传播
# print("train_predict",train_predict[0])
# print("target",target)
loss = loss_function(train_predict[0], target)
loss.backward() # 反向传播
optimizer.step() # 更新参数
total_loss += loss.item()
print("loss ",total_loss)
losses.append(total_loss)
#保存
torch.save(model,'E:\\data\\cbow.pt')
#读取
os.system("pause")
다음은 특정 단어에 대한 최근 어휘 평가를 수행하는 코드입니다.
#coding=gbk
import os
import jieba
import torch
from torch import nn, optim
from torch.autograd import Variable
import torch.nn.functional as F
path="E:\\data\\dataz.txt"
def read_file(path):
fp=open(path,encoding='utf8')
text=fp.readlines()
fp.close()
return text
def cut_words(text):
dict_index={
}
index=0
words_list=[]
for line in text:
line=line.replace('"','')
line=line.replace('“','')
line=line.replace('”','')
line=line.replace('。','')
line=line.replace('\n','')
line=line.replace(' ','')
words_cut=line.split(',')
for i in words_cut:
words_l=jieba.lcut(i)
for word in words_l:
if word not in dict_index.keys():
dict_index[word]=index
index=index+1
if len(words_l)>0:
words_list.append(words_l)
return words_list,dict_index
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, vocab_size)
self.output = nn.Linear(embedding_dim, vocab_size)
def forward(self, inputs):
embeds = sum(self.embeddings(inputs)).view(1, -1)
# out = F.relu(self.proj(embeds))
out = self.output(embeds)
nll_prob = F.log_softmax(out, dim=-1)
return nll_prob
def get_data_corpus(words_list,window_size):
data_corpus=[]
for words in words_list:
if len(words)<2:
continue
else:
for index in range(len(words)):
l=[]
target=words[index]
l.append(target)
try:
l.append(words[index+1])
l.append(words[index+2])
except:
pass
try:
l.append(words[index-1])
l.append(words[index-2])
except:
pass
data_corpus.append(l)
return data_corpus
text=read_file(path)
words_list,dict_index=cut_words(text)
print(dict_index)
path='E:\\data\\cbow.pt'
model = torch.load('E:\\data\\cbow.pt')
print(type(model.state_dict())) # 查看state_dict所返回的类型,是一个“顺序字典OrderedDict”
for param_tensor in model.state_dict(): # 字典的遍历默认是遍历 key,所以param_tensor实际上是键值
print(param_tensor,'\t',model.state_dict()[param_tensor].size())
embedings=model.state_dict()['embeddings.weight']
print(embedings)
print(len(embedings[0]))
# print("萧炎:",dict_index['萧炎'])
dict_values={
}
for key in dict_index.keys():
dict_values[dict_index[key]]=key
def get_most_approch(embedings,target_id,k):
target_vec=embedings[target_id]
dict_k={
}
index=0
for vec in embedings:
dict_k[index]=float(torch.dot(vec,target_vec))
index=index+1
sort_z=sorted(dict_k.items(),key=lambda e:e[1],reverse=True
) #排序
for i in sort_z[0:k]:
print(dict_values[i[0]])
get_most_approch(embedings,dict_index['萧炎'],10)
os.system("pause")
테스트 결과 중 하나를 살펴보세요:
위 사진은 Xiao Yan과 관련하여 테스트한 30개의 단어입니다. 위의 단어 중 많은 부분이 사람이 말하는 것이므로 여전히 괜찮다는 것을 알 수 있습니다. Xiao Yan은 사람의 이름입니다. , 둘째, 제자 나란(Nalan)은 샤오옌(Xiao Yan)과 밀접한 관련이 있으며, 이는 이 모델이 일정한 효과가 있음을 보여줍니다.
데이터 세트를 내 리소스에 업로드하고, 코드를 실행하려는 사람들은 데이터 세트를 다운로드할 수 있습니다.