caffe convolution layer 笔记

来源:互联网 发布:power map for mac 编辑:程序博客网 时间:2024/06/03 12:53

主要说一下Forward过程:

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 + bottom[i]->offset(n), weight,
          top_data + top[i]->offset(n));
      if (this->bias_term_) {
        const Dtype* bias = this->blobs_[1]->cpu_data();
        this->forward_cpu_bias(top_data + top[i]->offset(n), bias);
      }
    }
  }
}

void BaseConvolutionLayer<Dtype>::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_gemm<Dtype>(CblasNoTrans, CblasNoTrans, conv_out_channels_ /
        group_, conv_out_spatial_dim_, kernel_dim_,
        (Dtype)1., weights + weight_offset_ * g, col_buff + col_offset_ * g,
        (Dtype)0., output + output_offset_ * g);
  }
}

forward_cpu_gemm是计算weights和input的矩阵乘法,其中weights是out_channels*kernel_dim,

input是kernel_dim*out_spatial_dim。

out_channels指输出通道数,kernel_dim指kernel_h*kernel_w*channels(输入通道数),

out_spatial_dim指out_height*out_width。


input是需要经过conv_im2col_cpu才能被使用。conv_im2col_cpu封装在vision_layer.hpp中,是一个内联函数。

inline void conv_im2col_cpu(const Dtype* data, Dtype* col_buff) {
  im2col_cpu(data, conv_in_channels_, conv_in_height_, conv_in_width_,
      kernel_h_, kernel_w_, pad_h_, pad_w_, stride_h_, stride_w_, col_buff);
}

void im2col_cpu(const Dtype* data_im, const int channels,
    const int height, const int width, const int kernel_h, const int kernel_w,
    const int pad_h, const int pad_w,
    const int stride_h, const int stride_w,
    Dtype* data_col) {
  int height_col = (height + 2 * pad_h - kernel_h) / stride_h + 1;
  int width_col = (width + 2 * pad_w - kernel_w) / stride_w + 1;
  int channels_col = channels * kernel_h * kernel_w;
  for (int c = 0; c < channels_col; ++c) {
    int w_offset = c % kernel_w;
    int h_offset = (c / kernel_w) % kernel_h;
    int c_im = c / kernel_h / kernel_w;
    for (int h = 0; h < height_col; ++h) {
      for (int w = 0; w < width_col; ++w) {
        int h_pad = h * stride_h - pad_h + h_offset;
        int w_pad = w * stride_w - pad_w + w_offset;
        if (h_pad >= 0 && h_pad < height && w_pad >= 0 && w_pad < width)
          data_col[(c * height_col + h) * width_col + w] =
            data_im[(c_im * height + h_pad) * width + w_pad];
        else
          data_col[(c * height_col + h) * width_col + w] = 0;
      }
    }
  }
}

data_im是channels*height*width的输入map,拉成一行后的下标表示为:idx=c*(height*width)+h*width+w,

表示为第c个通道,第h行,第w列的下标序号。

data_col是(channels * kernel_h * kernel_w)*(height*width)的直接用作卷积的输入map,它的每一列表示

各个通道对应的数据块拉成一列后相接得到。

1 0