NLP文本分类学习笔记3:基于CNN的文本分类

卷积神经网络CNN#

CNN是前馈神经网络,包含输入层,卷积层,池化层,全连接层,输出层
1、输入层,以输入彩色图像为例,输入数据为二维,包含RGB三个通道
2、卷积层,使用多个不同权重,大小的卷积核,平移固定的步长,提取图像的特征(对应位置相乘求和,如下图所示,3*3的卷积核对5*5的图像计算,步长为1,为了更好捕获边缘特征,实际中会对图像进行填充),最后输入到激活函数

3、池化层,用于特征过滤与选取,降低维度,常见的有最大池化,平均池化等,最大池化是选取区域中的最大值代替该区域,平均池化是求区域中的平均值代替该区域
以2*2的,步长为1的池化为例,如下图:

4、最后通过全连接层和输出层,组合计算特征,完成分类等任务

基于CNN的文本分类#

1、在论文Convolutional Neural Networks for Sentence Classification中提出了CNN用于文本分类的方法
2、在论文A Sensitivity Analysis of (and Practitioners’ Guide to) Convolutional Neural Networks for Sentence Classification讨论了只包含单层卷积的CNN模型中各个参数针对文本分类的影响,并给出了对于参数设置相对好的建议(下图来源于本论文)
3、以下图为例介绍用于文本分类的CNN结构过程。

  • 对于I like this movie very much !这句话,将每个词用5维的词向量表示
  • 在卷积层使用各有两个,尺寸为4*5,3*5,2*5的卷积核(共六个)对词向量组成的句子矩阵进行卷积,最后使用激活函数
  • 在池化层,对于得到的每个特征使用最大池化,并拼接在一起,得到一个六维向量
  • 最后通过softmax函数进行二分类

主要思想#

卷积的过程实际提取了N-Gram特征,如上图的卷积核大小为4,3,2:以2为例,实际提取了句子I like,like this,this movie等等这样一系列特征。

pytorch实现基于CNN的文本分类#

模型结构参数如下,对于10分类的任务达到了87.46%的准确率。关于代码更详细的说明参考:NLP文本分类学习笔记0:数据预处理及训练说明

  • 每个输入的批次为【128,32】128为批次大小,32为句子填充截断后统一长度
  • 经过词嵌入层,数据变为【128,32,200】200为word2vec预训练词向量维度
    为了便于使用nn.Conv2d(其中需要通道数),所以使用unsqueeze(1)为数据增加一个维度变为【128,1,32,200】
    在卷积层,使用不同大小(2*200,3*200,4*200)的卷积核进行计算,每个卷积核使用256个
  • 以卷积核大小为2*200为例,数据计算后为【128,256,31,1】,经过激活函数后,使用squeeze(3)去除最后一个维度,变为【128,256,31】
  • 在池化层,使用大小为31的1为最大池化,数据变为【128,256,1】,使用squeeze(2)去除最后一个维度,变为【128,256】
  • 在三种卷积核都完成后,将特征进行列拼接,数据变为【128,768】(256*3)
  • 最后通过dropout与全连接层输出
Copy
import json import pickle import torch import torch.nn as nn import torch.nn.functional as F import numpy as np class Config(object): """配置参数""" def __init__(self, embedding_pre): self.embedding_path = 'data/embedding.npz' self.embedding_model_path = "mymodel/word2vec.model" self.train_path = 'data/train.df' # 训练集 self.dev_path = 'data/valid.df' # 验证集 self.test_path = 'data/test.df' # 测试集 self.class_path = 'data/class.json' # 类别名单 self.vocab_path = 'data/vocab.pkl' # 词表 self.save_path ='mymodel/cnn.pth' # 模型训练结果 self.embedding_pretrained = torch.tensor(np.load(self.embedding_path, allow_pickle=True)["embeddings"].astype( 'float32')) if embedding_pre == True else None # 预训练词向量 self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 设备 self.dropout = 0.5 # 随机失活 self.num_classes = len(json.load(open(self.class_path, encoding='utf-8'))) # 类别数 self.n_vocab = 0 # 词表大小,在运行时赋值 self.epochs = 10 # epoch数 self.batch_size = 128 # mini-batch大小 self.maxlen = 32 # 每句话处理成的长度(短填长切) self.learning_rate = 1e-3 # 学习率 self.embed_size = self.embedding_pretrained.size(1) \ if self.embedding_pretrained is not None else 200 # 字向量维度 self.filter_sizes = (2, 3, 4) # 卷积核尺寸 self.num_filters = 256 # 卷积核数量(channels数) class Model(nn.Module): def __init__(self, config): super(Model, self).__init__() if config.embedding_pretrained is not None: self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False) else: vocab = pickle.load(open(config.vocab_path, 'rb')) config.n_vocab=len(vocab.dict) self.embedding = nn.Embedding(config.n_vocab, config.embed_size, padding_idx=config.n_vocab - 1) self.convs = nn.ModuleList( [nn.Conv2d(1, config.num_filters, (k, config.embed_size)) for k in config.filter_sizes]) self.dropout = nn.Dropout(config.dropout) self.fc = nn.Linear(config.num_filters * len(config.filter_sizes), config.num_classes) def conv_and_pool(self, x, conv): x = F.relu(conv(x)).squeeze(3) x = F.max_pool1d(x, x.size(2)).squeeze(2) return x def forward(self, x): out = self.embedding(x) out = out.unsqueeze(1) out = torch.cat([self.conv_and_pool(out, conv) for conv in self.convs], 1) out = self.dropout(out) out = self.fc(out) return out
posted @   启林O_o  阅读(234)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
点击右上角即可分享
微信分享提示
CONTENTS