首页 > 编程知识 正文

卷积 相关,卷积层和卷积核

时间:2023-05-03 12:29:51 阅读:257534 作者:4935

本文转自http://blog.csdn.net/tangwei2014和https://blog.csdn.net/jiongnima/article/details/69487519,转载目的便于自己查看学习

第一位大神解析:

deeplab发表在ICLR 2015上。论文下载地址:Semantic Image Segmentation with Deep Convolutional Nets and Fully Connected CRFS.

deeplab方法概述
deeplab方法分为两步走,第一步仍然采用了FCN得到 coarse score map并插值到原图像大小,然后第二步借用fully connected CRF对从FCN得到的分割结果进行细节上的refine。(有关FCN的内容介绍,可以参考我的前面得一篇博客:http://blog.csdn.net/tangwei2014/article/details/46882257)
下面这张图很清楚地展示了整个结构:

然后这张图展示了CRF处理前后的效果对比,可以看出用了CRF以后,细节确实改善了很多:

deeplab对FCN更加优雅的处理方式
在第一步中,deeplab仍然采用了FCN来得到score map,并且也是在VGG网络上进行fine-tuning。但是在得到score map的处理方式上,要比原FCN处理的优雅很多。
还记得CVPR 2015的FCN中是怎么得到一个更加dense的score map的吗? 是一张500x500的输入图像,直接在第一个卷积层上conv1_1来了一个100的大padding。最终在fc7层勉强得到一个16x16的score map。虽然处理上稍显粗糙,但是毕竟人家是第一次将图像分割在CNN上搞成end-to-end,并且在当时performance是state-of-the-art,也很理解。
deeplab摒弃了这种做法,取而代之的是对VGG的网络结构上做了小改动:将VGG网络的pool4pool5层的stride由原来的2改为了1。就是这样一个改动,使得vgg网络总的stride由原来的32变成8,进而使得在输入图像为514x514,正常的padding时,fc7能得到67x67的score map, 要比FCN确实要dense很多很多。
但是这种改变网络结果的做法也带来了一个问题: stride改变以后,如果想继续利用vgg model进行fine tuning,会导致后面filter作用的区域发生改变,换句话说就是感受野发生变化。这个问题在下图(a) (b)中通过花括号体现出来了:

Hole算法
于是乎,作者想出了一招,来解决两个看似有点矛盾的问题:
既想利用已经训练好的模型进行fine-tuning,又想改变网络结构得到更加dense的score map.
这个解决办法就是采用Hole算法。如下图(a) (b)所示,在以往的卷积或者pooling中,一个filter中相邻的权重作用在feature map上的位置都是物理上连续的。如下图(c)所示,为了保证感受野不发生变化,某一层的stride由2变为1以后,后面的层需要采用hole算法,具体来讲就是将连续的连接关系是根据hole size大小变成skip连接的(图(c)为了显示方便直接画在本层上了)。不要被(c)中的padding为2吓着了,其实2个padding不会同时和一个filter相连。
pool4的stride由2变为1,则紧接着的conv5_1, conv5_2和conv5_3中hole size为2。接着pool5由2变为1, 则后面的fc6中hole size为4。

 

第二位大神解析:

原作者解析caffe的卷积层时,在conv_layer.cpp中有一个卷积核膨胀操作,在conv_layer.cpp的第17行有如下代码

 

const int kernel_extent = dilation_data[i] * (kernel_shape_data[i] - 1) + 1;


   上面的代码描述了卷积核的膨胀操作,我们不妨来做个假设,卷积核为3*3的,膨胀系数为2,那么,卷积核膨胀之后,卷积核的单边尺寸就变成了2*(3-1)+1,即卷积核的尺寸变成了5*5,笔者在最初看到这一行代码的时候相当疑惑,不太明白卷积核由3*3变成5*5是怎么操作的,这个时候,caffe.proto就起了作用,我们打开caffe.proto,找到卷积层的参数定义,在message ConvolutionParameter中,找到关于dilation的定义如下

// Factor used to dilate the kernel, (implicitly) zero-filling the resulting // holes. (Kernel dilation is sometimes referred to by its use in the // algorithme à trous from Holschneider et al. 1987.) repeated uint32 dilation = 18; // The dilation; defaults to 1


   在caffe.proto中,阐述了卷积核膨胀的使用情景,即在à trous算法中,这是一个有关小波分析的算法。卷积核膨胀是将卷积核扩张到膨胀尺度约束的尺度中,并将原卷积核没有占用的区域填充零,为了使说明更加形象,下面笔者绘制卷积核膨胀示意图为大家解析一下卷积核膨胀操作:

   在上面的示意图中,卷积核由3*3膨胀到了5*5,读者朋友们可以看到,膨胀后的卷积核中填充了一些0,读者朋友们可以试着画出其他尺寸的卷积核搭配不同膨胀系数的膨胀效果,而具体的膨胀操作是在img2col中实现的,img2col.cpp笔者将在后话解析。

   下面笔者分析一下膨胀系数与卷积核膨胀的关系,首先回到卷积核膨胀公式:

膨胀的卷积核尺寸 = 膨胀系数 * (原始卷积核尺寸 - 1) + 1

   首先由于卷积的操作特性,卷积核尺寸是奇数,则原始卷积核尺寸减一为偶数。那么,在上述公式中,膨胀系数*偶数-1为奇数,保证了膨胀的卷积核尺寸为奇数。其次,笔者认为,卷积核的膨胀系数刻画了卷积核高和宽方向的扩张倍数,可将上述公式看作:

膨胀的卷积核尺寸 - 1 = 膨胀系数 * (原始卷积核尺寸 - 1)

   到此为止,卷积核膨胀就解析完毕了,通过对卷积核膨胀的理解,笔者感受到,在阅读源码不明白时,尤其在对卷积这种抽象的操作中的细节不明白时,可以动笔画一画,将不形象转为形象,问题就迎刃而解了!

 

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。