textCNN论文与原理——短文本分类

前言
之前书写了使用pytorch进行短文本分类,其中的数据处理方式比较简单粗暴 。自然语言处理领域包含很多任务,很多的数据向之前那样处理的话未免有点繁琐和耗时 。在pytorch中众所周知的数据处理包是处理图片的torchvision,而处理文本的少有提及,快速处理文本数据的包也是有的,那就是torchtext[1] 。下面还是结合上一个案例:【深度学习】textCNN论文与原理——短文本分类(基于pytorch)[2],使用torchtext进行文本数据预处理,然后再使用torchtext进行模型分类 。
关于torchtext的基本使用除了可以参考官方文档,也可以看看这篇文章:TorchText用法示例及完整代码[3] 。
下面就开始看看该如何进行处理吧 。
1数据处理
首先导入包:
fromtorchtextimportdata
我们处理的语料中,主要涉及两个内容:文本,文本对应的类别 。下面使用torchtext构建这两个字段:
#文本内容,使用自定义的分词方法,将内容转换为小写,设置最大长度等TEXT=data.Field(tokenize=utils.en_seg,lower=True,fix_length=config.MAX_SENTENCE_SIZE,batch_first=True)#文本对应的标签LABEL=data.LabelField(dtype=torch.float)
其中的一些参数在一个config.py文件中,如下:
#模型相关参数RANDOM_SEED=1000#随机数种子BATCH_SIZE=128#批次数据大小LEARNING_RATE=1e-3#学习率EMBEDDING_SIZE=200#词向量维度MAX_SENTENCE_SIZE=50#设置最大语句长度EPOCH=20#训练测轮次#语料路径NEG_CORPUS_PATH=‘ 。/corpus/neg.txt’POS_CORPUS_PATH=‘ 。/corpus/pos.txt’
utils.en_seg是自定义的文本分词函数,如下:
defen_seg(sentence):“”“简单的英文分词方法,:paramsentence:需要分词的语句返回分词结果”“”returnsentence.split()
当然也可以书写更复杂的,或者使用spacy 。下面就是书写读取文本数据到torchtext对象的数据了,便于使用torchtext中的方法,如下:
defget_dataset(corpus_path,text_field,label_field,datatype):“”“构建torchtext数据集:paramcorpus_path:数据路径:paramtext_field:torchtext设置的文本域:paramlabel_field:torchtext设置的文本标签域:paramdatatype:文本的类别torchtext格式的数据集以及设置的域”“”fields=[(‘text’,text_field),(‘label’,label_field)]examples=[]withopen(corpus_path,encoding=‘utf8’)asreader:forlineinreader:content=line.rstrip()ifdatatype==‘pos’:label=1else:label=0#content[:-2]是由于原始文本最后的两个内容是空格和 。,这里直接去掉,并将数据与设置的域对应起来examples.append(data.Example.fromlist([content[:-2],label],fields))returnexamples,fields
现在就可以获取torchtext格式的数据了,如下:
#构建data数据pos_examples,pos_fields=dataloader.get_dataset(config.POS_CORPUS_PATH,TEXT,LABEL,‘pos’)neg_examples,neg_fields=dataloader.get_dataset(config.NEG_CORPUS_PATH,TEXT,LABEL,‘neg’)all_examples,all_fields=pos_examples+neg_examples,pos_fields+neg_fields#构建torchtext类型的数据集total_data=http://www.dg8.com.cn/news/data.Dataset(all_examples,all_fields)
有了上面的数据,下面就可以快速地为准备模型需要的数据了,如切分,构造批次数据,获取字典等,如下:
#数据集切分train_data,test_data=http://www.dg8.com.cn/news/total_data.split(random_state=random.seed(config.RANDOM_SEED),split_ratio=0.8)#切分后的数据查看##数据维度查看print(‘lenoftraindata:%r’%len(train_data))#lenoftraindata:8530print(‘lenoftestdata:%r’%len(test_data))#lenoftestdata:2132##抽一条数据查看print(train_data.examples[100].text)#[‘never’,‘engaging’,‘,’,‘utterly’,‘predictable’,‘and’,‘completely’,‘void’,‘of’,‘anything’,‘remotely’,#‘interesting’,‘or’,‘suspenseful’]print(train_data.examples[100].label)#0#为该样本数据构建字典,并将子每个单词映射到对应数字TEXT.build_vocab(train_data)LABEL.build_vocab(train_data)#查看字典长度print(len(TEXT.vocab))#19206#查看字典中前10个词语print(TEXT.vocab.itos[:10])#[‘《unk》’,‘《pad》’,‘,’,‘the’,‘a’,‘and’,‘of’,‘to’,‘ 。’,‘is’]#查找‘name’这个词对应的词典序号,本质是一个dictprint(TEXT.vocab.stoi[‘name’])#2063#构建迭代(iterator)类型的数据train_iterator,test_iterator=data.BucketIterator.splits((train_data,test_data),batch_size=config.BATCH_SIZE,sort=False)
这样一看,是不是减少了我们书写的很多代码了 。下面就是老生常谈的模型预测和模型效果查看了 。
2构建模型并训练
模型的相关理论已在前文介绍,如果忘了可以回过头看看 。模型还是那个模型,如下:
importtorchfromtorchimportnnimportconfigclassTextCNN(nn.Module):#output_size为输出类别(2个类别,0和1),三种kernel,size分别是3,4,5,每种kernel有100个def__init__(self,vocab_size,embedding_dim,output_size,filter_num=100,kernel_list=(3,4,5),dropout=0.5):super(TextCNN,self).__init__()self.embedding=nn.Embedding(vocab_size,embedding_dim)#1表示channel_num,filter_num即输出数据通道数,卷积核大小为(kernel,embedding_dim)self.convs=nn.ModuleList([nn.Sequential(nn.Conv2d(1,filter_num,(kernel,embedding_dim)),nn.LeakyReLU(),nn.MaxPool2d((config.MAX_SENTENCE_SIZE-kernel+1,1)))forkernelinkernel_list])self.fc=nn.Linear(filter_num*len(kernel_list),output_size)self.dropout=nn.Dropout(dropout)defforward(self,x):x=self.embedding(x)#[128,50,200](batch,seq_len,embedding_dim)x=x.unsqueeze(1)#[128,1,50,200]即(batch,channel_num,seq_len,embedding_dim)out=[conv(x)forconvinself.convs]out=torch.cat(out,dim=1)#[128,300,1,1],各通道的数据拼接在一起out=out.view(x.size(0),-1)#展平out=self.dropout(out)#构建dropout层logits=self.fc(out)#结果输出[128,2]returnlogits
为了方便模型训练,测试书写了两个函数,当然也和之前的相同,如下:
defbinary_acc(pred,y):“”“计算模型的准确率:parampred:预测值:paramy:实际真实值返回准确率”“”correct=torch.eq(pred,y).float()acc=correct.sum()/len(correct)returnaccdeftrain(model,train_data,optimizer,criterion):“”“模型训练:parammodel:训练的模型:paramtrain_data:训练数据:paramoptimizer:优化器:paramcriterion:损失函数该论训练各批次正确率平均值”“”avg_acc=[]model.train()#进入训练模式fori,batchinenumerate(train_data):pred=model(batch.text)loss=criterion(pred,batch.label.long())acc=binary_acc(torch.max(pred,dim=1)[1],batch.label)avg_acc.append(acc)optimizer.zero_grad()loss.backward()optimizer.step()#计算所有批次数据的结果avg_acc=np.array(avg_acc).mean()returnavg_accdefevaluate(model,test_data):“”“使用测试数据评估模型:parammodel:模型:paramtest_data:测试数据该论训练好的模型预测测试数据,查看预测情况”“”avg_acc=[]model.eval()#进入测试模式withtorch.no_grad():fori,batchinenumerate(test_data):pred=model(batch.text)acc=binary_acc(torch.max(pred,dim=1)[1],batch.label)avg_acc.append(acc)returnnp.array(avg_acc).mean()
涉及相关包的话,就自行导入即可 。下面就是创建模型和模型训练测试了 。好紧张,又到了这个环节了 。
#创建模型text_cnn=model.TextCNN(len(TEXT.vocab),config.EMBEDDING_SIZE,len(LABEL.vocab))#选取优化器optimizer=optim.Adam(text_cnn.parameters(),lr=config.LEARNING_RATE)#选取损失函数criterion=nn.CrossEntropyLoss()#绘制结果model_train_acc,model_test_acc=[],[]#模型训练forepochinrange(config.EPOCH):train_acc=utils.train(text_cnn,train_iterator,optimizer,criterion)print(“epoch={},训练准确率={}”.format(epoch+1,train_acc))test_acc=utils.evaluate(text_cnn,test_iterator)print(“epoch={},测试准确率={}”.format(epoch+1,test_acc))model_train_acc.append(train_acc)model_test_acc.append(test_acc)#绘制训练过程plt.plot(model_train_acc)plt.plot(model_test_acc)plt.ylim(ymin=0.5,ymax=1.01)plt.title(“TheaccuracyoftextCNNmode”)plt.legend([‘train’,‘test’])plt.show()
模型最后的结果如下:

textCNN论文与原理——短文本分类 textCNN论文与原理——短文本分类

文章插图

    推荐阅读