Caffe关键技术之仿真(一)

从当年流行的”编程高手必读Linux源码“,到市面上各色各样的XXX源码解析、剖析,我们已经看过太多太烂的源码分析。

读一份源码最痛之处在于,突然蹦出一大段代码,数据结构一个认不得,也不知道变量从何而来,函数更看都不懂。

似乎,那些很烂的作者,总喜欢迎难而上,你越不喜欢大段代码,他就每次首先贴一大段代码。

丝毫不对顺序做优化,也不知道标记出什么是重要的,什么是不重要的,连一份概况都没有。

这不叫源码分析,这叫随堂笔记。

高中时候,曾经拜读过侯捷老师的《深入浅出MFC》,其中最有趣的是它的第二章”MFC六大关键技术之仿真“。

这与许多写源码分析的作者大相庭径,既没有一大段代码,也不做什么概括。

它的”深入“精髓很简单,就是拆源码,将复杂、严谨的源码实现,结合自己的理解,以一种简洁、传神的方式仿真。

读这样的代码,是很轻松的,因为本来很复杂的源码,经过作者精心编排和二次改写后,看起来要和蔼可亲的多。

当然,我们不必去写书,但起码要学会拆源码,去仿真、简化、二次改写源码。

读一份复杂的源码,切记眼高手低。我在二次改写Caffe时,遇到的最大问题就是,尽管同一段代码看了许多遍,

每次理解竟然都不同,有错的,也有不足的,只有亲手编译、Debug之后,才发现,原来自己一直读”错“了。

”勿在浮台筑高楼“,这是《深入浅出MFC》这本书的精髓,其实也可以拓展到大部分源码分析问题上。

Caffe关键技术①·开放且先进的设计理念

1.1 引用库:瞧瞧你为什么配置Caffe要一天

Caffe是基于C++写成的,它不是C,它是严格的C++,严格到几乎是与C++ Primer提倡的,相似的现代C++编程风格。

C++标准库由ISO C++委员会严格审查控制,不像Java,所以它的内置库资源受到了严格的限制。

但这丝毫不会阻止C++的强大引用库的能力,但给配置这些库带来很大的麻烦。

广义上来说,Caffe引用的库分为如下几类:

1. 并行数学计算:cblas(CPU)、cublas(GPU)

2. GPU调度:CUDA

3. 本地数据库:LMDB/LevelDB

4、C++标准库扩展:Boost库(开源社区维护,史上最炫、最庞大的C++功能库集合)

5、日志管理与调试:Google GLog

6、执行命令解析:Google Gflags

7、图像处理与变换:OpenCV

8、数据结构设计,及高速序列化/反序列化:Google Protocol Buffer

9、参数扩展与可移植性:HDF5

这些库虽然你可能都没有用过,但是它们分别在处理相关任务上,速度绝对是No.1

当然,这些库有一个很不争的事实,和Google有撇不清的关系,而且Google还被墙了。这与作者Yangqing Jia的工作环境有关。

Caffe写于2013年末,作者2012年在Google MTV实习过,并且参与了Google Brain项目。

Google Brain项目的最大贡献,就是第一代大规模机器学习系统DistBelief(第二代为TensorFlow,已开源)

所以,Caffe就有了一个特殊性,它是学术界的人写的,但是这个人又精通工业界的那些技术。

我称之为,Caffe是一个半工业半学术级的框架。

你在Caffe的代码中,可以看到一些典型的工业级代码的思路和做法,比如 [严格的函数参数传入]:

Google内部对其程序员的代码,为了保持很好的可读性,特作以下规定:

void fun(std::string &str);
这样的函数我们很难分清楚str究竟是输入参数还是输出参数。

因此推荐这样写:
1、输入参数
void fun(const std::string &str);
2、输出参数
void fun(std::string *str);

这种代码风格,在Caffe中是严格执行的。

C++是严谨的语言,而良好的C++代码,则必须具有等量的严谨性。

1.2 CPU/GPU混合编程

Google Brain的DistBelief系统硬伤在于,它是基于分布式CPU节点计算的。

总负责人Andrew Ng在跳槽到Baidu之后,很懊悔自己当初的设计理念,他这样说道:


几年前我启动并主导了一个项目,当时还在谷歌,这个项目叫谷歌大脑。该项目利用谷歌的计算基础设施来构建神经网络。

规模大概比之前的神经网络扩大了一百倍,我们的方法是用约一千台电脑。这确实使深度学习取得了相当大的进展。用到相当多的计算机。不久之后我发现,之前我并没意识到,用一千台电脑是一项非常昂贵的技术。因此,我和我的朋友,意识到,利用一种不同的技术,仅用三台电脑,而非一千台,就可以做到这点,而秘诀就是利用GPU技术。

所以,Caffe在原始的设计理念上,就是以GPU为核心计算,CPU为辅助控制和I/O的这样框架。

由C/C++提供的编译宏功能,使得Caffe可以灵活的混合编程,仅仅添加一条宏,就能Build出不同平台需求的代码。

最新版Caffe,在CPU与GPU上,平衡的非常好。CPU多线程控制与I/O,GPU的多线程计算,两者水乳交融。

与之相对的是Theano,它几乎没有释放整台机器的全部计算力,无论你在其上二次封装什么样的库(Keras,Lasagne)

充其量也只是升级版的玩具,所以,Theano适合入门学习,但不要过度的依赖它,因为它实在太慢了。

1.3 数据结构

面向对象的设计理念有时是件麻烦事。

“类变量应该是私有的,仅且应当只由公有的方法提供接口,用于外部的控制”,Caffe依然严格的执行面向对象的设计原则。

这不是一个好主意,因为源码中会遍布着get、set方法,造成恶劣的不可读性。

所以Google提供了一个思路——将所有数据结构统一管理,以脚本形式快速定义,由机器自动生成冗繁的get、set。

这就是使用Google Buffer Protocol的第一个原因。

经典的系统级应用程序设计,对于数据的管理,必然要实现可持久化——频繁地在内存、硬盘之间进行数据交流。

这在应用程序设计中,称之为序列化、反序列化。

传统的序列化过程,需要程序员人工记忆序列顺序内容。当反序列化时,需要严格遵照顺序恢复,十分麻烦。

更重要的是,一般通用程序框架的反序列化的效率并不好(如Qt、MFC)

Google在Buffer Protocol中,使用了一种高效的编码方式,使得反序列化效率非常高,显著地增强了I/O能力。

这是使用Google Buffer Protocol的第二个,也是最重要的原因。

1.4 数据库

Google Buffer Protocol能够使得任意复杂的数据结构数据,快速编码为单个字符串,这就为“键-值”型数据库造桥铺路。

长期以来,应用级程序开发,通常会使用SQLite作为本地数据库(最典型的是安卓开发)。

SQL方式为数据的存储提供了方便,但同时它是慢的,慢到几乎不可以用于为高性能大数据计算提供I/O缓冲。

此时,Google 又开发了配套的快速 “键-值”型本地数据库LevelDB,跳过SQL,直接底层实现BST来存储。

LevelDB的I/O速度几乎是SQLite的几十倍,所以,早期的Caffe,数据封装由LevelDB负责。

在最新版Caffe中,广泛换成了LMDB。它多牺牲了一点内存空间用于缓存,却带来了比LevelDB更优

的I/O带宽。在如今内存贬值、白菜价的年代,LMDB显然受到主流追捧。毕竟I/O带宽,对于并行程序设计太重要了。

1.5 日志记录与调试

为程序的执行进行详细的日志记录,这是工业级代码的基本做法。

因为一旦程序崩溃了,作为主管,你不仅可以迅速定位位置、查找原因,还可以揪出隐藏在幕后的“背锅侠”。

Caffe中,几乎是遍布了日志记录代码,GLOG的简洁易用性,功不可没。

GLOG的日志记录分为四级,INFO、WARNING、ERROR、FATAL。

你可以通过 google::SetLogDestination 指定输出你要的日志级别,这四个级别是有趣的。

INFO级通常都是一些执行流程信息,WARNING级则是你需要注意的地方,但实际用的并不多。

ERROR级属于严重错误,但是并不会终止程序,作者无法确定接下来会发生什么事。

FATAL级属于致命错误,必须终止程序,这是不可争辩的事实。

FATAL级日志的实现,本质是封装了C/C++提供的assert(断言)功能。

assert代码编写过程中常用手段,GLOG利用assert,还定义了一些条件检查宏,如:

CHECK、CHECK_EQ,CHECK_LT,这些宏能够简化程序逻辑,给Debug带来方便。

毕竟,一个严谨的程序,需要杜绝任何以外情况。凡是估料到执行问题,都应当

使用CHECK宏加以断言标记,来保证程序的严谨性。

1.6 C++核心的一千零一夜

Boost库是C++最为激动人心的库之一,不仅仅是因为它编译完居然占用了3G空间,存在着一万多个引用的头文件。

最重要的是它提供了一些非常便利的功能,在Caffe中使用最广的,就是四大智能指针:

shared_ptr(全局自动释放)、scoped_ptr(局部自动释放)

weak_ptr(多线程安全访问)、thread_specific_ptr(多线程副本指针)

这些指针,让Caffe的代码秀气,安全,且充满灵活性。

其次,多线程程序设计一直是操作系统的兵家必争之地。现代操作系统的多线程功能,一般封装在操作系统内核中。

一些开发者会直接利用Linux内核提供的pThread进行代码设计,比如Tomas Mikolov的Word2Vec。

这给跨平台编译源码,带来了麻烦(很多人为了编译Word2Vec,不惜装Linux,或者找虚拟机)。

Caffe默认使用了Boost库的多线程功能,同Qt的设计理念一样,Boost库为Windows/Linux的内核。

以统一的接口,封装了多线程内核函数。这其实为Caffe for Windows的移植工作提供了便利。

除此之外,Boost库的多线程方案十分强大,足以设计大型的、安全的多线程应用程序。

1.7 数学计算

CBLAS与CUBLAS的函数接口几乎是一致的。

实际上,NVIDIA在设计CUBLAS的时候,是故意为之的模仿,减轻了CPU/GPU混合编程的代码混乱问题。

Caffe在底层封装了一些数学函数,也实现了一些高级的数学函数。

不要去死记硬背他们,也不要囫囵吞枣式的一步实现。

它们贯穿了Caffe的计算代码全部,所以,你在改写Caffe的初期,只需要选择实现其中的一小部分功能编程实现。

时间: 2024-10-05 05:14:41

Caffe关键技术之仿真(一)的相关文章

虚拟现实的关键技术和三大特点

虚拟现实是多种技术的综合,包括实时三维计算机图形技术,广角(宽视野)立体显示技术,对观察者头.眼和手的跟踪技术,以及触觉/力觉反馈.立体声.网络传输.语音输入输出技术等. 现有虚拟现实系统的关键技术 1:动态环境建模技术 虚拟环境的建立是虚拟现实技术的核心内容.动态环境建模技术的目的是获取实际环境的三维数据,并根据应用的需要,利用获取的三维数据建立相应的虚拟环境模型.三维数据的获取可以采用CAD技术(有规则的环境),而更多的环境则需要采用非接触式的视觉建模技术,两者的有机结合可以有效地提高数据获

云计算应用现状与关键技术

云计算是一种新型的计算模式,其主要特点是在互联网存在的基础上通过动态可伸缩的虚拟化资源来进行计算.随者云计算的兴起,世界着名的IT企业都加入到了云计算的开发当中,近些年来我国也对云计算技术的开发也越来越重视.有关数据显示,在未来云计算所占IT成本的比例将会超过30%,在各大IT公司的大力推动下,云计算将会有更加广阔的发展空间.云计算应用现状与关键技术 1.云计算技术的现状 云计算技术正在逐渐步入成熟化阶段,其使用范围越来越广.在科研领域可以通过云计算进行地震监测.海洋信息监控.天文信息计算处理:

聊聊推送的架构及关键技术实现

推送是在日常终端使用场景中经常碰到,特别是移动互联网普及之后,手机终端成为了消息推送的主战场,例如生活服务类的优惠券推送,咨询类的新闻推送,电商类的购物推送等等,在业务用户触达上起到了至关重要的作用,那我们今天就来揭开一下推送这个隐藏在业务背景之下的技术实现 系统架构及模块介绍 这是一个比较完整的推送业务架构图,分为三个部分:业务层.通道层和客户端常驻服务,一般来说客户端常驻服务和通道层维持一个长连接通道实现数据的双向传递,而业务层实现的是基于推送业务形态的展示,例如推送的定时任务推送,接口推送

Java Hotspot G1 GC的一些关键技术

G1 GC,全称Garbage-First Garbage Collector,通过-XX:+UseG1GC参数来启用,作为体验版随着JDK 6u14版本面世,在JDK 7u4版本发行时被正式推出,相信熟悉JVM的同学们都不会对它感到陌生.在JDK 9中,G1被提议设置为默认垃圾收集器(JEP 248).在官网中,是这样描述G1的: The Garbage-First (G1) collector is a server-style garbage collector, targeted for

<脱机手写汉字识别若干关键技术研究>

脱机手写汉字识别若干关键技术研究 对于大字符集识别问题,一般采用模板匹配的算法,主要是因为该算法比较简单,识别速度快.但直接的模板匹配算法往往无法满足实际应用中对识别精度的需求.为此任俊玲编著的<脱机手写汉字识别若干关键技术研究>在模板匹配算法的基础上,结合统计分析和统计信号处理的原理,对脱机手写汉字识别算法以及相关问题进行了研究,力求在基本不降低识别速度的基础上较大地提高识别的精度. 内容简介 书籍计算机书籍<脱机手写汉字识别若干关键技术研究>从脱机手写汉字识别为大类别数模式识别

无线通信网络学习之LTE关键技术之SON(20141220)

鉴于之前每天才写一个相关知识点,而且偶尔还由于工作原因,没有每天都跟进,所以决定今天再写一个关于LTE关键技术的知识,也是最后一个SON. SON:(Self Organized Network)自组织网络: 包含三个方面的内容:自配置,ANR(自动邻区优化),MRO(切换自优化): 自动配置是基站小区设备自动完成小区基本参数的配置和升级: 自优化是指小区中各个手机,通过自动配置邻区来为有特殊链路需求的通信设备提供一条优选的链路: 切换是指通信终端在移动的过程中,从一个小区到另一个小区的过程,在

无线通信网络学习之LTE关键技术之MIMO(20141219)

MIMO故名思意就是多输入多输出. 首先来了解一下关于增益的概念及计算方法: 在扩频通信系统中有两个重要的概念:处理增益和抗干扰容限. 处理增益是用来说明通信系统信噪比改善的程度,△是系统干扰的一个性能指标.一般把扩频信号带宽W与信息带宽△F之比成为处理增益Gp, 即 Gp=W/△F 举个例子:全速信息带宽为9.6Kbit/s,扩频带宽为1.2288Mbit/s ,扩频增益为21dB .   算法:10lg(1.2288*1024/9.6)=21dB. 接下来再谈谈关于增益的几个描述单位: dB

无线通信网络学习之LTE关键技术之OFDM(20141213)

LTE网络有几个关键的技术,分别是:OFDM,AMC,HARQ,MIMO,ICIC,SON 今天首先来了解一下OFDM:(Orthogonal Frequency Division Multiplexing)正交频分复用 将信道分为多个正交子信道,将高速数据信号转换成并行的低速子数据流,调制到每个子信道上进行传输. 正交频分复用系统是由离散傅里叶变换(DFT)和快速傅里叶方法(FFT)研制的一个多载波传输系统,即正交频分复用(OFDM)系统. 了解了上述的定义后,接下来通过几个图来了解正交频分复

中文事件抽取关键技术研究(谭红叶 博士毕业论文)

中文事件抽取关键技术研究(谭红叶 博士毕业论文) 事件抽取的定义 ACE2005 将该项任务定义为:识别特定类型的事件,并进行相关信息的确定和抽取,主要的相关信息包括:事件的类型和子类型.事件论元角色等.根据这个定义,可将事件抽取的任务分成两大核心子任务:(1)事件的检测和类型识别:(2)事件论元角色的抽取.除此以外,由于绝大部分的论元角色都是实体,因此实体的识别也是事件抽取的一项基本任务. 信息抽取的定义 Andrew McCallum所提出的定义具有普遍意义.他将信息抽取定义为(A.McCa