caffe源碼分析--poolinger_layer.cpp

來源:互聯網
上載者:User

標籤:caffe   deep learning   機器學習   源碼分析   神經網路   


caffe源碼分析--poolinger_layer.cpp


對於採樣層,cafffe裡實現了最大採樣和平均採樣的演算法。

最大採樣,給定一個掃描視窗,找最大值,

平均採樣,掃描視窗內所有值的平均值。


其實對於caffe的實現一直有個疑問,

就是每一層貌似沒有綁定一個啟用函數?

看ufldl教程,感覺啟用函數是必要存在的。

這怎麼解釋呢?


看到源碼中,看到一些啟用函數,比如sigmoid_layer.cpp和sigmoid_layer.cu。

也就是說,啟用函數作為layer層面來實現了。當然,還有tanh_layer和relu_layer。


那,這個意思是說,讓我們建立網路的時候更加隨意,可自由搭配啟用函數嗎?

但是,我看了caffe內建的那些例子,貌似很少見到用了啟用函數layer的,頂多看到用了relu_layer,其他的沒見過。

這意思是說,啟用函數不重要嗎?真是費解啊。


// Copyright 2013 Yangqing Jia#include <algorithm>#include <cfloat>#include <vector>#include "caffe/layer.hpp"#include "caffe/vision_layers.hpp"#include "caffe/util/math_functions.hpp"using std::max;using std::min;namespace caffe {template <typename Dtype>void PoolingLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,      vector<Blob<Dtype>*>* top) {  CHECK_EQ(bottom.size(), 1) << "PoolingLayer takes a single blob as input.";  CHECK_EQ(top->size(), 1) << "PoolingLayer takes a single blob as output.";  KSIZE_ = this->layer_param_.kernelsize();//核大小  STRIDE_ = this->layer_param_.stride();//步長  CHANNELS_ = bottom[0]->channels();//通道  HEIGHT_ = bottom[0]->height();//高  WIDTH_ = bottom[0]->width();//寬  POOLED_HEIGHT_ = static_cast<int>(      ceil(static_cast<float>(HEIGHT_ - KSIZE_) / STRIDE_)) + 1;//計算採樣之後的高  POOLED_WIDTH_ = static_cast<int>(      ceil(static_cast<float>(WIDTH_ - KSIZE_) / STRIDE_)) + 1;//計算採樣之後的寬  (*top)[0]->Reshape(bottom[0]->num(), CHANNELS_, POOLED_HEIGHT_,//採樣之後大小      POOLED_WIDTH_);  // If stochastic pooling, we will initialize the random index part.  if (this->layer_param_.pool() == LayerParameter_PoolMethod_STOCHASTIC) {    rand_idx_.Reshape(bottom[0]->num(), CHANNELS_, POOLED_HEIGHT_,      POOLED_WIDTH_);  }}// TODO(Yangqing): Is there a faster way to do pooling in the channel-first// case?template <typename Dtype>void PoolingLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,      vector<Blob<Dtype>*>* top) {  const Dtype* bottom_data = bottom[0]->cpu_data();//採樣層輸入  Dtype* top_data = (*top)[0]->mutable_cpu_data();//採樣層輸出  // Different pooling methods. We explicitly do the switch outside the for  // loop to save time, although this results in more codes.  int top_count = (*top)[0]->count();  switch (this->layer_param_.pool()) {  case LayerParameter_PoolMethod_MAX://最大採樣方法    // Initialize    for (int i = 0; i < top_count; ++i) {      top_data[i] = -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_;            int wstart = pw * STRIDE_;            int hend = min(hstart + KSIZE_, HEIGHT_);            int wend = min(wstart + KSIZE_, WIDTH_);            for (int h = hstart; h < hend; ++h) {//找出核範圍內最大              for (int w = wstart; w < wend; ++w) {                top_data[ph * POOLED_WIDTH_ + pw] =                  max(top_data[ph * POOLED_WIDTH_ + pw],                      bottom_data[h * WIDTH_ + w]);              }            }          }        }        // compute offset 指標移動到下一個channel。注意代碼這裡的位置。採樣是針對每個channel的。        bottom_data += bottom[0]->offset(0, 1);        top_data += (*top)[0]->offset(0, 1);      }    }    break;  case LayerParameter_PoolMethod_AVE:    for (int i = 0; i < top_count; ++i) {      top_data[i] = 0;    }    // 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_;            int wstart = pw * STRIDE_;            int hend = min(hstart + KSIZE_, HEIGHT_);            int wend = min(wstart + KSIZE_, WIDTH_);            for (int h = hstart; h < hend; ++h) {//核範圍內算平均              for (int w = wstart; w < wend; ++w) {                top_data[ph * POOLED_WIDTH_ + pw] +=                    bottom_data[h * WIDTH_ + w];              }            }            top_data[ph * POOLED_WIDTH_ + pw] /=                (hend - hstart) * (wend - wstart);          }        }        // compute offset        bottom_data += bottom[0]->offset(0, 1);        top_data += (*top)[0]->offset(0, 1);      }    }    break;  case LayerParameter_PoolMethod_STOCHASTIC://這種演算法這裡未實現    NOT_IMPLEMENTED;    break;  default:    LOG(FATAL) << "Unknown pooling method.";  }}template <typename Dtype>Dtype PoolingLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,      const bool propagate_down, vector<Blob<Dtype>*>* bottom) {  if (!propagate_down) {    return Dtype(0.);  }  const Dtype* top_diff = top[0]->cpu_diff();  const Dtype* top_data = top[0]->cpu_data();  const Dtype* bottom_data = (*bottom)[0]->cpu_data();  Dtype* bottom_diff = (*bottom)[0]->mutable_cpu_diff();  // Different pooling methods. We explicitly do the switch outside the for  // loop to save time, although this results in more codes.  memset(bottom_diff, 0, (*bottom)[0]->count() * sizeof(Dtype));  switch (this->layer_param_.pool()) {  case LayerParameter_PoolMethod_MAX:    // The main loop    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) {            int hstart = ph * STRIDE_;            int wstart = pw * STRIDE_;            int hend = min(hstart + KSIZE_, HEIGHT_);            int wend = min(wstart + KSIZE_, WIDTH_);            for (int h = hstart; h < hend; ++h) {              for (int w = wstart; w < wend; ++w) {                bottom_diff[h * WIDTH_ + w] +=//採樣層輸出的殘傳播給輸入。由於是最大採樣方法,輸出存的都是輸入範圍內最大的值,所以殘差傳播的時候也只有範圍內最大的值受影響                    top_diff[ph * POOLED_WIDTH_ + pw] *                    (bottom_data[h * WIDTH_ + w] ==                        top_data[ph * POOLED_WIDTH_ + pw]);              }            }          }        }        // offset  移動到下一個channel        bottom_data += (*bottom)[0]->offset(0, 1);        top_data += top[0]->offset(0, 1);        bottom_diff += (*bottom)[0]->offset(0, 1);        top_diff += top[0]->offset(0, 1);      }    }    break;  case LayerParameter_PoolMethod_AVE:    // The main loop    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) {            int hstart = ph * STRIDE_;            int wstart = pw * STRIDE_;            int hend = min(hstart + KSIZE_, HEIGHT_);            int wend = min(wstart + KSIZE_, WIDTH_);            int poolsize = (hend - hstart) * (wend - wstart);            for (int h = hstart; h < hend; ++h) {              for (int w = wstart; w < wend; ++w) {                bottom_diff[h * WIDTH_ + w] +=//採樣層輸出的殘差傳播給輸入,由於是平均採樣,所以權重都是1 / poolsize。                  top_diff[ph * POOLED_WIDTH_ + pw] / poolsize;              }            }          }        }        // offset        bottom_data += (*bottom)[0]->offset(0, 1);        top_data += top[0]->offset(0, 1);        bottom_diff += (*bottom)[0]->offset(0, 1);        top_diff += top[0]->offset(0, 1);      }    }    break;  case LayerParameter_PoolMethod_STOCHASTIC:    NOT_IMPLEMENTED;    break;  default:    LOG(FATAL) << "Unknown pooling method.";  }  return Dtype(0.);}INSTANTIATE_CLASS(PoolingLayer);}  // namespace caffe

本文linger
本文連結:http://blog.csdn.net/lingerlanlan/article/details/38294169

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.