caffe源码分析-layer

本文主要分析caffe layer层,主要内容如下:

  1. 从整体上说明下caffe的layer层的类别,以及作用

  2. 通过proto定义与类Layer简要说明下Layer的核心成员变量;

  3. Layer类的核心成员函数


1. 类Layer overview

caffe中的Layer主要分为如下几个模块:

  1. 输入层Data Layers

Data Layers定义了caffe中网络的输入,依赖于高效的数据库,例如(LevelDB or LMDB)。并且可以对数据做预处理,例如mean subtraction, scaling, random cropping, mirroring。
常用的有:Input, ImageData.

  1. Vision Layers层(卷积相关)例如,卷积层Convolution Layer, 池化层Pooling Layer等

  2. 循环网络层Recurrent Layers 例如,LSTM, RNN等。

  3. Common Layers例如,Inner Product 全连接层,Dropout弃权层,等。

  4. Normalization Layers(归一化层)例如Local Response Normalization (LRN), Batch Normalization 。

  5. Activation / Neuron Layers(激活层),例如ReLU, Sigmoid等。

  6. Utility Layers, 例如Flatten, Reshape等。

  7. Loss Layers, 例如Sigmoid Cross-Entropy Loss, Sum-of-Squares / Euclidean等。

layer.hpp: 父类Layer,定义所有layer的基本接口。

data_layers.hpp: 继承自父类Layer,定义与输入数据操作相关的子Layer,例如DataLayer,HDF5DataLayer和ImageDataLayer等。

vision_layers.hpp: 继承自父类Layer,定义与特征表达相关的子Layer,例如ConvolutionLayer,PoolingLayer和LRNLayer等。

neuron_layers.hpp: 继承自父类Layer,定义与非线性变换相关的子Layer,例如ReLULayer,TanHLayer和SigmoidLayer等。

loss_layers.hpp: 继承自父类Layer,定义与输出误差计算相关的子Layer,例如EuclideanLossLayer,SoftmaxWithLossLayer和HingeLossLayer等。

common_layers.hpp: 继承自父类Layer,定义与中间结果数据变形、逐元素操作相关的子Layer,例如ConcatLayer,InnerProductLayer和SoftmaxLayer等。

layer_factory.hpp: Layer工厂模式类,负责维护现有可用layer和相应layer构造方法的映射表。

每个Layer根据自身需求的不同,会定义CPU或GPU版本的实现,例如ConvolutionLayer的CPU和GPU实现就定义在了两个文件中conv_layer.cpp, conv_layer.cu.


2. 通过proto定义与类Layer简要说明下Layer的核心成员变量

proto的LayerParameter核心参数如下,除了基础的参数外还有其他的继承类如:ConvolutionParameter额外参数。


// LayerParameter next available layer-specific ID: 145 (last added: crop_param)
message LayerParameter {
  optional string name = 1; // the layer name
  optional string type = 2; // the layer type
  repeated string bottom = 3; // the name of each bottom blob
  repeated string top = 4; // the name of each top blob

  // The train / test phase for computation.
  optional Phase phase = 10;

  repeated float loss_weight = 5;
  // The blobs containing the numeric parameters of the layer.
// Specifies training parameters (multipliers on global learning constants,
// and the name and other settings used for weight sharing).
  repeated ParamSpec param = 6;

  repeated BlobProto blobs = 7;

  // The size must be either 0 or equal to the number of bottoms.
  repeated bool propagate_down = 11;

  // Parameters for data pre-processing.
  optional TransformationParameter transform_param = 100;

  // Parameters shared by loss layers.
  optional LossParameter loss_param = 101;

  // Layer type-specific parameters.
  optional ConvolutionParameter convolution_param = 106;
  optional InnerProductParameter inner_product_param = 117;
}

上面的参数,我们重点关注下,ParamSpec,定义如下:


// Specifies training parameters (multipliers on global learning constants,
// and the name and other settings used for weight sharing).
message ParamSpec {
  // The names of the parameter blobs -- useful for sharing parameters among
  // layers, but never required otherwise.  To share a parameter between two
  // layers, give it a (non-empty) name.
  optional string name = 1;
  //......
  // The multiplier on the global learning rate for this parameter.
  optional float lr_mult = 3 [default = 1.0];

  // The multiplier on the global weight decay for this parameter.
  optional float decay_mult = 4 [default = 1.0];
}

此参数定义了反向传播过程的参数更新的学习率(结合solve中的base_lr),由于参数有weight和bias因此是repeated,使用的示例如下:

layer {
  name: "ip1"
  type: "InnerProduct"
  param { lr_mult: 1 }  // for weight
  param { lr_mult: 2 }  // for bias
  inner_product_param {
    num_output: 500
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
  bottom: "pool2"
  top: "ip1"
}

在solver.prototxt中我们定义了base_lr: 0.01,因此weight的学习率是0.01, bias的学习率是0.01*2.


3. Layer类的核心成员函数


template
class Layer{
protected:
  //protobuf文件中存储的layer参数,从protocal buffers格式的网络结构说明文件中读取
    //protected类成员,构造函数中初始化
    LayerParameter layer_param_;
    //层状态,参与网络的训练还是测试
    Phase phase_;
    // 可学习参数层权值和偏置参数,使用向量是因为权值参数和偏置是分开保存在两个blob中的
    // 在基类layer中初始化(只是在描述文件定义了的情况下)
    vector > > blobs_;
    // 标志每个可学习参数blob是否需要计算反向传递的梯度值
    vector param_propagate_down_;
    // 非LossLayer为零,LossLayer中表示每个top blob计算的loss的权重
    vector loss_;
private:
    /** Whether this layer is actually shared by other nets*/
    bool is_shared_;
    // 若该layer被shared,则需要这个mutex序列保持forward过程的正常运行
    shared_ptr forward_mutex_;
}

Layer的核心函数在于Forward,Backward,这两个函数调用Forward_cpu、Forward_gpu以及Backward_cpu,Backward_gpu(这四个函数子类需要实现)。


inline Dtype Forward(const vector*>& bottom,
                     const vector*>& top);
//给定相对于 top 层输出的梯度,计算其相对于输入的梯度,并传递到 bottom
 层。一个有参数的 layer 需要计算相对于各个参数的梯度值并存储在内部。
inline void Backward(const vector*>& top,
                     const vector& propagate_down,
                     const vector*>& bottom);

protected:
//纯虚函数,子类必须实现,使用cpu经行前向计算
virtual void Forward_cpu(const vector*>& bottom,
                         const vector*>& top) = 0;
//使用gpu经行前向计算, 如果gpu没有实现则使用默认的CPU版本
virtual void Forward_gpu(const vector*>& bottom,
                         const vector*>& top) {
    // LOG(WARNING) << "Using CPU code as backup.";
    return Forward_cpu(bottom, top);
}
//纯虚函数,派生类必须实现
virtual void Backward_cpu(const vector*>& top,
                          const vector& propagate_down,
                          const vector*>& bottom) = 0;
virtual void Backward_gpu(const vector*>& top,
                          const vector& propagate_down,
                          const vector*>& bottom) {
    // LOG(WARNING) << "Using CPU code as backup.";
    Backward_cpu(top, propagate_down, bottom);
}

例如Backward仅仅在Backward_cpu,Backward_gpu做了一层包装:

template 
inline void Layer::Backward(const vector*>& top,
                                   const vector& propagate_down,
                                   const vector*>& bottom) {
    switch (Caffe::mode()) {
        case Caffe::CPU:
            Backward_cpu(top, propagate_down, bottom);
            break;
        case Caffe::GPU:
            Backward_gpu(top, propagate_down, bottom);
            break;
        default:
            LOG(FATAL) << "Unknown caffe mode.";
    }
}

Forward同理:

// 前向传播和反向传播接口。 每个Layer的派生类都应该实现Forward_cpu()
template 
inline Dtype Layer::Forward(const vector*>& bottom,
                                   const vector*>& top) {
    // Lock during forward to ensure sequential forward
    Lock();
    Dtype loss = 0;
    Reshape(bottom, top);// we may change input data size(num)
    switch (Caffe::mode()) {
        case Caffe::CPU:
            Forward_cpu(bottom, top);
            // .......
            break;
        case Caffe::GPU:
            Forward_gpu(bottom, top);
#ifndef CPU_ONLY
            // gpu realize, omitted
#endif
            break;
        default:
            LOG(FATAL) << "Unknown caffe mode.";
    }
    Unlock();
    return loss;
}


caffe系列源码分析介绍

本系列深度学习框架caffe 源码分析主要内容如下:

1. caffe源码分析-cmake 工程构建:

caffe源码分析-cmake 工程构建主要内容:

自己从头构建一遍工程,这样能让我更好的了解大型的项目的构建。当然原始的caffe的构建感觉还是比较复杂(主要是cmake),我这里仅仅使用cmake构建,而且简化点,当然最重要的是支持CLion直接运行调试(如果需要这个工程可以评论留下你的邮箱,我给你发送过去)。

这里写图片描述

2. caffe的数据内存分配类SyncedMemory, 以及类Blob数据传输的媒介.

主要内容:
caffe源码分析-SyncedMemory
caffe源码分析-Blob
其中Blob分析给出了其直接与opencv的图片相互转化以及操作,可以使得我们更好的理解Blob.

3. caffe layer的源码分析,包括从整体上说明了layer类别以及其proto定义与核心函数.

内容如下:
caffe源码分析-layer
caffe源码分析-ReLULayer
caffe源码分析-inner_product_layer
caffe源码分析-layer_factory

首先分析了最简单的layer Relu,然后在是inner_product_layer全连接层, 最后是layer_factorycaffe中 以此工厂模式create各种Layer.

4. 数据输入层,主要是多线程+BlockingQueue的方式读取数据训练:

内容如下:
caffe源码分析-BlockingQueue
caffe源码分析-InternalThread
caffe源码分析-DataReader

5. IO处理例如读取proto文件转化为网络,以及网络参数的序列化

内容如下:
caffe源码分析-DataTransformer
caffe源码分析-db, io

6. 最后给出了使用纯C++结合多层感知机网络训练mnist的示例

内容如下:

caffe c++示例(mnist 多层感知机c++训练,测试)

类似与caffe一样按照layer、solver、loss、net等模块构建的神经网络实现可以见下面这篇blog,相信看懂了这个python的代码理解caffe框架会更简单点.

神经网络python实现


最后如果需要cmake + CLion直接运行调试caffe的代码工程,可以评论留下你的邮箱,我给你发送过去.

参考:
http://caffe.berkeleyvision.org/tutorial/layers.html
https://imbinwang.github.io/research/inside-caffe-code-layer

你可能感兴趣的:(caffe,caffe,layer,caffe,layer源码)