Caffe 源码(二) —— common 文件

2023-10-26

caffe 源码 —— common.hpp/cpp


这里主要是对 caffe 框架源码进行梳理与学习( 主要是 CPU 模式下的,所以暂时还不涉及 CUDA,cudnn 编程),不同时期回看源码收获不同,水平有限,如有错误之处还请留言指正交流。

首先的切入点就是 common.hpp, 其包含在 blob.hpplayer.cpp 头文件中,而 blob.hpplayer.cpp 这两者基本被框架所有网络相关层包含,所以可见 common.hpp 于 caffe 的重要性。

概括来说包含了以下内容:

  • 宏定义 : 主要用来实例化类模板
  • 全局初始化函数 : 初始化 gflags 和 glog
  • Caffe 类(单例模式类) : 随机数生成

下面我们就结合 common.cpp 来集体说说以下内容。

1. 宏定义

这里的宏定义主要是实例化制定的类模板。 caffe 主要使用了 float 和 double 两种精度的数据类型,所以在网络相关功能定义时都是使用了泛型模板编程,而在这里用 INSTANTIATE_CLASS(classname) 进行实例化。

#define INSTANTIATE_CLASS(classname) \
  char gInstantiationGuard##classname; \
  template class classname<float>; \
  template class classname<double>

相似的还有:

#define INSTANTIATE_LAYER_GPU_FORWARD(classname) \
  template void classname<float>::Forward_gpu( \
  const std::vector<Blob<float>*>& bottom, \
  const std::vector<Blob<float>*>& top); \
  template void classname<double>::Forward_gpu( \
  const std::vector<Blob<double>*>& bottom, \
  const std::vector<Blob<double>*>& top);

上面是实例化了 GPU 模式下的前向操作类,同理还有反向操作类。这里还有一个值得一提是:

#define DISABLE_COPY_AND_ASSIGN(classname) \
private:\
  classname(const classname&);\
  classname& operator=(const classname)

这是将类的拷贝构造函数和赋值构造函数设置成 private,禁止指定类的拷贝和赋值操作来初始化另一个类

2. 全局初始化函数

函数声明: void GlobalInit(int* pargc, char*** pargv)
功能:初始化 gflags 和 glog
源码(部分):

void GlobalInit(int* pargc, char*** pargv) {
  // Google flags.
  ::gflags::ParseCommandLineFlags(pargc, pargv, true);
  // Google logging.
  ::google::InitGoogleLogging(*(pargv)[0]);
}

3. Caffe 类(单例模式)

Caffe 类是一个懒汉模式的单例模式,简而言之即 Caffe 类将自己的构造函数设置成 private,这样程序就只能通过唯一的成员函数来初始化实例,在创建实例前做一个判断,只有当前不存在实例时才创建,这就保证了程序中只会有一个caffe 类的实例,这就是单例模式,这种使用时候才进行创建就是所谓的懒汉模式。这里我写了一个简单版的示例:

class Caffe_demo { // 懒汉单例的 Caffe_demo 类
public:
	~Caffe_demo(); // 析构函数
	Caffe_demo* Get() {  // 创建实例的唯一接口
		if (nullptr == m_caffe) {  // 如果
			m_caffe = new Caffe_demo();
		}
		return m_caffe;
	}

	class RNG {
		//......
	};
	// 其他内容....

private:
	Caffe_demo(); // 构造函数
	DISABLE_COPY_AND_ASSIGN(Caffe_demo); // 宏定义,见 1. 宏定义 部分
	static Caffe_demo * m_caffe; // 静态变量
};

Caffe_demo * m_caffe = nullptr;

这里的其他内容是一些,查询设备号,设置设备等功能,这里就不展开叙述了。下面的重点是包含在 Caffe 类中的 RNG 类, 随机数生成器(Random Number Generator),这个类是对 Boost库 和 CUDA 中随机数生成器的一个包装,对外以 RNG 类统一显示,首先引用知乎上一段关于随机数生成的回答:

随机数在caffe中是非常重要的,最重要的应用是权值的初始化,如高斯、xavier等,初始化的好坏直接影响最终的训练结果,其他的应用如训练图像的随机crop和mirror、dropout层的神经元的选择。

然后在 RNG 作为一个统一的接口,并不是直接通过 RNG 的成员函数来实现,而是内部又复合了另一个私有 Generator 类,用于随机数的生成,即调用需要通过三级的关系。

void* Caffe::RNG::generator() {
  return static_cast<void*>(generator_->rng());
}

这里的 rng() 类的定义中给了两个接口,是通过 Generator 类的构造函数实现的:

class Caffe::RNG::Generator {
 public:
  Generator() : rng_(new caffe::rng_t(cluster_seedgen())) {} // boost 随机生成器
  explicit Generator(unsigned int seed) : rng_(new caffe::rng_t(seed)) {} // 采用给定的种子初始化
  caffe::rng_t* rng() { return rng_.get(); } // 属性
 private:
  shared_ptr<caffe::rng_t> rng_; 
};

一个是可以认为设定随机种子 explicit Generator(unsigned int seed) ,如果固定随机种子,每次就可以获取相同的随机数结果,还有就是默认的无随机数种子的 Generator() ,就采用默认的 boost 库的随机函数进行随机数生成。这里的 rng_t 其实就是 boost 库随机数的返回形式,见 rng.hpp 中:

typedef boost::mt19937 rng_t;

而这里都使用了智能指针进行管理,且 Caffe 实例中也是使用了 boost::thread_specific_ptr 这类特殊指针,其行为类似于智能指针,智能管理线程,当线程退出时,自动释放资源。

rng.hpp

这里基于上述 common.hpp 的分析,caffe 框架下 include/util 中还包含了名为 rng.hpp 的头文件,其中主要是基于 RNG 类的随机生成数,再将它们混合,来达到充分随机。使用的是 Fisher–Yates shuffle 算法,其是用来将一个有限集合打乱的算法,这个算法生成的随机排列是等概率的,同时需要非常高效。

inline rng_t* caffe_rng() { // 获取 RNG 类的随机数
  return static_cast<caffe::rng_t*>(Caffe::rng_stream().generator());
}

// 使用 Fisher–Yates algorithm 算法对随机数进行混洗
template <class RandomAccessIterator, class RandomGenerator>
inline void shuffle(RandomAccessIterator begin, RandomAccessIterator end,
RandomGenerator* gen) {
  typedef typename std::iterator_traits<RandomAccessIterator>::difference_type
  difference_type;
  typedef typename boost::uniform_int<difference_type> dist_type;

  difference_type length = std::distance(begin, end);
  if (length <= 0) return;

  for (difference_type i = length - 1; i > 0; --i) {
    dist_type dist(0, i);
    std::iter_swap(begin + i, begin + dist(*gen));
  }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Caffe 源码(二) —— common 文件 的相关文章

随机推荐

  • Eureka的常用配置讲解

    1 关闭自我保护 保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景时 一旦进入保护模式 Eureka Server将会尝试保护其服务的注册表中的信息 不在删除服务注册表中的数据 当网络故障恢复后 Eureka Se
  • 外包四年太差劲,才幡然醒悟要跳槽

    前几天有个读者过来说 程序猿 外包干了四年太差劲了 感觉和外界差距有点大 现在被动醒悟 希望你能帮我制定一下学习路线 如果不是女朋友和我提分手 我估计现在还没醒悟 大专生 18年通过校招进入湖南某软件公司 干了3年多的CRUD 今年年初 感
  • VS--屏蔽编译warning警告设置

    VS 屏蔽编译warning警告设置 在 项目 gt 属性 gt 配置属性 gt C C gt 高级 的 禁用特定警告 中添加相应的警告编号 如4819
  • 机器学习-前期知识储备

    1 什么是机器学习 机器学习 利用数学模型来理解数据 发现数据中的规律 用作数据的分析和预测 数据通常由一组向量组成 这组向量中的每个向量都是一个样本 我们用 x i x i xi 来表示一个样本 其中 i
  • Spark Streaming实战对论坛网站动态行为pv,uv,注册人数,跳出率的多维度分析,实时统计每天pv,uv的sparkStreaming结合redis结果存入mysql供前端展示

    论坛数据运行代码自动生成 该生成的数据会作为Producer的方式发送给Kafka 然后SparkStreaming程序会从Kafka中在线Pull到论坛或者网站的用户在线行为信息 进而进行多维度的在线分析 数据格式如下 date 日期 格
  • 判断自己的mac是macOS x64 、 macOS ARM64

    在学习微信小程序时 需要安装微信开发者工具 那么mac用户怎么知道自己mac版本是macOS x64 还是macOS ARM64 解决方法如下 在终端输入uname a 具体操作 一 打开访达 二 应用程序 gt 实用工具 gt 终端 三
  • 微信小程序蓝牙扫描搜不到信号

    调试蓝牙连接的时候 我的手机突然搜不到蓝牙信号了 但别人手机可以 看了网上的做法 无非是要打开系统蓝牙权限 系统定位权限 小程序蓝牙权限 确认都打开之后仍旧不行 最后发现是一个微信应用权限被关掉了 打开以后能正常搜索
  • 【Microsoft Remote Desktop For Mac在Mac上远程Windows桌面】

    Microsoft Remote Desktop For Mac在Mac上远程Windows桌面 Microsoft Remote Desktop For Mac 下载链接 发牢骚 版本说明 所有下载均为beta版 下载网站截图 Micro
  • python xml读写

    1 xml例子
  • spark使用withColumn在dataFrame中增加一列、多列,配合cache函数一起使用

    在开发spark应用过程中需要往hive表中造测试数据 同时造多列数据 部分列之间存在逻辑计算关系 一般使用dataframe的函数 withColumn col name conditions 此时conditions可以直接是类似于 c
  • Leetcode刷题c++之915.分割数组

    题目描述 给定一个数组 nums 将其划分为两个连续子数组 left 和 right 使得 left 中的每个元素都小于或等于 right 中的每个元素 left 和 right 都是非空的 left 的长度要尽可能小 在完成这样的分组后返
  • LTE物理层基础

    Overview of the LTE Physical Layer 一 前言 本文介绍 Long Term Evolution LTE 的无线接入技术以及 Physical Layer PHY 这里主要讲解一下关于LTE的物理层OFDM相
  • 使用FFmpeg转录网络直播流

    爱奇艺万能播放器的最新版本增加了一个播放网络流的功能 不过 入口藏在播放器区域的右键菜单里 不太好找 找来一个直播流URL 比如东森新闻 http 60 199 188 151 HLS WG ETTV N index m3u8 试了一下 还
  • Pygame事件处理机制简介-慕课的python游戏开发入门02

    目录 首先解释几个问题 1 事件处理需求主要有以下几个方面 2 Pygame事件队列 3 Pygame事件 4 事件类型及属性 5 事件处理的重要函数 6 键盘事件 7 鼠标事件 8 处理事件函数 9 操作事件队列 10 生成事件 其次给出
  • opsForValue() 的 set 用法

    void set K var1 V var2 long var3 TimeUnit var5 opsForValue 中 set 用法 redisTemplate opsForValue set REDIS KEY PREFIX key h
  • 合肥工业大学编译原理实验三 LR(1)分析法

    前言 刚开始的时候觉得这个东西不好写 估计花的时间比前一个LL1更长 但后来转念一想 UI可以挪用上次的 改个标题 换点控件 换个总控程序不就可以了吗 剩下的问题就是用python的哪个数据结构来表示和存储LR文法的一些东西 比如项目怎么表
  • 编译nginx时报错:“./configure: error: C compiler cc is not found”

    环境 ubuntu 18 04 3 Hyper V 1 定位到 usr local nginx 这个目录为你的nginx所安装目录 我的是 usr local nginx nginx auto cc 2 给文件夹权限 等下我们要修改里面的
  • Cannot forward to error page for request [/] as the response has already been committed. As a result

    我遇到这个错误是因为我创建的spring boot 项目 使用jsp模板 但是jsp页面放在了resources文件夹里面所以出现了这个错误 创建了传统web项目的结构之后 修复了该问题 就是将jsp页面放在webapp WEB INF 文
  • 网络编程技术-----windows网络编程

    网络编程技术 c s简易模型 windows网络编程c 未使用select 1 比如qq DNF LOL等这些我们下载客户端的 都属于c s模型的一个应用 2 c s模型其实是概念层面的 实现层面可以是基于任何的网络协议 3 常见的还有b
  • Caffe 源码(二) —— common 文件

    caffe 源码 common hpp cpp 文章目录 caffe 源码 common hpp cpp 1 宏定义 2 全局初始化函数 3 Caffe 类 单例模式 rng hpp 这里主要是对 caffe 框架源码进行梳理与学习 主要是