一.前言

之前写过一篇基于循环神经网络(RNN)的情感分类文章,这次我们换种思路,采用卷积神经网络(CNN)来进行文本分类任务。倘若对CNN如何在文本上进行卷积的可以移步博主的快速入门CNN在NLP中的使用一文。话不多说,直接上干货。

二.数据集

2.1 数据集介绍

本次实验的数据集来源于Github上一个2.4k星的中文NLP开源数据集项目CLUEbenchmark(官方地址),本文选择的是其中的文本分类数据集waimai_10k。该数据集某外卖平台收集的用户评价,正向 4000 条,负向7987条,下面展示该数据集中的部分数据

1,不错,就是餐盒贵
1,火烧夹肉好咸啊!没法吃。其他还行
1,"味道不错,配送速度比预计快"
0,菜品质量好,味道好,就是百度的问题,总是用运力原因来解释,我也不懂这是什么原因,晚了三个小时呵呵厉害吧!反正订了就退不了,只能干等……
0,分量还可以……就是有点没特色……下回不吃啦
0,没什么味道,送来的晚凉了

2.2 数据集预处理

2.2.1 数据集划分

步骤一:把数据集划分为训练集、验证集和测试集,划分比例为6:2:2。

def split(data):"""划分训练集、验证集和测试集:6:2:2"""data_size = data.shape[0]indices = np.arange(data_size)np.random.shuffle(indices)train_size, valid_size = int(data_size * 0.6), int(data_size * 0.2)train_indices, valid_indices, test_indices = indices[:train_size], \indices[train_size:train_size + valid_size], indices[train_size + valid_size:]return data[train_indices], data[valid_indices], data[test_indices]

划分完成后,训练集、验证集和测试集的样本数分别为7192、2397和2398。

2.2.2 分词和删除停用词

步骤二:对划分好的训练集、验证集和测试集进行中文分词和删除停用词操作。分词采用jieba分词,分词后进行停用词的删除。

def tokenization(data, stop_words, save_path):"""中文分词,删除停用词"""dataset = []for label,review in data:review = jieba.cut(review)review = [c for c in review if c not in stop_words]dataset.append([label, review])with open(save_path, 'w', encoding='utf-8') as fp:json.dump(dataset, fp, ensure_ascii=False)

注意:在分词阶段发现有几条数据删完停用词后为空,对其采取的措施是将其从数据集中删除。

2.2.3 数据集统计分析

首先统计训练集,验证集和测试集的不同标签类别数据的分布情况

结论:可以看出划分后训练集、验证集和测试集的标签分布是一致的。

然后,统计了训练集,验证集和测试集的句子长度分布情况

结论:数据集的三部分的句子长度分布也是基本一致的。

2.3 Word2Vec词嵌入

2.3.1 词表的构建

步骤三:在训练集上构建词表,在构建词表的过程中过滤低频词(词频小于5的词)。

def build_vocabulary(data, min_count=1):"""构建中文词表"""vocabs = defaultdict(int)for _, review in data:for word in review:vocabs[word] += 1word2id = {}word2id['unk'] = 0for k,v in vocabs.items():if v < min_count:continue # 过滤低频词word2id[k] = len(word2id)with open('data/word2id.json', 'w', encoding='utf-8') as fp:json.dump(word2id, fp, ensure_ascii=False)

2.3.2 词嵌入的训练

步骤四:在训练集上训练Word2Vec词嵌入,并保存训练好的词嵌入,词嵌入的维度为100维。

if __name__ == "__main__":train_path = "data/train.json"sents = []# 加载词表with open('data/word2id.json', 'r', encoding='utf-8') as fp:word2id = json.load(fp)# 加载训练语料with open(train_path, "r", encoding="utf-8") as fp:for _,review in json.load(fp):sentence = []# 将训练语料中未出现在词表中的词全部处理为unkfor w in review:if word2id.get(w):sentence.append(w)else:sentence.append('unk')sents.append(sentence)# 训练词嵌入和保存model = word2vec.Word2Vec(sents) model.wv.save_word2vec_format('data/word2vec.bin', binary=False)

三.模型设计

本文设计两种堆叠方式的CNN用于文本分类任务:

  • 横向堆叠卷积:使用不同大小的卷积核提取句子不同维度的信息,然后进行拼接(concat)操作,最后将拼接的最终表示用于分类。
  • 纵向堆叠卷积:在某个卷积块(卷积+激活+池化)抽取的特征的基础上继续应用卷积块抽取更高维度的特征,然后将最终表示用于分类。

3.1 横向堆叠

横向堆叠卷积神经网络的大致示意图如下所示:

模型源码为:

import torch
import torch.nn as nn
import torch.nn.functional as Fclass GlobalMaxPool1d(nn.Module):def __init__(self):super(GlobalMaxPool1d, self).__init__()def forward(self, x):# x shape: (batch_size, channel, seq_len)# return shape: (batch_size, channel, 1)return F.max_pool1d(x, kernel_size=x.shape[2])class TextCNNH(nn.Module):def __init__(self, word_count, word_dim, num_filters, ngram_size, y_num, drop_prob):super(TextCNNH, self).__init__()# 词嵌入层self.word_embed = nn.Embedding(word_count, word_dim)# 卷积层self.convs = nn.ModuleList()for c,k in zip(num_filters, ngram_size):self.convs.append(nn.Conv1d(in_channels = word_dim, out_channels = c, kernel_size = k))self.pooling_layer = GlobalMaxPool1d()self.activation = nn.ReLU()self.dropout = nn.Dropout(drop_prob)self.fc = nn.Linear(sum(num_filters), y_num)def load_pretrained_word_embedding(self, pre_word_embeddings, updated=False):self.word_embed.weight = nn.Parameter(torch.Tensor(pre_word_embeddings))self.word_embed.weight.requires_grad = updateddef forward(self, word_ids):#转换为词向量word_emb = self.word_embed(word_ids)word_emb =  word_emb.transpose(1, 2)# 多尺度卷积embeds = []for conv in self.convs:embeds.append(self.pooling_layer(self.activation(conv(word_emb))).squeeze(-1))final_embed = torch.cat(embeds, dim=1)return self.fc(self.dropout(final_embed))

3.2 纵向堆叠

纵向堆叠的卷积神经网络的大致示意图如下所示:

模型源码为:

import torch
import numpy as np
import torch.nn as nn
import torch.nn.functional as Fclass GlobalMaxPool1d(nn.Module):def __init__(self):super(GlobalMaxPool1d, self).__init__()def forward(self, x):# x shape: (batch_size, channel, seq_len)# return shape: (batch_size, channel, 1)return F.max_pool1d(x, kernel_size=x.shape[2])class TextCNNV(nn.Module):def __init__(self, word_count, y_num, word_dim, num_filters, ngram_size, drop_prob):super(TextCNNV, self).__init__()self.word_embed = nn.Embedding(word_count, word_dim)self.conv1 = nn.Sequential(nn.Conv1d(word_dim, num_filters[0], kernel_size=ngram_size[0]), nn.ReLU(),nn.MaxPool1d(2))self.conv2 = nn.Sequential(nn.Conv1d(num_filters[0], num_filters[1], kernel_size=ngram_size[1]), nn.ReLU(), GlobalMaxPool1d())self.dropout = nn.Dropout(drop_prob)self.fc = nn.Linear(num_filters[1], y_num)self._init_weights(mean=0.0, std=0.05)def load_pretrained_word_embedding(self, pre_word_embeddings, updated=False):self.word_embed.weight = nn.Parameter(torch.Tensor(np.array(pre_word_embeddings)))self.word_embed.weight.requires_grad = updateddef _init_weights(self, mean=0.0, std=0.05):for module in self.modules():if isinstance(module, nn.Conv1d) or isinstance(module, nn.Linear):module.weight.data.normal_(mean, std)def forward(self, input):input = self.word_embed(input)input = input.transpose(1, 2)output = self.conv1(input)output = self.conv2(output)output = output.view(output.size(0), -1)return self.fc(self.dropout(output))

四.实验与结果

4.1 实验说明

模型训练与测评的主函数源码如下所示,在实验过程中通过训练集来训练模型,然后通过验证集来筛选模型,最后将在验证集上表现最好的模型用于测试集的测评

def main(args):# 加载数据集train_set = load('data/train.json')valid_set = load('data/valid.json')test_set = load('data/test.json')if args['model'] == 'textcnnv':model = TextCNNV(word_count=len(word2id),y_num=args['y_num'],word_dim=args['word_dim'], num_filters=args['num_filters'],ngram_size=args['ngram_size'],drop_prob=args['drop_prob'])elif args['model'] == 'textcnnh':model = TextCNNH(word_count=len(word2id),y_num=args['y_num'],word_dim=args['word_dim'], num_filters=args['num_filters'],ngram_size=args['ngram_size'],drop_prob=args['drop_prob'])if args['extra_embedding'] == True:# 加载词嵌入word_embedding = load_pretrained_embedding('data/word2vec.bin')model.load_pretrained_word_embedding(word_embedding, True)model.to(device)optimizer = optim.Adam(model.parameters(), args['lr'], weight_decay=args['wd'])valid_f1, valid_p,valid_r = [],[],[]best_f1, best_model = 0., Nonefor e in range(args['n_epochs']):train_loss = train(model, train_set, args['batch_size'], optimizer)valid_loss, f1, p, r = evaluate_accuracy(model, valid_set, args['batch_size'])valid_f1.append(f1)valid_p.append(p)valid_r.append(r)print('Epoch {} train_loss: {:.6f} valid_loss: {:.6f}, f1 {:.4f}, p {:.4f}, r {:.4f}'.format(e + 1, train_loss, valid_loss, f1, p, r))if best_f1 < f1:best_f1 = f1best_model = deepcopy(model)x = list(range(1, len(valid_f1) + 1))plt.title('Metrics On Valid Set')plt.plot(x, valid_f1)plt.plot(x, valid_p)plt.plot(x, valid_r)plt.legend(['f1-score', 'precision', 'recall'])plt.savefig('images/{}_outcome.png'.format(args['model']))plt.show()_, f1, precision, recall = evaluate_accuracy(best_model, test_set, args['batch_size'])print('testset: f1 {:.4f}, p {:.4f}, r {:.4f}'.format(f1, precision, recall))if __name__ == "__main__":try:params = {'model':'textcnnv', # ['textcnnv', 'textcnnh']'word_dim':100,'ngram_size':[2, 4],'num_filters':[64, 64],'lr':1e-4,'batch_size':64,'n_epochs':50,"embedding": "w2v",'y_num':2,'wd':0,'drop_prob':0.5}print(params)main(params)except Exception as exception:raise

4.2 具体实验结果

实验的测评指标包括F1分数、查准率和查全率。对于纵向堆叠的CNN,实验中设置的参数为:

params = {'model':'textcnnv', # ['textcnnv', 'textcnnh']'word_dim':100,'ngram_size':[2, 4],'num_filters':[64, 64],'lr':5e-4,'batch_size':64,'n_epochs':50,"extra_embedding": True,'y_num':2,'wd':0,'drop_prob':0.3
}

训练过程中验证集上的测评指标随epoch的变化情况如下所示:

对于横向堆叠的CNN,实验中设置的参数为:

params = {'model':'textcnnh', # ['textcnnv', 'textcnnh']'word_dim':100,'ngram_size':[2, 3, 4],'num_filters':[32, 32, 32],'lr':5e-4,'batch_size':64,'n_epochs':50,"extra_embedding": True,'y_num':2,'wd':0,'drop_prob':0.3
}

训练过程中验证集上的测评指标随epoch的变化情况如下所示:

两组实验在测试集上的结果如下表所示:

实验设置 F1-Score Precision Recall
TextCNNV + Word2Vec 0.7826 0.7728 0.7927
TextCNNH + Word2Vec 0.7799 0.7794 0.7804

结论:从实验结果可以看出使用CNN进行文本分类确定也能取得不错的性能,限于时间博主并没有进行太过细致的调参实验,有兴趣的小伙伴可以自己去试试。

五.结语

完整项目下载地址:基于CNN的中文文本分类实战(有条件的可以支持一下)

本文使用的模型图来源于:Convolutional Neural Networks for Text

以上便是本文的全部内容,要是觉得不错的话,可以点个赞或关注一下博主,你们的支持是博主进步的不竭动力,当然要是有问题的话也敬请批评指正!!!

基于CNN中文文本分类实战相关推荐

  1. textcnn文本词向量_基于Text-CNN模型的中文文本分类实战

    1 文本分类 文本分类是自然语言处理领域最活跃的研究方向之一,目前文本分类在工业界的应用场景非常普遍,从新闻的分类.商品评论信息的情感分类到微博信息打标签辅助推荐系统,了解文本分类技术是NLP初学者比 ...

  2. linux tf2 中文,tf2+cnn+中文文本分类优化系列(2)

    1 前言 接着上次的tf2+cnn+中文文本分类优化系列(1),本次进行优化:使用多个卷积核进行特征抽取.之前是使用filter_size=2进行2-gram特征的识别,本次使用filter_size ...

  3. [Python人工智能] 二十一.Word2Vec+CNN中文文本分类详解及与机器学习(RF\DTC\SVM\KNN\NB\LR)分类对比

    从本专栏开始,作者正式研究Python深度学习.神经网络及人工智能相关知识.前一篇文章分享了Keras实现RNN和LSTM的文本分类算法,并与传统的机器学习分类算法进行对比实验.这篇文章我们将继续巩固 ...

  4. 基于python文本挖掘实战_python实现CNN中文文本分类

    [实例简介] CNN 中文文本挖掘 文本分类 python 深度学习 机器学习 [实例截图] [核心代码] zh_cnn_text_classify-master └── zh_cnn_text_cl ...

  5. 基于Text-CNN模型的中文文本分类实战

    七月 上海 | 高性能计算之GPU CUDA培训 7月27-29日三天密集式学习  快速带你入门阅读全文> 正文共5260个字,21张图,预计阅读时间28分钟. Text-CNN 1.文本分类 ...

  6. 详解CNN实现中文文本分类过程

    摘要:本文主要讲解CNN实现中文文本分类的过程,并与贝叶斯.决策树.逻辑回归.随机森林.KNN.SVM等分类算法进行对比. 本文分享自华为云社区<[Python人工智能] 二十一.Word2Ve ...

  7. 万字总结Keras深度学习中文文本分类

    摘要:文章将详细讲解Keras实现经典的深度学习文本分类算法,包括LSTM.BiLSTM.BiLSTM+Attention和CNN.TextCNN. 本文分享自华为云社区<Keras深度学习中文 ...

  8. python中文文本分析_基于CNN的中文文本分类算法(可应用于垃圾邮件过滤、情感分析等场景)...

    基于cnn的中文文本分类算法 简介 参考IMPLEMENTING A CNN FOR TEXT CLASSIFICATION IN TENSORFLOW实现的一个简单的卷积神经网络,用于中文文本分类任 ...

  9. TensorFlow使用CNN实现中文文本分类

    TensorFlow使用CNN实现中文文本分类 读研期间使用过TensorFlow实现过简单的CNN情感分析(分类),当然这是比较low的二分类情况,后来进行多分类情况.但之前的学习基本上都是在英文词 ...

最新文章

  1. spring in action 4 线路图
  2. shell 解析 json
  3. IOC操作Bean管理XML方式(创建对象和set注入属性)
  4. DB2行转列(多维度)
  5. beetl调用java方法_08.自定义方法以及直接访问java类方法---《Beetl视频课程》
  6. tomcat集群共享session
  7. 【免费毕设】ASP.NET 网上选课系统的设计与实现(源代码+lunwen)
  8. AcWing 4244. 牛的比赛(双向建图BFS)
  9. Vue学习笔记之14-Vue-CLI脚手架
  10. C语言每个语句的最后必须有一个分号,C语言选择题附答案
  11. 2022CCPC网络预选赛题解
  12. 分时线的9代表什么_股权生命9条线,持有不同股权代表了什么?
  13. LONG RAW转换BLOB
  14. N卡电脑Ubuntu20.04+N卡驱动安装+windows11双系统安装(不符合条件的电脑也可以安装win11)2021.11.13
  15. 中国大学慕课MOOC第七章测试题答案
  16. android 崩溃原因,Android中导致小米系列手机直接崩溃的主要原因。
  17. 浅谈C/C++ 开发Excel插件之操作excel
  18. web service方法进行全文检索_软件架构分层方法论
  19. 微信的红包算法 了解一下两种就可以了
  20. NYU计算机系,NYU的Computer Science and Engineering「纽约大学计算机科学与工程系」

热门文章

  1. 自来水供水实时监测系统 智慧水务建设方案 供水泵站无人值守控制方案
  2. PDF文档工具:pdfFactory快照功能详解
  3. 特殊矩阵的压缩存储(对称矩阵,三角矩阵,对角矩阵,稀疏矩阵的顺序,链序存储,十字链表的建立)
  4. 航班号校验正则表达式
  5. php 导出cvs,php导出cvs文件简单类
  6. 目标是买车买房白富美
  7. 瑞星卡卡助手爆重大bug OE用户损失惨重
  8. [2008-05-18]我们的使命
  9. Edge 浏览器:隐藏功能揭秘与高效插件推荐
  10. 【codevs2495】水叮当的舞步