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与全连接层输出
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 @ 2022-04-08 10:23  启林O_o  阅读(228)  评论(0编辑  收藏  举报