caffe代码阅读7:LayerRegistry的实现细节-2016.3.18

2023-11-17

一、LayerRegistry的作用简介

LayerResistry的功能很简单,就是将类和对应的字符串类型放入到一个map当中去,以便灵活调用。主要就是注册类的功能

二、LayerRegistry类的详细介绍


1)构造函数和析构函数

构造函数
 
// 禁止实例化,因为该类都是静态函数,所以是私有的
  LayerRegistry() {}

2)类型定义

   // 函数指针Creator,返回的是Layer<Dtype>类型的指针
  typedef shared_ptr<Layer<Dtype> > (*Creator)(const LayerParameter&);
  // CreatorRegistry是字符串与对应的Creator的映射
  typedef std::map<string, Creator> CreatorRegistry;

3)成员函数

3-1加入一个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-2给定层的类型,创建层

这个创建层在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();
    // 获得注册表指针
    CreatorRegistry& registry = Registry();
    // 测试是否查找到给定type的Creator
    CHECK_EQ(registry.count(type), 1) << "Unknown layer type: " << type
        << " (known types: " << LayerTypeListString() << ")";
    // 调用对应的层的Creator函数
    return registry[type](param);
  }

3-3返回层的类型列表

  static vector<string> LayerTypeList() {
    // 获得注册表
    CreatorRegistry& registry = Registry();
    vector<string> layer_types;
    // 遍历注册表压入layer_types字符串容器
    for (typename CreatorRegistry::iterator iter = registry.begin();
         iter != registry.end(); ++iter) {
      layer_types.push_back(iter->first);
    }
    return layer_types;
  }

3-4返回一个string,就是把所有的类型都拼起来用逗号分隔形成一个字符串

  static string LayerTypeListString() {
    vector<string> layer_types = LayerTypeList();
    string layer_types_str;
    for (vector<string>::iterator iter = layer_types.begin();
         iter != layer_types.end(); ++iter) {
      if (iter != layer_types.begin()) {
        layer_types_str += ", ";
      }
      layer_types_str += *iter;
    }
    return layer_types_str;
  }
};


3-5 获取注册表(静态的,第一次的时候才new,以后都是直接return的)

// 产生一个CreatorRegistry映射的的实例赋值给g_registry_
  // 表示内部的注册表
  // 静态函数,第一次的时候会new然后return,其余时间都是return
  static CreatorRegistry& Registry() {
    static CreatorRegistry* g_registry_ = new CreatorRegistry();
    return *g_registry_;
  }

3-6此外还定义了一个层注册器

// LayerRegisterer
// 自己定义层的注册器
// 以供后面的宏进行使用
template <typename Dtype>
class LayerRegisterer {
 public:
  // 层的注册器的构造函数
  LayerRegisterer(const string& type,
                  shared_ptr<Layer<Dtype> > (*creator)(const LayerParameter&)) {
    // LOG(INFO) << "Registering layer type: " << type;
    // 还是调用的层注册表中的加入Creator函数加入注册表
    LayerRegistry<Dtype>::AddCreator(type, creator);
  }
};

三、其他:

为了方便作者还弄了个宏便于注册自己写的层类

#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)

下面对该宏进行详细解释:
// 生成g_creator_f_type(type, creator<Dtype>)的两个函数 (double和float类型)
#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>)    \

// 注册自己定义的类,类名为type,
// 假设比如type=bias,那么生成如下的代码
// 下面的函数直接调用你自己的类的构造函数生成一个类的实例并返回
// CreatorbiasLayer(const LayerParameter& param)
// 下面的语句是为你自己的类定义了LayerRegisterer<float>类型的静态变量g_creator_f_biasLayer(float类型,实际上就是把你自己的类的字符串类型和类的实例绑定到注册表)
// static LayerRegisterer<float> g_creator_f_biasLayer(bias, CreatorbiasLayer)
// 下面的语句为你自己的类定义了LayerRegisterer<double>类型的静态变量g_creator_d_biasLayer(double类型,实际上就是把你自己的类的字符串类型和类的实例绑定到注册表)
// static LayerRegisterer<double> g_creator_d_biasLayer(bias, CreatorbiasLayer)
#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)

四、Layer_factory.cpp中的实现

首先给出卷积层的参数
message ConvolutionParameter {
  optional uint32 num_output = 1; // The number of outputs for the layer
  optional bool bias_term = 2 [default = true]; // whether to have bias terms

  // Pad, kernel size, and stride are all given as a single value for equal
  // dimensions in all spatial dimensions, or once per spatial dimension.
  repeated uint32 pad = 3; // The padding size; defaults to 0
  repeated uint32 kernel_size = 4; // The kernel size
  repeated uint32 stride = 6; // The stride; defaults to 1

  // For 2D convolution only, the *_h and *_w versions may also be used to
  // specify both spatial dimensions.
  optional uint32 pad_h = 9 [default = 0]; // The padding height (2D only)
  optional uint32 pad_w = 10 [default = 0]; // The padding width (2D only)
  optional uint32 kernel_h = 11; // The kernel height (2D only)
  optional uint32 kernel_w = 12; // The kernel width (2D only)
  optional uint32 stride_h = 13; // The stride height (2D only)
  optional uint32 stride_w = 14; // The stride width (2D only)

  optional uint32 group = 5 [default = 1]; // The group size for group conv

  optional FillerParameter weight_filler = 7; // The filler for the weight
  optional FillerParameter bias_filler = 8; // The filler for the bias
  enum Engine {
    DEFAULT = 0;
    CAFFE = 1;
    CUDNN = 2;
  }
  optional Engine engine = 15 [default = DEFAULT];

  // The axis to interpret as "channels" when performing convolution.
  // Preceding dimensions are treated as independent inputs;
  // succeeding dimensions are treated as "spatial".
  // With (N, C, H, W) inputs, and axis == 1 (the default), we perform
  // N independent 2D convolutions, sliding C-channel (or (C/g)-channels, for
  // groups g>1) filters across the spatial axes (H, W) of the input.
  // With (N, C, D, H, W) inputs, and axis == 1, we perform
  // N independent 3D convolutions, sliding (C/g)-channels
  // filters across the spatial axes (D, H, W) of the input.
  optional int32 axis = 16 [default = 1];

  // Whether to force use of the general ND convolution, even if a specific
  // implementation for blobs of the appropriate number of spatial dimensions
  // is available. (Currently, there is only a 2D-specific convolution
  // implementation; for input blobs with num_axes != 2, this option is
  // ignored and the ND implementation will be used.)
  optional bool force_nd_im2col = 17 [default = false];
}
注册卷积层、注册池化层、注册ReLU层注册Tanh层,注册python层(如果开始python绑定的话)
代码如下:
// Make sure we include Python.h before any system header
// to avoid _POSIX_C_SOURCE redefinition
#ifdef WITH_PYTHON_LAYER
#include <boost/python.hpp>
#endif
#include <string>

#include "caffe/layer.hpp"
#include "caffe/layer_factory.hpp"
#include "caffe/proto/caffe.pb.h"
#include "caffe/vision_layers.hpp"

#ifdef WITH_PYTHON_LAYER
#include "caffe/python_layer.hpp"
#endif

namespace caffe {

// 写一个获取卷积层实例的函数
// Get convolution layer according to engine.
template <typename Dtype>
shared_ptr<Layer<Dtype> > GetConvolutionLayer(
    const LayerParameter& param) {
   // 从参数中获取是使用什么引擎进行计算CUDNN还是CAFFE还是DEFAULT
   // engine可从caffe.proto中看出是枚举类型的
  ConvolutionParameter_Engine engine = param.convolution_param().engine();
  if (engine == ConvolutionParameter_Engine_DEFAULT) {
    engine = ConvolutionParameter_Engine_CAFFE;
#ifdef USE_CUDNN
    engine = ConvolutionParameter_Engine_CUDNN;
#endif
  }
  if (engine == ConvolutionParameter_Engine_CAFFE) {
    //  直接初始化Caffe的卷积层
    return shared_ptr<Layer<Dtype> >(new ConvolutionLayer<Dtype>(param));
#ifdef USE_CUDNN
  } else if (engine == ConvolutionParameter_Engine_CUDNN) {
    // 初始化CUDNN的卷积层
    return shared_ptr<Layer<Dtype> >(new CuDNNConvolutionLayer<Dtype>(param));
#endif
  } else {// 否则就是出错了
    LOG(FATAL) << "Layer " << param.name() << " has unknown engine.";
  }
}
// 注册该卷积层,类型名为Convolution,获取卷积层的实例为GetConvolutionLayer函数
REGISTER_LAYER_CREATOR(Convolution, GetConvolutionLayer);

// 获取池化层的实例,同卷积层的逻辑
// Get pooling layer according to engine.
template <typename Dtype>
shared_ptr<Layer<Dtype> > GetPoolingLayer(const LayerParameter& param) {
  PoolingParameter_Engine engine = param.pooling_param().engine();
  if (engine == PoolingParameter_Engine_DEFAULT) {
    engine = PoolingParameter_Engine_CAFFE;
#ifdef USE_CUDNN
    engine = PoolingParameter_Engine_CUDNN;
#endif
  }
  if (engine == PoolingParameter_Engine_CAFFE) {
    return shared_ptr<Layer<Dtype> >(new PoolingLayer<Dtype>(param));
#ifdef USE_CUDNN
  } else if (engine == PoolingParameter_Engine_CUDNN) {
    PoolingParameter p_param = param.pooling_param();
    if (p_param.pad() || p_param.pad_h() || p_param.pad_w() ||
        param.top_size() > 1) {
      LOG(INFO) << "CUDNN does not support padding or multiple tops. "
                << "Using Caffe's own pooling layer.";
      return shared_ptr<Layer<Dtype> >(new PoolingLayer<Dtype>(param));
    }
    return shared_ptr<Layer<Dtype> >(new CuDNNPoolingLayer<Dtype>(param));
#endif
  } else {
    LOG(FATAL) << "Layer " << param.name() << " has unknown engine.";
  }
}

// 注册池化层
REGISTER_LAYER_CREATOR(Pooling, GetPoolingLayer);

// 注册ReLU层
// Get relu layer according to engine.
template <typename Dtype>
shared_ptr<Layer<Dtype> > GetReLULayer(const LayerParameter& param) {
  ReLUParameter_Engine engine = param.relu_param().engine();
  if (engine == ReLUParameter_Engine_DEFAULT) {
    engine = ReLUParameter_Engine_CAFFE;
#ifdef USE_CUDNN
    engine = ReLUParameter_Engine_CUDNN;
#endif
  }
  if (engine == ReLUParameter_Engine_CAFFE) {
    return shared_ptr<Layer<Dtype> >(new ReLULayer<Dtype>(param));
#ifdef USE_CUDNN
  } else if (engine == ReLUParameter_Engine_CUDNN) {
    return shared_ptr<Layer<Dtype> >(new CuDNNReLULayer<Dtype>(param));
#endif
  } else {
    LOG(FATAL) << "Layer " << param.name() << " has unknown engine.";
  }
}

REGISTER_LAYER_CREATOR(ReLU, GetReLULayer);

// 注册sigmoid层
// Get sigmoid layer according to engine.
template <typename Dtype>
shared_ptr<Layer<Dtype> > GetSigmoidLayer(const LayerParameter& param) {
  SigmoidParameter_Engine engine = param.sigmoid_param().engine();
  if (engine == SigmoidParameter_Engine_DEFAULT) {
    engine = SigmoidParameter_Engine_CAFFE;
#ifdef USE_CUDNN
    engine = SigmoidParameter_Engine_CUDNN;
#endif
  }
  if (engine == SigmoidParameter_Engine_CAFFE) {
    return shared_ptr<Layer<Dtype> >(new SigmoidLayer<Dtype>(param));
#ifdef USE_CUDNN
  } else if (engine == SigmoidParameter_Engine_CUDNN) {
    return shared_ptr<Layer<Dtype> >(new CuDNNSigmoidLayer<Dtype>(param));
#endif
  } else {
    LOG(FATAL) << "Layer " << param.name() << " has unknown engine.";
  }
}

REGISTER_LAYER_CREATOR(Sigmoid, GetSigmoidLayer);

// 注册softmax层
// Get softmax layer according to engine.
template <typename Dtype>
shared_ptr<Layer<Dtype> > GetSoftmaxLayer(const LayerParameter& param) {
  SoftmaxParameter_Engine engine = param.softmax_param().engine();
  if (engine == SoftmaxParameter_Engine_DEFAULT) {
    engine = SoftmaxParameter_Engine_CAFFE;
#ifdef USE_CUDNN
    engine = SoftmaxParameter_Engine_CUDNN;
#endif
  }
  if (engine == SoftmaxParameter_Engine_CAFFE) {
    return shared_ptr<Layer<Dtype> >(new SoftmaxLayer<Dtype>(param));
#ifdef USE_CUDNN
  } else if (engine == SoftmaxParameter_Engine_CUDNN) {
    return shared_ptr<Layer<Dtype> >(new CuDNNSoftmaxLayer<Dtype>(param));
#endif
  } else {
    LOG(FATAL) << "Layer " << param.name() << " has unknown engine.";
  }
}

REGISTER_LAYER_CREATOR(Softmax, GetSoftmaxLayer);

// 注册tanh层
// Get tanh layer according to engine.
template <typename Dtype>
shared_ptr<Layer<Dtype> > GetTanHLayer(const LayerParameter& param) {
  TanHParameter_Engine engine = param.tanh_param().engine();
  if (engine == TanHParameter_Engine_DEFAULT) {
    engine = TanHParameter_Engine_CAFFE;
#ifdef USE_CUDNN
    engine = TanHParameter_Engine_CUDNN;
#endif
  }
  if (engine == TanHParameter_Engine_CAFFE) {
    return shared_ptr<Layer<Dtype> >(new TanHLayer<Dtype>(param));
#ifdef USE_CUDNN
  } else if (engine == TanHParameter_Engine_CUDNN) {
    return shared_ptr<Layer<Dtype> >(new CuDNNTanHLayer<Dtype>(param));
#endif
  } else {
    LOG(FATAL) << "Layer " << param.name() << " has unknown engine.";
  }
}

REGISTER_LAYER_CREATOR(TanH, GetTanHLayer);

// 注册PYTHON层
#ifdef WITH_PYTHON_LAYER
template <typename Dtype>
shared_ptr<Layer<Dtype> > GetPythonLayer(const LayerParameter& param) {
  Py_Initialize();
  try {
    bp::object module = bp::import(param.python_param().module().c_str());
    bp::object layer = module.attr(param.python_param().layer().c_str())(param);
    return bp::extract<shared_ptr<PythonLayer<Dtype> > >(layer)();
  } catch (bp::error_already_set) {
    PyErr_Print();
    throw;
  }
}

REGISTER_LAYER_CREATOR(Python, GetPythonLayer);
#endif

// Layers that use their constructor as their default creator should be
// registered in their corresponding cpp files. Do not register them here.
}  // namespace caffe

五、总结

作者还真是煞费苦心,弄了个宏,一下子就注册了类。

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

caffe代码阅读7:LayerRegistry的实现细节-2016.3.18 的相关文章

  • 让macOS支持读写NTFS格式的移动硬盘

    第一步 获知磁盘的名称 两种方法可以知道磁盘名称 第一种 当插入移动硬盘时 桌面上会出现移动硬盘的图标还有名称 第二种 打开终端 输入diskutil list 即可知道磁盘名称 由图中可知我的移动硬盘名称是 备份 第二步 打开终端 按照以
  • 操作系统的逻辑结构

    2 1 操作系统的逻辑结构 逻辑结构 OS的设计和实现思路 逻辑结构的种类 1 整体结构 2 层次式结构 3 微内核结构 客户 服务器结构 Client Server 操作系统作为一个大型软件 它的设计逻辑实现的思路 我们叫做操作系统的逻辑

随机推荐

  • 壁纸网站研究:强大到没朋友的壁纸网站整理(动漫/二次元/宅男/风景/真人)

    1 wallhaven 域名 https wallhaven cc 介绍 一个强大的壁纸网站 包含人物 动漫 风景 同时有一些老司机内容 需要选择NSFW 但需要登录才能观看 隐藏功能 但是海外网站 国内网站较慢 有时候打不开 总结 语言
  • 【华为OD机试真题2023B卷 JAVA&JS】内存资源分配

    华为OD2023 B卷 机试题库全覆盖 刷题指南点这里 内存资源分配 知识点贪心编程基础 时间限制 1s 空间限制 32MB 限定语言 不限 题目描述 有一个简易内存池 内存按照大小粒度分类 每个粒度有若干个可用内存资源 用户会进行一系列内
  • Spring 中容器启动分析之refresh方法执行之前

    内容来自 自学星球 欢迎大家来了解我的星球 和星主 也就是我 一起学习 Java 深入 Java 体系中的所有技术 我给自己定的时间是一年 无论结果如何 必定能给星球中的各位带来点东西 想要了解更多 欢迎访问 自学星球 SSM系列源码文章及
  • JavaScript随机生成颜色

    function getRandomColor const letters 0123456789ABCDEF let color for let i 0 i lt 6 i color letters Math floor Math rand
  • IPv4数据报的分段与重组

    文章摘自书籍 深入理解计算机网络 王达 机械工业出版社 IPv4数据报头格式请点击此处 IPv4数据报的封装与解封装请点击此处 IPv4数据报的分段与重组 在网络层中还涉及一个分段的问题 那就是因为不同网络线路上可以传输的数据报大小是有限制
  • QT学习记录(三)通过ui和代码的方式往窗口添加组件

    写在前面 本文是b站教程的https www bilibili com video BV1g4411H78N p 5 vd source a3efe214b8a2ba185e92e79cb6d6321b的笔记 外加自己的一些其他想法 如有侵
  • mnist example for lstm in caffe

    下面给出在caffe中使用lstm的一个例子 其中数据集采用mnist 为了实现mnist数据的序列话 将mnist的每一行看成一帧 每一列则就是该帧的特征矢量 在使用lstm时 一定要注意clip markers 每个序列以0开始 后面接
  • Unity 编辑器-创建模板脚本,并自动绑定属性,添加点击事件

    当使用框架开发时 Prefab挂载的很多脚本都有固定的格式 从Unity的基础模板创建cs文件 再修改到应有的模板 会浪费一些时间 尤其是有大量的不同界面时 每个都改一遍 浪费时间不说 还有可能遗漏或错改 写个脚本创建指定的模板代替C 基础
  • 基于Spark的电商用户行为实时分析可视化系统(Flask-SocketIO)

    基于Spark的电商用户行为实时分析可视化系统 Flask SocketIO 项目简介 该项目已上线蓝桥课程 有需要的可凭邀请码 UB5mdLbl 学习哦 有优惠 课程地址 https www lanqiao cn courses 2629
  • 拉普拉斯时域卷积定理_如何证明频域卷积定理

    展开全部 设抄 IF表示傅立叶逆变换 则 因此有袭 故频域卷积定2113理5261得证 4102 扩展资料 频域卷积定理 频域卷积定理表明两信号1653在时域的乘积对应于这两个信号傅立叶变换的卷积除以2 卷积定理揭示了时间域与频率域的对应关
  • nacos注册中心/配置中心的使用

    Nacos下载 https github com alibaba nacos releases Nacos启动 此处为了演示方便 下载的是 Windows版本 nacos server 2 2 2 zip 进入 nacos server 2
  • response.setCharacterEncoding(charset) 报错

    eclipse tomcat服务启动运行项目 代码 response setCharacterEncoding charset 标红 我自己百度了很多 有一个说法是最靠谱的 HttpServletResponse存在于servlet api
  • JQ了解

    jQuery 一 jQuery的了解 1 定义 jQuery是一个兼容多浏览器的JavaScript框架 可以使用户方便地处理HTML 事件 实现动画效果 并且为网站提供方便的Ajax交互 2 作用 JS操作DOM的一个库 特点 轻量级 出
  • Maven构建与管理项目(二)

    Maven构建与管理项目 二 Maven核心概念 Maven坐标 什么是坐标 在平面几何中坐标 x y 可以标识平面中唯一的一点 Maven坐标主要组成 groupId 组织标识 包名 artifactId 项目名称 version 项目的
  • ST外设使用出错,一般排查步骤

    FMC 通信有误排查过程 1 STM32 官方设计资源 https www stmcu com cn STM32中文官网 gt 设计资源 gt 实战经验 2 Cube 库当中的官方例程 使用 everything 搜索 FMC 关键词 从而
  • 新路子!chatGPT+Python爬虫接私单怎么玩?

    就在这两天 关于ChatGPT的疾呼突然在社交平台上刷屏 很多人发现自己的号已经不在了 用户们感到前所未有的惶恐 已经有不少公司把 chatGPT引入工作流 未来已来 AI智能时代真的来了 普通人如何在智能时代谋求发展 这里提供一个思路 c
  • C++异常

    全文目录 概念 异常的抛出 在函数调用链中异常栈展开匹配原则 异常的重新抛出 异常安全 异常规范 C 标准库的异常体系 异常的优缺点 概念 C语言处理异常的方式 终止程序 返回错误码 很多系统的库函数就是使用这中方式 C 异常 异常是一种处
  • iphone原彩显示对眼睛好吗_iphonex原彩显示有必要开吗

    配置来看 iphoneX更好也2113更贵 iphone8注重5261实用 iphoneX注重装X 有钱就买iphone X 预算不足买iphone 8 4102iphone8和iphoneX的区别 1653外观设计 iPhone 8 Pl
  • 工程管理系统简介 工程管理系统源码 java工程管理系统 工程管理系统功能设计

    鸿鹄工程项目管理系统 Spring Cloud Spring Boot Mybatis Vue ElementUI 前后端分离构建工程项目管理系统 1 项目背景 一 随着公司的快速发展 企业人员和经营规模不断壮大 为了提高工程管理效率 减轻
  • caffe代码阅读7:LayerRegistry的实现细节-2016.3.18

    一 LayerRegistry的作用简介 LayerResistry的功能很简单 就是将类和对应的字符串类型放入到一个map当中去 以便灵活调用 主要就是注册类的功能 二 LayerRegistry类的详细介绍 1 构造函数和析构函数 构造