您的位置:首页 > Web前端

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

2018-01-17 19:20 375 查看

Caffe代码梳理

1、caffe目录结构



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)”,每个通道进行二维卷积,没有“翻转”,而是与输入图片做滑动窗口“相关”计算;多个通道与多个卷积核分别进行二维卷积,得到多通道输出,“合并”为一个通道;


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

#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 <typename Dtype>
class ReLULayer : public NeuronLayer<Dtype> {      //派生于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<Dtype>(param) {}
//返回类名字符串
virtual inline const char* type() const { return "ReLU"; }

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

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

}  // namespace caffe

#endif  // CAFFE_RELU_LAYER_HPP_

src/caffe/layers/relu_layer.cpp
#include <algorithm>
#include <vector>

#include "caffe/layers/relu_layer.hpp"

namespace caffe {

template <typename Dtype>
void ReLULayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& 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 <typename Dtype>
void ReLULayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down,
const vector<Blob<Dtype>*>& 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: