古诗生成的任务构建
导包,主函数get-data,构建word2index,记得给一个unk,index2word直接用list就可以了,然后是后建立数据集,用dataset老三样,init后面要将要用参数传进去,grtitem拿n句话,再将每句话的每个字的index给出来,后return出来这个地方要注意给他变成tensor类型,然后主函数开始实例化,traindataloder中传的参数有dataset和batchsize,这时候还要实例化一下模型,注意模型要传入的参数,还有实例化优化器,进入循环,取到了bach-index,他是一个tensor类型,在这里我们要把moudel中要用到的初始值和标签给表示出来,23个字对23个字,开始构建模型,一个模型中有个init和forward,在init中我们要设置几个参数,相当于继承,rnn模型需要什么参数,都要写好,中间的w就是embedingnum*hiddennum,batchfirst对其影响不大,他内部会自己转换,bidirectrional是双向的意思,这个乘与v的操作就相当于是一个线性层,再继承一下loss,在forward中对数据进行操作,我们给进去的数据是x,他是没有经过embedding的,进来之后进行embedding,然后将其传入rnn模型,这里我们可以看出来,其实我们这个大模型是自己建立的,数据只是进到rnn里面跑一下,需要他的返回值,根据shape我们可以知道rnn_out1是每个字的信息拼起来的,rnn_out2是包含每句话的信息,我们将rnn的
字符级别的输出乘上V,让他得到预测值,让下一个字成为标签,这样就可以计算loss了,这里计算loss的时候是下面调用,下面传的pre是三维的,我们要将其变成二维的,标签也是二维的,就可以算loss了,然后就是优化器等,算法结束,让他开始预测写诗,搞一个自动生成器,建立一个result,然后随机找一个字放到letter中,要排除符号,先将找到的第一个字放到列表中,然后将找到的这个字的index找到,将其放到设备上,这里要记住我们在生成的时候是需要自己去写这个循环的,不然就相当于没用到rnn的记忆,我们将h_0先设为0矩阵,然后开始循环23次,将index和h_0放进去,计算出来的index和h_0更新,根据index2word找到对应的字,然后将它添加到list中
import os
import torch.nn as nn
from torch.utils.data import Dataset,DataLoader
import torch
import random
def get_data(file,num=None):
with open(file,"r",encoding="utf-8") as f:
all_data = f.read().split("\n")
if num is None:
return all_data
return all_data[:num]
def build_cor(train_text):
word_2_index = {"UNK":0}
for p in train_text:
for w in p:
if w not in word_2_index:
word_2_index[w] = len(word_2_index)
return word_2_index
class PDataset(Dataset):
def __init__(self,all_text,word_2_index):
self.all_text = all_text
self.word_2_index = word_2_index
def __getitem__(self,index):
poetry = self.all_text[index]
poetry_index = [word_2_index.get(i,0) for i in poetry]
return torch.tensor(poetry_index)
def __len__(self):
return len(self.all_text)
class PModel(nn.Module):
def __init__(self,corpus_len,embedding_num,hidden_num):
super().__init__()
self.embedding = nn.Embedding(corpus_len,embedding_num)
self.rnn = nn.RNN(embedding_num,hidden_num,batch_first=True,num_layers=1,bidirectional=False)#是否为双向的
self.V = nn.Linear(hidden_num,corpus_len)#这个v是为了去做分类的,所以输出的维度是词表的大小,预测所有的词。
self.loss_fun = nn.CrossEntropyLoss()#多分类用的交叉熵损失函数
def forward(self,x,label=None,h_0=None):#这个h0是专门为了预测而做的,因为我们要用历史信息来预测下一个字。训练模型的时候它内部就自己会有。
batch_emb = self.embedding(x)
r