学习笔记: 源码 pooling_layer.cpp 略懂

来源:互联网 发布:淘宝游戏账号出售 编辑:程序博客网 时间:2024/05/22 11:30
PoolingLayer 相比于 ConvolutionLayer 简单多了……
Layer 三步走:SetUp,Forward 和 Backward.

1. LayerSetUp()
存储相应的layer param,例如 kernel_h, kernel_w,stride 等等。

2. Reshape()
根据 bottom 的形状大小对 top 进行形状大小的计算,并对top进行Reshape(),内存分配。
此外,如果 pooling 层是 max pooling,在 pooling_layer 还会有一个 数据成员 max_idx_ 来进行记录 pooling 过程中局部的 max 的 index。max_idx_ 的 blob 形状大小和 top一样。

3. Forward_cpu()
在 forward 的函数中,利用 switch case 选择 pooling 的类型(e.g. max, ave)。
这里只分析 max pooling。
case PoolingParameter_PoolMethod_MAX:...      mask = max_idx_.mutable_cpu_data();      caffe_set(top_count, -1, mask);...    caffe_set(top_count, Dtype(-FLT_MAX), top_data);   //FLT_MAX 正浮点数最大值    // The main loop    for (int n = 0; n < bottom[0]->num(); ++n) {      for (int c = 0; c < channels_; ++c) {        for (int ph = 0; ph < pooled_height_; ++ph) {          for (int pw = 0; pw < pooled_width_; ++pw) {            int hstart = ph * stride_h_ - pad_h_;            int wstart = pw * stride_w_ - pad_w_;            int hend = min(hstart + kernel_h_, height_);            int wend = min(wstart + kernel_w_, width_);            hstart = max(hstart, 0);            wstart = max(wstart, 0);            const int pool_index = ph * pooled_width_ + pw;   //pool_index 对应 top的位置            for (int h = hstart; h < hend; ++h) {  // 在小块中求最大值赋予top_data              for (int w = wstart; w < wend; ++w) {   //相应的mask[pool_index] 记录最大值的index                const int index = h * width_ + w;                // index 对应 bottom 的位置                if (bottom_data[index] > top_data[pool_index]) {                  top_data[pool_index] = bottom_data[index];                  if (use_top_mask) {                    top_mask[pool_index] = static_cast<Dtype>(index);                  } else {                    mask[pool_index] = index;        } } } } } }         // compute offset        bottom_data += bottom[0]->offset(0, 1);        top_data += top[0]->offset(0, 1);  //top_data 指针偏移一个channel_dim( = height * width)        if (use_top_mask) {          top_mask += top[0]->offset(0, 1);        } else {          mask += top[0]->offset(0, 1);    }  }  }    break;  inline int offset(const int n, const int c = 0, const int h = 0,        //计算blob在(n, c, h, w)坐标下相应      const int w = 0) const {                                                          //内存的index...    return ((n * channels() + c) * height() + h) * width() + w;  }

4. Backward_cpu()
case PoolingParameter_PoolMethod_MAX:    // The main loop    if (use_top_mask) {      top_mask = top[1]->cpu_data();    } else {      mask = max_idx_.cpu_data();    }    for (int n = 0; n < top[0]->num(); ++n) {      for (int c = 0; c < channels_; ++c) {        for (int ph = 0; ph < pooled_height_; ++ph) {          for (int pw = 0; pw < pooled_width_; ++pw) {            const int index = ph * pooled_width_ + pw;  //这里的index是对应top 的index            const int bottom_index =                use_top_mask ? top_mask[index] : mask[index];            bottom_diff[bottom_index] += top_diff[index];                 }        }        bottom_diff += bottom[0]->offset(0, 1);        top_diff += top[0]->offset(0, 1);        if (use_top_mask) {          top_mask += top[0]->offset(0, 1);        } else {          mask += top[0]->offset(0, 1);    } } }    break;

在 max pooling 的后向传播中,只将梯度传播给起作用的 bottom_data,我们在 max_idx_ 中有记录。即只将 top_diff 直接赋给起作用的 bottom_diff,而其他没有起作用的bottom_diff = 0。



0 0