剖析Caffe源码之Layer
目录
Layer介绍
Layer分析
LayerParameter
Class Layer
Layer派生类
Layer源码
Layer构造函数
SetUp函数
Forward函数
Backward函数
总结
参考资料
Layer介绍
如果将caffe比作成一个大楼,那么Blob就是盖成大楼的每块砖瓦,而Layer就是用Blob组成的一层层楼房,layer是神经网络中模型中比较关键的部分,是构成整个计算过程的基础。在上节中,通过对Blob源码进行剖析,对Blob进行了一定了解,而Layer是以Blob作为输入和输出,Layer其本质就是根据输入计算输出,每个layer只完成一类特定的计算,例如convolution操作、pooling、非线性变换、内积运算,以及数据加载、归一化和损失计算等。
上图是一个经典的卷积Layer,是以bottom blob为输入,输出为top blob。
官方文档:http://caffe.berkeleyvision.org/tutorial/net_layer_blob.html
Layer分析
在看Layer源码之前首先需要对整个Layer参数进行了解,Layer的入参除了Blob之外还有很多其他参数,用于配置
LayerParameter
LayerParameter参数的定义在src\caffe\proto\caffe.proto,是采用的ProtoBuf格式,上节已经对ProtoBuf 基本语法进行了解析:
注意在LayerParameter结构之前有一段说明,记录了该message中的number ID使用到了哪里,以及最近新添加的参数,ProtoBuf规定ID不能重复。原代码中对每个参数都进行了详细描述
message LayerParameter {optional string name = 1; // the layer name: Layer 名称optional string type = 2; // the layer type: Layer typerepeated string bottom = 3; // the name of each bottom blob: bottom blob入参名称repeated string top = 4; // the name of each top blob:top blob出参名称// The train / test phase for computation.optional Phase phase = 10; //是用于模型训练还是测试,TRAIN值为0:用于训练,TEST值为1:用于测试// The amount of weight to assign each top blob in the objective.// Each layer assigns a default value, usually of either 0 or 1,// to each top blob.repeated float loss_weight = 5;// 每个输出top blob的loss权重// Specifies training parameters (multipliers on global learning constants,// and the name and other settings used for weight sharing).repeated ParamSpec param = 6; //特定训练参数,可以查看ParamSpec结构// The blobs containing the numeric parameters of the layer.repeated BlobProto blobs = 7; // 每层的参数 blob// Specifies whether to backpropagate to each bottom. If unspecified,// Caffe will automatically infer whether each input needs backpropagation// to compute parameter gradients. If set to true for some inputs,// backpropagation to those inputs is forced; if set false for some inputs,// backpropagation to those inputs is skipped.//// The size must be either 0 or equal to the number of bottoms.repeated bool propagate_down = 11;// Rules controlling whether and when a layer is included in the network,// based on the current NetState. You may specify a non-zero number of rules// to include OR exclude, but not both. If no include or exclude rules are// specified, the layer is always included. If the current NetState meets// ANY (i.e., one or more) of the specified rules, the layer is// included/excluded.repeated NetStateRule include = 8;repeated NetStateRule exclude = 9;// Parameters for data pre-processing.optional TransformationParameter transform_param = 100;// Parameters shared by loss layers.optional LossParameter loss_param = 101;// Layer type-specific parameters.//// Note: certain layers may have more than one computational engine// for their implementation. These layers include an Engine type and// engine parameter for selecting the implementation.// The default for the engine is set by the ENGINE switch at compile-time.optional AccuracyParameter accuracy_param = 102;optional ArgMaxParameter argmax_param = 103;optional BatchNormParameter batch_norm_param = 139;optional BiasParameter bias_param = 141;optional ClipParameter clip_param = 148;optional ConcatParameter concat_param = 104;optional ContrastiveLossParameter contrastive_loss_param = 105;optional ConvolutionParameter convolution_param = 106;optional CropParameter crop_param = 144;optional DataParameter data_param = 107;optional DropoutParameter dropout_param = 108;optional DummyDataParameter dummy_data_param = 109;optional EltwiseParameter eltwise_param = 110;optional ELUParameter elu_param = 140;optional EmbedParameter embed_param = 137;optional ExpParameter exp_param = 111;optional FlattenParameter flatten_param = 135;optional HDF5DataParameter hdf5_data_param = 112;optional HDF5OutputParameter hdf5_output_param = 113;optional HingeLossParameter hinge_loss_param = 114;optional ImageDataParameter image_data_param = 115;optional InfogainLossParameter infogain_loss_param = 116;optional InnerProductParameter inner_product_param = 117;optional InputParameter input_param = 143;optional LogParameter log_param = 134;optional LRNParameter lrn_param = 118;optional MemoryDataParameter memory_data_param = 119;optional MVNParameter mvn_param = 120;optional ParameterParameter parameter_param = 145;optional PoolingParameter pooling_param = 121;optional PowerParameter power_param = 122;optional PReLUParameter prelu_param = 131;optional PythonParameter python_param = 130;optional RecurrentParameter recurrent_param = 146;optional ReductionParameter reduction_param = 136;optional ReLUParameter relu_param = 123;optional ReshapeParameter reshape_param = 133;optional ScaleParameter scale_param = 142;optional SigmoidParameter sigmoid_param = 124;optional SoftmaxParameter softmax_param = 125;optional SPPParameter spp_param = 132;optional SliceParameter slice_param = 126;optional SwishParameter swish_param = 147;optional TanHParameter tanh_param = 127;optional ThresholdParameter threshold_param = 128;optional TileParameter tile_param = 138;optional WindowDataParameter window_data_param = 129;
}
Class Layer
Layer是caffe较为复杂模块,其中layer是所有layer基类,定义所有layer的基本接口,其头文件为caffe\include\caffe\layer.hpp,C++文件在\src\caffe\layer.cpp中
在layer.hpp文件中其大部分接口都是虚函数,具体实现是由各个派生类来实现,class layer中的接口成员主要由以下列表:
Layer方法类别 | Layer方法 | 描述 |
构造与析构函数 | explicit Layer(const LayerParameter& param) | 带参数显示构造函数 |
virtual ~Layer() | 析构函数,由具体派生类来实现 | |
Setup以及LayerParameter相关函数 |
void SetUp (const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) |
bottom Blob为Layer输入参数 top Blob为其输出参数 为Layer的环境安装函数,主要是参数设置 |
virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top |
虚函数,Layer安装函数,由具体的派生类来实现 | |
virtual void Reshape (const vector<Blob<Dtype>*>& bottom, |
虚函数,根据bottom的输入shape,设置其输出Blob shape,由具体的派生类来实现 | |
const LayerParameter& layer_param() | 获取Layer的入参LayerParameter,将其存储在class layer中的私有变量layer_param_中 | |
virtual void ToProto(LayerParameter* param, bool write_diff = false); | 获取Layer的入参LayerParameter,将其存储在class layer中的私有变量layer_param_中 | |
virtual inline const char* type() | 虚函数,返回Layer type,具体实现由派生类来实现 | |
前向传播和后向传播 |
inline Dtype Forward(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) |
前向传播实现函数,bottom为输入,top为输出 |
inline void Backward(const vector<Blob<Dtype>*>& top, const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) |
后向传播实现函数,bottom为输入,top为输出 propagate_down为与bottom 大小相对的标志位vector,主要用来标记是否做误差梯度 |
|
virtual inline bool AllowForceBackward (const int bottom_index) |
虚函数,是否允许强制反向传播,如果 AllowForceBackward(i) == false,则会忽略force_backward设定,具体实现由派生类来实现 | |
inline bool param_propagate_down(const int param_id) | 指定该Layer是否计算相对权值和偏置项的梯度,具体相对谁由param_id指定 | |
inline void set_param_propagate_down(const int param_id, const bool value) | 设置该Layer是否计算相对权值或偏置项的梯度,具体相对谁由param_id指定 | |
virtual void Forward_cpu (const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) |
虚函数,CPU版本的前向传播函数,具体实现是由派生类来实现 | |
virtual void Forward_gpu (const vector<Blob<Dtype>*>& bottom, |
虚函数,GPU版本的前向传播函数,具体实现由派生类来实现 | |
Loss相关 | inline Dtype loss(const int top_index) | 返回某个top blob标量loss值 |
inline void set_loss(const int top_index, const Dtype value) | 根据给定的index,设置某个top blob标量loss值 | |
virtual inline const char* type() | 虚函数,返回Layer type,具体实现由派生类来实现 | |
Blob相关 | virtual inline int ExactNumBottomBlobs() | 虚函数,返回Bottom Blob的数量,具体实现由派生类来实现 |
virtual inline int MinBottomBlobs() | 虚函数,返回layer所需要的最小Bottom Blob数量,具体实现由派生类来实现 | |
virtual inline int MaxBottomBlobs() | 虚函数,返回layer期望的最多Bottom Blob数量,具体实现由派生类来实现 | |
virtual inline int ExactNumTopBlobs() | 虚函数,返回layer的输出Top Bottom Blob数量,具体实现由派生类来实现 | |
virtual inline int MinTopBlobs() | 虚函数,返回期望最小的Tob Blob数量,具体实现由派生类来实现 | |
virtual inline int MaxTopBlobs() | 虚函数,返回期望最大的Tob Blob数量,具体实现由派生类来实现 | |
virtual inline bool EqualNumBottomTopBlobs() | 虚函数,输入bottom与输出top数量是否相同,如果相对返回true,否则返回false,具体实现由派生类来实现 | |
virtual inline bool AutoTopBlobs() | 虚函数,是否允许匿名Top Blob,即由该layer自动创建,如为真,在Net:Init()函数会创建足够多的匿名Top Blob来满足该Layer ExactNumTopBlobs()、MinTopBlobs()需求 | |
Layer相关参数 | LayerParameter layer_param_ | 用于存储LayerParameter参数 |
Phase phase_ | 用于训练train还是test参数 | |
vector<shared_ptr<Blob<Dtype> > > blobs_ | Layer内部权值或偏置项,以Blob方式组织 | |
vector<bool> param_propagate_down_ | 标志位,是否计算对应参数的误差梯度 | |
vector<Dtype> loss_ | 标志位,在目标函数中,是否每个Top Blob都有非零权重 |
最新的caffe版本中Layer类中去掉了一个Layer是否被多个Net共享相关函数,例如IsShare(),ShareInParallel()等相关函数。
Layer派生类
从上面列表中在Layer大部分关键函数实现都是用的虚函数,并没有实现,而是需要相关的派生类自己实现,由此可知Layer只是个基类,定义了大部分功能的接口。
Caffe最新代码中由此Layer派生出:Data Layer、Vision Layer、Recurrent Layers、Common Layers、Normalization Layers、Activation/Neuron Layers、Utility Layers等几大功能模块。
每次Caffe的更新,都会将添加大量的Layer,下面是最新版本的Layer的分布图,与之前版本已经有了很大不同,但是其基本架构没用多大变化
Layer源码
通过官网资料:http://caffe.berkeleyvision.org/tutorial/net_layer_blob.html,看到每个layer的主要是三个关键函数实现:
setup:初始化layer,在网络链接时要首先调用setup初始化
Forward:前向传播,根据输入bottom计算输出,并发送到top
Backword:反向传播,根据输出的tio 计算出梯度误差,并发送给输出bottom。
官方文档说明如下:
最新版本的caffe Layer CPP文件\src\caffe\layer.cpp如下:
基本上为一个空文件,这个主要是
- Layer是个基类 大部分接口都是虚函数形式,需要派生类来实现
- 需要Layer实现的接口较少,直接在 caffe\include\caffe\layer.hpp函数中实现,代码会更简洁
Layer构造函数
Layer显式带参数构造函数源码如下:
通过函数注释说明可知道,构造函数是不需要派生类来实现的,由基类来实现,如果由其他一些特殊参数可以通过Setup函数来实现
- 首先将将传递的LayerParameter参数保存到layer_param_中,以便供后面进行从处理。
- 其次将LayerParameter中的phase单独保存到phase中 是用于Train还是Test
- 最后将LayerParameter中的blobs参数保存到blobs_中,为该层的数值参数的Blob
SetUp函数
SetUp()函数是Net调Layer首先需要做的第一步,对该Layer 一些变量环境进行安装:
该函数入参bottom是Layer的入参,top为Layer出参,Layer的shape在LayerSetup中进行设置。
首先调用CheckBlobCounts()对入参bottom和出参top进行检查,如果该检查不满足要求,可以在派生类中重新写该函数进行覆盖。
LayerSetup()函数由各个派生类来实现,主要是每个派生Layer类可能都有特殊的安装需求,需要在具体的Layer中实现。
Reshape()同样也是由派生类来实现,主要是具体实现的layer,其输出格式每个都不一样。
为每个输出top分配loss权重,从 LayerParameter参数中读取每个出身top的loss_weight,并调用set_loss,将其保存到loss_中,其中0是不参与目标计算,1是参与目标计算:
最后是将找到Blob 中diff_数据指针,调用caffe_set()将其保存到diff_中:
SetUp函数主要完成几件事情
- 调用派生类的LayerSetup,安装派生类的特殊要求
- 设置输出top的shape
- 设置Loss权重
Forward函数
Forward计算前向传播,其代码如下:
其处理首先要区分是在CPU上计算还是在GPU上进行计算,如果是在CPU上则调用Forward_cpu()函数,如果是在GPU上则调用Forward_gpu()函数,
上述两个函数为虚函数,需要在具体的Layer自己来实现。计算完成之后,根据所设置的权重是否计算输出权重,并输出最后的结果到top中。
Backward函数
Bakcward计算其后向传播,其函数源码为:
其处理流程同样区分CPU或者GPU,最后分别调用Backward_cpu或者Backward_gpu:
两个函数同样需要派生的Layer来实现
总结
通过对Layer源码可以看到其layer只是个框架基类,实现功能较少,需要每个相应的派生类来自己实现,后面将会对派生出来的几个大类分别进行分析
参考资料
《21天实战caffe》
http://caffe.berkeleyvision.org/tutorial/net_layer_blob.html
剖析Caffe源码之Layer相关推荐
- 剖析Caffe源码之Layer_factory
在<剖析Caffe源码之Layer>,对Layer代码进行了基本分析,可以知道Layer是所有的其他Layer的基本类,由此来扩展出各个神经网络中所需要的Layer,体现了caffe的可扩 ...
- 剖析Caffe源码之Net---Net构造函数
目录 Net构造函数 读取Prototxt ReadProtoFromTextFile UpgradeNetAsNeeded 设置网络状态 Init函数 FilterNet InsertSplits ...
- caffe源码分析-layer
本文主要分析caffe layer层,主要内容如下: 从整体上说明下caffe的layer层的类别,以及作用 通过proto定义与类Layer简要说明下Layer的核心成员变量; Layer类的核心成 ...
- Caffe源码中layer文件分析
Caffe源码(caffe version commit: 09868ac , date: 2015.08.15)中有一些重要的头文件,这里介绍下include/caffe/layer.hpp文件的内 ...
- 剖析Caffe源码之Net类变量
在<解析Net的构造函数源码>过程中,可以看到Net类有很多变量,用于存储网络中的各种信息,caffe中类的变量命名规则统一在变量名中加上'_',查看net.hpp代码可以看到使用了很多变 ...
- 剖析Caffe源码之Net(上)---NetParameter参数
前面几篇文章主要分析了Caffe中的Blob和Layer源码,了解到了Caffe中的参数数据结构文件caffe.proto,掌握了各个Layer是如何注册到Caffe中,下面将分析Net层. 在分析N ...
- 剖析Caffe源码之InputLayer
ImageDataLayer可以完成caffe自动读取图片进行模型训练和推断,但是在实际的应用中一般图像都是通过sensor采集而来,将采集得到的图片送到训练好的模型中进行识别.推断,此时就需要用到I ...
- 剖析Caffe源码之ImageDataLayer
目录 ImageDataLayer参数 Source root_folder new_height.new_width is_color crop_size Prototxt配置 Class Imag ...
- 剖析Caffe源码之Net---NetParameter参数
前面几篇文章主要分析了Caffe中的Blob和Layer源码,了解到了Caffe中的参数数据结构文件caffe.proto,掌握了各个Layer是如何注册到Caffe中,下面将分析Net层. 在分析N ...
最新文章
- 谷歌知名前 AI 研究员无辜被裁,CEO:调查!
- OpenStack 虚拟机启动流程 UML 分析(内含 UML 源码)
- git:config命令
- POJ - 1922 Ride to School(思维+贪心)
- python万年历源代码_python万年历实现代码 含运行结果
- 2017-2018-1 20155308 《信息安全系统设计基础》课堂第六章测试(补做)
- 一文快速探索视频用户网络画像与应用
- 最长等差数列_(Trivial) LeetCode 1027—最长等差子序列
- GD32 MCU USB开发学习记录
- c# 打印 html,c# – 使用模板打印
- WineQQ2012 最新下载
- ps初始化html面表时停止工作打不开,PS打不开提示不能初始化因为首选项是无效的该怎么处理?...
- 【Books系列】2022年:《拼职场》读书笔记
- Swift 5.1 温故而知新笔记系列之第七天
- 微信小程序后台销毁时间 演变和总结(热启动时间限制)
- 快捷键大全(实用版)
- burpsuit 靶场(Directory traversal)
- java eclipse 查看版本_怎么查看eclipse的版本号
- 欢迎使小程序 mpvue vantweapp
- 洛谷3165 CQOI2014 排序机械臂 splay