一文解决卷积池化反卷积的维度问题1. 背景其实这个之前LZ对这个关注度不是很高像tensorflow选择‘valid’和‘same’也就可以了但是对于caffe不可以。并且在海思芯片使用的caffe1.0据前端同事说很多骚操作在前端都是不支持的哭泣中即使在重训的时候可以重新写C来添加层在NNIE推断结果还是不行。。。按理说华为内部应该是有一波大神来构建对应的代码来支持比较新的网络层的这应该也算是一种技术壁垒吧纯属猜测。还有量化误差的问题这个真的也是无力吐槽据说9月份就会出tensorflow和pytorch定点化重训的包消息待确认效果呢也待确认坑还是蛮多的。回归重点本篇博客主要是参考这篇paperA guide to convolution arithmetic for deep learning篇幅不是很长30页左右而且包含很多图LZ查了很多博客都是用的这篇paper的截图读起来也很简单可以作为基础知识归纳2. 卷积、池化、反卷积转置卷积特别基础的什么是卷积LZ就不再赘述了主要关注卷积和转置卷积的维度关系1. 卷积对于任意的输入whi, padding: p, 核的大小k步长stride s我们可以得到输出的尺寸为⌊ . ⌋ \lfloor . \rfloor⌊.⌋是向下取整看到有博客向上和向下取整还是反的2. 池化池化层不太涉及到padding部分如果要保证对应的输入输出大小同样进行padding就可以了假设我们不考虑padding那么对于任意的ik和s输出的维度为3. 反卷积转置卷积a. 为什么叫反卷积或者转置卷积主要参考的https://www.zhihu.com/question/43609045总结说来就是正常情况下网络做关于卷积的运算有两个一个是进行前向推断的时候做的卷积操作另一个是在反向传播的时候需要计算对应的导数这是两个相反的过程.假设现在有一个4x4的输入假设我们核的大小为3x3stride1pad0如下图输入矩阵可展开为16维向量记作x xx输出矩阵可展开为4维向量记作y yy卷积运算可表示为y C x yCxyCx上面是网络卷积正向传播的过程那么反向传播呢直接截图了来自参考文献2所以反卷积其实就是正向传播时左乘C T C^TCT,而反向时左乘( C T ) T C (C^T)^TC(CT)TC所以反卷积逆卷积是针对网络做卷积这个过程来取名的而转置卷积即使是从数学推导上来取名的这个感觉都可以理解是啥就行了b. 维度问题看图来理解一下什么是转置卷积上述图是stirde不为1的情况通常使用转置卷积是为了扩大维度这样stride一般是大于1的那么在卷积过程中我们可以看到如果输入是2x2,为了扩充维度会进行补零的一个操作。在看一个例子通过a中的解释其实可以知道卷积和转置卷积是两个相反的过程那么换句话说原来卷积的输入变成了反卷积的输出维度也是这样但是在正向计算中我们是有向下取整操作的所以还要分情况考虑情况一情况二好啦维度问题记不住下次查下公式也就可以啦3. 工程上的一些思考其实涉及到tensorflow一个resize操作代替因为caffe里面没有resize层所以上采样的时候也就考虑到了转置卷积其中有两种方式第一种直接把转置卷积中的权重和偏置学出来当正常卷积的方式第二中其实就是当成一个双线性插值的操作1. 在caffe源码 include/caffe/filler.hpp有一段 brief Fills a Blob with coefficients for bilinear interpolation. A common use case is with the DeconvolutionLayer acting as upsampling. You can upsample a feature map with shape of (B, C, H, W) by any integer factor using the following proto. \code layer { name: upsample, type: Deconvolution bottom: {{bottom_name}} top: {{top_name}} convolution_param { kernel_size: {{2 * factor - factor % 2}} stride: {{factor}} num_output: {{C}} group: {{C}} pad: {{ceil((factor - 1) / 2.)}} weight_filler: { type: bilinear } bias_term: false } param { lr_mult: 0 decay_mult: 0 } } \endcode Please use this by replacing {{}} with your values. By specifying num_output: {{C}} group: {{C}}, it behaves as channel-wise convolution. The filter shape of this deconvolution layer will be (C, 1, K, K) where K is kernel_size, and this filler will set a (K, K) interpolation kernel for every channel of the filter identically. The resulting shape of the top feature map will be (B, C, factor * H, factor * W). Note that the learning rate and the weight decay are set to 0 in order to keep coefficient values of bilinear interpolation unchanged during training. If you apply this to an image, this operation is equivalent to the following call in Python with Scikit.Image. \code{.py} out skimage.transform.rescale(img, factor, modeconstant, cval0) \endcode */2. 怎么书写对应的pycaffe呢conv_param{kernel_size:3,stride:2,num_output:3,pad:1,weight_filler:dict(typebilinear),bias_term:False}coarse_resizecaffe.layers.Deconvolution(coarse_out,convolution_paramconv_param,param[dict(lr_mult0)])以为这样就大功告成了吗3. 棋盘格效应当factor比较小确实可以利用反卷积进行插值操作但是当factor比较大的时候就会出现比较明显的棋盘格效应。。。比较好的代替方式是采用上采样卷积但是这就违背了LZ一开始使用反卷积的意愿所以恩生活总是给你希望然后告诉你不行然后再给你希望周末愉快4. 参考文献A guide to convolution arithmetic for deep learning转置卷积理解https://www.zhihu.com/question/43609045caffe 转置卷积源码https://github.com/BVLC/caffe/commit/41df4cdce942c22f0d89ad8b0990d3ee7bd9cf31