引言
使用caffe有一段时间了,可是,目前使用的都是caffe自带的layer,随着自己对各种模型的熟悉,添加或修改现有layer的需求越来越大。最近一个项目需要使用可分离卷积,caffe当中,可以通过指定group参数实现可分离卷积,但是里面的实现方式效率不佳,在运行的时候出现显卡内存不足,所以果断放弃这种实现方案。
模块引入
为了能使得caffe支持可分离卷积,现在的办法就是往源代码里面增加扩展,并重新编译。这里我是用了https://github.com/yonghenglh6/DepthwiseConvolution实现的源代码。caffe目录里面有如下的实现内容,我们需要将对应的文件拷贝到自己的caffe文件目录下,然后清理掉以前的编译内容(使用命令 make clean),然后重新编译。
本来我以为这样重新编译完成以后,就可以使用pycaffe的接口直接写 caffe.layers.DepthwiseConvolution(),事实上在运行的时候报错无法找到对应的卷积名称,我琢磨猜想可能的原因是,里面只是实现对应的卷积过程,并没有写pycaffe的接口去供调用。
既然pycaffe接口不能用,DepthwiseConvolution一定是要用的,通常train.protxt等文件我都是利用pycaffe文件生成,所以在写卷积的时候还是调用的caffe.layers.Convolution(),但是多指定了一个group参数,并且这个参数值不为1。这样可以先成功的把train.prototxt文件生成出来,虽然里面有些内容不符合我们的设定,可以在后面做一些修改。然后可以利用下面这段代码:
import caffe.proto.caffe_pb2 as caffe_pb2
from google.protobuf.text_format import Merge
import argparse
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('source_prototxt')
parser.add_argument('target_prototxt')
args = parser.parse_args()
net = caffe_pb2.NetParameter()
Merge(open(args.source_prototxt, 'r').read(), net)
for layer in net.layer:
if layer.type == "Convolution":
if layer.convolution_param.group !=1:
layer.type = "DepthwiseConvolution"
with open(args.target_prototxt, 'w') as tf:
tf.write(str(net))
对train.prototxt文件进行解析,把所有的group参数不为1对应的卷积名称修改为DepthwiseConvolution,这样利用这个新的train.prototxt文件就可以做可分离卷积的操作了。
实际上,这还是一个很简单的引入新的模块的操作方法,好多些修改通常还会修改src/caffe/proto/caffe.proto文件,上面的可分离卷积没有使用到新的参数,所以并不涉及。
引入探讨
上面的方式还只是我们做了拿来主义,如果我们自己做修改,应该做哪些内容呢?下面是在github上一个比较经典的回答:
Update: see wiki at https://github.com/BVLC/caffe/wiki/Development-Hints
Here's roughly the process I follow.
- Add a class declaration for your layer to the appropriate one of
common_layers.hpp
,data_layers.hpp
,loss_layers.hpp
,neuron_layers.hpp
, orvision_layers.hpp
. Include an inline implementation oftype
and the*Blobs()
methods to specify blob number requirements. Omit the*_gpu
declarations if you'll only be implementing CPU code. - Implement your layer in
layers/your_layer.cpp
.SetUp
for initialization: reading parameters, allocating buffers, etc.Forward_cpu
for the function your layer computesBackward_cpu
for its gradient
- (Optional) Implement the GPU versions
Forward_gpu
andBackward_gpu
inlayers/your_layer.cu
. - Add your layer to
proto/caffe.proto
, updating the next available ID. Also declare parameters, if needed, in this file. - Make your layer createable by adding it to
layer_factory.cpp
. - Write tests in
test/test_your_layer.cpp
. Usetest/test_gradient_check_util.hpp
to check that your Forward and Backward implementations are in numerical agreement.
按照操作步骤来讲:
1、添加对于layers的头文件
2、写相关函数的cpu实现
3、如果还想支持gpu并行,需要写cuda实现的cu文件
4、修改caffe.proto参数文件,这个是可选的
5、将新增加的层加入到layer_factory文件(个人猜想:这个里面加入以后就可以支持pycaffe等的接口操作)
6、为了保证代码的健壮性,写相关的测试文件
有人把caffe添加新的层,定义了四个难度级别,具体内容可以查看caffe添加新的layer。