Caffe源码中Pooling Layer文件分析
Caffe源碼(caffe version commit: 09868ac , date: 2015.08.15)中有一些重要的頭文件,這里介紹下include/caffe/vision_layers文件中PoolingLayer類,在最新版caffe中,PoolingLayer類被單獨(dú)放在了include/caffe/layers/pooling_layer.hpp文件中,這兩個(gè)文件中PoolingLayer類的內(nèi)容及實(shí)現(xiàn)是完全一致的:
1.? include文件:
(1)、<caffe/blob.hpp>:此文件的介紹可以參考:http://blog.csdn.net/fengbingchun/article/details/59106613
(2)、<caffe/layer.hpp>:此文件的介紹可以參考:http://blog.csdn.net/fengbingchun/article/details/60871052
(3)、<caffe/proto/caffe.pb.h>:此文件的介紹可以參考:http://blog.csdn.net/fengbingchun/article/details/55267162
2.? 類PoolingLayer:池化層,Layer類的子類
Pooling layer的主要作用是降維,縮小feature map,圖像降采樣,方法有:
(1)、均值采樣:取區(qū)域平均值作為降采樣值;
(2)、最大值采樣:取區(qū)域最大值作為降采樣值;
(3)、隨機(jī)采樣:取區(qū)域內(nèi)隨機(jī)一個(gè)像素值。
<caffe/layers/pooling_layer.hpp>文件的詳細(xì)介紹如下:
#ifndef CAFFE_POOLING_LAYER_HPP_
#define CAFFE_POOLING_LAYER_HPP_#include <vector>#include "caffe/blob.hpp"
#include "caffe/layer.hpp"
#include "caffe/proto/caffe.pb.h"namespace caffe {
/*** @brief Pools the input image by taking the max, average, etc. within regions.** TODO(dox): thorough documentation for Forward, Backward, and proto params.*/
// 池化層,Layer類的子類,圖像降采樣,有三種Pooling方法:Max、Avx、Stochastic
template <typename Dtype>
class PoolingLayer : public Layer<Dtype> {public:
// 顯示構(gòu)造函數(shù)explicit PoolingLayer(const LayerParameter& param) : Layer<Dtype>(param) {}
// 參數(shù)初始化,通過類PoolingParameter獲取成員變量值,包括:
// global_pooling_、kernel_h_、kernel_w_、pad_h_、pad_w_、stride_h_、stride_w_virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top);
// 調(diào)整top blobs的shape,并有可能會(huì)reshape rand_idx_或max_idx_;
// 獲取成員變量值,包括:channels_、height_、width_、pooled_height_、pooled_width_virtual void Reshape(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top);
// 獲得Pooling layer的類型: Poolingvirtual inline const char* type() const { return "Pooling"; }
// 獲得Pooling layer所需的bottom blobs的個(gè)數(shù): 1virtual inline int ExactNumBottomBlobs() const { return 1; }
// 獲得Pooling layer所需的bottom blobs的最少個(gè)數(shù): 1virtual inline int MinTopBlobs() const { return 1; }// MAX POOL layers can output an extra top blob for the mask;// others can only output the pooled inputs.
// 獲得Pooling layer所需的bottom blobs的最多個(gè)數(shù): Max為2,其它(Avg, Stochastic)為1virtual inline int MaxTopBlobs() const {return (this->layer_param_.pooling_param().pool() ==PoolingParameter_PoolMethod_MAX) ? 2 : 1;}protected:
// CPU實(shí)現(xiàn)Pooling layer的前向傳播,僅有Max和Ave兩種方法實(shí)現(xiàn)virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top);
// GPU實(shí)現(xiàn)Pooling layer的前向傳播,Max、Ave、Stochastic三種方法實(shí)現(xiàn)virtual void Forward_gpu(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top);
// CPU實(shí)現(xiàn)Pooling layer的反向傳播,僅有Max和Ave兩種方法實(shí)現(xiàn)virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);
// GPU實(shí)現(xiàn)Pooling layer的反向傳播,Max、Ave、Stochastic三種方法實(shí)現(xiàn)virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);// Caffe中類的成員變量名都帶有后綴"_",這樣就容易區(qū)分臨時(shí)變量和類成員變量int kernel_h_, kernel_w_; // 濾波器(卷積核)大小int stride_h_, stride_w_; // 步長(zhǎng)大小int pad_h_, pad_w_; // 圖像擴(kuò)充大小int channels_; // 圖像通道數(shù)int height_, width_; // 圖像高、寬
// 池化后圖像高、寬
// pooled_height_ = (height_ + 2 * pad_h_ - kernel_h_) / stride_h_)) + 1
// pooled_width_ = (width_ + 2 * pad_w_ - kernel_w_) / stride_w_)) + 1int pooled_height_, pooled_width_;bool global_pooling_; // 是否全區(qū)域池化(將整幅圖像降采樣為1*1)Blob<Dtype> rand_idx_; // 隨機(jī)采樣索引,Pooling方法為STOCHASTIC時(shí)用到并會(huì)ReshapeBlob<int> max_idx_; // 最大值采樣索引,Pooling方法為MAX時(shí)用到并會(huì)Reshape
};} // namespace caffe#endif // CAFFE_POOLING_LAYER_HPP_
在caffe.proto文件中,有一個(gè)message是與pooling layer
相關(guān)的,如下:
message PoolingParameter { // Pooling層參數(shù)類enum PoolMethod { // 枚舉類型,Pooling的方法:Max(最大值采樣)、AVE(均值采樣)、STOCHASTIC(隨機(jī)采樣)MAX = 0;AVE = 1;STOCHASTIC = 2;}optional PoolMethod pool = 1 [default = MAX]; // The pooling method, pooling方法// Pad, kernel size, and stride are all given as a single value for equal// dimensions in height and width or as Y, X pairs.optional uint32 pad = 4 [default = 0]; // The padding size (equal in Y, X),圖像擴(kuò)充大小(添加圖像邊界的像素大小)optional uint32 pad_h = 9 [default = 0]; // The padding height,圖像擴(kuò)充大小,Yoptional uint32 pad_w = 10 [default = 0]; // The padding width,圖像擴(kuò)充大小,Xoptional uint32 kernel_size = 2; // The kernel size (square),濾波器(卷積核、滑動(dòng)窗)的大小(高=寬)optional uint32 kernel_h = 5; // The kernel height,濾波器(卷積核、滑動(dòng)窗)的高optional uint32 kernel_w = 6; // The kernel width,濾波器(卷積核、滑動(dòng)窗)的寬optional uint32 stride = 3 [default = 1]; // The stride (equal in Y, X),滑動(dòng)步長(zhǎng)(高=寬),卷積核卷積時(shí)平移的步幅optional uint32 stride_h = 7; // The stride height,滑動(dòng)步長(zhǎng),高optional uint32 stride_w = 8; // The stride width,滑動(dòng)步長(zhǎng),寬enum Engine {DEFAULT = 0;CAFFE = 1;CUDNN = 2;}optional Engine engine = 11 [default = DEFAULT]; //// If global_pooling then it will pool over the size of the bottom by doing// kernel_h = bottom->height and kernel_w = bottom->widthoptional bool global_pooling = 12 [default = false]; // 是否是全區(qū)域池化
}
pooling layer的測(cè)試代碼如下:
#include "funset.hpp"
#include <string>
#include <vector>
#include "common.hpp"int test_caffe_layer_pooling()
{caffe::Caffe::set_mode(caffe::Caffe::CPU); // set run caffe mode// set layer parametercaffe::LayerParameter layer_param;layer_param.set_phase(caffe::Phase::TRAIN);// cv::Mat -> caffe::Blobstd::string image_name = "E:/GitCode/Caffe_Test/test_data/images/a.jpg";cv::Mat mat1 = cv::imread(image_name, 1);if (!mat1.data) {fprintf(stderr, "read image fail: %s\n", image_name.c_str());return -1;}mat1.convertTo(mat1, CV_32FC3);std::vector<cv::Mat> mat2;cv::split(mat1, mat2);std::vector<int> mat_reshape{ 1, (int)mat2.size(), mat2[0].rows, mat2[0].cols };caffe::Blob<float> blob;blob.Reshape(mat_reshape);size_t size = mat2[0].rows * mat2[0].cols;float* data = new float[mat2.size() * size];memcpy(data, mat2[0].data, size * sizeof(float));memcpy(data + size, mat2[1].data, size * sizeof(float));memcpy(data + 2 * size, mat2[2].data, size * sizeof(float));blob.set_cpu_data(data);for (int method = 0; method < 2; ++method) {// set pooling parametercaffe::PoolingParameter* pooling_param = layer_param.mutable_pooling_param();if (method == 0) pooling_param->set_pool(caffe::PoolingParameter::MAX);else pooling_param->set_pool(caffe::PoolingParameter::AVE);pooling_param->set_kernel_size(3);pooling_param->set_pad(2);pooling_param->set_stride(2);pooling_param->set_global_pooling(false);std::vector<caffe::Blob<float>*> bottom_blob{ &blob }, top_blob{ &caffe::Blob<float>()/*, &caffe::Blob<float>() */ };// test PoolingLayer functioncaffe::PoolingLayer<float> pooling_layer(layer_param);pooling_layer.SetUp(bottom_blob, top_blob);fprintf(stderr, "top blob info: channels: %d, height: %d, width: %d\n",top_blob[0]->channels(), top_blob[0]->height(), top_blob[0]->width());pooling_layer.Forward(bottom_blob, top_blob);int height = top_blob[0]->height();int width = top_blob[0]->width();const float* p = top_blob[0]->cpu_data();std::vector<cv::Mat> mat3{ cv::Mat(height, width, CV_32FC1, (float*)p),cv::Mat(height, width, CV_32FC1, (float*)(p + height * width)),cv::Mat(height, width, CV_32FC1, (float*)(p + height * width * 2)) };cv::Mat mat4;cv::merge(mat3, mat4);mat4.convertTo(mat4, CV_8UC3);if (method == 0) image_name = "E:/GitCode/Caffe_Test/test_data/images/forward0.jpg";else image_name = "E:/GitCode/Caffe_Test/test_data/images/forward1.jpg";cv::imwrite(image_name, mat4);for (int i = 0; i < bottom_blob[0]->count(); ++i)bottom_blob[0]->mutable_cpu_diff()[i] = bottom_blob[0]->cpu_data()[i];for (int i = 0; i < top_blob[0]->count(); ++i)top_blob[0]->mutable_cpu_diff()[i] = top_blob[0]->cpu_data()[i];std::vector<bool> propagate_down{ true };pooling_layer.Backward(top_blob, propagate_down, bottom_blob);height = bottom_blob[0]->height();width = bottom_blob[0]->width();p = bottom_blob[0]->cpu_diff();std::vector<cv::Mat> mat5{ cv::Mat(height, width, CV_32FC1, (float*)p),cv::Mat(height, width, CV_32FC1, (float*)(p + height * width)),cv::Mat(height, width, CV_32FC1, (float*)(p + height * width * 2)) };cv::Mat mat6;cv::merge(mat5, mat6);mat6.convertTo(mat6, CV_8UC3);if (method == 0) image_name = "E:/GitCode/Caffe_Test/test_data/images/backward0.jpg";else image_name = "E:/GitCode/Caffe_Test/test_data/images/backward1.jpg";cv::imwrite(image_name, mat6);}delete[] data;return 0;
}
執(zhí)行結(jié)果如下圖:
圖像結(jié)果(Lena.jpg)如下:前向傳播、反向傳播,前兩幅為Max,后兩幅為Avg方法
GitHub:https://github.com/fengbingchun/Caffe_Test
總結(jié)
以上是生活随笔為你收集整理的Caffe源码中Pooling Layer文件分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Caffe源码中layer文件分析
- 下一篇: Ubuntu14.04 LTS中安装Ru