零基础学caffe源码 ReLU激活函数


原创 2016年08月03日 17:30:19





1、如何有效阅读caffe源码


    1、caffe源码阅读路线最好是从src/cafffe/proto/caffe.proto开始,了解基本数据结构内存对象和磁盘文件的一一映射关系,中间过程都由ProtoBuffer工具自动完成。

    2、看include/目录中.hpp头文件,通过头文件类申明理解整个框架。从基类向派生类,掌握这些类。

    3、看src/目录中.cpp和.cu源文件,亦可以按需求派生新的类。

    4、编写各类工具,集成到caffe内部,如tools/下就有训练模型,提取特征,转换数据格式等工具。

2、ReLU激活函数



-x)-1)和tanh(f(x)=sinhx/coshx,图形类似于arctanx,但是值域是[-1,1])作为激活函数。

    用ReLU(f(x)=max(0,x))作为激活函数的原因是:加速收敛、解决了梯度消失问题

3、ReLU函数caffe源码解析


    在models/bvlc_alexnet/train_val.prototxt网络模型设置中找到了ReLU层描述



[cpp] view plain copy

1. //ReLU层,新的非线性层
2. layer {  
3. "relu1"  //层名
4. "ReLU"  //层类型
5. "conv1"  //层输入
6. "conv1"  //层输出
7. }


下面开始按步骤解析源码:


3.1、阅读src/cafffe/proto/caffe.proto中ReLU层参数




[cpp] view plain copy


1. //存储ReLU层参数的数据结构类
2. message ReLUParameter {  
3. //message:数据结构类,ReLUParameter为其对象
4. //optional;表示一个可选字段,required:表示一个必须字段
5. //repeated:表示该字段可以包含多个元素,和optional特性相同,类似数组
6. float negative_slope = 1 [default
7. enum Engine {  //枚举Engine中所有元素
8.     DEFAULT = 0;  
9.     CAFFE = 1;  
10.     CUDNN = 2;  
11.   }  
12. default
13. }


3.2、阅读include/caffe/layers/relu_layer.hpp中类申明


[cpp] view plain copy


1. <span style="font-family:KaiTi_GB2312;font-size:24px;">//头文件中的 #ifndef/#define/#endif,防止该头文件被重复引用
2. #ifndef CAFFE_RELU_LAYER_HPP_   
3. #define CAFFE_RELU_LAYER_HPP_
4.   
5. #include <vector>
6.   
7. #include "caffe/blob.hpp"
8. #include "caffe/layer.hpp"
9. #include "caffe/proto/caffe.pb.h"
10.   
11. #include "caffe/layers/neuron_layer.hpp"
12.   
13. //ReLULayer,派生于NeuronLayer,实现了ReLU激活函数计算
14. namespace
15. //template:指定模板类型参数,Dtype:表示一个类型
16. template <typename
17. //新定义ReLULayer类,其继承NeuronLayer类
18. class ReLULayer : public
19. public:  
20. //显式构造函数,NeuronLayer的参数显式传递给ReLULayer,LayerParameter:protobuf文件中存储的layer参数
21. explicit ReLULayer(const
22.       : NeuronLayer<Dtype>(param) {}  
23. //虚内联函数,const成员函数,返回类名字符串
24. virtual inline const char* type() const { return "ReLU"; }  
25.   
26. protected:  //bottom为输入,top为输出
27. //前向传播函数
28. //CPU版本前馈实现
29. virtual void Forward_cpu(const
30. const
31. //GPU版本前馈实现
32. virtual void Forward_gpu(const
33. const
34.   
35. //反向传播函数
36. //top为输出blob,propagate_down为bottom索引,bottom为输入blob
37. virtual void Backward_cpu(const
38. const vector<bool>& propagate_down, const
39. virtual void Backward_gpu(const
40. const vector<bool>& propagate_down, const
41. };  
42.   
43. }  // namespace caffe
44.   
45. #endif  // CAFFE_RELU_LAYER_HPP_</span>

3.3、阅读src/caffe/layers/relu_layer.cpp中代码


[cpp] view plain copy


1. <span style="font-family:KaiTi_GB2312;font-size:24px;">#include <algorithm>  
2. #include <vector>
3.   
4. #include "caffe/layers/relu_layer.hpp"
5.   
6. namespace
7.   
8. template <typename
9. //定义前向传播函数
10. void ReLULayer<Dtype>::Forward_cpu(const
11. const
12. //(只读)获得输入blob的data指针
13. const Dtype* bottom_data = bottom[0]->cpu_data(); //->:指针引用
14. //(读写)获得输出blob的data指针
15.   Dtype* top_data = top[0]->mutable_cpu_data();  
16. //获得输入blob元素个数
17. const int
18. //Leak ReLU参数,从layer_param_中获得,默认为0(negative_slope=0),即普通ReLU
19. this->layer_param_.relu_param().negative_slope();  
20. for (int
21. //ReLU(f(x)=max(0,x))
22.         + negative_slope * std::min(bottom_data[i], Dtype(0));  
23.   }  
24. }  
25.   
26. template <typename
27. //定义反向传播函数
28. void ReLULayer<Dtype>::Backward_cpu(const
29. const vector<bool>& propagate_down,  
30. const
31. //如果需要做反向传播计算,propagate_down是与计算关于bottom的梯度相关,
32. //在caffe的BP实现中非常重要
33. if
34. //(只读)获得前一层的data指针,data:前向传播所用数据
35. const
36. //(只读)获得后一层的diff指针,diff:反向传播所用数据
37. const
38. //(读写)获得前一层的diff指针,是损失函数关于当前层的输入(bottom)的偏导数
39.     Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();  
40. //获得需要参与计算的元素总和
41. const int
42. //Leaky ReLU参数,默认为0
43. this->layer_param_.relu_param().negative_slope();  
44. for (int
45. //ReLU的导函数就是(bottom_data[i] > 0,根据求导链式法则,后一层的误差乘以导函数得到前一层的误差
46.       bottom_diff[i] = top_diff[i] * ((bottom_data[i] > 0)  
47. //negative_slope=0
48.     }  
49.   }  
50. }  
51.   
52. #ifdef CPU_ONLY
53. STUB_GPU(ReLULayer);  
54. #endif
55.   
56. INSTANTIATE_CLASS(ReLULayer);  
57.   
58. }  // namespace caffe</span>