TextCNN模型及原理实现方法

模型原理

将卷积神经网络原理应用到文本分类任务中,利用多个不同 s i z e size size k e r n e l kernel kernel来提取句子中的关键信息,(类似于多窗口大小的ngram),从而能够更好的捕捉句子的相关性。

网络结构

在这里插入图片描述

Tecnn的详细过程如下图

在这里插入图片描述

详细过程

  • Embedding: 第一层是图中最左边的 7 × 5 7 \times 5 7×5的句子矩阵,每行是词向量,维度 = 5,这可以类似与图像中的原始像素点。
  • Convolution: 然后经过 k e r n e l s i z e = 2 , 3 , 4 kernel_size = {2,3,4} kernelsize=2,3,4的一维卷积层,每个核都两个输出通道 c h a n n e l channel channel
  • MaxPolling: 第三层是一层的池化层,这样不同长度的句子经过 p o o l i n g pooling pooling层之后都能变成定长的表示。
  • FullConnection and Softmax: 最后接一层全连接的 s o f t m a x softmax softmax层,输出每个类别的概率。

通道(channels):

  • 图像可以利用 R , G , B R,G,B R,G,B作为不同的channel.
  • 文本的输入的channel通常是不同方式的embedding方式.比如word2vec或glove, 实践中也有利用静态词向量和 f i n e − t u n n i n g fine-tunning finetunning词向量作为不同的channel做法。

一维卷积:

  • 图像是二维数据。
  • 文本是一维数据,因此在TextCNN卷积用的是一维卷积,(在word_level级别上是一维卷积,虽然文本经过词向量的表达后是二维数据,但是在embedding-level上的二维卷积没有意义)一维卷积带来的问题是通过设计不同的kernel_size的filter获取不同宽度的视野

Pooling层:

利用CNN解决文本分类问题还很多,比如这篇A Convolutional Neural Network for Modelling Sentences ,最有意思的输入是在pooling 改成 (dynamic) k-max pooling,pooling阶段保留了 k k k个最大信息,保留了全局的序列信息
比如在情感分析场景中,举个例子:

“我觉得这个地方景色还不错,但是人也实在太多了”

虽然前半部分体现的情感是正向的,全局文本表达也是偏负向信息,利用 k − m a x − p o o l i n g k-max-pooling kmaxpooling能够很好的捕捉这类信息。

框架实现

这里使用 k e r a s keras keras库来实现textcnn:

import logging
from keras import Input
from keras.layers import Conv1D, MaxPool1D, Dense, Flatten, concatenate, Embedding
from keras.models import Model
from keras.utils import plot_model
def textcnn(max_sequence_length, max_token_num, embedding_dim, output_dim, model_img_path=None, embedding_matrix=None):
    """ TextCNN: 1. embedding layers, 2.convolution layer, 3.max-pooling, 4.softmax layer. """
    x_input = Input(shape=(max_sequence_length,))
    logging.info("x_input.shape: %s" % str(x_input.shape))  # (?, 60)
    if embedding_matrix is None:
        x_emb = Embedding(input_dim=max_token_num, output_dim=embedding_dim, input_length=max_sequence_length)(x_input)
    else:
        x_emb = Embedding(input_dim=max_token_num, output_dim=embedding_dim, input_length=max_sequence_length,
                          weights=[embedding_matrix], trainable=True)(x_input)
    logging.info("x_emb.shape: %s" % str(x_emb.shape))  # (?, 60, 300)
    pool_output = []
    kernel_sizes = [2, 3, 4] 
    for kernel_size in kernel_sizes:
        c = Conv1D(filters=2, kernel_size=kernel_size, strides=1)(x_emb)
        p = MaxPool1D(pool_size=int(c.shape[1]))(c)
        pool_output.append(p)
        logging.info("kernel_size: %s \t c.shape: %s \t p.shape: %s" % (kernel_size, str(c.shape), str(p.shape)))
    pool_output = concatenate([p for p in pool_output])
    logging.info("pool_output.shape: %s" % str(pool_output.shape))  # (?, 1, 6)
    x_flatten = Flatten()(pool_output)  # (?, 6)
    y = Dense(output_dim, activation='softmax')(x_flatten)  # (?, 2)
    logging.info("y.shape: %s \n" % str(y.shape))
    model = Model([x_input], outputs=[y])
    if model_img_path:
        plot_model(model, to_file=model_img_path, show_shapes=True, show_layer_names=False)
    model.summary()
    return model

特征

这里用的是词向量表示方式
数据量较大:可以直接随机初始化embeddings,然后基于语料通过训练模型网络来对embeddings进行更新和学习
数据量较小: 可以利用外部语料来预训练(pre_train)词向量,然后输入到embedding层,用预训练的词向量矩阵初始化embedding。(通过设置weights=[embedding_matrix])
静态(static)方式: 训练过程中不再更新embeddings.
实质上属于迁移学习,特别是再目标领域或数据量比较小的情况下,采用静态的词向量效果也不错,(通过设置trainable=False)
非静态(non-static)范式:在训练过程中对embeddings进行更新和微调(fine tune)能够加速收敛,通过设置trainable=True)

plot_model()画出的TextCNN模型结构图如下:
在这里插入图片描述

以下是基于PyTorch框架实现TextCNN模型代码,用于文本分类: ```python import torch import torch.nn as nn import torch.nn.functional as F class TextCNN(nn.Module): def __init__(self, vocab_size, embedding_dim, num_classes, num_filters, filter_sizes, dropout_prob): super(TextCNN, self).__init__() self.embedding = nn.Embedding(vocab_size, embedding_dim) self.convs = nn.ModuleList([ nn.Conv2d(in_channels=1, out_channels=num_filters, kernel_size=(fs, embedding_dim)) for fs in filter_sizes ]) self.dropout = nn.Dropout(dropout_prob) self.fc = nn.Linear(num_filters * len(filter_sizes), num_classes) def forward(self, x): x = self.embedding(x) # (batch_size, seq_len, embedding_dim) x = x.unsqueeze(1) # (batch_size, 1, seq_len, embedding_dim) x = [F.relu(conv(x)).squeeze(3) for conv in self.convs] # [(batch_size, num_filters, seq_len - filter_size + 1), ...] x = [F.max_pool1d(conv, conv.size(2)).squeeze(2) for conv in x] # [(batch_size, num_filters), ...] x = torch.cat(x, 1) # (batch_size, num_filters * len(filter_sizes)) x = self.dropout(x) logits = self.fc(x) return logits ``` 其中,`vocab_size`表示词汇表大小,`embedding_dim`表示词向量维度,`num_classes`表示分类数量,`num_filters`表示卷积核数量,`filter_sizes`表示卷积核尺寸列表,`dropout_prob`表示dropout概率。在`forward`函数中,先使用`embedding`层将输入的词id转换为词向量,然后进行卷积和池化操作,最后通过全连接层输出分类结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值