CAFFE源码学习笔记之七-layer_factory以及layer基类
2017-04-01 16:34
357 查看
一、前言
caffe的几大基本模块中之一——Blob已经梳理完毕,现在该轮到Layer了。这一章先梳理layer基类和工厂类,为data_layer做一下铺垫。
Layer定义了layer的初始化,前向传播,后向传播。前向传播可以计算loss,后向传播计算梯度信息。
layer类是caffe中最为庞大的一类,所以作者使用工厂模式,这样当我们使用caffe中已经有的层或者自己定义的层时只需要注册就行了。
在运行期间,可以通过将LayerParameter protobuf参数传入函数就可以调用该层:
注册层的方式有两种:
其一、如果新建层是由其自身的构造函数创建的,注册如下:
其二、如果新建层由其他ctreator函数创建,形如:
那么可以通过如下方式注册:
注意:每层只能注册一次。
二、源码分析
1、layer类
(1)成员变量
(2)层的构造
构造函数完成层参数的传入,包括该层用于训练还是测试,层中存储权值的blob_。
注意构造函数不能是虚函数。
SetUp函数是自定义层的“构造函数”,主要做:
第一、检查输入和输出的数量;
第二、真正的setup layer;
第三、根据输入和内部结构重构输出的维度;
第四、设置loss权重;
下面是每个函数的详解:
检查输入输出的个数,有些层需要多个输入或者输出
设置每层的loss权重
(3)前向传播
在前向传播之前需要保证reshape函数已经将top修正到合适的维度。
前向传播可以计算loss,具体的前向计算在具体的层中不一样,所以后面单独讲。
(4)后向传播
后向传播不是每次一层都需要的。
二、layer_factory
1、创建层注册表:
2、注册creator:
3、根据参数调用层:
该类不能被实例化,怎么做?将构造函数置于private域中。
在c++11中,可以直接跟“=delete”
最后,作者将注册写成了宏:
caffe的几大基本模块中之一——Blob已经梳理完毕,现在该轮到Layer了。这一章先梳理layer基类和工厂类,为data_layer做一下铺垫。
Layer定义了layer的初始化,前向传播,后向传播。前向传播可以计算loss,后向传播计算梯度信息。
layer类是caffe中最为庞大的一类,所以作者使用工厂模式,这样当我们使用caffe中已经有的层或者自己定义的层时只需要注册就行了。
在运行期间,可以通过将LayerParameter protobuf参数传入函数就可以调用该层:
LayerRegistry<Dtype>::CreateLayer(param);
注册层的方式有两种:
其一、如果新建层是由其自身的构造函数创建的,注册如下:
REGISTER_LAYER_CLASS(layername);
其二、如果新建层由其他ctreator函数创建,形如:
template <typename Dtype> Layer<Dtype*> GetlayernameLayer(const LayerParameter& param) { // your implementation }
那么可以通过如下方式注册:
REGISTER_LAYER_CREATOR(layername, GetlayernameLayer)
注意:每层只能注册一次。
二、源码分析
1、layer类
(1)成员变量
/** protobuf 中存储的层参数*/ LayerParameter layer_param_; /** 状态: TRAIN or TEST */ Phase phase_; /** 学习参数 */ vector<shared_ptr<Blob<Dtype> > > blobs_; /** 是否进行后向传播的标志,数据层等都不进行后向传播 */ vector<bool> param_propagate_down_; /** loss权重,一般只有最后一层权重不为0,其余层都不计算loss */ vector<Dtype> loss_;
(2)层的构造
构造函数完成层参数的传入,包括该层用于训练还是测试,层中存储权值的blob_。
注意构造函数不能是虚函数。
explicit Layer(const LayerParameter& param) : layer_param_(param) { phase_ = param.phase(); if (layer_param_.blobs_size() > 0) { blobs_.resize(layer_param_.blobs_size());//通常blob_[0]是w,blob_[1]是b for (int i = 0; i < layer_param_.blobs_size(); ++i) { blobs_[i].reset(new Blob<Dtype>()); blobs_[i]->FromProto(layer_param_.blobs(i)); } } }
SetUp函数是自定义层的“构造函数”,主要做:
第一、检查输入和输出的数量;
第二、真正的setup layer;
第三、根据输入和内部结构重构输出的维度;
第四、设置loss权重;
void SetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { CheckBlobCounts(bottom, top); LayerSetUp(bottom, top); Reshape(bottom, top); SetLossWeights(top); }
下面是每个函数的详解:
virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {}//bottom是输入数据,也就是上一层的输出; //top是输出,但是这个输出没有经过reshape; //该函数主要完成的是读入层参数完成层的搭建。
virtual void Reshape(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) = 0; //根据输入数据的维度修改输出和中间buffer的维度信息
检查输入输出的个数,有些层需要多个输入或者输出
virtual void CheckBlobCounts(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top)
设置每层的loss权重
inline void SetLossWeights(const vector<Blob<Dtype>*>& top) { const int num_loss_weights = layer_param_.loss_weight_size(); if (num_loss_weights) { CHECK_EQ(top.size(), num_loss_weights) << "loss_weight must be " "unspecified or specified once per top blob."; for (int top_id = 0; top_id < top.size(); ++top_id) { const Dtype loss_weight = layer_param_.loss_weight(top_id); if (loss_weight == Dtype(0)) { continue; }//如果权重为0,直接跳过 this->set_loss(top_id, loss_weight); const int count = top[top_id]->count(); Dtype* loss_multiplier = top[top_id]->mutable_cpu_diff(); caffe_set(count, loss_weight, loss_multiplier);//将权重信息存在diff_blob中。 } } }
(3)前向传播
在前向传播之前需要保证reshape函数已经将top修正到合适的维度。
前向传播可以计算loss,具体的前向计算在具体的层中不一样,所以后面单独讲。
(4)后向传播
后向传播不是每次一层都需要的。
inline bool param_propagate_down(const int param_id) { return (param_propagate_down_.size() > param_id) ? param_propagate_down_[param_id] : false; } /** * @brief Sets whether the layer should compute gradients w.r.t. a * parameter at a particular index given by param_id. */ inline void set_param_propagate_down(const int param_id, const bool value) { if (param_propagate_down_.size() <= param_id) { param_propagate_down_.resize(param_id + 1, true); } param_propagate_down_[param_id] = value; }
二、layer_factory
1、创建层注册表:
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_; }
2、注册creator:
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; }
3、根据参数调用层:
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);//regisry[type]是函数指针
该类不能被实例化,怎么做?将构造函数置于private域中。
在c++11中,可以直接跟“=delete”
private: LayerRegistry() {}
最后,作者将注册写成了宏:
#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>) \ #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) } // namespace caffe
相关文章推荐
- CAFFE源码学习笔记之七-layer_factory以及layer基类
- CAFFE源码学习笔记之七-layer_factory以及layer基类
- CAFFE源码学习笔记之七-layer_factory以及layer基类
- CAFFE源码学习笔记之七-layer_factory以及layer基类
- CAFFE源码学习笔记之七-layer_factory以及layer基类
- CAFFE源码学习笔记之七-layer_factory以及layer基类
- CAFFE源码学习笔记之七-layer_factory以及layer基类
- CAFFE源码学习笔记之七-layer_factory以及layer基类
- CAFFE源码学习笔记之七-layer_factory以及layer基类
- CAFFE源码学习笔记之七-layer_factory以及layer基类
- CAFFE源码学习笔记之七-layer_factory以及layer基类
- CAFFE源码学习笔记之十一-卷积层conv_layer
- CAFFE源码学习笔记之内积层-inner_product_layer
- CAFFE源码学习笔记之内积层-inner_product_layer
- CAFFE源码学习笔记之十一-卷积层conv_layer
- CAFFE源码学习笔记之内积层-inner_product_layer
- CAFFE源码学习笔记之十一-卷积层conv_layer
- CAFFE源码学习笔记之十一-卷积层conv_layer
- CAFFE源码学习笔记之十一-卷积层conv_layer
- CAFFE源码学习笔记之内积层-inner_product_layer