目录:
1、卷积是什么:在数学、实际生活、数字图像处理和机器学习中的卷积
2、卷积层是什么:从全连接层到卷积层
3、卷积层的kernal_size、padding、stride等超参数
4、卷积层的输入和输出的通道数(in_channels和out_channels)的意义
5、池化层
参考资料:
1、李沐动手学深度学习课程
2、b站up主“王木头学科学”对卷积的讲解
——————————————————————————————
1、卷积是什么?
卷积的数学公式
被积函数f、卷积核函数g
\[\int_{0}^{t}f(x)g(t-x)dx \]如何在实际意义中理解卷积?
假设\(f(x)\)为\(x\)时刻的某食物的进食量,\(g(t-x)\)为经历了\(t-x\)的时间的消化后胃里某食物的残留百分比(假设每种食物随着时间消化的残留百分比曲线都是一样的,稳定的)。假设每个\(x\)的取值对应的时刻均为进食时刻,而\(t\)时刻是当前时刻,那么\(f(x)g(t-x)\)就是在x时刻进食,然后经历了\(t-x\)的时间的消化后,当前\(t\)时刻胃里某食物的残留量。然后做积分即可得到当前\(t\)时刻,胃里各种食物的总残留量
可以看出,这是一个输入不稳定(进食\(f\)),输出稳定(消化\(g\))的系统,我们用卷积求系统的存量,卷积反映了过去对当前的影响
如果把\(f\)和\(g\)卷积的过程可视化(如下),可以看到\(f\)和\(g\)对应相乘是扭曲的,翻转\(g\)后才不扭曲。注意“翻转”这个动作,在卷积中很重要
数字图像处理中的卷积
对于数字图像来说,卷积核通常有这些类型:平滑(模糊)卷积核,锐化(增强)卷积核,边缘卷积核等。这些核与图像的卷积操作就是之前写过的卷积公式,只不过积分换成求和(离散的pixels),计算过程形象地说,就是把卷积核g先顺时针旋转180度,再去与图像f中的对应pixel的值相乘后相加,即为卷积核中心对应的pixel的新数值。我们可以理解为卷积反映了周围像素点对中心像素点影响,而卷积核g决定如何影响
*卷积核函数有时会被称为卷积算子,一些固定的算子之所以形状和数值固定,是因为是通过差分算出来的
机器学习中的卷积(实则为“交叉相关”)
机器学习中的卷积计算,实则为交叉相关计算,卷积核不会顺时针旋转180度(因为1-方便算;2-卷积核是机器自己找的,可以理解为position-wise,不管你转不转,卷积核会对应位置地去找到值,最后相乘再相加后的结果是一样的)
这时候,卷积核可以理解为特征提取器=特征过滤器(filter),去提取图像的局部特征,学到的不同的卷积核就对应地去提取不同种类的特征。而卷积这个操作,可以理解为一个主动的选择,从一个kernal_size大小pixels的信息中去选择某特征相关的信息,然后提取出来作为卷积后1个pixel的数值
———————————————————————————————
2、卷积层是什么?
从全连接层到卷积层:卷积是被限制的全连接层
限制1:局部性
why?就人的经验来看,识别一个物体并不需要看全图,看局部的特征就行
what?感受野在局部——小小的卷积核
好处?多个卷积层叠加后,感受野就大了,比 一层卷积层with一个很大的感受野(全连接层的感受野是全图) 效果好
限制2:平移不变性
why?在图像中平移物体,物体的位置改变不影响物体的识别
what?卷积核全图固定,即 全图参数共享
好处?无论输入图像的大小,参数量始终固定,不会像全连接层一样——参数量随着输入增大而变得非常大
从数学公式上看全连接层与卷积层
全连接层:\(h_{i,j} = \sum_{a,b}v_{i,j,a,b}x_{i+a,j+b}\)
卷积层:\(h_{i,j} = \sum_{a=-\Delta}^{\Delta}\sum_{b=-\Delta}^{\Delta}v_{a,b}x_{i+a,j+b}\)
局部性体现在a和b取值有限制
平移不变性体现在参数v与i,j(位置)无关
———————————————————————————————
3、卷积层的超参数:kernel_size, padding, stride
Pytorch默认值
Pytorch中padding默认值为0(不填充),stride默认值为1
如何由输入size和上述超参数计算输出size?
公式:\(out = \frac{in - \text{kernel_size} + 2*padding + stride}{stride}\)
公式里out和in可以为\(H_{out}\)和\(H_{in}\),或,\(W_{out}\)和\(W_{in}\)
我们常取2*padding = kernal_size - 1,这样的话:
1、如果stride取默认值1,则输入size = 输出size
2、如果stride取值为2,则向下取整后(floor),输出size=输入size/2
如果要让padding比较好算,最好kernal_size取奇数,而且一般比较小,如\(\text{3*3,5*5}\)。减小输出size不靠调大卷积核,一般调大stride
因此,padding可以降低输出size的减少量,而stride(在分母上)可以成倍地减少输出size
怎么调三个参数的总结
kernal_size
三者中最重要。由于多层卷积层with小核 效果不输 单层卷积核with大核,且小核算起来快(kernal_size大小与计算复杂度相关),一般取3*3,或Inception
padding
一般取2*padding = kernal_size - 1,便于算输出size(具体见上文)
stride
一般取1,这样一点点看信息看得相对完整。但是,如果我们想让输出size小于输入size,可以设置一些stride=2的卷积层,均匀地插入所有卷积层中
————————————————————————————————
4、in_channels和out_channels的意义
Pytorch中需要设置这两个参数,比如self.conv = nn.Conv2d(in_channels=3, out_channels=6, kernel_size=3, stride=1, padding=0)
in_channels
图像的输入通道,比如灰度图输入通道为1,彩色图输入通道为3(RGB)——彩色图如果转为灰度图会丢失信息
输入通道数 = 卷积核通道数,即,图像的每个通道都要和卷积核对应通道(卷积核的不同通道可能是不一样的值,看学到了什么)做运算,最后结果是所有通道结果的加和
out_channels
输出通道数 = 卷积核数 = 识别的不同pattern数
总结
可以发现,无论图像输入通道有几个,经过1个卷积核的计算,就只会得到一个输出(被加和了!),与几个卷积核做运算就会得到几个输出(即输出通道数量=卷积核数量=此层识别的pattern数),另一方面,如果你把此层的输入通道理解为上一层的输出通道,就会发现,图像的每个输入通道与卷积核对应通道的运算结果相加,其实是在识别并组合上一个卷积层输出的不同pattern
为什么要不断识别又不断组合?想象一下,上一层不同输出识别的是比如猫胡须、猫耳朵、猫脸颊的轮廓,经当前层的组合,可能其中一个输出通道变成识别一个猫头的轮廓,然后最顶层,可能就是识别出一只猫
kernel_size = 1
如果kernel_size=1,则此层不识别空间模式,只是融合通道,如下图
卷积核是几维的?
4维:\((c_{out}, c_{in}, k_{h}, k{w})\)
\(c_{out}\)决定此层输出图像的通道数
\(c_{in}\)等于此层输入图像的通道数,与输入图像的每个对应通道分别做运算的结果 加和,得到输出图像的一个通道的结果
————————————————————————————————
5、池化层
常用的有Maxpooling(返回窗口内的最大值)、Meanpooling(返回窗口内的平均值)
特点:
1、图像通道数不变:对输入图像的每个通道分别做池化后输出,不加和
2、无需要学习的参数;有kernal_size、padding、stride这些超参数
3、【优点】可能可以减小计算量,但是如果padding加多的话就未必了
4、【优点】对微小位置变化有鲁棒性,缓解卷积层对位置变化的敏感性
5、【缺点】对细节的捕捉可能有所不足:比如AlphaGo就没有池化层,因为下围棋不能随便缺行缺列
6、池化层已经用的越来越少,原因包括:
• 如果是为了减少计算量,卷积层stride也可以做这样的事情,而且目前算力增强,可能这方面需求不是很迫切
• 如果是为了对微小扰动鲁棒,现在会做很多数据增强,可以让模型多见微小扰动,从而不会过分去拟合某些微小扰动
—————————————————————————————————
相关代码见我另一博客