这两天跟Caffe的源码死磕了一阵,有点吐血的感觉,果然我和大神的思维还是有点差距的.......
这篇主要记录一下Caffe的一个重要layer——卷积层的实现,首先需要明确,在lenet的示例中,用的是conv_layer,但它并非是最基础的卷积层,它是继承了
base_conv_layer,这个才是最基础的卷积层,很多卷积函数实际上是在这里面实现的。
阅读过程中参考了多篇博文,感觉讲得比较系统的是这篇:http://www.cnblogs.com/louyihang-loves-baiyan/p/5154337.html。这里再补充一些需要注意的内容。
一、经典图片的标识错误
首先被广泛提及的是贾杨清大神自己汇出的图片,其中的两个H*W是不一样的:
二、卷积操作具体过程
由上图也可以总结一下整个卷积层操作的过程:
1、首先把原图像(图片左上)分解成可以被卷积层处理的矩阵(右上),这一步是在base_conv_layer的forward_cpu_gemm函数中完成的。conv_layer只是调用了该函数。
2、这里需要先说明一个参数group,groups是代表卷积核组的个数。引入gruop主要是为了选择性的连接卷基层的输入端和输出端的channels,避免全连接的过拟合。贾大神的原话是:when group=2, the first half of the filters are only connected to the first half of the input channels, and the second half only connected to the second half。
而根据另一作者的科普文(https://code.google.com/p/cuda-convnet/wiki/LayerParams#Local_response_normalization_layer_(across_maps)),group还可以设定为随机模式,即第一个group的输入端与第二个group的卷积核相连。
3、但根据官方的说明,建议group就保持为1,此时的卷积层与上一层就是全相连的关系。此时的运算就完全如同上图一样,具体过程可以参照作者的回答:https://www.zhihu.com/question/28385679,filter Matrix乘以Feature Matrix的转置,得到输出矩阵Cout x (H x W),即是输出的三维Blob(Cout x H x W)。