热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Caffe源码(四):base_conv_layer分析

目录目录简单介绍主要函数LayerSetUp函数Reshape函数forward_cpu_gemm函数forward_cpu_bias函数backward_cpu_gemm函数

目录

  • 目录
  • 简单介绍
  • 主要函数
    • LayerSetUp 函数
    • Reshape 函数
    • forward_cpu_gemm 函数
    • forward_cpu_bias 函数
    • backward_cpu_gemm函数
    • weight_cpu_gemm 函数
    • backward_cpu_bias 函数

简单介绍
base_conv_layer.cpp 中定义了 BaseConvolutionLayer 类的一些成员函数,而BaseConvolutionLayer 是 ConvolutionLayer 的父类,ConvolutionLayer中用到的一些函数都在这里定义,所以在看conv_layer前需要看此源代码。

主要函数

1. LayerSetUp 函数:

template <typename Dtype>
void BaseConvolutionLayer::LayerSetUp(const vector*>& bottom,
const vector*>& top) {
CHECK_EQ(4, bottom[0]->num_axes()) <<"Input must have 4 axes, "
<<"corresponding to (num, channels, height, width)";
// Configure the kernel size, padding, stride, and inputs.
ConvolutionParameter conv_param = this->layer_param_.convolution_param();
CHECK(!conv_param.has_kernel_size() !=
!(conv_param.has_kernel_h() && conv_param.has_kernel_w()))
<<"Filter size is kernel_size OR kernel_h and kernel_w; not both";
CHECK(conv_param.has_kernel_size() ||
(conv_param.has_kernel_h() && conv_param.has_kernel_w()))
<<"For non-square filters both kernel_h and kernel_w are required.";
CHECK((!conv_param.has_pad() && conv_param.has_pad_h()
&& conv_param.has_pad_w())
|| (!conv_param.has_pad_h() && !conv_param.has_pad_w()))
<<"pad is pad OR pad_h and pad_w are required.";
CHECK((!conv_param.has_stride() && conv_param.has_stride_h()
&& conv_param.has_stride_w())
|| (!conv_param.has_stride_h() && !conv_param.has_stride_w()))
<<"Stride is stride OR stride_h and stride_w are required.";
if (conv_param.has_kernel_size()) {
kernel_h_ = kernel_w_ = conv_param.kernel_size();
} else {
kernel_h_ = conv_param.kernel_h();
kernel_w_ = conv_param.kernel_w();
}//用户自定义kernel size 的两种方式
CHECK_GT(kernel_h_, 0) <<"Filter dimensions cannot be zero.";
CHECK_GT(kernel_w_, 0) <<"Filter dimensions cannot be zero.";
if (!conv_param.has_pad_h()) {
pad_h_ = pad_w_ = conv_param.pad();
} else {
pad_h_ = conv_param.pad_h();
pad_w_ = conv_param.pad_w();
}
if (!conv_param.has_stride_h()) {
stride_h_ = stride_w_ = conv_param.stride();
} else {
stride_h_ = conv_param.stride_h();
stride_w_ = conv_param.stride_w();
}
// Special case: im2col is the identity for 1x1 convolution with stride 1
// and no padding, so flag for skipping the buffer and transformation.
is_1x1_ = kernel_w_ == 1 && kernel_h_ == 1
&& stride_h_ == 1 && stride_w_ == 1 && pad_h_ == 0 && pad_w_ == 0;
// Configure output channels and groups.
channels_ = bottom[0]->channels();
num_output_ = this->layer_param_.convolution_param().num_output();
CHECK_GT(num_output_, 0);
group_ = this->layer_param_.convolution_param().group();
CHECK_EQ(channels_ % group_, 0);
CHECK_EQ(num_output_ % group_, 0)
<<"Number of output should be multiples of group.";
//channel 和 输出 feature map 个数必须为group的整数倍,每个group中只用本group的featrue map
if (reverse_dimensions()) {
conv_out_channels_ = channels_;
conv_in_channels_ = num_output_;
} else {
conv_out_channels_ = num_output_;//用户指定输出feature map的数量
conv_in_channels_ = channels_;
}
// Handle the parameters: weights and biases.
// - blobs_[0] holds the filter weights
// - blobs_[1] holds the biases (optional)
bias_term_ = this->layer_param_.convolution_param().bias_term();//默认为 true
if (this->blobs_.size() > 0) {
LOG(INFO) <<"Skipping parameter initialization";
} else {
if (bias_term_) {
this->blobs_.resize(2);
} else {
this->blobs_.resize(1);
}
// Initialize and fill the weights:
// output channels x input channels per-group x kernel height x kernel width
this->blobs_[0].reset(new Blob(
conv_out_channels_, conv_in_channels_ / group_, kernel_h_, kernel_w_));
shared_ptr > weight_filler(GetFiller(
this->layer_param_.convolution_param().weight_filler()));
weight_filler->Fill(this->blobs_[0].get()); //用weight_filler初始化
// If necessary, initialize and fill the biases.
if (bias_term_) {
vector<int> bias_shape(1, num_output_);
this->blobs_[1].reset(new Blob(bias_shape));
shared_ptr > bias_filler(GetFiller(
this->layer_param_.convolution_param().bias_filler()));
bias_filler->Fill(this->blobs_[1].get());
}
}
// Propagate gradients to the parameters (as directed by backward pass).
this->param_propagate_down_.resize(this->blobs_.size(), true);
}

2.Reshape 函数:

template <typename Dtype>
void BaseConvolutionLayer::Reshape(const vector*>& bottom,
const vector*>& top) {
CHECK_EQ(4, bottom[0]->num_axes()) <<"Input must have 4 axes, "
<<"corresponding to (num, channels, height, width)";//blob是四维数组
num_ = bottom[0]->num();
height_ = bottom[0]->height();
width_ = bottom[0]->width();
CHECK_EQ(bottom[0]->channels(), channels_) <<"Input size incompatible with"
" convolution kernel.";
// TODO: generalize to handle inputs of different shapes.
for (int bottom_id = 1; bottom_id CHECK_EQ(num_, bottom[bottom_id]->num()) <<"Inputs must have same num.";
CHECK_EQ(channels_, bottom[bottom_id]->channels())
<<"Inputs must have same channels.";
CHECK_EQ(height_, bottom[bottom_id]->height())
<<"Inputs must have same height.";
CHECK_EQ(width_, bottom[bottom_id]->width())
<<"Inputs must have same width.";
}//有多少个bottom 就有多少个top输出,要求每个bottom有相同的shape,因为用的是同一组filter
// Shape the tops.
compute_output_shape();//在conv_layer中定义,计算输出feature map 的shape
for (int top_id = 0; top_id top[top_id]->Reshape(num_, num_output_, height_out_, width_out_);
}
if (reverse_dimensions()) {
conv_in_height_ = height_out_;//根据pad情况计算所得输出top 的height,具体如何计算在conv_layer的compute_output_shape()中定义
conv_in_width_ = width_out_;
conv_out_spatial_dim_ = height_ * width_;
} else {
conv_in_height_ = height_; //输入bottom 的height
conv_in_width_ = width_; //输入bottom 的width
conv_out_spatial_dim_ = height_out_ * width_out_;
}
kernel_dim_ = conv_in_channels_ * kernel_h_ * kernel_w_;//对应一个输出的feature map
weight_offset_ = conv_out_channels_ * kernel_dim_ / group_ / group_;
col_offset_ = kernel_dim_ * conv_out_spatial_dim_ / group_;
output_offset_ = conv_out_channels_ * conv_out_spatial_dim_ / group_;
// The im2col result buffer will only hold one image at a time to avoid
// overly large memory usage. In the special case of 1x1 convolution
// it goes lazily unused to save memory.
if (reverse_dimensions()) {
col_buffer_.Reshape(1, kernel_dim_, height_, width_);
} else {
col_buffer_.Reshape(1, kernel_dim_, height_out_, width_out_);
}
// Set up the all ones "bias multiplier" for adding biases by BLAS
if (bias_term_) {
vector<int> bias_multiplier_shape(1, height_out_ * width_out_);
bias_multiplier_.Reshape(bias_multiplier_shape);
caffe_set(bias_multiplier_.count(), Dtype(1),
bias_multiplier_.mutable_cpu_data());
}
}

3.forward_cpu_gemm 函数:

template type>
void BaseConvolutionLayertype>::forward_cpu_gemm(const Dtype* input,
const Dtype* weights, Dtype* output, bool skip_im2col) {
const Dtype* col_buff = input;
if (!is_1x1_) {
if (!skip_im2col) {
conv_im2col_cpu(input, col_buffer_.mutable_cpu_data());
}
col_buff = col_buffer_.cpu_data();
}
for (int g = 0; g caffe_cpu_gemmtype>(CblasNoTrans, CblasNoTrans, conv_out_channels_ /
group_, conv_out_spatial_dim_, kernel_dim_ / group_,
(Dtype)1., weights + weight_offset_ * g, col_buff + col_offset_ * g,
(Dtype)0., output + output_offset_ * g);
}
}// 实现卷积操作

4.forward_cpu_bias 函数:

template type>
void BaseConvolutionLayertype>::forward_cpu_bias(Dtype* output,
const Dtype* bicas) {
caffe_cpu_gemmtype>(CblasNoTrans, CblasNoTrans, num_output_,
height_out_ * width_out_, 1, (Dtype)1., bias, bias_multiplier_.cpu_data(),
(Dtype)1., output);
}//卷积后加bias

4.backward_cpu_gemm函数:

template type>
void BaseConvolutionLayertype>::backward_cpu_gemm(const Dtype* output,
const Dtype* weights, Dtype* input) {
Dtype* col_buff = col_buffer_.mutable_cpu_data();
if (is_1x1_) {
col_buff = input;
}
for (int g = 0; g caffe_cpu_gemmtype>(CblasTrans, CblasNoTrans, kernel_dim_ / group_,
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);
}
if (!is_1x1_) {
conv_col2im_cpu(col_buff, input);
}计算关于bottom data的导数以便传给下一层

5.weight_cpu_gemm 函数:

template type>
void BaseConvolutionLayertype>::weight_cpu_gemm(const Dtype* input,
const Dtype* output, Dtype* weights) {
const Dtype* col_buff = input;
if (!is_1x1_) {
conv_im2col_cpu(input, col_buffer_.mutable_cpu_data());
col_buff = col_buffer_.cpu_data();
}
for (int g = 0; g caffe_cpu_gemmtype>(CblasNoTrans, CblasTrans, conv_out_channels_ / group_,
kernel_dim_ / group_, conv_out_spatial_dim_,
(Dtype)1., output + output_offset_ * g, col_buff + col_offset_ * g,
(Dtype)1., weights + weight_offset_ * g);
}
}//计算关于weight的导数用于更新。

6.backward_cpu_bias 函数:

template type>
void BaseConvolutionLayertype>::backward_cpu_bias(Dtype* bias,
const Dtype* input) {
caffe_cpu_gemvtype>(CblasNoTrans, num_output_, height_out_ * width_out_, 1.,
input, bias_multiplier_.cpu_data(), 1., bias);
} 计算关于bias的导数

推荐阅读
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • ALTERTABLE通过更改、添加、除去列和约束,或者通过启用或禁用约束和触发器来更改表的定义。语法ALTERTABLEtable{[ALTERCOLUMNcolu ... [详细]
  • web.py开发web 第八章 Formalchemy 服务端验证方法
    本文介绍了在web.py开发中使用Formalchemy进行服务端表单数据验证的方法。以User表单为例,详细说明了对各字段的验证要求,包括必填、长度限制、唯一性等。同时介绍了如何自定义验证方法来实现验证唯一性和两个密码是否相等的功能。该文提供了相关代码示例。 ... [详细]
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • This article discusses the efficiency of using char str[] and char *str and whether there is any reason to prefer one over the other. It explains the difference between the two and provides an example to illustrate their usage. ... [详细]
  • 本文记录了在vue cli 3.x中移除console的一些采坑经验,通过使用uglifyjs-webpack-plugin插件,在vue.config.js中进行相关配置,包括设置minimizer、UglifyJsPlugin和compress等参数,最终成功移除了console。同时,还包括了一些可能出现的报错情况和解决方法。 ... [详细]
  • 本文介绍了一个适用于PHP应用快速接入TRX和TRC20数字资产的开发包,该开发包支持使用自有Tron区块链节点的应用场景,也支持基于Tron官方公共API服务的轻量级部署场景。提供的功能包括生成地址、验证地址、查询余额、交易转账、查询最新区块和查询交易信息等。详细信息可参考tron-php的Github地址:https://github.com/Fenguoz/tron-php。 ... [详细]
  • SpringBoot整合SpringSecurity+JWT实现单点登录
    SpringBoot整合SpringSecurity+JWT实现单点登录,Go语言社区,Golang程序员人脉社 ... [详细]
  • node.jsrequire和ES6导入导出的区别原 ... [详细]
  • 本文介绍了利用ARMA模型对平稳非白噪声序列进行建模的步骤及代码实现。首先对观察值序列进行样本自相关系数和样本偏自相关系数的计算,然后根据这些系数的性质选择适当的ARMA模型进行拟合,并估计模型中的位置参数。接着进行模型的有效性检验,如果不通过则重新选择模型再拟合,如果通过则进行模型优化。最后利用拟合模型预测序列的未来走势。文章还介绍了绘制时序图、平稳性检验、白噪声检验、确定ARMA阶数和预测未来走势的代码实现。 ... [详细]
  • Introduction(简介)Forbeingapowerfulobject-orientedprogramminglanguage,Cisuseda ... [详细]
  • 学习笔记17:Opencv处理调整图片亮度和对比度
    一、理论基础在数学中我们学过线性理论,在图像亮度和对比度调节中同样适用,看下面这个公式:在图像像素中其中:参数f(x)表示源图像像素。参数g(x)表示输出图像像素。 ... [详细]
author-avatar
mobiledu2502923083
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有