点击上方,选择星标或置顶,每天给你送干货
!
阅读大概需要25分钟
跟随小博主,每天进步一丢丢
作者:小占同学
学校:中国科学技术大学
方向:自然语言处理
本文是本人所写的NLP基础任务——文本分类的【深入TextCNN】系列文章之一。【深入TextCNN】系列文章是结合PyTorch对TextCNN从理论到实战的详细教程。
本文适合阅读的对象:
本文的重点部分是:
文章很长,读者若耐心读完,必将对TextCNN的理解提升一个层次。建议按计划分几次读完。本文并不适合毫无基础的新手。另外,本文列出了非常详尽的参考文档/参考论文,是每位对相关知识点感兴趣的读者的绝佳知识拓展,可以好好利用一下。
本人才疏学浅,有不足之处请各位不吝赐教,共同探讨!本文会不定期更新,不断修正里面的疏漏内容,增加新理解和新体会。
在传统神经网络中,网络层之间输入与输出的连接关系可以由一个权值参数矩阵来表示。对于全连接网络,任意一对输入与输出神经元之间都产生交互,形成稠密的连接结构。这里面的交互是指每个单独的参数值,该参数值表示了前后层某两个神经元节点之间的交互。
在卷积神经网络中,卷积核尺度远小于输入的维度,这样每个输出神经元仅与前一层特定局部区域内的神经元存在连接权重(即产生交互),我们称这种特性为稀疏交互。
稀疏交互的物理意义:通常图像、文本、语音等现实世界中的数据都具有局部的特征结构, 我们可以先学习局部的特征, 再将局部的特征组合起来形成更复杂和抽象的特征。
参数共享是指在同一个模型的不同模块中使用相同的参数。卷积运算中的参数共享让网络只需要学一个参数集合,而不是对于每一位置都需要学习一个单独的参数集合。
参数共享的物理意义:使得卷积层具有平移等变性。在第三个特点中会谈到。
显然,我们可以看到,卷积神经网络在存储大小和统计效率方面极大地优于传统的使用矩阵乘法的神经网络。
假如图像中有一只猫,那么无论它出现在图像中的任何位置,我们都应该将它识别为猫,也就是说神经网络的输出对于平移变换来说应当是等变的。特别地,当函数f(x)与g(x)满足f(g(x))=g(f(x))时,我们称f(x)关于变换g具有等变性。在猫的图片上先进行卷积,再向右平移l像素的输出,与先将图片向右平移l像素再进行卷积操作的输出结果是相等的。
卷积运算实际是分析数学中的一种运算方式,在卷积神经网络中通常是仅涉及离散卷积的情形。因卷积运算的作用就类似于滤波,因此也称卷积核为filter即滤波器的意思。滤波器可以从原始的像素特征中抽取某些特征,如:边缘、角度、形状等。而在实际上,在卷积神经网络中我们并不会手工设计卷积核中的每个卷积核点值,而是通过学习算法自动学得卷积核中每个位置的值。
单个卷积核只能提取一种类型的特征,那么我们若想使卷积层能够提取多个特征,则可以并行使用多个卷积核,其中每个卷积核提取一种特征。feature map 特征图是卷积层的输出的别名。
另外,必须要说明一下,现在大部分的深度学习教程中都把卷积定义为图像矩阵和卷积核的按位点乘。实际上,这种操作应该是互相关(cross-correlation),而卷积需要把卷积核顺时针旋转180度(即翻转)然后再做点乘。互相关是一个衡量两个序列相关性的函数,通常是用滑动窗口的点积计算来实现。互相关和卷积的区别仅仅在于卷积核是否进行翻转,因此互相关也可以称为不翻转卷积。
必须要注意的是,卷积神经网络使用的数据可以是一维、二维和三维的,对于这三种数据,每种都可以是单通道或者是多通道的(可以参见《深度学习》花书p219页表9.1)。下面我们介绍不同维数据的情况下通道数不同的卷积操作。
CLASS torch.nn.Conv1d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros')
在由多个输入平面组成的输入信号上应用1D卷积。
例子:
m = nn.Conv1d(16, 33, 3, stride=2)
input = torch.randn(20, 16, 50)
output = m(input)
output.shape
#torch.Size([20, 33, 24])
1.若channel数等于1,filter个数等于1时。
首先给出公式,在一维卷积中,我们有公式:
上图中的输入的数据维度为1,长度为8,channel数为1,过滤器filter的维度、个数均为1,长度为5。公式(1)中,
和
分别为输入序列长度和输出序列长度,其它的均为卷积网络中的常见参数。假定这里的padding为0,dilation为1和stride为1,根据给定条件,
等于8,kernel_size等于5,那么就有一维卷积后输出序列
等于8−5+1=4。
2.若channel数不等于1,filter个数等于1时。
channel不影响输出序列的维度。假设输入数据的channel数量变为6,即输入数据shape为8×6(另,这里channel的概念相当于自然语言处理中的embedding,而该输入数据代表8个单词,其中每个单词的词向量长度为6)。由于卷积操作中过滤器的channel数量必须与输入数据的channel数量相同,于是过滤器的shape由5变为5×6。在卷积的过程中,输入数据与过滤器在每个channel上分别卷积,之后将卷积后的每个channel上的对应数值相加,即执行4×4次6个数值相加的操作,最终输出的数据序列长度和channel等于1时一样仍为4,维度为1维。
3.不管channel数是多少,若过滤器filter数量为n,那么输出数据的shape就变为4×n。原因就是卷积后,在channel方向会进行对应数值相加,而增加滤器不会进行这种操作。
4.dilation参数。空洞卷积。dilation参数的作用,它控制卷积核点之间的间距大小。如下图所示:
5.一维卷积常用于序列模型,NLP领域,但往往很多时候二维卷积我们也用在NLP领域之中。
CLASS torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros')
在由多个输入平面组成的输入信号上应用2D卷积。
例子:
# With square kernels and equal stride
m = nn.Conv2d(16, 33, 3, stride=2)
# non-square kernels and unequal stride and with padding
m = nn.Conv2d(16, 33, (3, 5), stride=(2, 1), padding=(4, 2))
# non-square kernels and unequal stride and with padding and dilation
m = nn.Conv2d(16, 33, (3, 5), stride=(2, 1), padding=(4, 2), dilation=(3, 1))
input = torch.randn(20, 16, 50, 100)
output = m(input)
print(output.shape)
#torch.Size([20, 33, 26, 100])
1.若channel数等于1,filter个数等于1时。
首先给出公式,在二维卷积中,我们有公式
图中的输入数据shape为14×14,channel数为1,过滤器大小为5×5,过滤器个数为1,二者做卷积,输出的数据维度为10×10(14−5+1=10)。
2.若channel数不等于1,filter个数等于1时。
channel不影响输出数据的维度。假设输入数据的channel数为3,即输入的数据shape变为14×14×3,由前述可知,过滤器大小也变为5×5×3。在卷积的过程中,过滤器与数据在每个channel方向分别卷积,之后将卷积后得到对应数值相加,即执行10×10次3个数值相加的操作,最终输出的数据shape为10×10。
3.不管channel数是多少,若过滤器filter数量为n,那么输出数据的shape就变为10×10×n。
假设channel数为3,过滤器数量为16,那么我们就有16个大小为5×5×3的过滤器,最终输出的数据维度就变为10×10×16。可以理解为分别执行每个过滤器的卷积操作,最后将每个卷积的输出在第三个维度(channel 维度)上进行拼接。当filter个数为多个时情况如下图所示:
4.可视化理解二维卷积:
下图已经进行了操作padding,卷积核大小为3×3,步长stride等于1:
下图则说明了上图工作的详细内部情况(只是说明计算过程,输入大小和卷积核并不一样):
5.二维卷积常用于计算机视觉、图像处理领域。
CLASS torch.nn.Conv3d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros')
在由多个输入平面组成的输入信号上应用3D卷积。
例子:
#With square kernels and equal stride
m = nn.Conv3d(16, 33, 3, stride=2)
# non-square kernels and unequal stride and with padding
m = nn.Conv3d(16, 33, (3, 5, 2), stride=(2, 1, 1), padding=(4, 2, 0))
input = torch.randn(20, 16, 10, 50, 100)
output = m(input)
print(output.shape)
#torch.Size([20, 33, 8, 50, 99])
1.三维卷积主要思想和一维二维的相似,主要区别就是输入数据本身是几维的,那么就用几维卷积。对于三维卷积的输出深度
、高度
和宽度
的计算公式分别如下,具体参数不再详细介绍,都是按标准的方式来写的。
这里介绍一种最通用的形式:
假设输入数据的shape为
,channel数为
,过滤器每个维度的长度为
,即过滤器shape为
,channel数为
,过滤器数量为n。padding等于[0, 0, 0],dilation等于[1, 1, 1]。那么三维卷积的输出为
。
2.三维卷积常用于医学领域(CT音像),视频处理领域(检测动作及人物行为)。
池化也叫做亚采样、下采样(downsampling)或子采样(subsampling),主要针对非重叠区域,包括均值池化(mean pooling)、最大池化(max pooling)。池化操作的本质是降采样。例如,我们可以利用最大池化将4×4的矩阵降采样为2×2的矩阵。
均值池化通过对邻域内特征数值求平均来实现,能够抑制由于邻域大小受限造成估计值方差增大的现象,特点是对背景的保留效果更好。均值池化是求窗口中元素的均值。
最大池化则通过取邻域内特征的最大值来实现,能够抑制网络参数误差造成估计均值偏移的现象,特点是更好地提取纹理信息。最大池化是求窗口中元素的最大值。
特殊的池化方式还包括相邻重叠区域的池化以及空间金字塔池化。池化操作除了能显著降低参数量外,还能够保持对平移、伸缩、旋转操作的不变性。这里就不展开细讲了。
添加池化层的作用:
因为TextCNN中用的是最大池化(1-Max pooling),那我们这里就只详细介绍下PyTorch中的MaxPool类。和PyTorch的卷积类类似,池化类也分为一、二和三维的。那我这里就讲一下一维的情况,二维和三维的类似,只是输入数据的维度不同。
CLASS torch.nn.MaxPool1d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False)
例子:
m = nn.MaxPool1d(3, stride=2)
input = torch.randn(20, 16, 50)
output = m(input)
output.shape
#torch.Size([20, 16, 24])
卷积神经网络的核心思想是捕捉局部特征,对于文本来说,局部特征就是由若干单词组成的滑动窗口,类似于N-gram。卷积神经网络的优势在于能够自动地对N-gram特征进行组合和筛选,获得不同抽象层次的语义信息。
图1是论文[1]中用于文本分类的卷积神经网络模型架构。
图1 双通道的TextCNN结构
图2 用于文本分类任务的TextCNN结构描述 这里详细解释TextCNN架构及词向量矩阵是如何做卷积的。
第(2)部分是重点,理解好卷积过程是关键。
(1)第一层为输入层。输入层是一个
的矩阵,其中
为一个句子中的单词数,
是每个词对应的词向量的维度。也就是说,输入层的每一行就是一个单词所对应的
维的词向量。另外,这里为了使向量长度一致对原句子进行了padding操作。我们这里使用
表示句子中第
个单词的
维词嵌入。
每个词向量可以是预先在其他语料库中训练好的,也可以作为未知的参数由网络训练得到。这两种方法各有优势,预先训练的词嵌入可以利用其他语料库得到更多的先验知识,而由当前网络训练的词向量能够更好地抓住与当前任务相关联的特征。因此,图中的输入层实际采用了双通道的形式,即有两个
的输入矩阵,其中一个用预训练好的词嵌入表达,并且在训练过程中不再发生变化;另外一个也由同样的方式初始化,但是会作为参数,随着网络的训练过程发生改变。
(2)第二层为卷积层,第三层为池化层。
首先,我们要注意到卷积操作在计算机视觉(CV)和NLP中的不同之处。在CV中,卷积核往往都是正方形的,比如
的卷积核,然后卷积核在整张image上沿高和宽按步长移动进行卷积操作。与CV中不同的是,在NLP中输入层的"image"是一个由词向量拼成的词矩阵,且卷积核的宽和该词矩阵的宽相同,该宽度即为词向量大小,且卷积核只会在高度方向移动。因此,每次卷积核滑动过的位置都是完整的单词,不会将几个单词的一部分"vector"进行卷积,词矩阵的行表示离散的符号(也就是单词)[2],这就保证了word作为语言中最小粒度的合理性(当然,如果研究的粒度是character-level而不是word-level,需要另外的方式处理)。
然后,我们详述这个卷积、池化过程。由于卷积核和word embedding的宽度一致,一个卷积核对于一个sentence,卷积后得到的结果是一个vector,其shape=(sentence_len - filter_window_size + 1, 1),那么,在经过max-pooling操作后得到的就是一个Scalar。我们会使用多个filter_window_size(原因是,这样不同的kernel可以获取不同范围内词的关系,获得的是纵向的差异信息,即类似于n-gram,也就是在一个句子中不同范围的词出现会带来什么信息。比如可以使用3,4,5个词数分别作为卷积核的大小),每个filter_window_size又有num_filters个卷积核(原因是卷积神经网络学习的是卷积核中的参数,每个filter都有自己的关注点,这样多个卷积核就能学习到多个不同的信息。[2]中也提到使用多个相同size的filter是为了从同一个窗口学习相互之间互补的特征。比如可以设置size为3的filter有64个卷积核)。一个卷积核经过卷积操作只能得到一个scalar,将相同filter_window_size卷积出来的num_filter个scalar组合在一起,组成这个filter_window_size下的feature_vector。最后再将所有filter_window_size下的feature_vector也组合成一个single vector,作为最后一层softmax的输入。对这个过程若有不清楚的地方,可以对照着图2(该图来自论文[2])来看,图2非常完美地诠释了这个过程。
形式化的说明如下:在输入为
的矩阵上,使用一个kernel
与一个窗口(window)
进行卷积操作,产生一个特征
,即:
其中
代表由输入矩阵的第
行到第
行所组成的一个大小为
的窗口,由
拼接而成。
表示窗口中的单词数,
为
维的权重矩阵(因此一个filter需要学习的参数个数是
个),
为偏置参数,
为非线性函数。
和
进行点积运算(dot product,逐元素相乘得到的结果再求和)。过滤器应用到一个句子上,从上往下一次移动一步(
),如在
上经卷积操作得到
,在
上经卷积操作得到
...,然后将它们拼接起来得到的
就是我们的feature map。每一次卷积操作相当于一次特征向量的提取,通过定义不同的窗口,就可以提取出不同的特征向量,构成卷积层的输出。
最后是池化层。如图中所示的网络采用了1-Max池化,即为从每个滑动窗口产生的特征向量中筛选出一个最大的特征,然后将这些特征拼接起来构成向量表示。也可以选用K-Max池化(选出每个特征向量中最大的K个特征),或者平均池化(将特征向量中的每一维取平均)等,达到的效果都是将不同长度的句子通过池化得到一个定长的向量表示。
在整个过程中,通过训练得到的参数包括:filter们的权值矩阵
们,激活函数中的偏置项
,softmax函数中的权重矩阵,若词向量也加入训练进来的话,则包括该word embeddings。
(3)得到文本句子的向量表示之后,后面的网络结构就和具体的任务相关了。本例中展示的是一个文本分类的场景,因此最后接入了一个全连接层,并使用Softmax激活函数输出每个类别的概率。
首先,我们默认的TextCNN模型超参数一般都是这种配置。如下表:
这里将一下调参的问题,主要方法来自论文[2]。在最简单的仅一层卷积的TextCNN结构中,下面的超参数都对模型表现有影响:
在这里提出TextCNN基础参数配置和调参方法,我们在【深入TextCNN】的实战篇马上就会用到。后面我也会总结各个模型的调参方法的。
本文主要讲清楚了一维、二维和三维卷积,和文本分类中卷积操作的具体过程。不同维的卷积使用是根据卷积输入的数据来定,另外,当数据有多个channel时,也要进行相应处理。在文本分类中,主要是要注意一下和CV场景中不同的情况,卷积核不是一个正方形,是一个宽和word embedding相同、长表示n-gram的窗口。一个卷积层会使用多个不同大小的卷积核,往往是(3, 4, 5)这种类型。每一种大小的卷积核也会使用很多个。
[1] Convolutional Neural Networks for Sentence Classification
https://arxiv.org/abs/1408.5882
[2] A Sensitivity Analysis of (and Practitioners' Guide to) Convolutional Neural Networks for Sentence Classification
https://arxiv.org/abs/1510.03820
知乎地址(点击阅读原文):
https://zhuanlan.zhihu.com/p/77634533
方便交流学习,备注:昵称-学校(公司)-方向,进入DL&NLP交流群。
方向有很多:机器学习、深度学习,python,情感分析、意见挖掘、句法分析、机器翻译、人机对话、知识图谱、语音识别等。
记得备注呦
推荐阅读:
【ACL 2019】腾讯AI Lab解读三大前沿方向及20篇入选论文
【一分钟论文】IJCAI2019 | Self-attentive Biaffine Dependency Parsing
【一分钟论文】 NAACL2019-使用感知句法词表示的句法增强神经机器翻译
【一分钟论文】Semi-supervised Sequence Learning半监督序列学习
【一分钟论文】Deep Biaffine Attention for Neural Dependency Parsing