作為cnn中最重要的卷積,最簡(jiǎn)單的理解就為:

其中,卷積主要的參數(shù)有:
stride 步長(zhǎng) ? ? ? ? ? ? ?stride_w,stride_h
kernel_size ? ? ? ? ? ? kernel_w,kernel_w
dilation ? ? ? ? ? ? ? ? ? ?膨脹系數(shù)
padding? ? ? ? ? ? ? ? ? pad_w,pad_h
卷積層:conv_layer.cpp
里面主要有
compute_output_shape() ? ?計(jì)算輸出blob的大小
Forward_cpu
Backward_cpu
其中Forword_cpu主要用到了forward_cpu_gemm,這個(gè)位于base_conv_layer,
forward_cpu_gemm里面使用到了conv_im2col_cpu,caffe_cpu_gemm。
conv_im2col_cpu ? 是把輸入圖像變?yōu)橐粋€(gè)矩陣,這樣子做能直接和卷積核組成的矩陣做點(diǎn)乘,得到的矩陣就為 卷積后每一個(gè)特征圖就為為這矩陣中一個(gè)行向量。
查看cov_im2col_cpu;

我們先以im2col_cpu為入手:
主要參數(shù)為:
1.data ?
?2.conv_channels 卷積的通道數(shù)
3.conv_input_shape.cpu_data()[1] ? ? ? ? 即image_h 輸入圖像的height,主要下標(biāo)
4conv_input_shape.cpu_data()[1] ? ? ? ? ?image_w
5.padding_h,padding_w
6.stride_h,stride_w
7.dilation ? ?膨脹系數(shù)

推導(dǎo)過程太復(fù)雜了,這里有一個(gè)單通道的完整的推導(dǎo)過程:lib.csdn.net/article/aiframework/62849
總之,im2col,就是把一個(gè)圖片上的對(duì)應(yīng)每一個(gè)卷積核大小的窗函數(shù)里面的元素,變?yōu)榱邢蛄?,隨著步長(zhǎng)的移動(dòng),得到不同的列向量,合并起來得到一個(gè)矩陣,也就是col_buff
那caffe中是怎么樣計(jì)算卷積的:
我們先從單通道入手,用一個(gè)單通道卷積核去卷積一個(gè)單通道圖像:

在不考慮膨脹系數(shù)的情況下,N=((image_h+2*pad_h-kenrel_h)/stride_h+1)*((image_w+2*pad_w-kenrel_w)/stride_w+1),其實(shí)就是計(jì)算經(jīng)卷積后輸出的圖像的長(zhǎng)與寬,再相乘,得到feature map的大小。
那當(dāng)是多通道圖片(比如說最開始的三通道,以及經(jīng)過一層卷積后的擁有很多通道的特征圖)的情況是什么樣的?

下面以一個(gè)實(shí)際的例子:

這就是caffe卷積的原理。
caffe_gpu_gemm(CblasNoTrans,CblasTrans,M,N,K(Dtype)1,top_diff,bottom_data,(Dtype)1,weights_diff)
voidcaffe_gpu_gemm(constCBLAS_TRANSPOSETransA,constCBLAS_TRANSPOSETransB,const intM,const intN,const intK,constDtypealpha,constDtype* A,constDtype*B,constDtypebeta,
Dtype* C);
caffe_gpu_gemm(CblasTrans,CblasNoTrans,kernel_dim_,
conv_out_spatial_dim_,conv_out_channels_/group_,
(Dtype)1.,weights +weight_offset_* g,output +output_offset_* g,
(Dtype)0.,col_buff +col_offset_* g);