单纯的将自己的笔记上的内容一点点搬运过来。
在复习卷积神经网络的同时还能学习一下系统级c++程序的规范和技巧。
×××××××××××××××××
一、前言
本系列就是要把caffe这样一个系统级的框架从头到尾梳理一下,在我读caffe的时候是按照自顶向下的方式进行的,就是先从程序入口入手,快速梳理一下整体的框架和结构。在大体摸清了框架之后在开始顺着每个模块自下而上的将每个模块整理一遍。后来在读的过程中发现caffe在进行神经网络的搭建的时候就是这样一种自顶向下的思路。
二、程序入口
(1)caffe的程序入口就是caffe.cpp,在~/caffe-master/tools文件夹下存放。该文件目录里还有计算图像均值,设备查询,图像格式转换,单独的训练和测试入口等等。
打开该文件第一眼就蒙蔽了……….
百度一下发现原来就是gflags-命令行参数工具。
具体用法是DEFINE_string(name,default_value,”description”),之后就可以在命令行中输入name+value,简化了命令行参数的处理。
~/caffe-master/tools/caffe -train -gpu 0;#表示使用编号为0的gpu设备进行训练
caffe命令行格式:
紧接着是一个命令注册表,就是将命令字符串和相应的函数指针存放在map中:
caffe命令行格式:
caffe <command> <args>
command就是通过注册表注册的命令:
train
test
device_query
time
args就是DEFINE_name格式的:
-solver 模型配置文件,后跟prototxt文件;
-gpu gpu设备id;
-snapshot 恢复训练或者finetune,后跟solverstate文件
还有gpu_id的获取:
static void get_gpus(vector<int>* gpus)
说到这里插一句就是在caffe中所有需要被函数改变的参数都是指针传入,所有不能更改的参数都是const引用。之所以这样前者是效率问题,后者是为了向用户显示变量的读写特性,明确告知用户该变量是不可变的。
(2)train()、test()函数分别描述了训练和测试的过程。这些函数都经由RegisterBrewFunction()注册。
在train函数内部还有其余命令行参数的具体表示。
(3)在main函数中,程序通过命令行参数,由GetBrewFunction()调用。
三、训练的流程:
(1)在train()阶段,程序最终将通过solver->Solve()进入solver对象中,并调用Solve()函数;
train()——solver->Solve()
(2)在Solver::Solve()中,程序又通过函数Solver::Step(int iters)开始每次的迭代。
train()——solver->Solve()——Solver::Step()
(3)在每次迭代中,调用net_->ForwardBackward()进行前向loss计算和后向梯度计算。
程序下一步就是在Net对象中进行整个网络的逐层计算了。
中间可以看到caffe在一个批次的迭代结束后,将每次迭代的loss相加除以迭代次数得到了平均loss。
train()——solver->Solve()——Solver::Step()——net->forwardBackward()
最后,达到迭代最大次数就调用ApplyUpdate()更新权值。
四、网络的初始化
网络的初始化和训练有一样的流程。
(1)solver::init()中有分别初始化训练网络和测试网络的函数,可以看出在训练和测试的时候两者是不一样的。
net_是solver类的成员变量,就是Net类型的智能指针:
shared_ptr<Net<Dtype> > net_
初始化调用shared_ptr的成员函数reset(),读取网络参数。
(2)在Net类中,net的构造函数的关键就是Init(param),就是通过proto参数进行初始化。
net的构造过程就是根据各层的参数,从layerid=0开始,一层一层的构造。
(3)从顶向下,现在开始进入Layer层了,layer的构造函数只是根据protobuf参数初始化存储权值或者偏置的Blob,任何自定义的layer都需要通过Setup()函数进行。
(4)在Layer中看到,每层的输入和输出都是Blob型的容器组成的vector。进入Blob类中:
data_是每层前向传播的数据,diff_则是残差。
数据类型是SyncedMemory的智能指针。
至此,caffe的训练流程和初始化流程就梳理完毕了。
五、总结
自顶向下的梳理完毕,现在程序流动到了SyncedMemory,该类是整个caffe的内存模型,管理着cpu内存和gpu显存,以及他们之间的同步和交换。所以接下来就自下往上梳理一下SyncedMemory。