转载请注明出处,楼燚(yì)航的blog,http://home.cnblogs.com/louyihang-loves-baiyan/

Vision_layer里面主要是包括了一些关于一些视觉上的操作,比如卷积、反卷积、池化等等。这里的类跟data layer一样好很多种继承关系。主要包括了这几个类,其中CuDNN分别是CUDA版本,这里先不讨论,在这里先讨论ConvolutionLayer

  • BaseConvolutionLayer
  • ConvolutionLaye
  • DeconvolutionLayer
  • CuDNNConvolutionLayer
  • Im2colLayer
  • LRNLayer
  • CuDNNLRNLayer
  • CuDNNLCNLayer
  • PoolingLayer
  • CuDNNPoolingLayer
  • SPPLayer
    这里我画了一个类图,将关系梳理了一下:

BaseConvolutionLayer

其继承自Layer,是一个卷积以及反卷积操作的基类,首先我们来看BaseConvolutionLayer的LayerSetUp函数

void BaseConvolutionLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom,const vector<Blob<Dtype>*>& top)//首先这里主要是在配置卷积kernel 的size,padding,stride以及inputsConvolutionParameter conv_param = this->layer_param_.convolution_param();force_nd_im2col_ = conv_param.force_nd_im2col();channel_axis_ = bottom[0]->CanonicalAxisIndex(conv_param.axis());const int first_spatial_axis = channel_axis_ + 1;const int num_axes = bottom[0]->num_axes();num_spatial_axes_ = num_axes - first_spatial_axis;CHECK_GE(num_spatial_axes_, 0);vector<int> bottom_dim_blob_shape(1, num_spatial_axes_ + 1);vector<int> spatial_dim_blob_shape(1, std::max(num_spatial_axes_, 1));// 设置kernel的dimensionskernel_shape_.Reshape(spatial_dim_blob_shape);int* kernel_shape_data = kernel_shape_.mutable_cpu_data();

接着是设置相应的stride dimensions,对于2D,设置在h和w方向上的stride,代码太长列出简要的

pad_.Reshape(spatial_dim_blob_shape);
int* pad_data = pad_.mutable_cpu_data();
pad_data[0] = conv_param.pad_h();
pad_data[1] = conv_param.pad_w();
......一堆if else判断

对于kernel的pad也做相应设置

pad_.Reshape(spatial_dim_blob_shape);
int* pad_data = pad_.mutable_cpu_data();
pad_data[0] = conv_param.pad_h();
pad_data[1] = conv_param.pad_w();

接下来是对widhts 和bias左设置和填充,其中blob[0]里面存放的是filter weights,而blob[1]里面存放的是biases,当然biases是可选的,也可以没有

//设置相应的shape,并检查
vector<int> weight_shape(2);
weight_shape[0] = conv_out_channels_;
weight_shape[1] = conv_in_channels_ / group_;bias_term_ = this->layer_param_.convolution_param().bias_term();
vector<int> bias_shape(bias_term_, num_output_);//填充权重
this->blobs_[0].reset(new Blob<Dtype>(weight_shape));
shared_ptr<Filler<Dtype> > weight_filler(GetFiller<Dtype>(this->layer_param_.convolution_param().weight_filler()));
weight_filler->Fill(this->blobs_[0].get());
//填充偏置项
if (bias_term_) {this->blobs_[1].reset(new Blob<Dtype>(bias_shape));shared_ptr<Filler<Dtype> > bias_filler(GetFiller<Dtype>(this->layer_param_.convolution_param().bias_filler()));bias_filler->Fill(this->blobs_[1].get());
}

ConvolutionLayer

ConvolutionLayer继承了BaseConvolutionLayer,主要作用就是将一副image做卷积操作,使用学到的filter的参数和biaes。同时在Caffe里面,卷积操作做了优化,变成了一个矩阵相乘的操作。其中有两个比较主要的函数是im2col以及col2im。
图中上半部分是一个传统卷积,下图是一个矩阵相乘的版本

下图是在一个卷积层中将卷积操作展开的具体操作过程,他里面按照卷积核的大小取数据然后展开,在同一张图里的不同卷积核选取的逐行摆放,不同N的话,就在同一行后面继续拼接,不同个可以是多个通道,但是需要注意的是同一行里面每一段都应该对应的是原图中中一个位置的卷积窗口。

对于卷积层中的卷积操作,还有一个group的概念要说明一下,groups是代表filter 组的个数。引入gruop主要是为了选择性的连接卷基层的输入端和输出端的channels,否则参数会太多。每一个group 和1/ group的input 通道和 1/group 的output通道进行卷积操作。比如有4个input, 8个output,那么1-4属于第一组,5-8属于第二个gruop

ConvolutionLayer里面,主要重写了Forward_cpu和Backward_cpu

void ConvolutionLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,const vector<Blob<Dtype>*>& top) {const Dtype* weight = this->blobs_[0]->cpu_data();for (int i = 0; i < bottom.size(); ++i) {const Dtype* bottom_data = bottom[i]->cpu_data();Dtype* top_data = top[i]->mutable_cpu_data();for (int n = 0; n < this->num_; ++n) {this->forward_cpu_gemm(bottom_data + n * this->bottom_dim_, weight,top_data + n * this->top_dim_);if (this->bias_term_) {const Dtype* bias = this->blobs_[1]->cpu_data();this->forward_cpu_bias(top_data + n * this->top_dim_, bias);}}}
}

可以看到其实这里面他调用了forward_cpu_gemm,而这个函数内部又调用了math_function里面的caffe_cpu_gemm的通用矩阵相乘接口,GEMM的全称是General Matrix Matrix Multiply。其基本形式如下:
\[C=alpha*op( A )*op( B ) + beta*C,\]

template <typename Dtype>
void ConvolutionLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {//反向传播梯度误差const Dtype* weight = this->blobs_[0]->cpu_data();Dtype* weight_diff = this->blobs_[0]->mutable_cpu_diff();for (int i = 0; i < top.size(); ++i) {const Dtype* top_diff = top[i]->cpu_diff();const Dtype* bottom_data = bottom[i]->cpu_data();Dtype* bottom_diff = bottom[i]->mutable_cpu_diff();//如果有bias项,计算Bias导数if (this->bias_term_ && this->param_propagate_down_[1]) {Dtype* bias_diff = this->blobs_[1]->mutable_cpu_diff();for (int n = 0; n < this->num_; ++n) {this->backward_cpu_bias(bias_diff, top_diff + n * this->top_dim_);}}//计算weightif (this->param_propagate_down_[0] || propagate_down[i]) {for (int n = 0; n < this->num_; ++n) {// 计算weights权重的梯度if (this->param_propagate_down_[0]) {this->weight_cpu_gemm(bottom_data + n * this->bottom_dim_,top_diff + n * this->top_dim_, weight_diff);}//计算botttom数据的梯度,下后传递if (propagate_down[i]) {this->backward_cpu_gemm(top_diff + n * this->top_dim_, weight,bottom_diff + n * this->bottom_dim_);}}}}
}

转载于:https://www.cnblogs.com/louyihang-loves-baiyan/p/5154337.html

Caffe源码解析5:Conv_Layer相关推荐

  1. 深度学习框架Caffe源码解析

    作者:薛云峰(https://github.com/HolidayXue),主要从事视频图像算法的研究, 本文来源微信公众号:深度学习大讲堂.  原文:深度学习框架Caffe源码解析  欢迎技术投稿. ...

  2. caffe源码解析—image_data_layer层

    caffe data layer相关层的继承结构 image-data-layer层关键代码注释 DataLayerSetUp函数 //将imagelist中的图片以 image+label格式 读入 ...

  3. Caffe源码解析4: Data_layer

    转载请注明出处,楼燚(yì)航的blog,http://home.cnblogs.com/louyihang-loves-baiyan/ data_layer应该是网络的最底层,主要是将数据送给blo ...

  4. Caffe源码解析2:SycedMem

    from:https://www.cnblogs.com/louyihang-loves-baiyan/p/5150554.html 转载请注明出处,楼燚(yì)航的blog,http://www.c ...

  5. Caffe源码解析1:Blob

    from:https://www.cnblogs.com/louyihang-loves-baiyan/p/5149628.html 转载请注明出处,楼燚(yì)航的blog,http://www.c ...

  6. Caffe源码解析(一) —— caffe.proto

    文章作者:Tyan 博客:noahsnail.com  |  CSDN  |  简书 caffe.proto是caffe数据结构定义的主要文件,本文主要是在caffe.proto代码的基础上加上了部分 ...

  7. Caffe源码解析—核函数

    目录 forward_cpu_gemm forward_cpu_bias backward_cpu_bias weight_cpu_gemm backward_cpu_gemm 其余函数参考链接 fo ...

  8. 零基础学caffe源码 ReLU激活函数

    零基础学caffe源码 ReLU激活函数 原创 2016年08月03日 17:30:19 1.如何有效阅读caffe源码 1.caffe源码阅读路线最好是从src/cafffe/proto/caffe ...

  9. win版本caffe源码libcaffe研究

    版权声明:本文为博主在研究工作中经验分享,包括研究成果,欢迎交流和批评:其中参考资料的标注难免会有疏漏之处,如有请告知,立马更正,谢谢:未经博主允许不得转载. [cpp]  view plain co ...

最新文章

  1. 深度揭秘Windows 7
  2. 关于requestAnimationFrame与setInterval的一点差异
  3. Oracle-AWR性能报告解读
  4. 【Python基础】50个令人大开眼界的 Matplotlib 可视化项目
  5. 【转载】target='_blank' 安全漏洞示例
  6. 电商产品评论数据情感分析代码详解
  7. 他读博期间发表3篇Science,28岁任武大教授,35岁入“杰青”名单,让人叹服!...
  8. 洛谷 P1008 [NOIP1998 普及组] 三连击
  9. web.xml配置文件详解
  10. vba 判断是否为数字
  11. PS魔棒工具的使用方法
  12. mandriva urpm类命令
  13. python输入整数输出英文_python练习 英文字符的鲁棒输入+数字的鲁棒输入
  14. redis 模糊删除keys
  15. 移动端300ms延迟_移动端300ms延迟原因及解决方案
  16. 交换机与路由器工作原理
  17. vue封装自定义数字键盘组件
  18. windows下Ardupilot编译环境搭建
  19. Pbootcms自定义分页样式,适用于多种环境
  20. java 进制转换工具_进制转换工具(JAVA)

热门文章

  1. python turtle画气球-micro:bit + LoRa 实现气球追踪
  2. 财务需要学python-财务人要学Python吗?
  3. python爬虫详细步骤-Python爬虫的两套解析方法和四种爬虫实现过程
  4. python爬虫教程pdf-《Python爬虫开发与项目实战》pdf完整版
  5. python爬虫流程-Python爬虫程序架构和运行流程原理解析
  6. 免费学python的网站-免费学习Python编程的3个优秀的网站资源
  7. python中文编辑器推荐-八款Python编辑器对比介绍推荐
  8. python百度云资源-Python开发视频百度云分享
  9. python编程实例视屏-python实现实时视频流播放代码实例
  10. python导入本地文件-Python使用import导入本地脚本及导入模块的技巧总结