通常的情况下,我们遇到的train_val.prototxt文件的输入层都是下面这样的:
name: "CIFAR10_quick"
layer {
name: "cifar"
type: "Data"
top: "data"
top: "label"
include {
phase: TRAIN
}
transform_param {
# mirror: true
# mean_file: "examples/cifar10/mean.binaryproto"uu
mean_file: "myself/00b/00bmean.binaryproto"
}
data_param {
# source: "examples/cifar10/cifar10_train_lmdb"
source: "myself/00b/00b_train_lmdb"
batch_size: 50
backend: LMDB
}
}
layer {
name: "cifar"
type: "Data"
top: "data"
top: "label"
include {
phase: TEST
}
transform_param {
# mean_file: "examples/cifar10/mean.binaryproto"
mean_file: "myself/00b/00bmean.binaryproto"
}
data_param {
# source: "examples/cifar10/cifar10_test_lmdb"
source: "myself/00b/00b_val_lmdb"
batch_size: 50
backend: LMDB
}
}
但是在FCN的网络中我遇到了这样的一个输入层,这显然并不是我们常见的caffe输入层了。
layer {
name: "data"
type: "Python"
top: "data"
top: "label"
python_param {
module: "pascalcontext_layers" # 模型名称 -- usually the filename
layer: "PASCALContextSegDataLayer" # 层名称-- the class name in the module
param_str: "{\'context_dir\': \'../../data/pascal-context\', \'seed\': 1337, \'split\': \'train\', \'voc_dir\': \'../../data/pascal\'}" # 这里还指定了一些参数
}
}
Caffe通过Boost中的Boost.Python模块来支持使用Python定义Layer
原因有两点:
- 使用C++增加新的Layer繁琐、耗时而且很容易出错
- 开发速度与执行速度之间的trade-off
按照上面的层定义,我们会写一个名称为pascalcontext_layers.py的python文件,文件的类名为PASCALContextSegDataLayer
通常这个类会继承caffe.Layer类,然后必须重写setup(),reshape(),forward(),backward()函数,其他的函数可以自己定义,没有限制。
setup()是类启动时该做的事情,在建立网络的时候只执行一次,一般是读取参数用的,比如层所需数据的初始化,参数检查。
reshape()就是取数据然后把它规范化为四维的矩阵,每次取数据都会调用此函数。
forward()就是网络的前向运行,这里就是把取到的数据往前传递,因为没有其他运算。
backward()就是网络的反馈,data层作为数据输入层是没有反馈(反向传播过程)的,所以这里就直接pass,参数propagate_down是用来做反向传播控制用的。
那么为什么fcn需要自己定义网络的输入层呢?
有时候需要自己写点输入层以应对各种不同的数据输入,比如是需要在图像中取块而不想写成LMDB,这时候可以考虑使用python直接写一个层。而且输入层不需要GPU加速,写起来也比较容易。详细如何定义输入层可参见fcn源码.