[caffe笔记004]: caffe添加新层之添加maxout层
来源:互联网 发布:辛酉政变 知乎 编辑:程序博客网 时间:2024/05/16 17:44
针对2017年2月时caffe官网版本。
1. caffe官网中添加新层的流程
官方增加新层的流程可见如下链接:
https://github.com/BVLC/caffe/wiki/Development
- Add a class declaration for your layer to
include/caffe/layers/your_layer.hpp
.- Include an inline implementation of
type
overriding the methodvirtual inline const char* type() const { return "YourLayerName"; }
replacingYourLayerName
with your layer’s name. - Implement the
{*}Blobs()
methods to specify blob number requirements; see /caffe/include/caffe/layers.hpp to enforce strict top and bottom Blob counts using the inline{*}Blobs()
methods. - Omit the
*_gpu
declarations if you’ll only be implementing CPU code.
- Include an inline implementation of
- Implement your layer in
src/caffe/layers/your_layer.cpp
.- (optional)
LayerSetUp
for one-time initialization: reading parameters, fixed-size allocations, etc. Reshape
for computing the sizes of top blobs, allocating buffers, and any other work that depends on the shapes of bottom blobsForward_cpu
for the function your layer computesBackward_cpu
for its gradient (Optional – a layer can be forward-only)
- (optional)
- (Optional) Implement the GPU versions
Forward_gpu
andBackward_gpu
inlayers/your_layer.cu
. - If needed, declare parameters in
proto/caffe.proto
, using (and then incrementing) the “next available layer-specific ID” declared in a comment abovemessage LayerParameter
- Instantiate and register your layer in your cpp file with the macro provided in
layer_factory.hpp
. Assuming that you have a new layerMyAwesomeLayer
, you can achieve it with the following command:
INSTANTIATE_CLASS(MyAwesomeLayer);REGISTER_LAYER_CLASS(MyAwesome);
- Note that you should put the registration code in your own cpp file, so your implementation of a layer is self-contained.
- Optionally, you can also register a Creator if your layer has multiple engines. For an example on how to define a creator function and register it, see
GetConvolutionLayer
incaffe/layer_factory.cpp
. - Write tests in
test/test_your_layer.cpp
. Usetest/test_gradient_check_util.hpp
to check that your Forward and Backward implementations are in numerical agreement.
2. 增加新层实践
因为官网的只给出了流程,并没给出具体例子,因此将结合添加maxout层对整个流程进行说明。
旧版本添加maxout以及maxout原理可参考下面博客。
http://blog.csdn.net/kuaitoukid/article/details/41865803
Step1: 确定要添加的层的基类
相比于上面博客中旧版caffe对层的分类,现在的caffe中层的分类有所改变,去掉了vision层,直接由layer层派生。除此之外还有loss层,neuron层,以及data层。
- loss层和data层顾名思义,不加赘述
- 输入blob和输出blob的大小一样,从neuron层派生。例如激活层ReLU,以及逐点操作的exp层和power层。需要实现虚函数SetUp
,Forward_cpu
,Backward_cpu
。
- 输入blob和输出blob的大小不一样,直接从layer层派生。例如conv层,将要添加的maxout层。需要实现虚函数SetUp
,Reshape
,Forward_cpu
,Backward_cpu
Step2: caffe.proto定义该层的参数
- 添加Maxout LayerParameter的ID
在message LayerParameter
最后一行添加MyMaxoutParameter
,并将ID按顺序设置为没有用过的数字。
optional MyMaxoutParameter my_maxout_param = 147;
message LayerParameter
的注释中有最后添加的层名以及可用的ID号,为了便于以后使用,建议更改一下。
// NOTE// Update the next available ID when you add a new LayerParameter field.//// LayerParameter next available layer-specific ID: 147 (last added: recurrent_param)
- 添加Maxout layer的参数消息
在caffe.proto任意位置添加Maxout layer的参数消息:
// message that stores paremeters used to maxout layersmessage MyMaxoutParameter { // the number of output for this layer optional uint32 num_output = 1;}
- 添加Maxout layer的层名
在message V1LayerParameter
中的enum LayerType
添加Maxout层的层名:
MYMAXOUT = 40;
同时添加:
optional MyMaxoutParameter my_maxout_param = 43;
数字只要不重复就可以。
Step3: 增加maxout层的头文件到./include/caffe/layers/mymaxout.hpp
主要在MyMaxoutLayer
类中定义构造函数和SetUp
,Reshape
,Forward_cpu
,Backward_cpu
函数以及一些变量。
#ifndef CAFFE_MYMAXOUT_LAYER_HPP_#define CAFFE_MYMAXOUT_LAYER_HPP_#include <vector>#include "caffe/blob.hpp"#include "caffe/layer.hpp"#include "caffe/proto/caffe.pb.h"namespace caffe { template <typename Dtype> class MyMaxoutLayer : public Layer<Dtype> { public: explicit MyMaxoutLayer(const LayerParameter& param) : Layer<Dtype>(param) {} virtual inline const char* type() const { return "MyMaxout"; } virtual void SetUp(const vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>& top); virtual void Reshape(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top); protected: virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top); //virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom, // vector<Blob<Dtype>*>* top); virtual void Backward_cpu(const vector<Blob<Dtype>*>& top, const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom); //virtual void Backward_gpu(const vector<Blob<Dtype>*>& top, // const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom); int num_output_; int num_; int channels_; int height_; int width_; int group_size_; Blob<Dtype> max_idx_; }; }#endif
Step4: 增加maxout层的源文件到./src/caffe/layers/mymaxout.cpp SetUp
: 进行check Reshape
: 更改top blob的大小 Forward_cpu
: 实现正向传播 Backward_cpu
: 实现反向传播 REGISTER_LAYER_CLASS
: 最后注册层。
#include <cstdio> #include <vector> #include "caffe/util/im2col.hpp" #include "caffe/util/math_functions.hpp" #include "caffe/layers/mymaxout.hpp" namespace caffe { template <typename Dtype> void MyMaxoutLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>& top) { const MyMaxoutParameter& my_maxout_param = this->layer_param_.my_maxout_param(); CHECK(my_maxout_param.has_num_output()) << "num_output should be specified."; } template <typename Dtype> void MyMaxoutLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top){ num_output_ = this->layer_param_.my_maxout_param().num_output(); CHECK_GT(num_output_, 0) << "output number cannot be zero."; // bottom num_ = bottom[0]->num(); channels_ = bottom[0]->channels(); height_ = bottom[0]->height(); width_ = bottom[0]->width(); // TODO: generalize to handle inputs of different shapes. for (int bottom_id = 1; bottom_id < bottom.size(); ++bottom_id) { CHECK_EQ(num_, bottom[bottom_id]->num()) << "Inputs must have same num."; CHECK_EQ(channels_, bottom[bottom_id]->channels()) << "Inputs must have same channels."; CHECK_EQ(height_, bottom[bottom_id]->height()) << "Inputs must have same height."; CHECK_EQ(width_, bottom[bottom_id]->width()) << "Inputs must have same width."; } // Set the parameters, compute the group size CHECK_EQ(channels_ % num_output_, 0) << "Number of channel should be multiples of output number."; group_size_ = channels_ / num_output_; top[0]->Reshape(num_, num_output_, height_, width_); max_idx_.Reshape(num_, num_output_, height_, width_);}template <typename Dtype> void MyMaxoutLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { int featureSize = height_ * width_; Dtype* mask = NULL; mask = max_idx_.mutable_cpu_data(); //printf("1.maxout_forward\n"); const int top_count = top[0]->count(); caffe_set(top_count, Dtype(0), mask); //printf("2.maxout_forward\n"); 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 < num_; n ++) { for (int o = 0; o < num_output_; o ++) { for (int g = 0; g < group_size_; g ++) { if (g == 0) { for (int h = 0; h < height_; h ++) { // á?2??-?·óDμ??ù?aà? for (int w = 0; w < width_; w ++) { int index = w + h * width_; top_data[index] = bottom_data[index]; mask[index] = index; } } } else { for (int h = 0; h < height_; h ++) { for (int w = 0; w < width_; w ++) { int index0 = w + h * width_; int index1 = index0 + g * featureSize; if (top_data[index0] < bottom_data[index1]) { top_data[index0] = bottom_data[index1]; mask[index0] = index1; } } } } } bottom_data += featureSize * group_size_; top_data += featureSize; mask += featureSize; } } } } template <typename Dtype> void MyMaxoutLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top, const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) { if (!propagate_down[0]) { return; } // const Dtype* top_diff = top[0]->cpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); caffe_set(bottom[0]->count(), Dtype(0), bottom_diff); const Dtype* mask = max_idx_.mutable_cpu_data(); int featureSize = height_ * width_; for (int i = 0; i < top.size(); i ++) { const Dtype* top_diff = top[i]->cpu_diff(); Dtype* bottom_diff = bottom[i]->mutable_cpu_diff(); for (int n = 0; n < num_; n ++) { for (int o = 0; o < num_output_; o ++) { for (int h = 0; h < height_; h ++) { // á?2??-?·óDμ??ù?aà? for (int w = 0; w < width_; w ++) { int index = w + h * width_; int bottom_index = mask[index]; bottom_diff[bottom_index] += top_diff[index]; } } bottom_diff += featureSize * group_size_; top_diff += featureSize; mask += featureSize; } } } } #ifdef CPU_ONLYSTUB_GPU(MyMaxoutLayer);#endINSTANTIATE_CLASS(MyMaxoutLayer);REGISTER_LAYER_CLASS(MyMaxout); } // namespace caffe
Step5: 重新编译
make cleanmake all -j16
3. 注意事项
从layer层派生一定得实现四个虚函数
SetUp
,Reshape
,Forward_cpu
,Backward_cpu
;从neuron派生则不需要实现Reshape
函数。虚函数的函数名,函数返回值,函数参数以及参数类型必须得和基类中的定义一致,建议直接从基类中拷贝。否则可能在编译时报如下错误:
./include/caffe/layer_factory.hpp"135:67: error: cannot allocate an object of abstract type
- [caffe笔记004]: caffe添加新层之添加maxout层
- caffe添加新层教程
- caffe添加新层教程
- windows-caffe添加新层
- caffe添加新层windows
- caffe 添加一个新层
- Caffe-Windows添加新层
- caffe添加新层教程
- caffe中添加新层
- caffe添加一个新层
- caffe添加新的层
- caffe添加新层windows
- caffe添加新层windows
- caffe添加新层教程
- caffe添加新层教程
- caffe源码解析之添加新的Layer(maxout)
- caffe 添加Python层
- 在caffe中添加新的层
- 高精度除法
- 基于Opencv实现Matlab的bwmorph中的bridge操作
- android播放音频,视频的操作及注意事项
- java中的变量
- HDU1300 Pearls (动态规划)
- [caffe笔记004]: caffe添加新层之添加maxout层
- 【BATCH程序】反熊孩子神器
- 17.2 边缘触发和条件触发
- 函数
- MyBatis-学习笔记(3)——关联查询
- 《Spring实战》学习笔记(三)面向切面的Spring
- 最小二乘法概念简述
- codevs 舒适的路线 1001
- Matplotlib is building the font cache using fc-list. This may take a moment解决办法