最近,在看caffe源码时,偶然在网上看到一个问题?觉得挺有意思,于是,仔细的查了相关资料,并将总结写在这里,供大家迷惑时,起到一点启示作用吧。

问题的题目是CNN中的一个卷积层输入64个通道的特征子图,输出256个通道的特征子图,那么,该层一共包含多少个卷积核?

对于上面这个问题,目前有两种答案,每一种答案的区别是所基于的卷积核的维度不同而导致的。下面是两种答案的解析过程:

第一种答案:卷积核是二维的(caffe源码中以卷积核二维转化成相应矩阵),那么就需要64*256个卷积核来对输入特征子图进行卷积,其中,输入的每个通道对应64种不同的卷积核进行卷积,再将64种卷积核得到的卷积结果合并成一张输出特征子图;这样,就会得到256个通道的特征子图。

第二种答案:卷积核是三维的(caffe大神贾杨清老师的回答中就是这么认为的),那么一个卷积核的表示为C*H*W(C:通道数,H:卷积核的高,W:卷积核宽)。那么对于输入的特征子图,就需要一个大小为64*h*w的卷积核进行卷积,得到一张特征子图。这样,就需要256个不同卷积核,每个卷积核的通道数为64,从而得到256个通道的特征子图。

  显然,这两种答案都有一定的依据,不管如何认为,其最终的目的都是要将卷积层复杂的卷积问题转化为矩阵的相乘问题,从而大大的提高计算速度。

  那么,肯定有很多朋友,尤其是像我这种深度学习的菜鸟,一开始还是比较迷糊的,对于上面的解释还是不知所云。那么,下面,我就来对这两种观点进行具体分析,不足之处,希望大家能指出来,共同学习。

一,卷积核是二维的

  我们知道,在caffe中卷积层的运算是首先通过img2col()将各个卷积核和输入特征子图转化为向量,然后多个卷积核或输入特征子图的向量组合成为矩阵;接下来,通过矩阵相乘运算得到卷积的结果,再通过col2img()将向量转化为特征子图。M个卷积核卷积一张输入图像的矩阵计算如下图所示:

图来自http://www.cnblogs.com/laiqun/p/6055498.html

其中,M表示二维卷积核的个数,K=k*k表示二维卷积核的大小;这样,每个k*k大小的二维卷积核转化为一个行向量,M个二维卷积核对应M个行向量就得到了M*K的卷积矩阵A。

再说矩阵B:假设输入的每张特征子图大小为r*r,二维卷积核的大小为k*k,扩展大小pad,步长为stride,那么对于每张特征子图,按卷积核每次卷积图像的大小k*k,将该块卷积的图像转化为行向量,长度也为k*k=K,这样,依据卷积核与输入图像卷积的过程,将每一次卷积核卷积的区域转化为一个行向量,各个行向量按照卷积先后顺序以列进行排列,从而得到了矩阵B。此外,对于卷积后得到的二维特征子图的大小,在caffe中的计算公式如下(这里假设,输入图像和卷积和大小都是q*q的,即长与宽相等):

  输出特征子图大小:n*n=[(r+2*pad-k)/strde+1]*[(r+2*pad-k)/strde+1]

如果我们令pad=0,stride=1,那么就会变成我们熟悉的形式,即n*n=[(r-k)+1]*[(r-k)/+1]。比如,输入特征图大小为32*32,卷积核大小为3*3,那么输出的特征子图大小为(32-3+1)*(32-3+1)=28*28。

  好了,现在我们知道了矩阵B的列N=n*n,然后通过矩阵相乘运行,即A*BT=(M*K)*(N*K)T=(M*K)*(K*N)=(M*N)=C,即得到了最终的矩阵C。当然,在caffe中可能会存在偏置项,那么这个矩阵C还要加上偏置矩阵P,然后得到最终的输出矩阵D,再通过col2img()将D中的每一行转化为一张特征图,就得到了输出的各个特征子图,从而完成了该卷积层的卷积运算。

二,卷积核是三维的

  对于卷积核是三维的情况,主要参考的是贾杨清老师在知乎上的一个解答。即认为每个输入图像和每个卷积核的大小表示为C*H*W,即:

  由上图知道,一个输入特征图的表示是C*H*W(通道数*长*宽),一个卷积核的大小表示为C*K*K(注意:这里,如果认为卷积核是三维的,就必须保证卷积核的通道数跟输入特征图的通道数相同,否则卷积失败),那么根据卷积核一次卷积的图像区域,将该区域图像转化为行向量,即得到一个C*k*k的行向量。

  按此方式,将一张图像按照卷积的顺序得到的行向量按列排列,就得到了最终的特征矩阵如下:

上图知道,对于一个C*H*W的图像,按照卷积核大小进行卷积,转化为的特征矩阵大小为:(H*W)*(C*K*K)。

那么,对于多个卷积核而言,将多个卷积核转化为卷积矩阵过程如下:

这里,卷积核的个数为Cout,每个卷积核的大小为C*K*K,同理,将每个卷积核转化为一个行向量C*K*K,按照卷积核个数按列排列,就得到卷积矩阵Cout*(C*K*K)。

  最后,将卷积矩阵与输入特征矩阵的转置进行相乘,就得到了最终的输出特征矩阵[Cout*(C*K*K)]*[(H*W)*(C*K*K)]T=[Cout*(C*K*K)]*[(C*K*K)*(H*W)]=Cout*(H*W)。这样,再将输出矩阵的每一行转化为一张特征图,就得到了Cout张输出特征子图。而这,也就印证了:卷积层输出的特征图个数等于卷积核的个数。

  以上,就是对两种对于卷积核的维度不同看法的具体分析,不管怎么定义,都有其充分的理由和实践证明。并且,最重要的是,不管卷积核定义为二维还是三维,都是为了数据转化为矩阵的形式,从而将卷积层的复杂的卷积过程,转化为矩阵的相乘的简单运算,大大的提高了计算的速度。

  最后,通过一个具体的例子,来看一下将卷积转化为矩阵运算的过程:

参考链接:http://www.cnblogs.com/laiqun/p/6055498.html

     https://www.zhihu.com/question/28385679

     Convolution in Caffe: a memo · Yangqing/caffe Wiki · GitHub 

              High Performance Convolutional Neural Networks for Document Processing
              https://hal.archives-ouvertes.fr/file/index/docid/112631/filename/p1038112283956.pdf

关于caffe 是如何卷积的一点总结的更多相关文章

  1. caffe源码 卷积层

    通俗易懂理解卷积 图示理解神经网络的卷积 input: 3 * 5 * 5 (c * h * w) pading: 1 步长: 2 卷积核: 2 * 3 * 3 * 3 ( n * c * k * k ...

  2. caffe中全卷积层和全连接层训练参数如何确定

    今天来仔细讲一下卷基层和全连接层训练参数个数如何确定的问题.我们以Mnist为例,首先贴出网络配置文件: name: "LeNet" layer { name: "mni ...

  3. caffe中LetNet-5卷积神经网络模型文件lenet.prototxt理解

    caffe在 .\examples\mnist文件夹下有一个 lenet.prototxt文件,这个文件定义了一个广义的LetNet-5模型,对这个模型文件逐段分解一下. name: "Le ...

  4. caffe中的卷积

    https://www.zhihu.com/question/28385679 如上,将三维的操作转换到二维上面去做,然后调用GEMM库进行矩阵间的运算得到最后结果. 两个矩阵相乘,需要中间的那个维度 ...

  5. caffe卷积输入通道如何到输出通道

    今天一个同学问 卷积过程好像是对 一个通道的图像进行卷积, 比如10个卷积核,得到10个feature map, 那么输入图像为RGB三个通道呢,输出就为 30个feature map 吗, 答案肯定 ...

  6. caffe源码阅读(1)_整体框架和简介(摘录)

    原文链接:https://www.zhihu.com/question/27982282 1.Caffe代码层次.回答里面有人说熟悉Blob,Layer,Net,Solver这样的几大类,我比较赞同. ...

  7. caffe学习(1):多平台下安装配置caffe

    如何在 centos 7.3 上安装 caffe 深度学习工具   有好多朋友在安装 caffe 时遇到不少问题.(看文章的朋友希望关心一下我的创业项目趣智思成) 今天测试并整理一下安装过程.我是在阿 ...

  8. Caffe源码解析5:Conv_Layer

    转载请注明出处,楼燚(yì)航的blog,http://home.cnblogs.com/louyihang-loves-baiyan/ Vision_layer里面主要是包括了一些关于一些视觉上的操 ...

  9. 【转】Caffe初试(五)视觉层及参数

    本文只讲解视觉层(Vision Layers)的参数,视觉层包括Convolution, Pooling, Local Response Normalization (LRN), im2col等层. ...

随机推荐

  1. 300行ABAP代码实现一个最简单的区块链原型

    不知从什么时候起,区块链在网上一下子就火了. 这里Jerry就不班门弄斧了,网上有太多的区块链介绍文章.我的这篇文章没有任何高大上的术语,就是300行ABAP代码,实现一个最简单的区块链原型. 我个人 ...

  2. innobackupex 全备、增备脚本

    全备脚本:innobackupex --defaults-file=/etc/my.cnf --user root --password mypasswd /mydata/fullbak/ 增备脚本: ...

  3. OpenLayers学习笔记2——坐标转换问题

    参照别人的添加marker的demo来改造时,发现无论怎样更改经纬度,都是停留在同一个位置.过了一两天突然想起可能是坐标参考的问题,尝试搜了一下,果然是这个问题.问题是这样子的: WMTS中地图的坐标 ...

  4. hdu-1272 小希的迷宫---并查集或者DFS

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1272 题目大意: Problem Description 上次Gardon的迷宫城堡小希玩了很久(见 ...

  5. 【转】iOS 上常用的两个功能:点击屏幕和return退出隐藏键盘和解决虚拟键盘挡住UITextField的方法

    iOS上面对键盘的处理很不人性化,所以这些功能都需要自己来实现, 首先是点击return和屏幕隐藏键盘 这个首先引用双子座的博客 http://my.oschina.net/plumsoft/blog ...

  6. python_41_with语句

    #为了避免打开文件后忘记关闭,可以通过管理上下文,即:with open('log','r') as f: # 如此方式,当with代码块执行完毕时,内部会自动关闭并释放文件资源. with open ...

  7. C# File和Directory类

    File和Directory类 作为实用类,File和Directory类都提供了许多方法,用于处理文件系统以及其中的文件和目录.这些是静态方法,涉及移动文件.查询和更新属性并创建FileStream ...

  8. React后台管理系统- rc-pagination分页组件封装

    1.用户列表页面使用的rc-pagination分页组件 Github地址: https://github.com/react-component/pagination 2.安装 cnpm insta ...

  9. Spring+ ApplicationListener

    有时候 需要在容器初始化完成后,加载些 代码字典或不常变的信息  放入缓存之类的,这里使用spring 初始化bean,并实例化 1.创建一个ApplicationListener类 import o ...

  10. Yii2.X 如何避开pathinfo不能处理中文名开头的bug

    /** * @return string original file base name */ public function getBaseName() { // https://github.co ...