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

1、如何有效阅读caffe源码

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

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

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

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

2、ReLU激活函数

    激活函数,用在各个卷积层和全连接层输出位置。激活函数是深度网络非线性的主要来源。通常包括:simgoid(f(x)=(1+e-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层描述

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

下面开始按步骤解析源码:
3.1、阅读src/cafffe/proto/caffe.proto中ReLU层参数

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

3.2、阅读include/caffe/layers/relu_layer.hpp中类申明
  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 caffe {  
  15. //template:指定模板类型参数,Dtype:表示一个类型  
  16. template <typename Dtype>  
  17. //新定义ReLULayer类,其继承NeuronLayer类  
  18. class ReLULayer : public NeuronLayer<Dtype> {  
  19.  public:  
  20. //显式构造函数,NeuronLayer的参数显式传递给ReLULayer,LayerParameter:protobuf文件中存储的layer参数  
  21.   explicit ReLULayer(const LayerParameter& param)   
  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 vector<Blob<Dtype>*>& bottom,  
  30.       const vector<Blob<Dtype>*>& top);  
  31.   //GPU版本前馈实现  
  32.   virtual void Forward_gpu(const vector<Blob<Dtype>*>& bottom,  
  33.       const vector<Blob<Dtype>*>& top);  
  34.   
  35. //反向传播函数  
  36.   //top为输出blob,propagate_down为bottom索引,bottom为输入blob  
  37.   virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,  
  38.       const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);  
  39.   virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,  
  40.       const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);  
  41. };  
  42.   
  43. }  // namespace caffe  
  44.   
  45. #endif  // CAFFE_RELU_LAYER_HPP_</span>  
3.3、阅读src/caffe/layers/relu_layer.cpp中代码
  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 caffe {  
  7.   
  8. template <typename Dtype>  
  9. //定义前向传播函数  
  10. void ReLULayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,  
  11.     const vector<Blob<Dtype>*>& top) {  
  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 count = bottom[0]->count();  
  18.   //Leak ReLU参数,从layer_param_中获得,默认为0(negative_slope=0),即普通ReLU  
  19.   Dtype negative_slope = this->layer_param_.relu_param().negative_slope();  
  20.   for (int i = 0; i < count; ++i) {  
  21.     top_data[i] = std::max(bottom_data[i], Dtype(0)) //ReLU(f(x)=max(0,x))  
  22.         + negative_slope * std::min(bottom_data[i], Dtype(0));  
  23.   }  
  24. }  
  25.   
  26. template <typename Dtype>  
  27. //定义反向传播函数  
  28. void ReLULayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,  
  29.     const vector<bool>& propagate_down,  
  30.     const vector<Blob<Dtype>*>& bottom) {  
  31.   //如果需要做反向传播计算,propagate_down是与计算关于bottom的梯度相关,  
  32.   //在caffe的BP实现中非常重要  
  33.   if (propagate_down[0]) {  
  34.     //(只读)获得前一层的data指针,data:前向传播所用数据  
  35.     const Dtype* bottom_data = bottom[0]->cpu_data();  
  36.     //(只读)获得后一层的diff指针,diff:反向传播所用数据  
  37.     const Dtype* top_diff = top[0]->cpu_diff();  
  38.     //(读写)获得前一层的diff指针,是损失函数关于当前层的输入(bottom)的偏导数  
  39.     Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();  
  40.     //获得需要参与计算的元素总和  
  41.     const int count = bottom[0]->count();  
  42.     //Leaky ReLU参数,默认为0  
  43.     Dtype negative_slope = this->layer_param_.relu_param().negative_slope();  
  44.     for (int i = 0; i < count; ++i) {  
  45.     //ReLU的导函数就是(bottom_data[i] > 0,根据求导链式法则,后一层的误差乘以导函数得到前一层的误差  
  46.       bottom_diff[i] = top_diff[i] * ((bottom_data[i] > 0)  
  47.           + negative_slope * (bottom_data[i] <= 0));  //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>  

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值