layer层的作用
Caffe
十分强调网络的层次性,
数据输入,卷积,非线性变换(
ReLU
等),
网络连接,损失函数计算等操作都由一个Layer
来
实现。
layer是网络的基本单元,由此派生出各种层类。创建一个caffe
模型只需要定义一个
prototxt
文件即可。也可以通过
修改layer或增加自己layer
来实现自己的模型
。
要创建一个Caffe模型,需要在协议缓冲区定义文件(prototxt)中定义模型架构。
层和层参数定义在
src/caffe/proto/caffe.proto
文件中。
编译之后产生
.pb.cc
和一个
pb.h
的文件。
在
neuron_layers.hpp、data_layer.hpp、vision_layers.hpp、common_layers.hpp、loss_layers.hpp这5
大类层头文件中都有调用,可以把
prototxt
中每层的配置参数读入到配置网络的每一层的程序中。
layer.hpp 抽象基类介绍
layer.hpp
是所有
layer
相关的头文件,是抽象出来的基类,其他
5
大类都是在它基础上继承得到。
layer
中主要有三个参数:
(
1
)
layer_param_
是
protobuf
文件中存储的
layer
参数
;
(
2
)
blobs_
存储
layer
的参数,在程序中用的;
(
3
)
param_propagate_down_ bool
类型用来表示是否计算各个
blob
参数的
diff
,即传播误差。
Layer
中三个主要函数:
(1)SetUp()
根据实际的参数设置进行实现,对各种类型的参数初始化;
(2)Forward()
和
Backward()
对应前向计算和反向更新,输入统一都是
bottom
,输出为
top
,其中
Backward
里面
propagate_down
参数,用来表示该
Layer
是否反向传播参数。
在
Forward
和Backward
的具体实现里,会根据Caffe::mode()
进行对应的操作,即使用cpu或者gpu进行计算,两个都实现了对应的接口Forward_cpu
、Forward_gpu
和Backward_cpu
、Backward_gpu
,这些接口都是virtual
,具体还是要根据layer的类型进行对应的计算(注意:有些layer并没有GPU计算的实现,所以封装时加入了CPU的计算作为后备)。
另外,还实现了ToProto
的接口,将Layer的参数写入到protocol buffer文件中。
Layer中程序框架
从图中可以得到
layer
主要有
5
大类组成
:
(1)数据层
Data层为数据输入层,头文件定义src/caffe/include/caffe/data_layer.hpp中,作为网络的最底层,主要实现数据输入和格式的转换。
(2)神经元(激活)层
Neuron层为元素级别运算层,头文件定义在src/caffe/include/caffe/neuron_layers.hpp中,其派生类主要是元素级别的运算(比如Dropout运算,激活函数ReLu,Sigmoid等)。
(3)特征表达层
Vision层为图像卷积相关层,头文件定义在src/caffe/include/caffe/vision_layers.hpp 中,像convolusion、pooling、LRN都在里面,按官方文档的说法,是可以输出图像的,这个要看具体实现代码了。里面有个im2col的实现。
(4)网络连接层
Common层为网络连接层,头文件定义在src/caffe/include/caffe/common_layer.hpp中。Caffe提供了单个层或多个层的连接,并在这个头文件中声明。包括了常用的全连接层InnerProductLayer类。
(5)损失函数层
Loss层为损失函数层,头文件定义在src/caffe/include/caffe/loss_layers.hpp中。前面的data layer和common layer都是中间计算层,虽然会涉及到反向传播,但传播的源头来自于loss_layer,即网络的最终端。这一层因为要计算误差,所以输入都是2个blob,输出1个blob。
总之,data
负责输入,
vision
负责卷积相关的计算,
neuron
和
common
负责中间部分的数据计算,而
loss
是最后一部分,负责计算反向传播的误差。具体的实现都在
src/caffe/layers
里面。