[新手学Caffe之三]如何在Caffe中加入新的layer并利用Matlab进行调试

本文详细介绍了在Caffe中添加新layer的步骤,包括修改proto文件,编写并实现layer的hpp与cpp,配置layer_factory,以及利用MATLAB进行调试。以Shlu激活函数为例,演示了如何在proto中添加参数,然后实现和测试新layer。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如何在Caffe中加入新的layer并利用Matlab进行调试

Caffe当中已经实现了很多常用的layer,但是在有些时候,通过单独使用或者组合这些已有的layer并没法实现我们想要的功能,这时便只能自己添加一个新的layer了,最新版Caffe添加一个layer主要步骤有四个:

  1. 在proto中添加layer相应的参数
  2. 编写实现layer的函数:hpp、cpp、cu
  3. 有些layer需要在layer_factory中进行装配
  4. layer的调试

下面以实现一个激活函数层为例,来完整地进行这样一个步骤,并用Matlab来进行调试。

我们要实现如下的激活函数:

f(x)=x10x+1ifx>1if1x1ifx<1

很简单,由于要实现的是一个激活函数,因此可以参照caffe里面sigmoid激活函数的实现。

在proto中添加layer相应的参数

打开caffe/src/proto/caffe.proto,306行,可以看到如下:

// NOTE
// Update the next available ID when you add a new LayerParameter field.
//
// LayerParameter next available layer-specific ID: 139 (last added: batchnorm_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
  ...

我们添加的是一个layer,因此便要在LayerParameter中添加我们写的Layer的Parameter,由于LayerParameter经常要改,因此前面标注了一个NOTE,来记录LayerParameter的更新情况,

// LayerParameter next available layer-specific ID: 139 (last added: batchnorm_param)

这句话的意思是,现在最新添加的layerparameter是batchnorm_param,ID是139,这是用来实现Batchnormlize用的。那我们要新添加layer的话,ID就应该是140,或者其他比139更大的数,防止与之前一定的Layer的ID冲突。
在往下,在大概355行左右,

// 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 ConcatParameter concat_param = 104;
  optional ContrastiveLossParameter contrastive_loss_param = 105;
  optional ConvolutionParameter convolution_param = 106;
  optional DataParameter data_param = 107;
  optional DropoutParameter dropout_param = 108;
  optional DummyDataParameter dummy_data_param = 109;
  optional EltwiseParameter eltwise_param = 110;
  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 LogParameter log_param = 134;
  optional LRNParameter lrn_param = 118;
  optional MemoryDataParameter memory_data_param = 119;
  optional MVNParameter mvn_param = 120;
  optional PoolingParameter pooling_param = 121;
  optional PowerParameter power_param = 122;
  optional PReLUParameter prelu_param = 131;
  optional PythonParameter python_param = 130;
  optional ReductionParameter reduction_param = 136;
  optional ReLUParameter relu_param = 123;
  optional ReshapeParameter reshape_param = 133;
  optional SigmoidParameter sigmoid_param = 124;
  optional SoftmaxParameter softmax_param = 125;
  optional SPPParameter spp_param = 132;
  optional SliceParameter slice_param = 126;
  optional TanHParameter tanh_param = 127;
  optional ThresholdParameter threshold_param = 128;
  optional TileParameter tile_param = 138;
  optional WindowDataParameter window_data_param = 129;

这些便是Caffe之前所定义的一些Layer,可以看到sigmoid层是这么定义的,

  optional SigmoidParameter sigmoid_param = 124;

那么在此,我们仿照这个定义方法,定义一个Shlu激活函数:

optional ShluParameter shlu_param = 140;

之前的NOTE表明,最新添加的Layer ID是139,因此我们添加Shlu_Layer,令其ID为140.

然后再往下,要定义Shlu_Layer所需要的参数,类似于Convolution_Layer需要设定kernel_size等,我们新添加的Layer也要设定所需要的参数,仿照SigmoidParameter的写法


message SigmoidParameter {
  enum Engine {
    DEFAULT = 0;
    CAFFE = 1;
    CUDNN = 2;
  }
  optional Engine engine = 1 [default = DEFAULT];
}

照抄一个ShluParameter,把CUDNN=2删掉,因为不编写CUDNN下的激活函数代码(封装好了的,无法修改),也就用不到CUDNN Engine。

message ShluParameter {
  enum Engine {
    DEFAULT = 0;
    CAFFE = 1;
  }
  optional Engine engine = 1 [default = DEFAULT];
}

好了,到这一步,就基本完成了proto的修改,重新make一下即可。

编写实现layer的函数:hpp与cpp

修改完proto之后,便要实现我们要新加入的Shlu_Layer了,与Sigmoid类似,首先在caffe/include/layer/中加入shlu_layer.hpp,仿照sigmoid_layer.hpp即可,然后再caffe/src/layer/中加入shlu_layer.cpp,也是仿照sigmoid_layer.cpp,进行一些修改。
再次make,可能会有一些错误,按照错误信息调试修改一下就好了。

修改layer_factory.cpp

仿照layer_factory.cpp中sigmoid_layer的配置,进行shlu_layer的配置,记得添加对shlu_layer.hpp头文件的引用,并且删除其中CUDNN的部分。
make一下,如果通过,那shlu_layer就基本实现了,但还要具体测试一下。

利用MATLAB进行调试

Caffe的MATLAB接口可是个好东西,用MATLAB调试可以很方便地看到各种数据的形式以及结果。
我们这边需要调试自己实现的激活函数,shlu_layer。
第一步便是编写一个测试网络,具体如下:

name: "SHLUTEST"
input: "data"
input_dim: 1
input_dim: 1
input_dim: 100
input_dim: 100

# 测试后向过程必须加,不然回传的梯度都会是0
force_backward: true

layer {
  name: "shlu1"
  type: "Shlu" #这里的名字应该跟你之前定义的一致,要注意大小写
  bottom: "data"
  top: "shlu1"
  }

编写的这个网络实现的便是输入数据维数1*1*100*100,通过shlu_layer。
接下来,打开Matlab,

cd caffe
matlab

编写代码如下:

addpath ./matlab
model = './shlu_test.prototxt';
caffe.set_mode_cpu();
# 测试gpu代码时请用GPU模式
#caffe.set_mode_gpu();
#caffe.set_device(gpu_id);
net = caffe.Net(model, 'test');
# 生成1*1*100*100维度的正态分布随机数,并填入'data'层的blobs
net.blobs('data').set_data(randn(net.blobs('data').shape));
# 前向过程
net.forward_prefilled();
# 检查生成的"res"是否是期望的结果
res = net.blobs('shlu1').get_data();
# 后向过程
# diff为自己设置的梯度值,保证维度一致
net.blobs('shlu1').set_diff(diff);
net.backward_prefilled();
# 检查生成的"data_diff"是否是期望的结果
data_diff = net.blobs('data').get_diff();

分别在cpu模式与gpu模式下都调试一遍,保证没有错误,再进行自己所需要的网络的整体配置。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值