1.caffe中通过构造两个矩阵实现:
Caffe中的卷积计算是将卷积核矩阵和输入图像矩阵变换为两个大的矩阵A与B,然后A与B进行矩阵相乘得到结果C(利用GPU进行矩阵相乘的高效性),三个矩阵的说明如下:
(1)在矩阵A中
M为卷积核个数,K=k*k,等于卷积核大小,即第一个矩阵每行为一个卷积核向量(是将二维的卷积核转化为一维),总共有M行,表示有M个卷积核。
(2)在矩阵B中
image_h:输入图像的高度
image_w:输入图像的宽度
pad_h:在输入图像的高度方向两边各增加pad_h个单位长度(因为有两边,所以乘以2)
pad_w:在输入图像的宽度方向两边各增加pad_w个单位长度(因为有两边,所以乘以2)
kernel_h:卷积核的高度
kernel_w:卷积核的宽度
stride_h:高度方向的滑动步长;
stride_w:宽度方向的滑动步长。
因此,N为输出图像大小的长宽乘积,也是卷积核在输入图像上滑动可截取的最大特征数。
K=k*k,表示利用卷积核大小的框在输入图像上滑动所截取的数据大小,与卷积核大小一样大。
(3)在矩阵C中
矩阵C为矩阵A和矩阵B相乘的结果,得到一个M*N的矩阵,其中每行表示一个输出图像即feature map,共有M个输出图像(输出图像数目等于卷积核数目)
(在Caffe中是使用src/caffe/util/im2col.cu中的im2col和col2im来完成矩阵的变形和还原操作)
2.如何构造A,B矩阵进行正向传播
下面使用一下@贾扬清大神在知乎上解释Caffe计算卷积的图来解释一下上面的操作:
这是将输入转换为feature matrix的过程(im2col),这里的feature matrix对应于上图中的矩阵B的转置,k即是卷积核的尺寸,C为输入的维度,矩阵B中的K=C x k x k,当然N就等于H' x W'了,H',W'对应于输出的高和宽,显然:
H'=(H-k+2*pad)/stride+1,W'=(W-k+2*pad)/stride+1
这组公式想必大家很熟悉了,就不加以解释了。接下来我们看看A矩阵:
A矩阵对应于filter matrix,Cout是输出的维度,亦即卷积核的个数,K= C x k x k.
所以在caffe中,先调用im2col将filters和input转换为对应filter matrix(A)和feature matrix(B'),然后再用filter matrix乘以feature matrix的转置,就得到了C矩阵,亦即输出矩阵,再将C矩阵通过col2im转换为对应的feature map,这就是caffe中完整的卷积的前向传播过程。
Caffe里用的是CHW的顺序,有些library也会用HWC的顺序(比如说CuDNN是两个都支持的),这个在数学上其实差别不是很大,还是一样的意思。
3.反向传播及转置卷积
(1)反向传播:
(2)转置卷积:
其实转置卷积相对于卷积在神经网络结构的正向和反向传播中做相反的运算。
所以所谓的转置卷积其实就是正向时左乘,而反向时左乘,即的运算。
虽然转置卷积层和卷积层一样,也是可以train参数的,但是实际实验过程中,作者发现,让转置卷积层可学习,并没有带来performance的提升,所以实验中的转置卷积层的lr全部被置零了
注意:在代码中可以看出,为了得到和原图像size一模一样的分割图,FCN中还使用了crop_layer来配合deconvolution层。
参考:
1.FCNѧϰ:Semantic Segmentation
https://zhuanlan.zhihu.com/p/22976342?utm_source=tuicool&utm_medium=referral