Caffe中Layer注册机制

2023-11-11

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;
}
执行结果如下:


GitHubhttps://github.com/fengbingchun/Caffe_Test

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Caffe中Layer注册机制 的相关文章

  • Window下用caffe实现MNIST训练

    本博包含MNIST原始数据的格式转化 以及分类训练 1 数据转化 Caffe源码中src caffe caffe examples mnist convert mnist data cpp提供的实现代码并不能直接在Windows下运行 这里
  • caffe源码 之 CPU与GPU数据同步类

    本文主要解析caffe源码文件 src caffe SycedMem cpp 该文件主要实现cpu与gpu的内存同步 先看SycedMem hpp中SycedMem的类定义 ifndef CAFFE SYNCEDMEM HPP define
  • Caffe可以直接对图像的像素进行分类吗?

    我想将图像的像素分类为 是街道 或 不是街道 我有一些训练数据KITTI数据集我看到 Caffe 有一个IMAGE DATA图层类型 标签以与输入图像大小相同的图像形式存在 除了 Caffe 之外 我解决这个问题的第一个想法是在应该分类的像
  • 大图像的语义分割

    我正在处理数量有限的大尺寸图像 每个图像都可以有3072 3072像素 为了使用 FCN 或 U net 训练语义分割模型 我构建了一个大样本的训练集 每个训练图像是128 128 在预测阶段 我所做的是将大图像切成小块 与训练集相同128
  • Tensorflow的非对称填充假设

    为什么 TensorFlow 选择在右下角填充 With SAME填充 对我来说 在第一个真实像素处启动内核的中心锚点是合乎逻辑的 由于使用了不对称填充 这导致与其他一些框架存在差异 我确实明白 原则上不对称填充是好的 因为否则会留下未使用
  • Caffe sigmoid交叉熵损失

    我正在使用 sigmoid 交叉熵损失函数来解决多标签分类问题 如下所示本教程 然而 在他们的教程结果和我的结果中 输出预测都在范围内 Inf Inf 而 sigmoid 的范围是 0 1 sigmoid 仅在反向传播中处理吗 也就是说 前
  • 如何修改Imagenet Caffe模型?

    我想修改 ImageNet caffe 模型 如下所述 由于时间网络的输入通道数与此不同 空间网络 20 vs 3 我们对 ImageNet 模型滤波器进行平均 先跨过通道一层 然后复制平均结果 20 时间网络的初始化 我的问题是如何才能达
  • 为 Caffe 生成 LMDB

    我正在尝试使用 caffe 我正在使用 python 包装器 构建用于显着性分析的深度学习模型 但我无法理解如何为此目的生成 lmdb 数据结构 我已经浏览了 Imagenet 和 mnist 示例 我明白我应该以以下格式生成标签 my t
  • 在 Mac 上安装 Caffe 错误:“致命错误:找不到‘cblas.h’文件”

    我一直在关注本指南 http playittodeath ru how to install caffe on mac os x yosemite 10 10 4 安装在我的 El Capitan macbook pro 上 使用 CMak
  • LMDB 文件以及它们如何用于 caffe 深度学习网络

    我对深度学习很陌生 在使用 caffe 深度学习网络时遇到一些问题 基本上 我没有找到任何文档来解释如何解决我现在正在处理的一系列问题 请让我先解释一下我的情况 我有数千张图像 我必须对它们进行一系列预处理操作 对于每个预处理操作 我必须将
  • Caffe的Python接口:“导入caffe”时出错

    我正在尝试在 Caffe 的 Python 界面中运行它 我已经运行了命令make pycaffe在 caffe 目录中并且运行良好 现在 当我运行命令时import caffe在终端的 python 环境中 Ubuntu 14 04 我收
  • Caffe 运行测试失败

    成功构建 caffe 后 我进行了 runtest 但在 ImageDataLayer DBTest DataTransformTest HDF5OutputLayerTest 和一些求解器中失败 构建 链接到特定路径时是否缺少步骤 这是测
  • GoogLeNet 模型的微调

    我从头开始训练 GoogLeNet 模型 但它并没有给我带来有希望的结果 作为替代方案 我想在我的数据集上对 GoogLeNet 模型进行微调 有谁知道我应该遵循什么步骤 假设您正在尝试进行图像分类 这些应该是微调模型的步骤 1 分类层 原
  • Caffe 快照:.solverstate 与 .caffemodel

    训练网络时 每 N 次迭代拍摄的快照有两种形式 一个是 solverstate 文件 我想它就像它听起来的那样 存储损失函数和梯度的状态等 另一个是 caffemodel 文件 我知道它存储训练后的参数 如果您想要预训练的模型 caffem
  • 未定义符号:_ZdlPvm

    我在用阿波罗咖啡 https github com Russell91 apollocaffe and 重新检查 https github com Russell91 ReInspect Apollocaffe在 c 库中并且Reinspe
  • 如何设计深度卷积神经网络? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 据我了解 所有 CNN 都非常相似 它们都有一个卷积层 后面是池化层和 relu 层 有些具有专门的层 例如 FlowNet 和 Segn
  • Caffe 中的预测 - 异常:输入 blob 参数与网络输入不匹配

    我使用 Caffe 使用非常简单的 CNN 结构对非图像数据进行分类 我在尺寸为 n x 1 x 156 x 12 的 HDF5 数据上训练网络没有任何问题 但是 我在对新数据进行分类时遇到了困难 如何在不进行任何预处理的情况下进行简单的前
  • 如何在 Caffe 中沿着通道分割 Blob

    我想在Caffe中分割Blob通道 这样我就可以分割一个Blob N c w h 分成两个大小相同的输出 Blob N c 2 w h 我上面描述的是非常笼统的 我实际上想做的是将一个两通道输入图像分离成两个不同的图像 一个进入卷积层 另一
  • 卷积 ImageNet 网络对于翻转图像具有不变性

    我正在使用深度学习 caffe 框架进行图像分类 我有一些有头像的硬币 有些是左向的 有些是右向的 为了对它们进行分类 我使用常见的方法 从预训练的 ImageNet 网络中获取权重和结构 该网络已经捕获了大量图像模式 并主要训练最后一层以
  • 如何在Python中导入caffe模块?

    我在 Windows 发布版 x64 上构建了 caffe cpp 的 dll 我将扩展名 dll 更改为 pyd 并尝试将其导入到 python 中 import caffe File caffe master python caffe

随机推荐

  • 【机器学习】CART决策树原理及python实现

    本文为博主学习机器学习决策树部分的一些笔记和思考 以及python编程实现算法的具体步骤 决策树 decision tree 是一类常见的机器学习方法 在已知各种情况发生概率的基础上 通过构成决策树来求取净现值的期望值大于等于零的概率 评价
  • Jmeter接口自动化(八)函数 上

    今天我们继续来学习Jmeter中的函数助手 在测试过程中我们为了模拟用户真实的请求 提交表单的信息都是动态变化的 这个需要不同变化的数据 就是参数化 Jmeter在配置元件和前置处理器中都能帮助我们进行参数化 但都有局限性 为了更好的帮助我
  • 被逼无奈在小公司熬了2年,现在我终于进了腾讯测试岗...

    其实两年前校招的时候就往腾讯投了一次简历 结果很明显凉了 随后这个理想就被暂时放下了 但是这个种子一直埋在心里 想着总有一天会再次挑战的 其实这两年除了工作以外 其余时间基本上都在学习 打磨自己的技术水平 也会坚持上论坛写写东西 也因此结识
  • 八十.找出二进制中1的个数(位运算)

    请实现一个函数 输入一个整数 输出该数二进制表示中1的个数 方法一 挪动1 向左挪 import java util Scanner public class LianXi public static void main String ar
  • 服务器2003怎么做网站,windows2003做网站该怎么设置!

    IIS 开始 设置 控制面板 添加删除程序 选下的添加删除WINDOWS组件 应用程序服务器 里面有个IIS 把光盘放进去就可以装了 安装完成后 打开浏览器输入 http localhost 检查IIS是否正常 Web服务器属性的设置 通过
  • 服务容错保护断路器Hystrix之二:Hystrix工作流程解析

    一 总运行流程 当你发出请求后 hystrix是这么运行的 详细解释个步骤 1 创建 HystrixCommand or HystrixObservableCommand Object HystrixCommand 用于返回单一的响应 Hy
  • Anaconda for win10下载与安装

    文章目录 一 Anaconda介绍 二 下载与安装 1 下载 2 安装与配置环境变量 3 利用conda搭建新的环境 4 修改jupyter lab默认启动位置 三 参考资料 一 Anaconda介绍 anaconda是一个开源的pytho
  • [C语言编程练习][11]编写一个程序,创建一个包含26个元素的数组,并在其中储存26个小写字母。然后打印数组的所有内容。

    编写一个程序 创建一个包含26个元素的数组 并在其中储存26个小写字母 然后打印数组的所有内容 编写一个程序 创建一个包含26个元素的数组 并在其中储存26个小写字母 然后打印数组的所有内容 include
  • Verilog入门精简教程

    Verilog入门 1 关键字 1 1 module module endmodule 代表一个模块 我们的代码写在这个两个关键字中间 1 2 input output input关键词 模块的输入信号 比如input Clk Clk是外面
  • 影响无线AP终端接入数量的几大因素

    人们常说无线AP这个东西最多也就带10 20人 用户再接入的话会造成整个AP下的用户上网效果很差 甚至经常出现接入受限制的提示 一个设备的硬件往往对接入人数的多少有着很大的关联 那么是不是无线设备厂商直接使用堆硬件的方法就可以实现高带机量呢
  • vue配置文件介绍

    1 vue config js 配置文件 https cli vuejs org zh config vue config js 2 README md 说明文件 3 package json 模块依赖 4 node modules 下载的
  • k8s工作负载型控制器

    k8s工作负载型控制器 文章目录 k8s工作负载型控制器 Deployment ReplicaSet ReplicaSet的工作原理 何时使用ReplicaSet DaemonSet 创建DaemonSet Daemon Pods是如何被调
  • ArcGIS 的基本使用

    在地理信息系统的相关开发过程中 采用一种好的方式去展现地图 以及在地图中融合各种各样的空间数据 是很重要的 ArcGIS 就是一个用于创建 管理 共享和分析空间数据的优秀平台 包含了各种地图服务组件 移动和桌面应用 以及开发者工具 这里记录
  • Ubuntu 16.04中error: No Fortran 77 compiler问题解决

    在安装mpich 3 2 1中遇到如下问题 解决方案 sudo apt get install g77 结果发现不行 如下图 另一种解决方案 安装gfortran sudo apt get install gfortran 问题解决 PS
  • 马上:Zxing、Zbar、HMS Scankit 扫码优化

    Zxing zxing 一款Java Android 很流行的二维码 条形码扫码库 开源 可移植 简单易用的api 相信大家对接触过zxing 库 在高端性能机器扫码效果还是很不错的 但面对复杂的扫码环境而言强光 弯曲 形变等情况 Zxin
  • nacos 系列学习(一、nacos服务安装)

    前几章写了使用Eureka作为服务注册 开始学习使用nacos 1 下载 下载地址 https github com alibaba nacos releases tag 1 3 1 选择这个zip下载 下载完毕后我们可以看看目录结构 修改
  • Python读取excel表格数据并绘制成柱状图

    Python的功能十分强大 它不仅可以用来做爬虫 还可以用来做数据分析哦 那么今天我就带着大家用Python 分析表格数据 并绘制成柱状图 让大家感受一下用python来绘制图表是一种什么感觉 这是我们今天要分析的表格数据 表格名称为tes
  • API需要同时维护多个版本。如何优雅的设计?

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 在项目中经常遇到 相同的数据 对不同的客户以及不同的终端 需要输出不同的数据 更有特殊的情况 需要对一个数据 在不同的终端表示形式不一样 综合多种考虑 需要一种支持扩展 并
  • C语言抽签(抽奖)小程序

    include
  • Caffe中Layer注册机制

    Caffe内部维护一个注册表用于查找特定Layer对应的工厂函数 Layer Factory的设计用到了设计模式里的工厂模式 Caffe的Layer注册表是一组键值对 key value LayerRegistry里用map数据结构维护一个