零基础入门NLP——新闻分类
基于TextCNN的文本表示
一、TextCNN介绍
TextCNN利用CNN进行文本特征抽取,不同大小的卷积核分别抽取n-gram特征,卷积计算出的特征图经过MaxPooling保留最大的特征值,然后拼接成一个向量作为文本表示。
这里基于TextCNN原始论文的设定,分别采用100个大小为2,3,4的卷积核,最后得到的文本向量大小为100*3=300维。
TextCNN的结构如图所示
二、向量大小变换
(1)首先我们的单词经过Embedding后的维度是(batch_size,sen_len,embed_size),在图中是最左侧的矩阵,其中:
-
batch_size是批次大小,通常为了提高计算效率,将数据分成num_batch个批次,每个批次的大小是batch_size,也就是每次输入batch_size个数据
-
sen_len是句子长度(单词数量)
-
embed_size是词向量维度
(2)然后,使用不同大小的卷积核提取n-gram特征。 -
卷积操作nn.Conv2d要求输入必须对应(B,H,C,W),因此我们认为输入是(batch_size, 1, sen_len, embed_size),增加的1是输入通道数input_channel;
-
这里卷积核大小filter_sizes是[2, 3, 4],在写代码时,nn.Conv2d()的参数kernel_size指的就是卷积核大小,但是要写成(filter_size, input_size),因为我们使用的卷积核分别是[2, input_size], [3, input_size], [4, input_size],input_size与embed_size都是输入向量的维度
-
得到的特征图大小(nn.Conv2d计算后)是(batch_size, out_channel, filter_height, 1),filter_height的计算公式是sen_len - filter_size + 1,步长为1,因为卷积核和向量矩阵的宽度相等,所以卷积核是向下滑动的,得到的特征图就是一个个列向量(看图)
(3)之后,经过MaxPooling保留最大特征值。 -
池化的大小为(filter_height, 1),filter_height是我们计算出的特征图的高度,1是因为特征图的宽度是1,也就是经过池化后,每个列向量都变成一个值(看图),所以池化后的特征图大小为(batch_size,out_channel,1,1)
-
一般我们删除无用的维度,即变成(batch_size,out_channel)
(4)再拼接成一个向量作为文本的表示,也可以输入至输出层,进行分类。
向量的维度变换如图所示:
TextCNN模型的代码如下:
# TextCNN
import torch
import torch.nn as nn
import torch.nn.functional as F
class TextCNN(nn.Module):
def __init__(self, sen_len, input_size, batch_embed):
super(TextCNN, self).__init__()
# 模型搭建
self.filter_sizes = [2,3,4]
self.out_channel = 100
self.convs = nn.ModuleList([nn.Conv2d(1, self.out_channel, (filter_size, input_size), bias = True)
for filter_size in self.filter_sizes])
#前向传播
pooled_outputs = []
for i in range(len(self.filter_sizes)):
filter_height = sen_len - self.filter_sizes[i]+1
conv = self.convs[i](batch_embed)
hidden = F.relu(conv)
#batch_size * out_channel * filter_height * 1
mp = nn.MaxPool2d((filter_height, 1)) # (filter_height, filter_width)
# batch_size * out_channel * 1 * 1
pooled = mp(hidden).reshape(sen_sum, slef.out_channel)
pooled_outputs.append(pooled)
以上就是我个人对TextCNN的认识,欢迎大家交流指正。