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,其它直接return
static 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中获得字符串type
CreatorRegistry& registry = Registry(); // 获取注册表指针
// 验证是否查找到给定type的creator
CHECK_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 type
static 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的creator
LayerRegisterer(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注册机制的更多相关文章
- caffe layer注册机制
Caffe内部维护一个注册表用于查找特定Layer对应的工厂函数(Layer Factory的设计用到了设计模式里的工厂模式).Layer_factory的主要作用是负责Layer的注册,已经注册完事 ...
- TensorFlow中的设备管理——Device的创建与注册机制
背景 [作者:DeepLearningStack,阿里巴巴算法工程师,开源TensorFlow Contributor] 作为一款优秀的异构深度学习算法框架,TensorFlow可以在多种设备上运行算 ...
- 分享:Android中利用机器码注册机制防止破解(转)
转自:http://blog.csdn.net/huzgd/article/details/6684094 最近做一个Android应用时遇到这个问题,客户要求功能必须注册才能使用,而程序本身又不是联 ...
- 怎样在caffe中添加layer以及caffe中triplet loss layer的实现
关于triplet loss的原理.目标函数和梯度推导在上一篇博客中已经讲过了.详细见:triplet loss原理以及梯度推导.这篇博文主要是讲caffe下实现triplet loss.编程菜鸟.假 ...
- Batch Normalization 与 Caffe中的 相关layer
在机器学习领域,通常假设训练数据与测试数据是同分布的,BatchNorm的作用就是深度神经网络训练过程中, 使得每层神经网络的输入保持同分布. 原因:随着深度神经网络层数的增加,训练越来越困难,收敛越 ...
- .Net中Remoting通信机制简单实例
.Net中Remoting通信机制 前言: 本程序例子实现一个简单的Remoting通信案例 本程序采用语言:c# 编译工具:vs2013工程文件 编译环境:.net 4.0 程序模块: Test测试 ...
- 浅谈Linux中的信号处理机制(二)
首先谢谢 @小尧弟 这位朋友对我昨天夜里写的一篇<浅谈Linux中的信号处理机制(一)>的指正,之前的题目我用的“浅析”一词,给人一种要剖析内核的感觉.本人自知功力不够,尚且不能对着Lin ...
- caffe中权值初始化方法
首先说明:在caffe/include/caffe中的 filer.hpp文件中有它的源文件,如果想看,可以看看哦,反正我是不想看,代码细节吧,现在不想知道太多,有个宏观的idea就可以啦,如果想看代 ...
- 【转】深入Windows内核——C++中的消息机制
上节讲了消息的相关概念,本文将进一步聊聊C++中的消息机制. 从简单例子探析核心原理 在讲之前,我们先看一个简单例子:创建一个窗口和两个按钮,用来控制窗口的背景颜色.其效果 图1.效果图 Win32 ...
随机推荐
- K8S Deployment 命令
创建 Deployment kubectl create -f https://kubernetes.io/docs/user-guide/nginx-deployment.yaml --record ...
- jenkins + k8s + lnp
前提条件: K8S 已部署好,traefik也部署完成 K8S 集群上都挂载NFS盘,防止jenkins挂掉后配置消失 基础镜像使用 lnp,PHP 5.6.31 nginx/1.8.1 基础镜像 ...
- n=n+1 放在print(s)的上面的影响 (2) n=n=+1在前面,则不满足前面<100条件时候,才跳出while的循环,这时候while循环结束, 到了外面的下一步-->print()
1+2+3+....+100= ? n=1 s = 0 while n < =100: s = s+n n= n+1 # n=n+1 在print(s)上面的情况 print(s)
- 【C#】#100 调用摄像头
需求:由于项目需要获得用户的头像,所以需要用C#调用摄像头获取头像. 下面写一个调用摄像头的方法 案例:调用摄像头的一个DEMO[效果图] 使用的类库:AForge.dll [Demo下载,Dem ...
- 【原创】uwsgi中多进程+多线程原因以及串行化accept() - thunder_lock说明
如有不对,请详细指正. 最近再研究uwsgi如何部署python app,看uwsgi的文档,里面有太多的参数,但每个参数的解释太苍白,作为菜鸟的我实在是不懂.想搞清楚uwsgi的工作原因以及里面的一 ...
- Centos7使用yum安装Mysql5.7.19的详细步骤(可用)
Centos7的yum源中默认是没有mysql,因为现在已经用mariaDB代替mysql了. 首先我们下载mysql的repo源,我们可以去mysql官网找最新的repo源地址 地址: https: ...
- Windows 7防火墙阻止了远程桌面连接的解决方法
在[系统属性]中已经设置了允许远程桌面连接了,但是还是不能远程桌面的话,很可能是你的windows防火墙处于“启用”状态,防火墙阻止了windows 7系统的远程桌面连接.你可以使用以下的方法检查解决 ...
- 七:Java之封装、抽象、多态和继承
本文章介绍了关于Java中的面向对象封装.抽象.继承.多态特点 Java面向对象主要有四大特性:封装.抽象.继承和多态. 一.封装 封装就是将抽象得到的数据和行为(或功能)相结合,形成一个有机的总体, ...
- kubernetes API Server 权限管理实践
API Server权限控制方式介绍 API Server权限控制分为三种:Authentication(身份认证).Authorization(授权).AdmissionControl(准入控制). ...
- crontab定时执行
一.crond简介 crond是linux下用来周期性的执行某种任务或等待处理某些事件的一个守护进程,与windows下的计划任务类似,当安装完成操作系统后,默认会安装此服务工具,并且会自动启动cro ...