Caffe的项目架构和源码解析(2)

1

图2 自动生成的c++类 Glob

这个工具也是谷歌出品,用来打印初始化、运行时的信息,记录意外中断等。使用先要初始化google的logging库。一般在caffe中常见的LOG(INFO)…和CHECK(XXX)…都是它执行的。相关的内容可以参考下面的图片,图3是标出颜色的是代码中用到了的打印,图4是对应打印到屏幕上的信息。

1

图3 c++代码

1

图4 打印信息 LMDB

lmdb是一个读取速度快、轻量级的数据库,支持多线程、多进程并发,数据由key-value对存储。caffe还提供leveldb的接口,本文只讨论python实现的lmdb。在这个数据库中存放的是序列化生成的字符串。caffe提供脚本文件先生成lmdb格式的数据,这个脚本文件会生成一个文件夹,文件夹下包括两个文件,一个数据文件,一个lock文件。然后调用训练网络的DataLayer层来读取lmdb格式的数据。图5是定义ldmb数据库类型,图6是将数据序列化再存入数据库中。

1

图5 定义db

1

图6 存入db 3.caffe基本结构 Blob

这是caffe的数据存储类blob,它实现了关于一个变量的所有相关信息和相关操作。存储数据的方式可以看成是一个N维的c数组,存储空间连续。例如存储图片是4维(num, channel, height, width),变量(n,k,h,w)在数组中存储位置为((n*K+k)*H+h)*W+w。相应的四维参数保存为(out_channel, in_channel, filter_size, filter_size)。blob有以下三个特征:

两块数据,一个是原始data,一个是求导值diff

两种内存分配方式,一种是分配在cpu上,一种是分配在gpu上,通过前缀cpu、gpu来区分

两种访问方式,一种是不能改变数据,一种能改变数据

其中让人眼前一亮的是data和diff的设计,其实在卷积网络中,很多情况下一个变量不仅有它自身的值,另外还有cost function对它的导数,采用过多的变量来保存这两个信息还不如将它们放在一起直观,下图是源码blob.hpp中的定义。

1

图7 定义blob Layer

caffe根据不同的功能将它们包装成不同的Layer,例如卷积、pooling、非线性变换、数据层等等。具体有多少种layer及其内容参考官方文档即可,本文主要讨论它的实现,它的实现分为三个部分,也可参考演示图8:

setup,初始化每一层,和它对应的连接关系

forward,由bottom求top

backward,由top的梯度求bottom的梯度,有参数的求参数梯度

1

图8 caffe的layer实现方式

而前向传播、后向传播的函数也分别有两种实现方式,一种基于gpu一种基于cpu。Forward函数,参数分别是两个存放blob指针的vector,分别是bottom、top。通过指针数组的方式能够实现多个输入多个输出。值得一提的是,caffe的卷积部分采用了将数据进行变换,变成矩阵之后再用矩阵乘法来实现卷积,cudnn也是采用这样的方式,经过我的实验,确实这种方式比直接实现cuda kernel要快一些。caffe大部分底层实现都是用blas或者cublas处理的。

Net

Net它将不同的层正确的连接起来,是层和它们之间连接的集合。通过Net::Init()来初始化模型,构造blobs和layers,调用layers的setup函数。Net的Forward函数内部调用了ForwardPrefilled,并且调用了ForwardFromTo,它从给定的层数id(start)到end来调用Layer对象的Forward函数。

Solver

Solver是控制网络的关键所在,它的具体功能包括解析传递的prototxt、执行train、调用网络前向传播计算输出和loss、后向传播计算梯度、根据不同优化方式更新参数(可能不止有learning rate这种参数,而是由alpha、beta构成的更新方式)等。在解析.prototxt时,首先初始化NetParameter对象,用于放置全部的网络参数, 然后在初始化训练网络的时候,通过net变量给出的proto文件地址,来解析并获取网络的层次结构参数。其中的函数solve会根据命令行传递进来的参数来解析并恢复之前保存好的网络文件和权重等,恢复上次执行的iteration次数、loss等。当网络参数配置好,需要恢复的文件处理完成就调用net.cpp的Forward函数开始执行网络。Forward会返回这一次迭代的loss,然后打印出来。接下来会调用ApplyUpdata函数,它会根据不同的策略来改变当前权重的学习率大小,再更新权重。此外,solver还提供保存快照的功能。

4.运行实例

假如是自己的图片数据,可以按照如下的方法来进行分类。我全部采用的c++,改源代码比较方便。

将图片整理成train和test两个文件夹,并将图片的名称和label保存到一个txt中

将数据变成lmdb格式,采用的是convert_imagenet这个工具

生成均值处理后的图片,采用compute_image_mean这个工具

修改模型并执行train

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/2b8e84b5eaf465290a3430aeec0151c3.html