im2col()
矩阵卷积
卷积就是卷积核跟图像矩阵的运算。卷积核是一个小窗口,记录的是权重。卷积核在输入图像上按步长滑动,每次操作卷积核对应区域的输入图像,将卷积核中的权值和对应的输入图像的值相乘再相加,赋给卷积核中心所对应的输出特征图的一个值,如下图所示(这里卷积核要旋转180 °):
如果还不懂的话,可以类比均值滤波,用一个矩阵算子对于图像上一块图像,对于像素点相乘,再相加,这就是卷积。(再理解简单点,就是两个矩阵的乘法,但是此时乘法的规则是对应点相乘,最后再相加,得到一个结果。)
那么im2col()有什么用呢?
im2col的作用就是优化卷积运算,如何优化呢?
我们先学习一下这个函数的原理。
我们假设卷积核的尺寸为2×2,输入图像尺寸为3×3.im2col做的事情就是对于卷积核每一次要处理的小窗,将其展开到新矩阵的一行(列),新矩阵的列(行)数,就是对于一副输入图像,卷积运算的次数(卷积核滑动的次数),如下图所示:
以最右侧一列为例,卷积核为2*2,所以新矩阵的列数就为4;步长为一,卷积核共滑动4次,行数就为4.再放一张图应该看得更清楚。
输入为4×4,卷积核为3×3,则新矩阵为9×4 。看到这里我就产生了一个疑问:我们把一个卷积核对应的值展开,到底应该展开为行还是列呢?卷积核的滑动先行后列还是相反?区别在哪?
这其实主要取决于我们使用的框架访存的方式。计算机一次性读取相近的内存是最快的,尤其是当需要把数据送到GPU去计算的时候,这样可以节省访存的时间,以达到加速的目的。不同框架的访存机制不一样,所以会有行列相反这样的区别。
在caffe框架下,im2col是将一个小窗的值展开为一行,而在matlab中则展开为列。所以说,行列的问题没有本质区别,目的都是为了在计算时读取连续的内存。
这也解释了我们为什么要通过这个变化来优化卷积。如果按照数学上的步骤做卷积读取内存是不连续的,这样就会增加时间成本。同时我们注意到做卷积对应元素相乘再相加的做法跟向量内积很相似,所以通过im2col将矩阵卷积转化为矩阵乘法来实现。
im2col()用法说明
B = im2col(A,[m n],block_type)
block_type取值: distinct 和sliding。distinct:图像块不重叠(也就是滑过去在没有的地方补0), sliding:图像块滑动,可以重叠。默认的是sliding
MATLAB举例说明
a=[1,2,3;
4,5,6;
7,8,9;]
im2col(a,[2,2],'distinct')
im2col(a,[2,2],'sliding')
结果
a =
1 2 3
4 5 6
7 8 9
%block_type为:distinct
ans =
1 7 3 9
4 0 6 0
2 8 0 0
5 0 0 0
%block_type为:sliding
ans =
1 4 2 5
4 7 5 8
2 5 3 6
5 8 6 9
对结果进行解释
当block_type为distinct时,在MATLAB中,是列优先,[2,2]我们可以想象为一个2×2的矩形框,开始是框住1 2 4 5 之后,矩形框向下移动(列优先嘛,所以都是先列后行,结果是1 2 4 5),由于distinct是不重叠,所以矩形框下一框的是 7 8 0 0(没有用0填充),依次类推
block_type为sliding时,区别就是可以重叠,第一个矩形框住的是 1 2 4 5 ,那个第二个框住的就是 4 5 7 8,依次类推
注意
im2col()是将矩阵变成列向量,而col2im()则是把列向量变成矩阵,二者作用相反。