项目实训(十三)--textcnn--MVP

本文介绍了TextCNN在文本分类问题上的优势,它通过一维卷积获取n-gram特征,尤其适合短文本分类。TextCNN结构包含预处理、embedding、卷积、池化和全连接层,通过不同尺寸的卷积核提取特征,再进行最大池化和softmax处理。代码实现展示了如何使用预训练词向量和TextCNN模型。经过实验,TextCNN在项目中取得了超过90%的高准确率。
摘要由CSDN通过智能技术生成

项目实训(十三)

本文记录在项目中的textcnn

引言

对于文本分类问题,常见的方法无非就是抽取文本的特征,比如使用doc2evc或者LDA模型将文本转换成一个固定维度的特征向量,然后在基于抽取的特征训练一个分类器。 然而研究证明,TextCnn在文本分类问题上有着更加卓越的表现。从直观上理解,TextCNN通过一维卷积来获取句子中n-gram的特征表示。TextCNN对文本浅层特征的抽取能力很强,在短文本领域如搜索、对话领域专注于意图分类时效果很好,应用广泛,且速度快,一般是首选;对长文本领域,TextCNN主要靠filter窗口抽取特征,在长距离建模方面能力受限,且对语序不敏感。这点可以引入注意力机制解决。

CNN可以识别出当前任务中具有预言性的n元语法(且如果使用特征哈希可以使用无约束的n元语法词汇,同时保持词嵌入矩阵的约束);CNN卷积结构还允许有相似成分的n元语法分享预测行为,即使在预测过程中遇见未登录的特定n元语法;层次化的CNN每层有效着眼于句子中更长的n元语法,使得模型还可以对非连续n元语法敏感。

结构

在这里插入图片描述

步骤

首先将输入的数据进行预处理,将句子处理为相同的长度seq_len;
将处理好的句子输入embedding层进行向量化处理。在这一层中,我们可以加载使用预训练的词向量模型,也可以进行随机初始化。在这一层,词向量的维度为embed_size;这一层的输出是每个句字序列的矩阵X;
将矩阵X输入卷积层,在卷积层设置不同的卷积核,用于提取不同维度的特征。由于句子中相邻的单词关联性总是很高的,因此可以使用一维卷积。在textcnn中,卷积层包含了不同窗口大小的卷积核,卷积核宽度一致,为embed_size;这一层可以得到多个特征图;
将特征图输入池化层进行最大池化,池化后的结果进行拼接,输入全连接层并做softmax处理,最后得到最终结果。

代码实现

    def __init__(self, dataset, embedding):
        # 各类路径
        self.model_name = 'TextCNN'
        self.train_path = dataset + '/data/t_train.txt'  # 训练集
        self.dev_path = dataset + '/data/t_test.txt'  # 验证集
        self.test_path = dataset + '/data/t_test.txt'  # 测试集
        self.class_list = [x.strip() for x in open(
            dataset + '/data/class2.txt', encoding='utf-8').readlines()]  # 分类
        self.save_path = dataset + '/saved_dict/' + self.model_name + '.ckpt'  # 模型训练结果
        self.log_path = dataset + '/log/' + self.model_name

        # textcnn使用预先训练好的词向量作embedding layer。对于数据集里的所有词,因为每个词都可以表征成一个向量,因此我们可以得到一个嵌入矩阵
        self.vocab_path = dataset + '/data/vocab.pkl'  # 词表
        self.embedding_pretrained = torch.tensor(
            np.load(dataset + '/data/' + embedding)["embeddings"].astype('float32')) \
            if embedding != 'random' else None  # 预训练词向量
        # CPU OR GPU
        self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

        # 训练预测参数
        self.dropout = 0.5  # 随机失活
        self.require_improvement = 1000  # 若超过1000batch效果还没提升,则提前结束训练
        self.num_classes = len(self.class_list)  # 类别数
        self.n_vocab = 0  # 词表大小,在运行时赋值
        self.num_epochs = 75  # epoch数
        self.batch_size = 128  # mini-batch大小
        self.pad_size = 32  # 每句话处理成的长度(短填长切)
        self.learning_rate = 1e-3  # 学习率

        # 卷积网络参数
        self.embed = self.embedding_pretrained.size(1) \
            if self.embedding_pretrained is not None else 300  # 字向量维度
        self.filter_sizes = (2, 3, 4)  # 卷积核尺寸
        self.num_filters = 256  # 卷积核数量(channels数)
 def __init__(self, config):
        super(Model, self).__init__()
        # 加载预训练词向量或者随机初始化, 词向量维度为embed_size
        # 在本模型中,使用预训练的词向量对字符进行初始化embedding
        if config.embedding_pretrained is not None:
            self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False)
        else:
            self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1)

        # 储存不同 module,并自动将每个 module 的 parameters 添加到网络之中
        # 输入一个句子,首先对这个句子进行切词,假设有s个单词。
        # 对每个词,跟句嵌入矩阵M, 可以得到词向量。
        # 假设词向量一共有d维。那么对于这个句子,便可以得到s行d列的矩阵A
        # 把矩阵A看成是一幅图像,使用卷积神经网络去提取特征。
        # 由于句子中相邻的单词关联性总是很高的,因此可以使用一维卷积。
        # 即文本卷积与图像卷积的不同之处在于只在文本序列的一个方向(垂直)做卷积
        # textcnn包含了不同窗口大小的卷积核,在这里设置的是(2,3,4),便于多特征提取
        self.convs = nn.ModuleList(
            [nn.Conv2d(1, config.num_filters, (k, config.embed)) 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)

    # 卷积池化层,对三个特征图做最大池化
    # 不同尺寸的卷积核得到的特征(feature map)大小也是不一样的,因此我们对每个特征图使用池化函数,使它们的维度相同。
    # 常用的就是1-max pooling,提取出feature map照片那个的最大值,通过选择每个feature map的最大值,可捕获其最重要的特征。
    # 这样每一个卷积核得到特征就是一个值,对所有卷积核使用1-max pooling。

    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[0])
        out = out.unsqueeze(1)

        # 将池化层输出级联起来,可以得到最终的特征向量,这个特征向量再输入全连接做分类。
        # 这个地方可以使用drop out防止过拟合。
        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

将项目的数据通过textcnn进行分类后,取得了超过90%的准确度。成为整个项目中准确率最高的模型。

参考

https://blog.csdn.net/pipisorry/article/details/85076712
https://zhuanlan.zhihu.com/p/73176084

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值