Caffe内部维护一个注册表用于查找特定Layer对应的工厂函数(Layer Factory的设计用到了设计模式里的工厂模式)。Caffe的Layer注册表是一组键值对(key, value)( LayerRegistry里用map数据结构维护一个CreatorRegistry list, 保存各个Layer的creator的函数句柄),key为Layer的类型(Layer类名去掉后面的”Layer”字符串),value为其对应的工厂函数(creator的函数句柄):

typedef shared_ptr<Layer<Dtype> > (*Creator)(const LayerParameter&);
typedef std::map<string, Creator> CreatorRegistry;

注册表类型为CreatorRegistry,实际类型为std::map<string, Creator>。可以通过Registry 函数获取注册表的全局单例。而注册的过程就是一个map操作。

Caffe是通过宏定义的方式注册各种Layer,在编译阶段自动执行宏替换就注册了所有的Layer. 每一个Layer type只允许注册一次。使用两组宏来控制Layer的注册:

#define REGISTER_LAYER_CREATOR(type, creator)                                  \LayerRegisterer<float> g_creator_f_##type(#type, creator<float>);     \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)

REGISTER_LAYER_CLASS宏可以实现将指定Layer注册到全局注册表中,首先定义一个工厂函数用来产生Layer对象,然后调用REGISTER_LAYER_CREATOR将工厂函数和Layer的类型名进行注册,支持两种Layer的数据类型,float和double。两个变量一个对应float,一个对应double,这两个变量的初始化,也就是它们的构造函数实际上完成Layer的注册动作。REGISTER_LAYER_CLASS实际上是为每一个Layer创建一个creator函数.

LayerRegisterer对象初始化时(会调用LayerRegisterer类构造函数)实际上又是调用LayerRegistry类的静态方法 AddCreator函数。

以下是对Caffe code中layer_factory.hpp文件的注释:

/*** @brief A layer factory that allows one to register layers.* During runtime, registered layers could be called by passing a LayerParameter* protobuffer to the CreateLayer function:**     LayerRegistry<Dtype>::CreateLayer(param);** There are two ways to register a layer. Assuming that we have a layer like:**   template <typename Dtype>*   class MyAwesomeLayer : public Layer<Dtype> {*     // your implementations*   };** and its type is its C++ class name, but without the "Layer" at the end* ("MyAwesomeLayer" -> "MyAwesome").** If the layer is going to be created simply by its constructor, in your c++* file, add the following line:**    REGISTER_LAYER_CLASS(MyAwesome);** Or, if the layer is going to be created by another creator function, in the* format of:**    template <typename Dtype>*    Layer<Dtype*> GetMyAwesomeLayer(const LayerParameter& param) {*      // your implementation*    }** (for example, when your layer has multiple backends, see GetConvolutionLayer* for a use case), then you can register the creator function instead, like** REGISTER_LAYER_CREATOR(MyAwesome, GetMyAwesomeLayer)** Note that each layer type should only be registered once.*/#ifndef CAFFE_LAYER_FACTORY_H_
#define CAFFE_LAYER_FACTORY_H_#include <map>
#include <string>#include "caffe/common.hpp"
#include "caffe/proto/caffe.pb.h"namespace caffe {template <typename Dtype>
class Layer;// LayerRegistry:注册类,将每一个Layer的type(std::string)和对应的creator(函数指针)存放到一个map中
template <typename Dtype>
class LayerRegistry {public:// LayerRegistry里用map数据结构, 维护一个CreatorRegistry list, 保存各个layer的creator的函数句柄typedef shared_ptr<Layer<Dtype> > (*Creator)(const LayerParameter&); // 函数指针,返回Layer<Dtype>类型的指针typedef std::map<string, Creator> CreatorRegistry;// 获取注册表,内部注册表,静态函数,仅第一次调用时会new,其它直接returnstatic CreatorRegistry& Registry() { // 只创建一个map实例// 全局静态变量(map实例)static CreatorRegistry* g_registry_ = new CreatorRegistry();return *g_registry_;}// Adds a creator.// AddCreator函数用来向Registry列表中添加一组<type, creator>// 向map中加入一个映射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;}// Get a layer using a LayerParameter.// 在net.cpp中会被调用,在初始化整个网络的时候会根据参数文件中的层的类型去创建该层的实例static shared_ptr<Layer<Dtype> > CreateLayer(const LayerParameter& param) {if (Caffe::root_solver()) {LOG(INFO) << "Creating layer " << param.name();}const string& type = param.type(); // 从LayerParameter中获得字符串typeCreatorRegistry& registry = Registry(); // 获取注册表指针// 验证是否查找到给定type的creatorCHECK_EQ(registry.count(type), 1) << "Unknown layer type: " << type<< " (known types: " << LayerTypeList() << ")";return registry[type](param); // 根据layer name, 调用相应creator函数}private:// Layer registry should never be instantiated - everything is done with its// static variables.// 禁止实例化LayerRegistry() {}// 返回layer typestatic string LayerTypeList() {CreatorRegistry& registry = Registry(); // 获取注册表指针string layer_types;// 遍历注册表for (typename CreatorRegistry::iterator iter = registry.begin();iter != registry.end(); ++iter) {if (iter != registry.begin()) {layer_types += ", ";}layer_types += iter->first;}return layer_types;}
};// LayerRegisterer:Layer注册器,供后面的宏使用
template <typename Dtype>
class LayerRegisterer {public:// 向LayerRegistry的registry list中, 添加一个layer的creatorLayerRegisterer(const string& type,shared_ptr<Layer<Dtype> > (*creator)(const LayerParameter&)) {// LOG(INFO) << "Registering layer type: " << type;LayerRegistry<Dtype>::AddCreator(type, creator);}
};// 通过宏定义注册各种Layer
// 将创建layer对象的函数指针加入map
#define REGISTER_LAYER_CREATOR(type, creator)                                  \LayerRegisterer<float> g_creator_f_##type(#type, creator<float>);     \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#endif  // CAFFE_LAYER_FACTORY_H_

以下是用于获取所有层名的函数:

#include "funset.hpp"
#include "common.hpp"int get_layer_type_list()
{caffe::LayerRegistry<double>::CreatorRegistry& registry = caffe::LayerRegistry<double>::Registry();std::vector<std::string> layers_list;for (caffe::LayerRegistry<double>::CreatorRegistry::iterator iter = registry.begin(); iter != registry.end(); ++iter) {layers_list.push_back(iter->first);}fprintf(stdout, "layer count: %d\n", layers_list.size());for (int i = 0; i < layers_list.size(); i++) {fprintf(stdout, "%d:    %s\n", i+1, layers_list[i].c_str());}return 0;
}

执行结果如下:

GitHub: https://github.com/fengbingchun/Caffe_Test

Caffe中Layer注册机制相关推荐

  1. caffe中layer的一些特殊操作,比如split

    slice:在某一个维度,按照给定的下标,blob拆分成几块.比如要拆分channel,总数50,下标为10,20,30,40,那就是分成5份,每份10个channel,输出5个layer. conc ...

  2. Caffe中对MNIST执行train操作执行流程解析

    之前在 http://blog.csdn.net/fengbingchun/article/details/49849225 中简单介绍过使用Caffe train MNIST的文章,当时只是仿照ca ...

  3. TensorFlow中的设备管理——Device的创建与注册机制

    背景 [作者:DeepLearningStack,阿里巴巴算法工程师,开源TensorFlow Contributor] 作为一款优秀的异构深度学习算法框架,TensorFlow可以在多种设备上运行算 ...

  4. 在caffe中添加新层 L1 Loss layer

    本文地址:http://blog.csdn.net/ismarvellous/article/details/79069661,转载请注明出处. 本文涉及的所有完整文件可在我的github下载. 1. ...

  5. Caffe源码中layer文件分析

    Caffe源码(caffe version commit: 09868ac , date: 2015.08.15)中有一些重要的头文件,这里介绍下include/caffe/layer.hpp文件的内 ...

  6. 多线程 python layer_在Caffe中加Python Layer的方法

    Author: Zongwei Zhou | 周纵苇 Weibo: @MrGiovanni Email: zongweiz@asu.edu Acknowledgement: Md Rahman Sid ...

  7. caffe中的layer

    layer是神经网络搭建的脚手架,理解了layer,才能盖好神经网络这座摩天大楼. 下图是一张关于layer的思维导图,在功力到达一定程度的时候才可练此功,到时一定会有不一样的收获. 1. Outli ...

  8. Citrix XenDesktop 中VDA向DDC注册机制解析

    直接切入正题吧,至于什么是VDA?什么是DDC之类的我就不用做过多介绍了. 众所周知用户如果需要使用虚拟桌面,那么必须将虚拟桌面部署在DDC的交付组中并将虚拟桌面交付给用户.而且虚拟桌面在DDC中是已 ...

  9. caffe中的softmax layer

    在caffe中的lenet实现最后一层是softmax layer,输出分类的结果,下面就简单介绍一下softmax回归. 1,首先,在caffe中,softmax layer输出的是原始的输入在每一 ...

最新文章

  1. 2016年EDM营销新年策略分享
  2. mysql 回表查询优化_MySQL中的回表查询与索引覆盖:一次百万级别分页查询使用Limit 从90秒到0.6毫秒的优化...
  3. scala语言示例_var关键字与Scala中的示例
  4. ESP32 分区介绍
  5. android excel布局,Android实现仿excel数据表格效果
  6. 2021年中国机器人行业研究报告
  7. 计算多项式的值(信息学奥赛一本通-T1012)
  8. python cnn代码详解 keras_python – CNN返回相同的分类结果(keras)
  9. Linux 数据处理
  10. 免杀需要的基本汇编知识
  11. 逆战选择服务器后显示器,让你的画面更流畅 逆战FPS值调节方法
  12. 2021陈文灯数学复习指南百度云_【干货分享】21考研数学:高等数学常用公式、定理汇总(含打印版)...
  13. excel查标准正态分布_利用Excel的NORMSDIST计算正态分布函数表
  14. AirSim中的物理引擎
  15. 博客系统前端(页面设计)
  16. 计算机无法装补丁,Win7系统无法安装补丁提示缺少Service Pack系统组件的原因及解决方法...
  17. 奋斗者——一个高级咨询师是怎样炼成的
  18. Java做彩虹进度条,Android自定义控件-彩虹条进度条
  19. HDMI 收发器简化家庭影院系统设计
  20. 教程 | 如何使用地图可视化疫情情况

热门文章

  1. 程序员必备技能:如何画好架构图?
  2. matlab实现移动平均
  3. 剑指offer:面试题33. 二叉搜索树的后序遍历序列
  4. 浅谈Angular如何自定义创建指令@Directive
  5. CentOS 不区分大小写的搜索
  6. 永成科技C++笔试题
  7. Revit初学者完整指南 The Complete Revit Guide for Beginners
  8. Rocksdb Iterator实现:从DBIter 到 TwoLevelIter 的漫长链路
  9. (办公)网页发送到桌面快捷方式怎么做
  10. HDU 6229 Wandering Robots 找规律+离散化