当前位置: 首页 > 编程日记 > 正文

Caffe中Layer注册机制

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

相关文章:

自动驾驶行业观察 | 停车不再难,L2到L4的泊车辅助系统技术剖析

作者 | 陈光来源 | 自动驾驶干货铺&#xff08;ID:IntelligentDrive&#xff09;【导读】在汽车智能化的浪潮中&#xff0c;车载传感器发展迅速&#xff0c;越来越多搭载了先进传感器的汽车进入了我们的视野。比如能够在高速公路上实现单车道巡航的凯迪拉克CT6&#xff0c;以及…

Unity Log重新定向

Unity Log重新定向 使用Unity的Log的时候有时候需要封装一下Debug.Log(message)&#xff0c;可以屏蔽Log或者把log内容写到文本中。通过把文本内容传送到服务器中&#xff0c;查找bug出现的原因。但是封装之后的日志系统如果双击跳转的时候&#xff0c;会跳转到自定义的日志系统…

Javascript 检查一组 radio 中的哪一个被勾选

2019独角兽企业重金招聘Python工程师标准>>> 以前检查单选按钮是否被选择时&#xff0c;我使用的是 if else 一个一个的检查其 checked 属性。 这样虽然可以&#xff0c;但是当一组 radio 有很多个时&#xff0c;就很麻烦了。 可以通过 getElementsByName 得到所有…

二维码Aztec简介及其解码实现(zxing-cpp)

Aztec Code是1995年&#xff0c;由Hand HeldProducts公司的Dr. Andrew Longacre设计。它是一种高容量的二维条形码格式。它可以对ASCII和扩展ASCII码进行编码。当使用最高容量和25%的纠错级别的時候&#xff0c;Aztec可以对3000个字符或者3750个数字进行编码。Aztec的矩阵大小在…

顶配12699 元、没有5G,“浴霸三摄”的iPhone你会买吗?

作者 | 屠敏出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;北京时间 9 月 11 日凌晨 1 点&#xff0c;以「Apple 特别活动」为主题的苹果秋季发布会正式于史蒂夫乔布斯剧院拉开帷幕。按照惯例&#xff0c;在发布会之前&#xff0c;业界“毫不留情”地对新品进行了…

阿里P7架构师告诉你Java架构师必须知道的 6 大设计原则

在软件开发中&#xff0c;前人对软件系统的设计和开发总结了一些原则和模式&#xff0c; 不管用什么语言做开发&#xff0c;都将对我们系统设计和开发提供指导意义。本文主要将总结这些常见的原则&#xff0c;和具体阐述意义。 开发原则 面向对象的基本原则(solid)是五个&#…

rhel6用centos163 yum源

cd /etc/yum.repos.d/wget wget http://mirrors.163.com/.help/CentOS6-Base-163.reposed -i "s/\$releasever/6/" CentOS6-Base-163.repo

打破深度学习局限,强化学习、深度森林或是企业AI决策技术的“良药”

算法、算力和数据是人工智能时代的三驾马车&#xff0c;成为企业赋能人工智能的动力&#xff0c;但它们自身的特性也为企业和高校在研究和落地应用过程带来了重重挑战。比如&#xff0c;训练算法的成本高昂&#xff0c;数据从采集、处理到存储已面临瓶颈&#xff0c;目前针对算…

JAVA springboot微服务b2b2c电子商务系统(十三)断路器聚合监控(Hystrix Turbine)

讲述了如何利用Hystrix Dashboard去监控断路器的Hystrix command。当我们有很多个服务的时候&#xff0c;这就需要聚合所以服务的Hystrix Dashboard的数据了。这就需要用到Spring Cloud的另一个组件了&#xff0c;即Hystrix Turbine。一、Hystrix Turbine简介看单个的Hystrix D…

二维码Data Matrix的解码实现(zxing-cpp)

二维码Data Matrix的介绍可以参考http://blog.csdn.net/fengbingchun/article/details/44279967 ,以下是通过zxing-cpp开源库实现的对Data Matrix进行解码的测试代码&#xff1a;#include "funset.hpp" #include <string> #include <fstream> #include &…

PHP mongodb 的使用

mongodb 不用过多的介绍了&#xff0c;NOSQL的一种&#xff0c;是一个面向文档的数据库&#xff0c;以其方便灵活的数据结构&#xff0c;对于开发者来说是比较友好的&#xff0c;同时查询的速度也是比较快的&#xff0c;现在好多网站 开始使用mongodb ,具体的介绍可以网上查找。…

必看,61篇NeurIPS深度强化学习论文解读都这里了

作者 | DeepRL来源 | 深度强化学习实验室&#xff08;ID: Deep-RL&#xff09;NeurIPS可谓人工智能年度最大盛会。每年全球的人工智能爱好者和科学家都会在这里聚集&#xff0c;发布最新研究&#xff0c;并进行热烈探讨&#xff0c;大会的技术往往这未来几年就会演变成真正的研…

07-09-Exchange Server 2019-配置-Outlook 2019

[在此处输入文章标题] 《系统工程师实战培训》 -07-部署邮件系统 -09-Exchange Server 2019-配置-Outlook 2019 作者&#xff1a;学 无 止 境 QQ交流群&#xff1a;454544014 MSUCDemo01 MSUCDemo02 MSUCDemo03 MSUCDemo04 MSUCDemo05 启用邮箱 MSUCDemo01i-x-Cloud.com MSUCDe…

二维码QR Code简介及其解码实现(zxing-cpp)

二维码QR Code(Quick Response Code)是由Denso公司于1994年9月研制的一种矩阵二维码符号&#xff0c;它具有一维条码及其它二维条码所具有的信息容量大、可靠性高、可表示汉字及图象多种文字信息、保密防伪性强等优点。二维码QR Code呈正方形&#xff0c;常见的是黑白两色。在3…

jQuery学习(一)

因为项目需要&#xff0c;同时也因为兴趣&#xff0c;在近一段时间研究和使用了jQuery&#xff0c;它真的是太强大了&#xff0c;代码非常的优雅和简洁&#xff0c;好后悔现在才开始了解它&#xff0c;虽然目前网络上关于jQuery的资料、学习心得&#xff0c;教程多得你看不完&a…

知乎算法团队负责人孙付伟:Graph Embedding在知乎的应用实践

演讲嘉宾 | 孙付伟出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;9月6-7日&#xff0c;在由CSDN主办的2019中国AI开发者大会&#xff08;AI ProCon 2019&#xff09;的 机器学习专场中&#xff0c;知乎算法团队负责人孙付伟在机器学习专场中分享了《Graph Embedding…

一维码Codabar简介及其解码实现(zxing-cpp)

一维码Codabar&#xff1a;由4条黑色线条&#xff0c;3条白色线条&#xff0c;合计7条线条所组成&#xff0c;每一个字元与字元之间有一间隙Gap做区隔。条形码Codabar包含21个字元&#xff1a;(1)、10个数字0~9;(2)、””, ”-”,”*”, ”/”, ”$”, .”, ”:”等7个特殊符号…

node 压缩模块速成

1. 压缩与解压缩处理可以使用zlib模块进行压缩及解压缩处理,压缩文件以后可以减少体积&#xff0c;加快传输速度和节约带宽 代码2. 压缩对象压缩和解压缩对象都是一个可读可写流方法说明zlib.createGzip返回Gzip流对象&#xff0c;使用Gzip算法对数据进行压缩处理zlib.createGu…

hadoop作业初始化过程详解(源码分析第三篇)

&#xff08;一&#xff09;概述我们在上一篇blog已经详细的分析了一个作业从用户输入提交命令到到达JobTracker之前的各个过程。在作业到达JobTracker之后初始化之前&#xff0c;JobTracker会通过submitJob方法&#xff0c;为每个作业都创建一个JobInProgress对象(本文以后简称…

百度无人车急刹车

导语&#xff1a;没人会怀疑人工智能在未来的地位&#xff0c;也没人会怀疑无人驾驶将改变我们的生活&#xff0c;但百度首次出现亏损&#xff0c;“现金牛”业务遭遇越发严重的挑战&#xff0c;无人驾驶行业的征途却越发漫长且荆棘密布&#xff0c;这个公司该如何走到“流着奶…

STM32中EXTI和NVIC的关系

&#xff08;1&#xff09;NVIC(嵌套向量中断)&#xff1a;NVIC是Cortex-M3核心的一部分&#xff0c;关于它的资料不在《STM32的技术参考手册》中&#xff0c;应查阅ARM公司的《Cortex-M3技术参考手册》Cortex-M3的向量中断统一由NVIC管理。 &#xff08;2&#xff09;EXTI(外部…

一维码Code 93简介及其解码实现(zxing-cpp)

一维码Code 93: Code 93码与Code 39码的字符集相同&#xff0c;但93码的密度要比39码高&#xff0c;因而在面积不足的情况下&#xff0c;可以用93码代替39码。它没有自校验功能,为了确保数据安全性,采用了双校验字符,其可靠性比39条码还要高.一维码Code 39的介绍可以参考&#…

HEVC/H.265 的未来必须是使用并行处理(OpenCL?) OpenCV和OpenCL区别

1 扩展库简介OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个致力于实时处理计算机视觉问题的开源库。它最初由Intel公司开发&#xff0c;以GPL许可协议发布&#xff0c;后来由Willow Garage基金会负责开发和维护&#xff0c;以BSD许可协议发布&…

一维码Code 128简介及其解码实现(zxing-cpp)

一维码Code 128&#xff1a;1981年推出&#xff0c;是一种长度可变、连续性的字母数字条码。与其他一维条码比较起来&#xff0c;相对较为复杂&#xff0c;支持的字元也相对较多&#xff0c;又有不同的编码方式可供交互运用&#xff0c;因此其应用弹性也较大。Code 128特性&…

21个必须知道的机器学习开源工具!

作者 | SebastianScholl译者 | 刘静&#xff0c;责编 | 郭芮出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;本文将介绍21种用于机器学习的开源工具。以下为译文&#xff1a;你肯定已经了解流行的开源工具&#xff0c;如R、Python、Jupyter笔记本等。但是&#xff…

eclipse中egit插件使用

2019独角兽企业重金招聘Python工程师标准>>> 这篇文章当时制作有点粗糙&#xff0c;建议阅读升级版&#xff1a;eclipse中egit插件使用--升级版 使用git作为项目的代码管理工具现在是越来越火&#xff0c;网上有各种各样的文章、博客、讨论&#xff0c;其中以命令行…

一维码EAN 8简介及其解码实现(zxing-cpp)

一维码EAN 8&#xff1a;属于国际标准条码&#xff0c;由8个数字组成&#xff0c;属EAN的简易编码形式(EAN缩短码)。当包装面积小于120平方公分以下无法使用标准码时&#xff0c;可以申请使用缩短码。依结构的不同&#xff0c;EAN条码可区分为&#xff1a;1&#xff0e; EAN 1…

三年、四大顶会,深度推荐系统18篇论文只有7个可以复现

作者 | 深度传送门来源 | 深度传送门&#xff08;ID:gh_5faae7b50fc5&#xff09;导读&#xff1a;本文是“深度推荐系统”专栏的第十篇文章&#xff0c;这个系列将介绍在深度学习的强力驱动下&#xff0c;给推荐系统工业界所带来的最前沿的变化。本文主要根据RecSys 2019中论文…

PHP教程中验证正整数is_int($value+0),为什么要这样?

2019独角兽企业重金招聘Python工程师标准>>> 最近学习PHP应用&#xff0c;其中有一段是要验证变量是否为正整数&#xff0c;除了is_numeric($value)外&#xff0c;还要加上is_int($value0)且($value0) > 0&#xff0c;为什么还要 0呢&#xff1f;直接验证$value不…

[给12306支招]取消车票预订-采用全额预售(充值)

为什么80%的码农都做不了架构师&#xff1f;>>> 取消车票预订 预订给车票销售带来的负面效应: 产生"占座", 如果用户不付款就会造成席位在支付期内无法销售.回收成本, 超过支付期需要回收车票.恶意占座, 如果恶意占座会造成大量真正要买票的客户无法购票…