caffe源码_concat_layer

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lantuxin/article/details/83278630

参考网站:https://blog.csdn.net/bailufeiyan/article/details/50876728

主要功能:将多个输入bottom中的blob连接起来,但这种是按连接轴axis确定不同连接方式:0-按行连接,1-按列连接

举例说明:a1=[[1,2,3],[4,5,6]]; a2=[[7,8,9],[10,11,12]],连接a1与a2

axis:0状态:[[1,2,3],[4,5,6],[7,8,9],[10,11,12]]-----------------(n_1 + n_2 + ... + n_K) * c_1 * h * w

axis:1状态:[[1,2,3,7,8,9],[4,5,6,10,11,12]]--------------------n_1 * (c_1 + c_2 + ... + c_K) * h * w

#include <vector>

#include "caffe/layers/concat_layer.hpp"
#include "caffe/util/math_functions.hpp"

namespace caffe {

template <typename Dtype>
void ConcatLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top) {
  const ConcatParameter& concat_param = this->layer_param_.concat_param();
  CHECK(!(concat_param.has_axis() && concat_param.has_concat_dim()))
      << "Either axis or concat_dim should be specified; not both.";
}

//整个函数就是实现对层数据的读取,数据格式的正确性判断,将输出top的结构初始化为输入bottom一样的
template <typename Dtype>
void ConcatLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top) {
  const int num_axes = bottom[0]->num_axes();
//bottom[0]应该是一个feature map,这里bottom[0]->num_axes()表示输入bottom[0]包含几个轴
//比如正常情况下(num, channels, height, width)就是4个轴
  const ConcatParameter& concat_param = this->layer_param_.concat_param();
  // concat_param定义为引用类型,间接寻址,其本身初始化后不能改变
  if (concat_param.has_concat_dim()) {
    //判断prototxt层中的concat_dim是否被设置,设置了就执行
    concat_axis_ = static_cast<int>(concat_param.concat_dim());
    // Don't allow negative indexing for concat_dim, a uint32 -- almost
    // certainly unintended.static_cast--允许执行任意的隐式转换和相反转换动作
    CHECK_GE(concat_axis_, 0) << "casting concat_dim from uint32 to int32 "
        << "produced negative result; concat_dim must satisfy "
        << "0 <= concat_dim < " << kMaxBlobAxes;
    //连接轴必须大于等于0
    CHECK_LT(concat_axis_, num_axes) << "concat_dim out of range.";
    //连接轴必须小于可用轴数量
  } else {
    concat_axis_ = bottom[0]->CanonicalAxisIndex(concat_param.axis());
    //转换坐标轴索引,将[-N,N]转换为[0,N),负索引表示从后往前访问,-1表示最后一个元素,-2表示第N-2个元素,以此类推
    //但这里为什么要转换坐标轴呢?后面或许有答案
  }
  // Initialize with the first blob.
  vector<int> top_shape = bottom[0]->shape();//初始化输出top的shape
  num_concats_ = bottom[0]->count(0, concat_axis_);//计算从开始轴0到结束轴concat_axis_的数量
  concat_input_size_ = bottom[0]->count(concat_axis_ + 1);
  int bottom_count_sum = bottom[0]->count();//输入bottom[0]总像素点个数
  for (int i = 1; i < bottom.size(); ++i) {
    CHECK_EQ(num_axes, bottom[i]->num_axes())
        << "All inputs must have the same #axes.";
    for (int j = 0; j < num_axes; ++j) {
      if (j == concat_axis_) { continue; }
      CHECK_EQ(top_shape[j], bottom[i]->shape(j))
          << "All inputs must have the same shape, except at concat_axis.";
    }
    bottom_count_sum += bottom[i]->count();
    top_shape[concat_axis_] += bottom[i]->shape(concat_axis_);
  }
  top[0]->Reshape(top_shape);
  //将top转为bottom[0]->shape()的结构
  CHECK_EQ(bottom_count_sum, top[0]->count());
  if (bottom.size() == 1) {
    top[0]->ShareData(*bottom[0]);
    top[0]->ShareDiff(*bottom[0]);
  }
}

template <typename Dtype>
void ConcatLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top) {
  if (bottom.size() == 1) { return; }
  Dtype* top_data = top[0]->mutable_cpu_data();
  //top[0]在reshape中已经按照bottom的结构做了初始化,这里定义一个top_data的指针用于修改top中的数据
  int offset_concat_axis = 0;
  const int top_concat_axis = top[0]->shape(concat_axis_);
  for (int i = 0; i < bottom.size(); ++i) {
    const Dtype* bottom_data = bottom[i]->cpu_data();
    const int bottom_concat_axis = bottom[i]->shape(concat_axis_);
    for (int n = 0; n < num_concats_; ++n) {
      caffe_copy(bottom_concat_axis * concat_input_size_,
          bottom_data + n * bottom_concat_axis * concat_input_size_,
          top_data + (n * top_concat_axis + offset_concat_axis)
              * concat_input_size_);
      //这里复制一次内存位置就增加: 1 * bottom_concat_axis * concat_input_size_
      // 第一个参数bottom_concat_axis * concat_input_size_为每次可以复制的长度
      //以2个bottom为例,先将地址从bottom[0]至bottom[0]+n * bottom_concat_axis * concat_input_size_
      //按照每次bottom_concat_axis * concat_input_size_的长度进行复制,
      //复制给top_data指向的起始地址处开始,自然每次存储bottom_concat_axis * concat_input_size_长度的数据
      //然后将bottom[1]至bottom[1]+n * bottom_concat_axis * concat_input_size_
      //的数据复制到从top_data+(0 * top_concat_axis + offset_concat_axis)* concat_input_size_)开始
      //到top_data+(n * top_concat_axis + offset_concat_axis)* concat_input_size_)
    }
    offset_concat_axis += bottom_concat_axis;
  }
}

template <typename Dtype>
void ConcatLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
      const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {
  if (bottom.size() == 1) { return; }
  const Dtype* top_diff = top[0]->cpu_diff();
  int offset_concat_axis = 0;
  const int top_concat_axis = top[0]->shape(concat_axis_);
  for (int i = 0; i < bottom.size(); ++i) {
    const int bottom_concat_axis = bottom[i]->shape(concat_axis_);
    if (propagate_down[i]) {
      Dtype* bottom_diff = bottom[i]->mutable_cpu_diff();
      for (int n = 0; n < num_concats_; ++n) {
        caffe_copy(bottom_concat_axis * concat_input_size_, top_diff +
            (n * top_concat_axis + offset_concat_axis) * concat_input_size_,
            bottom_diff + n * bottom_concat_axis * concat_input_size_);
        //梯度与前向传播中数据concat是相反的,这里就需要把梯度从top_diff分开并分别存储到多个bottom_diff中
      }
    }
    offset_concat_axis += bottom_concat_axis;
  }
}

#ifdef CPU_ONLY
STUB_GPU(ConcatLayer);
#endif

INSTANTIATE_CLASS(ConcatLayer);
REGISTER_LAYER_CLASS(Concat);

}  // namespace caffe

猜你喜欢

转载自blog.csdn.net/lantuxin/article/details/83278630