about云开发

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 487|回复: 2

[技术应用] 注册免费送体验金平台

[复制链接]

201

主题

45

听众

1

收听

版主

Rank: 7Rank: 7Rank: 7

积分
3342

最佳新人热心会员

发表于 2018-11-6 21:47:10 | 显示全部楼层 |阅读模式
问题导读:
1、如何理解多通道卷积神经网络?
2、如何随机初始化的embedding?
3、如何实现Multi_Channel_CNN?
4、如何应用stack函数?


关注最新经典文章,欢迎关注公众号


导读

最近在梳理文本分类的各个神经网络算法,特地一个来总结下。

今天我们讲多通道卷积神经网络。

先前知识补充

先说点注册送体验金无需申请的,我们最刚开始的分类其实就是embedding层之后直接经过线性层进行降维,将其映射到分类上,图为:
2018-11-06_213522.png

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


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

有了上面的注册送体验金无需申请,我们引出multi_channel_CNN就容易多了。


multi_channel_CNN

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


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

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


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

实践

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

class Multi_Channel_CNN 初始化:
[Python] 纯文本查看 复制代码
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)
       if opts.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即可。


数据流通部分:
[Python] 纯文本查看 复制代码
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 = []
       for conv in self.convs:
           l.append(F.relu(conv(out)).squeeze(3))  # torch.Size([64, 100, 39])
       out = l
       l = []
       for i in out:
           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))
       return out

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

数据对比
2018-11-06_213836.png
可以明显看出多通道优点还是很突出的。
github地址:https://github.com/zenRRan/Senti ... ulti_channel_CNN.py


作者:zenRRan
来源:深度学习自然语言处理

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条

QQ|小黑屋|about云开发-学问论坛|社区 ( 京ICP备12023829号

GMT+8, 2018-11-15 03:21 , Processed in 0.387167 second(s), 33 queries , Gzip On.

Powered by Discuz! X3.2 Licensed

快速回复 返回顶部 返回列表