如果直接将图像根据各像素点的向量作为图片特征输入模型,例如LR、SVM、DNN等模型进行分类,理论上可行,但是面临以下问题:
卷积原理:
CNN通过卷积核对图像的各个子区域进行特征提取,而不是直接从像素上提取特征。子区域称为感受野。
卷积运算:图片感受野的像素值与卷积核的像素值进行按位相乘后求和,加上偏置之后过一个激活函数(一般是Relu)得到特征图Feature Map。
特征图:卷积结果不再是像素值,而是感受野形状和卷积核的匹配程度,称之为特征图Feature Map。卷积后都是输出特定形状的强度值,与卷积核形状差异过大的感受野输出为0(经过Relu激活),所以卷积核也叫滤波器Filter。
卷积的特点:
使用一个多通道卷积核对多通道图像卷积,结果仍是单通道图像。要想保持多通道结果,就得使用多个卷积核。同一个通道的卷积结果是一类特征(同一个卷积核计算的结果)。
卷积核的参数为待学习参数,可以通过模型训练自动得到。
图像识别中有很多复杂的识别任务,如果每个图像对应一个卷积核,那么卷积核会很大,参数过多。另外复杂图像形状各异,但是基本元素种类差不多。所以CNN使用多个不同尺寸的卷积核进行基本形状的提取
假设图像大小为 N ∗ N N*N N∗N矩阵,卷积核的尺寸为 K ∗ K K*K K∗K矩阵,图像边缘像素填充:P,卷积的步伐为S,那么经过一层这样的卷积后出来的图像为:W=(N-K+2P)/S+1。当步幅为1,padding=1时,卷积后图像尺寸不变。
池化层的作用:缩减图像尺寸;克服图像图像平移、轻微旋转的影响;间接增大后续卷积的感受野;降低运算量和参数量
池化的特点:
池化技巧:
如果有20个卷积层,max池化和ave池化混用,怎么安排?应该是前面的层用最大池化,尽可能的提取特征;后面层用ave池化,减少尺寸抗平移。
因为一开始就用平均池化,把特征平均掉了,就很难恢复了。所以是先提取特征再去噪。训练样本足够多的时候,不太容易被噪声所影响,直接用max池化。(足够的样本可以平均噪声)
而在不同场景用的池化操作也不一样:
CNN使用不同卷积核提取图像中特定的形状特征,配合池化操作进一步缩减图像尺寸,稳定特征。对低级特征进行卷积计算,得到相对高级的特征。所以多层卷积-池化,层层堆叠可以提取复杂特征。
需要注意的是:
一个常见的CNN例子如下图:
微积分中卷积的表达式为: S ( t ) = ∫ x ( t − a ) w ( a ) d a S(t) = \int x(t-a)w(a) da S(t)=∫x(t−a)w(a)da
离散形式是: s ( t ) = ∑ a x ( t − a ) w ( a ) s(t) = \sum\limits_ax(t-a)w(a) s(t)=a∑x(t−a)w(a)
这个式子如果用矩阵表示可以为: s ( t ) = ( X ∗ W ) ( t ) s(t)=(X*W)(t) s(t)=(X∗W)(t)
其中星号表示卷积。
如果是二维的卷积,则表示式为: s ( i , j ) = ( X ∗ W ) ( i , j ) = ∑ m ∑ n x ( i − m , j − n ) w ( m , n ) s(i,j)=(X*W)(i,j) = \sum\limits_m \sum\limits_n x(i-m,j-n) w(m,n) s(i,j)=(X∗W)(i,j)=m∑n∑x(i−m,j−n)w(m,n)
在CNN中,虽然我们也是说卷积,但是我们的卷积公式和严格意义数学中的定义稍有不同,比如对于二维的卷积,定义为: s ( i , j ) = ( X ∗ W ) ( i , j ) = ∑ m ∑ n x ( i + m , j + n ) w ( m , n ) s(i,j)=(X*W)(i,j) = \sum\limits_m \sum\limits_n x(i+m,j+n) w(m,n) s(i,j)=(X∗W)(i,j)=m∑n∑x(i+m,j+n)w(m,n)
这个式子虽然从数学上讲不是严格意义上的卷积,但是大牛们都这么叫了,那么我们也跟着这么叫了。后面讲的CNN的卷积都是指的上面的最后一个式子。
其中,我们叫W为我们的卷积核,而X则为我们的输入。如果X是一个二维输入的矩阵,而W也是一个二维的矩阵。但是如果X是多维张量,那么W也是一个多维的张量。
图像卷积:对输入的图像的不同局部的矩阵和卷积核矩阵各个位置的元素相乘,然后相加得到。
举个例子如下:
举例如下:
假设图像大小为 N ∗ N N*N N∗N矩阵,卷积核的尺寸为 K ∗ K K*K K∗K矩阵,图像边缘像素填充:P,卷积的步伐为S,那么经过一层这样的卷积后出来的图像为:W=(N-K+2P)/S+1
输入是多维的情况,在斯坦福大学的cs231n的课程上,有一个动态的例子
每个卷积核卷积的结果是一个3x3的矩阵,卷积的结果是一个3x3x2的张量。把上面的卷积过程用数学公式表达出来就是: s ( i , j ) = ( X ∗ W ) ( i , j ) + b = ∑ k = 1 n _ i n ( X k ∗ W k ) ( i , j ) + b s(i,j)=(X*W)(i,j) + b = \sum\limits_{k=1}^{n\_in}(X_k*W_k)(i,j) +b s(i,j)=(X∗W)(i,j)+b=k=1∑n_in(Xk∗Wk)(i,j)+b
其中, n _ i n n\_in n_in为输入矩阵的个数,或者是张量的最后一维的维数。 X k X_k Xk代表第k个输入矩阵(channel个)。 W k W_k Wk代表卷积核的第k个子卷积核矩阵。 s ( i , j ) s(i,j) s(i,j)即卷积核 W W W对应的输出矩阵的对应位置元素的值。
对图像的每个像素进行编号,用 x i , j x_{i,j} xi,j表示图像的第行第列元素;用 w m , n w_{m,n} wm,n表示卷积核filter第m行第n列权重,用 w b w_b wb表示filter的偏置项;用 a i , j a_{i,j} ai,j表示特征图Feature Map的第i行第j列元素;用 f f f表示激活函数(这个例子选择relu函数作为激活函数)。使用下列公式计算卷积:
a i , j = f ( ∑ m = 0 2 ∑ n = 0 2 w m , n x i + m , j + n + w b ) a_{i,j}=f(\sum_{m=0}^{2}\sum_{n=0}^{2}w_{m,n}x_{i+m,j+n}+w_{b}) ai,j=f(m=0∑2n=0∑2wm,nxi+m,j+n+wb)
如果卷积前的图像深度为D,那么相应的filter的深度也必须为D。我们扩展一下上式,得到了深度大于1的卷积计算公式:
a d , i , j = f ( ∑ d = 0 D − 1 ∑ m = 0 F − 1 ∑ n = 0 F − 1 w d , m , n x d , i + m , j + n + w b ) a_{d,i,j}=f(\sum_{d=0}^{D-1}\sum_{m=0}^{F-1}\sum_{n=0}^{F-1}w_{d,m,n}x_{d,i+m,j+n}+w_{b}) ad,i,j=f(d=0∑D−1m=0∑F−1n=0∑F−1wd,m,nxd,i+m,j+n+wb)
W2是卷积后Feature Map的宽度;W1是卷积前图像的宽度;F是filter的宽度;P是Zero Padding数量。D是深度(卷积核个数);F是卷积核filter的矩阵维数; w d , m , n w_{d,m,n} wd,m,n表示filter的第d层第m行第n列权重; a d , i , j a_{d,i,j} ad,i,j表示Feature Map图像的第d层第i行第j列像素。
每个卷积层可以有多个卷积核filter。每个filter和原始图像进行卷积后,都可以得到一个Feature Map。因此,卷积后Feature Map的深度(个数)和卷积层的filter个数是相同的。
2x2最大池化,步幅为2时,池化操作如下:
输入:1个图片样本,CNN模型的层数L和所有隐藏层的类型,对于卷积层,要定义卷积核的大小K,卷积核子矩阵的维度F,填充大小P,步幅S。对于池化层,要定义池化区域大小k和池化标准(MAX或Average),对于全连接层,要定义全连接层的激活函数(输出层除外)和各层的神经元个数。
输出:CNN模型的输出 a L a^L aL
1) 根据输入层的填充大小P,填充原始图片的边缘,得到输入张量 a 1 a^1 a1。
2)初始化所有隐藏层的参数 W , b W,b W,b
3)for l l l=2 to L − 1 L-1 L−1(层数 l l l):
a) 如果第 l l l层是卷积层,则输出为(*表示卷积,而不是矩阵乘法)
a l = R e L U ( z l ) = R e L U ( a l − 1 ∗ W l + b l ) a^l= ReLU(z^l) = ReLU(a^{l-1}*W^l +b^l) al=ReLU(zl)=ReLU(al−1∗Wl+bl)
(这里要定义卷积核个数,卷积核中每个子矩阵大小,填充padding(以下简称P)和填充padding(以下简称P))
b) 如果第 l l l层是池化层,则输出为: a l = p o o l ( a l − 1 ) a^l= pool(a^{l-1}) al=pool(al−1)
需要定义池化大小和池化标准,池化层没有激活函数
c) 如果第 l l l层是全连接层,则输出为: a l = σ ( z l ) = σ ( W l a l − 1 + b l ) a^l= \sigma(z^l) = \sigma(W^la^{l-1} +b^l) al=σ(zl)=σ(Wlal−1+bl)
4)对于输出层第L层: a L = s o f t m a x ( z L ) = s o f t m a x ( W L a L − 1 + b L ) a^L= softmax(z^L) = softmax(W^La^{L-1} +b^L) aL=softmax(zL)=softmax(WLaL−1+bL)
参考《卷积神经网络(CNN)》
1×1卷积作用是改变通道数,降低运算量和参数量。同时增加一次非线性变化,提升网络拟合能力。
所以可以先用1×1卷积改变通道数,再进行后续卷积操作,这个是Depth wise提出的。
卷积的尺寸决定卷积的视野,越大则提取的特征越宏观。但是大尺寸卷积,参数量和运算量都很大,而多个小尺寸卷积可以达到相同的效果,且参数量更小。还可以多次进行激活操作,提高拟合能力。例如:
一个5×5卷积参数量25,可以替换成两个3×3卷积。,参数量为18。每个3×3卷积可以替换成3×1卷积加1×3卷积,参数量为12。
实际CNN识别中,会遇到识别物体尺寸不一的情况。不同尺寸的物体需要不同尺寸的卷积核来提取特征。如果增加网络深度来处理,会造成:
为了使卷积层适应不同的物体尺寸,一般会在同一层网络中并列使用多种尺寸的卷积,以定位不同尺寸的物体。此时增加了网络宽度,而不会增加其深度。
2016年google的inception模型首先提出,结构如下:
这样会有一个问题: 网络太深造成梯度消失,前面的层基本就没有什么信息了(梯度消失学不到)。所以中间层引入两个辅助分类器,并配以辅助损失函数。防止前层网络信息丢失。具体地:
GoogleNet知识点:
GoogleNet:
可参考《CNN卷积神经网络之SENet及代码》
SENet:卷积操作中,每个通道对应一类特征。而不同特征对最终任务结果贡献是不一样的,所以考虑调整各通道的权重。
参考《CBAM重点干货和流程详解及Pytorch实现》
除了通道权重,CBAM还考虑空间权重,即:图像中心区域比周围区域更重要,由此设置不同位置的空间权重。CBAM将空间注意力和通道注意力结合起来。
Channel attention module:
此步骤与SENet不同之处是加了一个并行的最大值池化,提取到的高层特征更全面,更丰富。
Channel attention module:
将上一步得到的结果通过最大值池化和平均池化分成两个大小为H×W×1的张量,然后通过Concat操作将二者堆叠在一起(C为2),再通过卷积操作将通道变为1同时保证H和W不变,经过一个sigmoid得到spatial_out,最后spatial_out乘上一步的输入变回C×H×W,完成空间注意力操作
总结:
google对inception进行改造,出现了inception1→inception2→inception3→Xception→inception4→inception ResNetV1→inception →ResNetV2。
变种A是基础版的5×5改成两个3×3,B是3×3拆成两个,C是拆成的两个并联。
对卷积核进行了几种改造。但是设计思想都是:
1.大量应用1×1卷积核和n×1卷积核(1×3和3×1)
2.大量应用小卷积核(没有超过3乘3的)
3.并联卷积
最大贡献:标签平滑防止过拟合
inception ResNetV1&2最主要思想就是与shortcut结合。inception模块的输出和模块输入直接按位相加。即对应channel对应位置的元素相加。这样就要求输出的channel和尺寸要和输出的一致。而一般不池化尺寸可以不变,channel数通过最后一层的1×1卷积核来调整。
至于中间的细节,右侧的构造为啥是这样的,都是试验碰出来的,没必要纠结。
参考《CNN卷积神经网络之ResNeXt》
Resnet是微软何凯明搞出来的(93年的人)。主要也是借鉴shortcut思想,因为网络太深必然会碰到梯度消失的问题。然后就是一堆小卷积核,每两层抄一次近道是试验出来的效果。抄近道就必须保持前后的channel数一致。
最重要的部分就是:
然后Resnet又借鉴inception把网络都做宽了,就是Renext:
ResNeXt是ResNet和Inception的结合体,因此你会觉得与InceptionV4有些相似,但却更简洁,同时还提出了一个新的维度: cardinality (基数),在不加深或加宽网络增加参数复杂度的前提下提高准确率,还减少了超参数的数量。
进一步进行了等效转换的,采用了分组卷积的方法。