caffe添加新layer(按难度分类详细步骤)

http://gwyve.com/blog/2017/03/27/caffe-add-layer.html

声明:本博客欢迎转发,但请保留原作者信息! 
作者:高伟毅 
博客:https://gwyve.github.io/ 
微博:http://weibo.com/u/3225437531/

使用caffe有一段时间了,可是,目前使用的都是caffe自带的layer,随着自己对各种模型的熟悉,添加或修改现有layer的需求越来越大。

我认为对caffe的layer的修改,按照难度,可以分成以下几个阶段:

  1. 只修改layer在cpu里的计算过程,同时不修改parameter,相当于单纯新添加一个layer
  2. 修改layer在cpu计算过程,同时修改parameter
  3. 修改layer在cudnn的计算过程
  4. 修改layer在cuda的计算过程

说明:

  1. 这里使用最简单的mnist的例子,首先,保证caffe能够运行mnist的训练模型,即,运行./$CAFFE_ROOT/examples/mnist/train_lenet.sh能够出现下图的内容。
  2. 这里添加的layer命名为VeLayer,主要是根据Conv换个名字

first

  1. $ cp src/caffe/layers/conv_layer.cpp src/caffe/layers/ve_layer.cpp
  2. $ cp include/caffe/layers/conv_layer.hpp include/caffe/layers/ve_layer.hpp

开头的位置:#ifndef CAFFE_CONV_LAYER_HPP_ -> #ifndef CAFFE_VE_LAYER_HPP_ #define CAFFE_CONV_LAYER_HPP_ -> #define CAFFE_VE_LAYER_HPP_

类声明、构造函数声明:ConvolutionLayer -> VeLayer

type()返回:”Convolution” -> “Ve” 这个值改不改的意义不大,都可以运行

include : “caffe/layers/conv_layer.hpp” -> “caffe/layers/ve_layer.hpp”

函数属于类: ConvolutionLayer -> VeLayer

STUP_GPU: ConvolutionLayer -> VeLayer

INSTANTIATE: ConvolutionLayer -> VeLayer

添加 #include “caffe/layers/ve_layer.hpp”

在namespace caffe 下添加:

  1. // Get Ve layer according to engine.
  2. template <typename Dtype>
  3. shared_ptr<Layer<Dtype> > GetVeLayer(
  4. const LayerParameter& param) {
  5. ConvolutionParameter conv_param = param.convolution_param();
  6. ConvolutionParameter_Engine engine = conv_param.engine();
  7. #ifdef USE_CUDNN
  8. bool use_dilation = false;
  9. for (int i = 0; i < conv_param.dilation_size(); ++i) {
  10. if (conv_param.dilation(i) > 1) {
  11. use_dilation = true;
  12. }
  13. }
  14. #endif
  15. if (engine == ConvolutionParameter_Engine_DEFAULT) {
  16. engine = ConvolutionParameter_Engine_CAFFE;
  17. #ifdef USE_CUDNN
  18. if (!use_dilation) {
  19. engine = ConvolutionParameter_Engine_CUDNN;
  20. }
  21. #endif
  22. }
  23. if (engine == ConvolutionParameter_Engine_CAFFE) {
  24. return shared_ptr<Layer<Dtype> >(new VeLayer<Dtype>(param));
  25. #ifdef USE_CUDNN
  26. } else if (engine == ConvolutionParameter_Engine_CUDNN) {
  27. if (use_dilation) {
  28. LOG(FATAL) << "CuDNN doesn't support the dilated VE at Layer "
  29. << param.name();
  30. }
  31. return shared_ptr<Layer<Dtype> >(new CuDNNConvolutionLayer<Dtype>(param));
  32. #endif
  33. } else {
  34. LOG(FATAL) << "Layer " << param.name() << " VEVEVEVE has unknown engine.";
  35. throw; // Avoids missing return warning
  36. }
  37. }
  38. REGISTER_LAYER_CREATOR(Ve, GetVeLayer);

return shared_ptr<Layer >(new VeLayer(param));

这里REGISTER_LAYER_CREATOR里面的第一个参数是prototxt里面type的参数

make

把第二个conv层,改成Ve

type: “Convolution” -> “Ve” 这个“VE”是跟第4步的REGISTER_LAYER_CREATOR相呼应的。

./$CAFFE_ROOT/examples/mnist/train_lenet.sh 结果如图

second

这里依照难度1说的VeLayer,添加新的parameter

清除难度1编译成功的文件

  1. 在src/caffe/proto/caffe.proto的message V1LayerParameter {的enum LayerType {添加

VE = 40; //这个具体的ID根据实际更改的,并有觉得这一步有什么用,具体什么用,后面再看

  1. 在src/caffe/proto/caffe.proto的message LayerParameter { 添加

optional VeParameter ve_param = 147;

  1. 在src/caffe/proto/caffe.proto添加
  1. message VeParameter {
  2. optional uint32 num_output = 1; // The number of outputs for the layer
  3. optional bool bias_term = 2 [default = true]; // whether to have bias terms
  4. // Pad, kernel size, and stride are all given as a single value for equal
  5. // dimensions in all spatial dimensions, or once per spatial dimension.
  6. repeated uint32 pad = 3; // The padding size; defaults to 0
  7. repeated uint32 kernel_size = 4; // The kernel size
  8. repeated uint32 stride = 6; // The stride; defaults to 1
  9. // Factor used to dilate the kernel, (implicitly) zero-filling the resulting
  10. // holes. (Kernel dilation is sometimes referred to by its use in the
  11. // algorithme à trous from Holschneider et al. 1987.)
  12. repeated uint32 dilation = 18; // The dilation; defaults to 1
  13. // For 2D convolution only, the *_h and *_w versions may also be used to
  14. // specify both spatial dimensions.
  15. optional uint32 pad_h = 9 [default = 0]; // The padding height (2D only)
  16. optional uint32 pad_w = 10 [default = 0]; // The padding width (2D only)
  17. optional uint32 kernel_h = 11; // The kernel height (2D only)
  18. optional uint32 kernel_w = 12; // The kernel width (2D only)
  19. optional uint32 stride_h = 13; // The stride height (2D only)
  20. optional uint32 stride_w = 14; // The stride width (2D only)
  21. optional uint32 group = 5 [default = 1]; // The group size for group conv
  22. optional FillerParameter weight_filler = 7; // The filler for the weight
  23. optional FillerParameter bias_filler = 8; // The filler for the bias
  24. enum Engine {
  25. DEFAULT = 0;
  26. CAFFE = 1;
  27. CUDNN = 2;
  28. }
  29. optional Engine engine = 15 [default = DEFAULT];
  30. // The axis to interpret as "channels" when performing convolution.
  31. // Preceding dimensions are treated as independent inputs;
  32. // succeeding dimensions are treated as "spatial".
  33. // With (N, C, H, W) inputs, and axis == 1 (the default), we perform
  34. // N independent 2D convolutions, sliding C-channel (or (C/g)-channels, for
  35. // groups g>1) filters across the spatial axes (H, W) of the input.
  36. // With (N, C, D, H, W) inputs, and axis == 1, we perform
  37. // N independent 3D convolutions, sliding (C/g)-channels
  38. // filters across the spatial axes (D, H, W) of the input.
  39. optional int32 axis = 16 [default = 1];
  40. // Whether to force use of the general ND convolution, even if a specific
  41. // implementation for blobs of the appropriate number of spatial dimensions
  42. // is available. (Currently, there is only a 2D-specific convolution
  43. // implementation; for input blobs with num_axes != 2, this option is
  44. // ignored and the ND implementation will be used.)
  45. optional bool force_nd_im2col = 17 [default = false];
  46. }

将难度1添加的内容改成

  1. // Get Ve layer according to engine.
  2. template <typename Dtype>
  3. shared_ptr<Layer<Dtype> > GetVeLayer(
  4. const LayerParameter& param) {
  5. VeParameter ve_param = param.ve_param();
  6. VeParameter_Engine engine = ve_param.engine();
  7. #ifdef USE_CUDNN
  8. bool use_dilation = false;
  9. for (int i = 0; i < ve_param.dilation_size(); ++i) {
  10. if (ve_param.dilation(i) > 1) {
  11. use_dilation = true;
  12. }
  13. }
  14. #endif
  15. if (engine == VeParameter_Engine_DEFAULT) {
  16. engine = VeParameter_Engine_CAFFE;
  17. #ifdef USE_CUDNN
  18. if (!use_dilation) {
  19. engine = ConvolutionParameter_Engine_CUDNN;
  20. }
  21. #endif
  22. }
  23. if (engine == ConvolutionParameter_Engine_CAFFE) {
  24. return shared_ptr<Layer<Dtype> >(new VeLayer<Dtype>(param));
  25. #ifdef USE_CUDNN
  26. } else if (engine == ConvolutionParameter_Engine_CUDNN) {
  27. if (use_dilation) {
  28. LOG(FATAL) << "CuDNN doesn't support the dilated VE at Layer "
  29. << param.name();
  30. }
  31. return shared_ptr<Layer<Dtype> >(new CuDNNConvolutionLayer<Dtype>(param));
  32. #endif
  33. } else {
  34. LOG(FATAL) << "Layer " << param.name() << " VEVEVEVE has unknown engine.";
  35. throw; // Avoids missing return warning
  36. }
  37. }
  38. REGISTER_LAYER_CREATOR(Ve, GetVeLayer);

make

./$CAFFE_ROOT/examples/mnist/train_lenet.sh 结果如图

third

posted on 2017-12-11 21:39  塔上的樹  阅读(1337)  评论(0)    收藏  举报