caffe添加C++层和python层定义
2017-09-06 17:10
941 查看
caffe的网络层类型注册机制。
我们知道,caffe中有很多网络层(layer),每个层并单独定义成一个c++类,如卷积层class ConvolutionLayer、class PoolingLayer等。当我们自定义一个层结构,该如何融入caffe架构里去呢?为了实现这个目的,需要首先了解一下caffe层的构建机制。
在cpp源文件的最后,添加宏定义:
INSTANTIATE_CLASS(MytestLayer);
REGISTER_LAYER_CLASS(Mytest)
这两个宏定义大有来头,分析一下有助于理解caffe的构架
INSTANTIATE_CLASS(MytestLayer);
该宏定义只是在common.hpp中申明了一下MytestLayer 类,没有多少可说的
REGISTER_LAYER_CLASS(Mytest)
该宏定义是重点:
REGISTER_LAYER_CLASS定义如下,Creator_##type##Layer()函数返回层的指针,如:MytestLayer,与MytestLayer 类建立了联系。
内部调用REGISTER_LAYER_CREATOR(type, creator)宏,定义了两个静态(static)全局变量。
关注静态变量的类型为:LayerRegisterer,该类只有一个构造函数
调用LayerRegistry::AddCreator(type, creator); 静态成员函数,LayerRegistry类中的所有成员函数均是静态类型 static
registry 类型为std::map<string,Creator>,建立类别字符与类别指针的关系。key=“Mytest”,Creator=new MytestLayer()
每一个层源文件 *.cpp,均会自动调用此函数,并完成类型注册,生成层列表LayerTypeList
在 layer_factory.hpp 中:
然后便可利用python定义层接口。
查看layer_factory.hpp中python层定义接口:
PythonLayer.cpp
成员函数与python的对应关系:
LayerSetUp()—————->setup()
Reshape()—————->reshape()
Forward_cpu()—————->forward()
Backward_cpu()—————->backward()
网络初始化过程中,调用各层的layer::SetUp——>PythonLayer::LayerSetUp(bottom, top);完成最终的网络初始化。
一个小例子:
可以有多个python类型的层,可通过name属性作为区分。
我们知道,caffe中有很多网络层(layer),每个层并单独定义成一个c++类,如卷积层class ConvolutionLayer、class PoolingLayer等。当我们自定义一个层结构,该如何融入caffe架构里去呢?为了实现这个目的,需要首先了解一下caffe层的构建机制。
1. 编写源文件及头文件
首先,编写自己类(Mytest)的头文件、源文件:MytestLayer.hpp, MytestLayer.cpp在cpp源文件的最后,添加宏定义:
INSTANTIATE_CLASS(MytestLayer);
REGISTER_LAYER_CLASS(Mytest)
这两个宏定义大有来头,分析一下有助于理解caffe的构架
2. 分析宏定义
两个宏定义均可在layer_factory.hpp中查看。INSTANTIATE_CLASS(MytestLayer);
该宏定义只是在common.hpp中申明了一下MytestLayer 类,没有多少可说的
REGISTER_LAYER_CLASS(Mytest)
该宏定义是重点:
REGISTER_LAYER_CLASS定义如下,Creator_##type##Layer()函数返回层的指针,如:MytestLayer,与MytestLayer 类建立了联系。
#define REGISTER_LAYER_CLASS(type) \ template <typename Dtype> \ shared_ptr<Layer<Dtype> > Creator_##type##Layer(const LayerParameter& param) \ //函数指针!!!! { \ return shared_ptr<Layer<Dtype> >(new type##Layer<Dtype>(param)); \ } \ REGISTER_LAYER_CREATOR(type, Creator_##type##Layer)
内部调用REGISTER_LAYER_CREATOR(type, creator)宏,定义了两个静态(static)全局变量。
#define REGISTER_LAYER_CREATOR(type, creator) \ static LayerRegisterer<float> g_creator_f_##type(#type, creator<float>); \ static LayerRegisterer<double> g_creator_d_##type(#type, creator<double>) \
关注静态变量的类型为:LayerRegisterer,该类只有一个构造函数
template <typename Dtype> class LayerRegisterer { public: LayerRegisterer(const string& type, shared_ptr<Layer<Dtype> > (*creator)(const LayerParameter&)) { // LOG(INFO) << "Registering layer type: " << type; LayerRegistry<Dtype>::AddCreator(type, creator);/////静态成员函数 } };
调用LayerRegistry::AddCreator(type, creator); 静态成员函数,LayerRegistry类中的所有成员函数均是静态类型 static
template <typename Dtype> class LayerRegistry { public: typedef shared_ptr<Layer<Dtype> > (*Creator)(const LayerParameter&); typedef std::map<string, Creator> CreatorRegistry; static CreatorRegistry& Registry() { static CreatorRegistry* g_registry_ = new CreatorRegistry(); return *g_registry_; } // Adds a creator,将类别指针与“type”字符建立联系 static void AddCreator(const string& type, Creator creator) { CreatorRegistry& registry = Registry(); CHECK_EQ(registry.count(type), 0) << "Layer type " << type << " already registered."; registry[type] = creator; //////生成所有layer的类别列表 }
registry 类型为std::map<string,Creator>,建立类别字符与类别指针的关系。key=“Mytest”,Creator=new MytestLayer()
每一个层源文件 *.cpp,均会自动调用此函数,并完成类型注册,生成层列表LayerTypeList
3. 在Net中调用各层生成函数
Net中调用:layers_.push_back(LayerRegistry<Dtype>::CreateLayer(layer_param));
在 layer_factory.hpp 中:
// Get a layer using a LayerParameter. static shared_ptr<Layer<Dtype> > CreateLayer(const LayerParameter& param) { if (Caffe::root_solver()) { LOG(INFO) << "Creating layer " << param.name(); } const string& type = param.type(); CreatorRegistry& registry = Registry(); CHECK_EQ(registry.count(type), 1) << "Unknown layer type: " << type << " (known types: " << LayerTypeListString() << ")"; return registry[type](param); }
4 python定义层
打开python 层定义开关: WITH_PYTHON_LAYER := 1然后便可利用python定义层接口。
查看layer_factory.hpp中python层定义接口:
#ifdef WITH_PYTHON_LAYER template <typename Dtype> shared_ptr<Layer<Dtype> > GetPythonLayer(const LayerParameter& param) { Py_Initialize(); try { bp::object module = bp::import(param.python_param().module().c_str());///加载自己编写的python文件。是自定义python层与caffe之间的直接接口 bp::object layer = module.attr(param.python_param().layer().c_str())(param);///获取文件中python的层定义param参数 return bp::extract<shared_ptr<PythonLayer<Dtype> > >(layer)();////生成pythonLayer指针,查看PythonLayer定义 } catch (bp::error_already_set) { PyErr_Print(); throw; } } REGISTER_LAYER_CREATOR(Python, GetPythonLayer);//////////是不是有点眼熟? #endif
PythonLayer.cpp
namespace caffe { template <typename Dtype> class PythonLayer : public Layer<Dtype> { public: PythonLayer(PyObject* self, const LayerParameter& param) /////////////PythonLayer构造函数 : Layer<Dtype>(param), self_(bp::handle<>(bp::borrowed(self))) { } virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { // Disallow PythonLayer in MultiGPU training stage, due to GIL issues // Details: https://github.com/BVLC/caffe/issues/2936 if (this->phase_ == TRAIN && Caffe::solver_count() > 1 && !ShareInParallel()) { LOG(FATAL) << "PythonLayer is not implemented in Multi-GPU training"; } //////////python定义层的参数///////////////// self_.attr("param_str") = bp::str( this->layer_param_.python_param().param_str()); ////////////phase//////////////////// self_.attr("phase") = static_cast<int>(this->phase_); //////////调用setup()创建层/////////////////// self_.attr("setup")(bottom, top);//bottom与top已经初始化 } virtual void Reshape(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { self_.attr("reshape")(bottom, top); } virtual inline bool ShareInParallel() const { return this->layer_param_.python_param().share_in_parallel(); } virtual inline const char* type() const { return "Python"; } protected: virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { self_.attr("forward")(bottom, top); } virtual void Backward_cpu(const vector<Blob<Dtype>*>& top, const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) { self_.attr("backward")(top, propagate_down, bottom); } private: bp::object self_; }; } // namespace caffe
成员函数与python的对应关系:
LayerSetUp()—————->setup()
Reshape()—————->reshape()
Forward_cpu()—————->forward()
Backward_cpu()—————->backward()
网络初始化过程中,调用各层的layer::SetUp——>PythonLayer::LayerSetUp(bottom, top);完成最终的网络初始化。
layers_[layer_id]->SetUp(bottom_vecs_[layer_id], top_vecs_[layer_id]);
一个小例子:
layer { name: "data" type: "Python" ##pythonLayer类型 top: "data" top: "sem" top: "geo" python_param { ### 以下三个属性参数必不可少 module: "siftflow_layers" layer: "SIFTFlowSegDataLayer" param_str: "{\'siftflow_dir\': \'../data/sift-flow\', \'seed\': 1337, \'split\': \'trainval\'}" } } layer { name: "conv1_1" type: "Convolution" bottom: "data" top: "conv1_1" param { lr_mult: 1 decay_mult: 1 } param { lr_mult: 2 decay_mult: 0 } convolution_param { num_output: 64 pad: 100 kernel_size: 3 stride: 1 } }
可以有多个python类型的层,可通过name属性作为区分。
相关文章推荐
- [转]caffe中添加C++的自定义新层
- caffe添加一个新的层——c++版本
- Windows下cmake编译caffe,实现纯C++版本MTCNN人脸检测和关键点定位
- opencv(c++)OpenCV添加(混合)两个图像
- 为caffe添加最简单的全通层AllPassLayer
- 爱大鸟LoveShootBirds弱联网移动SDK添加(C++调Java)
- vs2008 c++中添加一个按钮需要添加消息处理函数
- 使用VAssistX为VS2008 c++代码添加函数头注释
- 20170226C++项目班08_修复bug/函数添加
- Caffemodel数据结构解析与Protocol Buffer技术详解(C++实例)
- C++项目添加依赖项
- 使用C/C++给静态类型数据添加运算符重载功能
- C++ MFC中添加自定义消息映射宏及添加消息响应函数
- vs2010 2012 c++ 为项目添加不同目录下文件方法
- VS2008 C++ 项目怎样添加“依赖”、“库目录”和“包含目录”
- Caffe实现多标签输入,添加数据层(data layer)
- 检查C++中的内存泄漏-通过添加代码来检测
- C++实现自动为对象添加“属性”访问代码
- caffe中添加新层
- C++ NLPIR+FRISO 项目的中文分词功能添加