阅读源码首先要从熟悉目录结构开始:https://blog.csdn.net/c20081052/article/details/80585888
熟悉完基本目录结构之后,就要进一步深入学习:https://www.zhihu.com/question/27982282/answer/80242005
源码阅读,首先从 src/caffe/proto/caffe.proto开始,了解 对象 和 磁盘文件的 对应关系。
之后看.hpp文件,理解整个框架,去猜测具体的实现,并从基类开始顺着 看他的派生类,这样就会很容易掌握这些类的用法。
再之后,就是针对性的看 cpp 和 cu文件。(一般,是对caffe 进行扩展,继承现有的类 来实现 新的类。并测试新类的正确性)
再再之后,可以尝试编写 各种类工具(如 训练、测试、特征提取、数据转换等工具)
caffe的整个训练的代码流程:https://www.cnblogs.com/liuzhongfeng/p/7289956.html
1.学习程序的第一步,先让程序跑起来,看看结果,这样就会有直观的感受。
Caffe的官网上Caffe | Deep Learning Framework提供了很多的examples,你可以很容易地开始训练一些已有的经典模型,如LeNet。我建议先从LeNet MNIST Tutorial开始,因为数据集很小,网络也很小但很经典,用很少的时间就可以跑起来了。当你看到terminal刷拉拉的一行行输出,看到不断减少的loss和不断上升的accuracy,训练结束你得到了99+%的准确率,感觉好厉害的样子。你可以多跑跑几个例子,熟悉一下环境和接口。
2.单步调试,跟着Caffe在网络里流动
当玩了几天之后,你对Caffe的接口有点熟悉了,对已有的例子也玩腻了,你开始想看看具体是怎么实现的了。我觉得最好的方法是通过单步调试的方式跟着程序一步一步的在网络里前向传播,然后再被当成误差信息传回来。
Caffe就像一个你平常编程中Project,你可以使用IDE或者GDB去调试它,这里我们不细说调试的过程。你可以先跟踪前向传播的过程,无非就是从高层次到低层次的调用Forward函数, Solver->Net->Layer->Specific Layer (Convolution等...).后向传播也类似,但因为你对Caffe里面的各种变量运算不熟悉,当你跟踪完前向传播时可能已经头晕眼花了,还是休息一下,消化一下整个前向传播的流程。
刚刚开始你没有必要对每个Layer的计算细节都那么较真,大概知道程序的运算流程就好,这样你才可以比较快的对Caffe有个大体的把握。
3.个性化定制Caffe
到这里,你已经可以说自己有用过Caffe了,但是还不能算入门,因为你还不知道怎么修改源码,满足自己特定的需求。我们很多时候都需要自己定义新的层来完成特定的运算,这时你需要在Caffe里添加新的层。
你一开肯定无从下手,脑子一片空白。幸运的是Caffe github上的WikiDevelopment · BVLC/caffe Wiki · GitHub已经有了教程了,而且这是最接近latest Caffe的源码结构的教程,你在网上搜到的Blog很多是有点过时的,因为Caffe最近又重构了代码。你可以跟着它的指导去添加自己的层。
虽然你已经知道要在哪里添加自己的东西了,但你遇到最核心的问题是如何写下面这四个函数。
forward_cpu()
forward_gpu()
backward_cpu()
backward_gpu()
你可以先模仿已有的层去实现这四个函数,而且我相信forward函数很快就可以写出来了,但backward的还是一头雾水。这时我们就要补补神经网络里最核心的内容了——Backpropagation.
4.理解并实现Backpropagation
这个我觉得是与平台无关的,不管你是使用Caffe、Torch 7,还是Theano,你都需要深刻理解并掌握的。因为我比较笨,花了好长时间才能够适应推导中的各种符号。其实也不难,就是误差顺着Chain rule法则流回到前面的层。我不打算自己推导后向传播的过程,因为我知道我没有办法将它表达得很好,而且网上已经有很多非常好的教程了。下面是我觉得比较好的学习步骤吧。
从浅层的神经网络(所谓的全连接层)的后向传播开始,因为这个比较简单,而且现在我们常说的CNN和LSTM的梯度计算也最终会回归到这里。
第一个必看的是Ng深入浅出的Ufldl教程UFLDL Tutorial,还有中文版的,这对不喜欢看英语的同学是个好消息。当然你看一遍不理解,再看一遍,忘了,再看,读个几遍你才会对推导过程和数学符号熟悉。我头脑不大行,来来回回看了好多次。
当然,Ufldl的教程有点短,我还发现了一个讲得更细腻清晰的教程,Michael Nielsen写的Neural networks and deep learning。它讲得实在太好了,以至于把我的任督二脉打通了。在Ufldl的基础上读这个,你应该可以很快掌握全连接层的反向传播。
最后在拿出standford大牛karpathy的一篇博客Hacker's guide to Neural Networks,这里用了具体的编程例子手把手教你算梯度,并不是推导后向传播公式的,是关于通用梯度计算的。用心去体会一下。
这时你跃跃欲试,回去查看Caffe源码里Convolution层的实现,但发现自己好像没看懂。虽说卷积层和全连接层的推导大同小异,但思维上还是有个gap的。我建议你先去看看Caffe如何实现卷积的,Caffe作者贾扬清大牛在知乎上的回答在 Caffe 中如何计算卷积?让我茅塞顿开。重点理解im2col和col2im.
这时你知道了Convolution的前向传播,还差一点就可以弄明白后向传播怎么实现了。我建议你死磕Caffe中Convolution层的计算过程,把每一步都搞清楚,经过痛苦的过程之后你会对反向传播有了新的体会的。在这之后,你应该有能力添加自己的层了。再补充一个完整的添加新的层的教程Making a Caffe Layer • Computer Vision Enthusiast。这篇教程从头开始实现了一个Angle To Sine Cosine Layer,包含了梯度推导,前向与后向传播的CPU和GPU函数,非常棒的一个教程。
最后,建议学习一下基本的GPU Cuda编程,虽然Caffe中已经把Cuda函数封装起来了,用起来很方便,但有时还是需要使用kernel函数等Cuda接口的函数。这里有一个入门的视频教程,讲得挺不错的NVIDIA CUDA初级教程视频。
caffe源码阅读流程补充:
Caffe的代码结构非常清晰简单,其实到现在为止,核心代码4万行左右。因为我只读过Caffe的代码,还评判不了缺点和优点。
其主要结构就是:Blob(数据)和Layer(层)组成Net(网络),用Slover求解。除了这几个主要结构,其他的除了少量的辅助类,就是大量的具体Layer和Slover的实现(而且基本都是CPU/GPU各一个版本,代码结构基本一样,意味着几乎减少了一小半的代码量)。
我认为不要开始就读代码,先掌握必要的基础,读代码会非常快。我认为从下面几步开始比较好:
前提:较为不错的C++水平,不需要C++11。
第一步:弄懂一个简单的神经网络的训练过程,比如3层神经网络如何识别手写数字这种小项目。有基础跳过。
第二步:毕竟是读代码,所以你要弄明白Caffe的依赖库都是做什么的,比如glog/gflags/lmdb你得知道有什么用,比较难的是Protocal buffers、CUDA和BLAS,有基础跳过。
第三步:了解整个项目的结构,这个在官网有介绍,其他回答也说的很好。无非是Blob/Layer/Net/Solver几个主要的类以及辅助类,再就是大量的Layer类的派生。Blob存放数据和参数,Layer负责每一层的计算,Net通过创建Blob和Layer构建整个网络,Solver运行求解整个网络。
第四步:有了上面的几步,就是阅读代码了。先构建一个网络跑通感受下。经过第三步你应该知道了主要类的作用,这一步其实就是去寻找这些作用具体实现的代码,应该不需要很费劲就会把主要的几个类的代码看明白。
第五步:各种Layer和Slover的实现。我觉的这部分读起来最大的问题就是是否掌握了各种层的理论知识。比如你早就掌握了ReLU激活函数,那么relu_layer.hpp/.cpp/.cu这个比较简单的层也就几分钟就看明白。
看的过程中的细节如果不影响进一步阅读可以先跳过。
caffe中的设计模式:https://zhuanlan.zhihu.com/p/20456649
在caffe中定义自己的层:
https://zhidao.baidu.com/question/1897850509799556740.html
https://www.huaweicloud.com/articles/c063495c2cedcecd05b40be6ab99ba86.html
https://blog.csdn.net/wanggao_1990/article/details/78863669
https://www.it610.com/article/1306184661927497728.htm
https://blog.csdn.net/kkk584520/article/details/52721838
https://blog.csdn.net/u013289254/article/details/70359995?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-15&spm=1001.2101.3001.4242
https://blog.csdn.net/qq_31347869/article/details/94169967
https://blog.csdn.net/thesby/article/details/50822250
https://support.huaweicloud.com/ti-atc-A800_3000_3010/altasatc_16_020.html
https://www.codenong.com/cs106883615/
http://www.meltycriss.com/2016/07/04/caffe_1_layer/
https://ewenwan.github.io/2018/07/caffe/
https://chaos.blog.csdn.net/article/details/65683988?utm_medium=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromMachineLearnPai2~default-1.essearch_pc&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromMachineLearnPai2~default-1.essearch_pc
通过B站视频,一些网页教程,自己练习基本的模型训练和阅读代码之后,最终 还是通过 深度学习 21天实战Caffe 这本书,得到了进一步的提升。
但是阅读源码和编写单元测试的时候,发觉,必须对caffe的依赖库进行学习,才能啃透caffe:
ØCUDA:GPU接口(NVIDIA提出的接口)
ØBLAS:矩阵运算接口(线性代数库)
ØProtoBuff:用于数据传输的库(google提出的库)https://developers.google.com/protocol-buffers/docs/overview;https://developers.google.com/protocol-buffers/docs/reference/overview
ØOpencv:用于读取和处理图像(图像处理库)https://docs.opencv.org/ref/2.4.13.6/dc/d8c/namespacecvflann.html
https://www.bilibili.com/video/BV1Q54y1z7kz?from=search&seid=773732718464513168
ØBoost:提供 智能指针、计时器、随机数产生器等(C++的扩展库)
ØGlog:用于写日志(google提出的库)https://github.com/google/glog#id9
ØGflags:用于处理命令行参数的一个库 https://gflags.github.io/gflags/
ØLevelDB/LMBD:用于存储数据(一个存储数据格式为 key/Value 的数据库)
ØSnappy:用于模型参数和训练参数的序列化和反序列化(google提出的一个
压缩 和 解压缩库)
ØHDF5:一种数据格式
ØGtest:用于进行单元测试(google提出的一个库)https://google.github.io/googletest/primer.html#simple-tests