详解文本分类之多通道CNN的理论与实践

阅读大概需要4分钟

跟随小博主,每天进步一丢丢

导读

最近在梳理文本分类的各个神经网络算法,特地一个来总结下。接下来将要一个文章一个文章的讲解各个算法的理论与实践。目录暂定为:

多通道卷积神经网络(multi_channel_CNN)

深度卷积神经网络(deep_CNN)

基于字符的卷积神经网络(Char_CNN)

循环与卷积神经网络并用网络(LSTM_CNN)

树状循环神经网络(Tree-LSTM)

Transformer(目前常用于NMT)

etc..

之后的以后再补充。今天我们先讲第一个,多通道卷积神经网络。

先前知识补充

先说点基础的,我们最刚开始的分类其实就是embedding层之后直接经过线性层进行降维,将其映射到分类上,图为:

然后因为参数太多,计算太慢,所以产生了pooling池化层,取指定维度的一个参数代表整个维度,从而大大降低了计算量,而且效果还不错。图为:

之后又有人想到没有充分的利用到句子的上下词语的关系,所以就讲图像算法的CNN运用到了NLP上,这个就相当于NLP里的n-gram(unigram,bigram,trigram...)一样,寻找相邻词语组合形成的特征。图为:

有了上面的基础,我们引出multi_channel_CNN就容易多了。

multi_channel_CNN

多通道,就是CNN中的一次性卷积要处理的多少组数据。比如图像中,如果是只有灰度值的图像就只有一个通道,如果是彩色图片的话,就会RGB三个图像(也就是三个通道)。那么NLP中怎么利用这个多通道特征呢?有人就想了NLP中不就一个句子长度 * embed维度组成的一个二维输入吗?是这样的,刚开始我们用的都是单通道的。

但是有人就提出了这样的想法:

初始化两个不同的embedding,将句子用两个embedding表示出来,这样就可以有两个通道了。

时间确实是这样的,但是我们常用的是一个是随机初始化的embedding,另一个是使用预训练embedding(w2v or GloVe ...)。图为:

实践

这个其实和图像是想的差不多了。(pytorch)

class Multi_Channel_CNN 初始化:

def __init__(self, opts, vocab, label_vocab):

super(Multi_Channel_CNN,self).__init__()

random.seed(opts.seed)

torch.manual_seed(opts.seed)

torch.cuda.manual_seed(opts.seed)

self.embed_dim = opts.embed_size

self.word_num = vocab.m_size

self.pre_embed_path = opts.pre_embed_path

self.string2id = vocab.string2id

self.embed_uniform_init = opts.embed_uniform_init

self.stride = opts.stride

self.kernel_size = opts.kernel_size

self.kernel_num = opts.kernel_num

self.label_num = label_vocab.m_size

self.embed_dropout = opts.embed_dropout

self.fc_dropout = opts.fc_dropout

self.embeddings = nn.Embedding(self.word_num,self.embed_dim)

self.embeddings_static = nn.Embedding(self.word_num,self.embed_dim)

ifopts.pre_embed_path !='':

embedding = Embedding.load_predtrained_emb_zero(self.pre_embed_path,self.string2id)

self.embeddings_static.weight.data.copy_(embedding)

else:

nn.init.uniform_(self.embeddings_static.weight.data, -self.embed_uniform_init,self.embed_uniform_init)

nn.init.uniform_(self.embeddings.weight.data, -self.embed_uniform_init,self.embed_uniform_init)

# 2 convs

self.convs = nn.ModuleList(

[nn.Conv2d(2,self.embed_dim, (K,self.embed_dim), stride=self.stride, padding=(K// 2, 0)) for K in self.kernel_size])

in_fea = len(self.kernel_size)*self.kernel_num

self.linear1 = nn.Linear(in_fea, in_fea// 2)

self.linear2 = nn.Linear(in_fea// 2, self.label_num)

self.embed_dropout = nn.Dropout(self.embed_dropout)

self.fc_dropout = nn.Dropout(self.fc_dropout)

这个部分主要将输入的通道数1改为2即可。

数据流通部分:

def forward(self, input):

static_embed =self.embeddings_static(input)# torch.Size([64, 39, 100])

embed =self.embeddings(input)# torch.Size([64, 39, 100])

x = torch.stack([static_embed, embed],1)# torch.Size([64, 2, 39, 100])

out=self.embed_dropout(x)

l = []

forconvinself.convs:

l.append(F.relu(conv(out)).squeeze(3))# torch.Size([64, 100, 39])

out= l

l = []

foriinout:

l.append(F.max_pool1d(i, kernel_size=i.size(2)).squeeze(2))# torch.Size([64, 100])

out= torch.cat(l,1)# torch.Size([64, 300])

out=self.fc_dropout(out)

out=self.linear1(out)

out=self.linear2(F.relu(out))

returnout

这里主要就是一个stack函数的应用,将两个embedding放到一个新的维度里。

数据对比

可以明显看出多通道优点还是很突出的。

github地址:

https://github.com/zenRRan/Sentiment-Analysis/blob/master/models/multi_channel_CNN.py

欢迎fork,有问题大家尽管指出!

PS:上述图片均来自于导师张梅山,唐都钰的《Deep Learning in Natural Language Processing》的情感分析篇。

IELTS a bit

rivaln. 竞争对手

v. 与...相匹敌

roarn/v. 咆哮,吼叫

robustadj. 强劲的;富有活力的

slipperyadj. 滑的;光滑的

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181105G1UUCM00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券