目录
- 目录
- 简单介绍
- 主要函数
- 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)";
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();
}
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();
}
is_1x1_ = kernel_w_ == 1 && kernel_h_ == 1
&& stride_h_ == 1 && stride_w_ == 1 && pad_h_ == 0 && pad_w_ == 0;
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.";
if (reverse_dimensions()) {
conv_out_channels_ = channels_;
conv_in_channels_ = num_output_;
} else {
conv_out_channels_ = num_output_;
conv_in_channels_ = channels_;
}
bias_term_ = this->layer_param_.convolution_param().bias_term();
if (this->blobs_.size() > 0) {
LOG(INFO) << "Skipping parameter initialization";
} else {
if (bias_term_) {
this->blobs_.resize(2);
} else {
this->blobs_.resize(1);
}
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());
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());
}
}
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)";
num_ = bottom[0]->num();
height_ = bottom[0]->height();
width_ = bottom[0]->width();
CHECK_EQ(bottom[0]->channels(), channels_) << "Input size incompatible with"
" convolution kernel.";
for (int bottom_id = 1; bottom_id < bottom.size(); ++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.";
}
compute_output_shape();
for (int top_id = 0; top_id < top.size(); ++top_id) {
top[top_id]->Reshape(num_, num_output_, height_out_, width_out_);
}
if (reverse_dimensions()) {
conv_in_height_ = height_out_;
conv_in_width_ = width_out_;
conv_out_spatial_dim_ = height_ * width_;
} else {
conv_in_height_ = height_;
conv_in_width_ = width_;
conv_out_spatial_dim_ = height_out_ * width_out_;
}
kernel_dim_ = conv_in_channels_ * kernel_h_ * kernel_w_;
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_;
if (reverse_dimensions()) {
col_buffer_.Reshape(1, kernel_dim_, height_, width_);
} else {
col_buffer_.Reshape(1, kernel_dim_, height_out_, width_out_);
}
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 < group_; ++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 < group_; ++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 < group_; ++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的导数