您的位置:首页 > 编程语言 > C语言/C++

caffe添加C++层和python层定义

2017-09-06 17:10 941 查看
caffe的网络层类型注册机制。

我们知道,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属性作为区分。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: