深度学习21天实战caffe学习笔记《6 : Caffe代码梳理》

Caffe代码梳理

1、caffe目录结构

深度学习21天实战caffe学习笔记《6 : Caffe代码梳理》_第1张图片

2、caffe阅读路线:

  • src/caffe/proto/caffe.proto          了解基本数据结构内存对象和磁盘文件的一一映射,主要由ProtoBuffer工具完成;
  • include头文件                                理解整个框架,从基类向派生类顺藤摸瓜;
  • .cpp和.cu文件                                caffe框架不需要大改,只需要按需求派生出新的类实现即可;
  • 编写各类工具集成到caffe内部         如tools下的工具;
注:快速追踪关键字
(1)多个终端,用vi的查找命令追踪;
(2)使用linux grep,在caffe根目录下运行:
      $grep -n -H -R "XXXXX"
      [  -n : 显示行号;  -H : 显示文件名;  -R : 递归查找每个子目录;]

3、caffe支持的速度学习特性

卷积层和全连接层统称为权值层,具有可学习参数(权值):
3.1、卷积层:
卷积层计算步骤由二维增加至三维、四维卷积,多了“通道(channel)”,每个通道进行二维卷积,没有“翻转”,而是与输入图片做滑动窗口“相关”计算;
多个通道与多个卷积核分别进行二维卷积,得到多通道输出,“合并”为一个通道;
深度学习21天实战caffe学习笔记《6 : Caffe代码梳理》_第2张图片

注:其中L、I、J参数可以在.prototxt中找到,图像大小M*N,输出通道K从日志文件可以找到。
3.2、全连接层
全连接层每个节点与相邻层的所有节点都连接,计算类型为矩阵-向量乘;
              y=Wx       (输入节点向量x;维度D;输出节点向量y,维度V;W为V.D维权值矩阵)

则:
单样本前向传播计算量:CaculationsMAC=V.D
参数统计:Params =V.D
CPR值 : CPR=Caculations/Params=1(始终为1,与输入输出维度无关,权值重复利用率很低)

卷积层vs全连接层:参数量全连接层是卷积层的16倍;计算量只有25%;(得益于权值共享&局部连接)
3.3、激活函数
常用的激活函数:
在caffe中位于:include/caffe/neural_layers.hpp

src/caffe/proto/caffe.proto

message ReLUParameter {

  optional float negative_slope = 1 [default = 0];
  enum Engine {
    DEFAULT = 0;
    CAFFE = 1;
    CUDNN = 2;
  }
  optional Engine engine = 2 [default = DEFAULT];
}
Relu.layer
#ifndef CAFFE_RELU_LAYER_HPP_
#define CAFFE_RELU_LAYER_HPP_

#include 

#include "caffe/blob.hpp"
#include "caffe/layer.hpp"
#include "caffe/proto/caffe.pb.h"

#include "caffe/layers/neuron_layer.hpp"

namespace caffe {

/**
 * @brief Rectified Linear Unit non-linearity @f$ y = \max(0, x) @f$.
 *        The simple max is fast to compute, and the function does not saturate.
 */
template 
class ReLULayer : public NeuronLayer {      //派生于NeuronLayer,实现Relu激活函数的计算
 public:
  /**
   * @param param provides ReLUParameter relu_param,
   *     with ReLULayer options:
   *   - negative_slope (\b optional, default 0).
   *     the value @f$ \nu @f$ by which negative values are multiplied.
   */
  //显示构造函数
  explicit ReLULayer(const LayerParameter& param)
      : NeuronLayer(param) {}
//返回类名字符串
  virtual inline const char* type() const { return "ReLU"; }

 protected:
  //前向传播函数
  virtual void Forward_cpu(const vector*>& bottom,
      const vector*>& top);
  virtual void Forward_gpu(const vector*>& bottom,
      const vector*>& top);

  //反向传播函数
  virtual void Backward_cpu(const vector*>& top,
      const vector& propagate_down, const vector*>& bottom);
  virtual void Backward_gpu(const vector*>& top,
      const vector& propagate_down, const vector*>& bottom);
};

}  // namespace caffe

#endif  // CAFFE_RELU_LAYER_HPP_

src/caffe/layers/relu_layer.cpp

#include 
#include 

#include "caffe/layers/relu_layer.hpp"

namespace caffe {

template 
void ReLULayer::Forward_cpu(const vector*>& bottom,
    const vector*>& top) {
  const Dtype* bottom_data = bottom[0]->cpu_data();
  Dtype* top_data = top[0]->mutable_cpu_data();
  const int count = bottom[0]->count();
  Dtype negative_slope = this->layer_param_.relu_param().negative_slope();
  for (int i = 0; i < count; ++i) {
    top_data[i] = std::max(bottom_data[i], Dtype(0))
        + negative_slope * std::min(bottom_data[i], Dtype(0));
  }
}

template 
void ReLULayer::Backward_cpu(const vector*>& top,
    const vector& propagate_down,
    const vector*>& bottom) {
  if (propagate_down[0]) {
    const Dtype* bottom_data = bottom[0]->cpu_data();
    const Dtype* top_diff = top[0]->cpu_diff();
    Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();
    const int count = bottom[0]->count();
    Dtype negative_slope = this->layer_param_.relu_param().negative_slope();
    for (int i = 0; i < count; ++i) {
      bottom_diff[i] = top_diff[i] * ((bottom_data[i] > 0)
          + negative_slope * (bottom_data[i] <= 0));
    }
  }
}


#ifdef CPU_ONLY
STUB_GPU(ReLULayer);
#endif

INSTANTIATE_CLASS(ReLULayer);

}  // namespace caffe



你可能感兴趣的:(Caffe)