导读git
最近在梳理文本分类的各个神经网络算法,特意一个来总结下。接下来将要一个文章一个文章的讲解各个算法的理论与实践。目录暂定为:github
多通道卷积神经网络(multi_channel_CNN)算法
深度卷积神经网络(deep_CNN)网络
基于字符的卷积神经网络(Char_CNN)app
循环与卷积神经网络并用网络(LSTM_CNN)dom
树状循环神经网络(Tree-LSTM)ide
Transformer(目前经常使用于NMT)函数
etc..spa
以后的之后再补充。今天咱们先讲第一个,多通道卷积神经网络。orm
先前知识补充
先说点基础的,咱们最刚开始的分类其实就是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)
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便可。
数据流通部分:
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放到一个新的维度里。
数据对比
能够明显看出多通道优势仍是很突出的。
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
rival n. 竞争对手
v. 与...相匹敌
roar n/v. 咆哮,吼叫
robust adj. 强劲的;富有活力的
slippery adj. 滑的;光滑的