最近实验当中借鉴了FPN网络,由于FPN网络对图片shape有要求,采用了两种方式,其一是在data_layer.cpp中,对原图进行padding操作;其二是需要对特征图进行类似crop操作,使得两者进行eltwise操作的时候shape是一致的。
简单说一下添加padding的操作,在data_layer.cpp的DataSetup()和load_batch()函数中添加:
1 //cv_img是读入的原图像,ext_img是填充pad的图像 2 //extRows,extCols是填充的行和列,具体可查opencv中的copyMakeBorder用法 3 copyMakeBorder(cv_img,ext_img,0,extRows,0,extCols,BORDER_CONSTANT);
下面介绍第二种Interp插值操作:
第一步:添加相应的代码,主要代码来源于:https://github.com/hszhao/PSPNet
1.在PSPNet/include/cafffe/layers/interp_layer.hpp添加代码,代码如下:
1 #ifndef CAFFE_INTERP_LAYER_HPP_ 2 #define CAFFE_INTERP_LAYER_HPP_ 3 4 #include <vector> 5 6 #include "caffe/blob.hpp" 7 #include "caffe/layer.hpp" 8 #include "caffe/proto/caffe.pb.h" 9 10 namespace caffe { 11 /** 12 * @brief Changes the spatial resolution by bi-linear interpolation. 13 * The target size is specified in terms of pixels. 14 * The start and end pixels of the input are mapped to the start 15 * and end pixels of the output. 16 */ 17 template <typename Dtype> 18 class InterpLayer : public Layer<Dtype> { 19 public: 20 explicit InterpLayer(const LayerParameter& param) 21 : Layer<Dtype>(param) {} 22 virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom, 23 const vector<Blob<Dtype>*>& top); 24 virtual void Reshape(const vector<Blob<Dtype>*>& bottom, 25 const vector<Blob<Dtype>*>& top); 26 27 virtual inline const char* type() const { return "Interp"; } 28 virtual inline int ExactNumBottomBlobs() const { return 1; } //此处可以根据需求修改Interp层的输入个数,默认是1;下同 29 virtual inline int ExactNumTopBlobs() const { return 1; } 30 31 protected: 32 virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom, 33 const vector<Blob<Dtype>*>& top); 34 virtual void Forward_gpu(const vector<Blob<Dtype>*>& bottom, 35 const vector<Blob<Dtype>*>& top); 36 virtual void Backward_cpu(const vector<Blob<Dtype>*>& top, 37 const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom); 38 virtual void Backward_gpu(const vector<Blob<Dtype>*>& top, 39 const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom); 40 41 int num_, channels_; 42 int height_in_, width_in_; 43 int height_out_, width_out_; 44 int pad_beg_, pad_end_; 45 int height_in_eff_, width_in_eff_; 46 }; 47 48 } // namespace caffe 49 50 #endif // CAFFE_CONV_LAYER_HPP_
2.在PSPNet/include/caffe/util/interp.hpp中添加代码,代码如下:
1 #ifndef CAFFE_UTIL_INTERP_H_ 2 #define CAFFE_UTIL_INTERP_H_ 3 4 #include <cublas_v2.h> 5 #include "caffe/proto/caffe.pb.h" 6 7 namespace caffe { 8 9 // Bi-linear interpolation 10 // IN : [channels height1 width1] cropped from a bigger [Height1 Width1] image 11 // OUT: [channels height2 width2] cropped from a bigger [Height2 Width2] image 12 13 template <typename Dtype, bool packed> 14 void caffe_cpu_interp2(const int channels, 15 const Dtype *data1, const int x1, const int y1, const int height1, const int width1, const int Height1, const int Width1, 16 Dtype *data2, const int x2, const int y2, const int height2, const int width2, const int Height2, const int Width2); 17 18 template <typename Dtype, bool packed> 19 void caffe_gpu_interp2(const int channels, 20 const Dtype *data1, const int x1, const int y1, const int height1, const int width1, const int Height1, const int Width1, 21 Dtype *data2, const int x2, const int y2, const int height2, const int width2, const int Height2, const int Width2); 22 23 // Backward (adjoint) operation 24 template <typename Dtype, bool packed> 25 void caffe_cpu_interp2_backward(const int channels, 26 Dtype *data1, const int x1, const int y1, const int height1, const int width1, const int Height1, const int Width1, 27 const Dtype *data2, const int x2, const int y2, const int height2, const int width2, const int Height2, const int Width2); 28 29 template <typename Dtype, bool packed> 30 void caffe_gpu_interp2_backward(const int channels, 31 Dtype *data1, const int x1, const int y1, const int height1, const int width1, const int Height1, const int Width1, 32 const Dtype *data2, const int x2, const int y2, const int height2, const int width2, const int Height2, const int Width2); 33 34 // Create Gaussian pyramid of an image. Assume output space is pre-allocated. 35 // IN : [channels height width] 36 template <typename Dtype, bool packed> 37 void caffe_cpu_pyramid2(const int channels, 38 const Dtype *data, const int height, const int width, 39 Dtype *data_pyr, const int levels); 40 41 template <typename Dtype, bool packed> 42 void caffe_gpu_pyramid2(const int channels, 43 const Dtype *data, const int height, const int width, 44 Dtype *data_pyr, const int levels); 45 46 /* 47 template <typename Dtype, bool packed> 48 void caffe_cpu_mosaic(const int channels, 49 const Dtype *data1, const MosaicParameter mosaic_params1, 50 const Dtype *data_pyr, const int levels, 51 Dtype *data2, const MosaicParameter mosaic_params2); 52 template <typename Dtype, bool packed> 53 void caffe_gpu_mosaic(const int channels, 54 const Dtype *data1, const MosaicParameter mosaic_params1, 55 const Dtype *data_pyr, const int levels, 56 Dtype *data2, const MosaicParameter mosaic_params2); 57 */ 58 59 } // namespace caffe 60 61 #endif
3.在PSPNet/include/caffe/common.cuh 添加代码,代码如下:
1 #ifndef CAFFE_COMMON_CUH_ 2 #define CAFFE_COMMON_CUH_ 3 4 #include <cuda.h> 5 6 #if !defined(__CUDA_ARCH__) || __CUDA_ARCH__ >= 600 //注意标红需要添加,不然会报错(根据自己服务器CUDA配置需求添加) 7 8 #else 9 // CUDA: atomicAdd is not defined for doubles 10 static __inline__ __device__ double atomicAdd(double *address, double val) { 11 unsigned long long int* address_as_ull = (unsigned long long int*)address; 12 unsigned long long int old = *address_as_ull, assumed; 13 if (val==0.0) 14 return __longlong_as_double(old); 15 do { 16 assumed = old; 17 old = atomicCAS(address_as_ull, assumed, __double_as_longlong(val +__longlong_as_double(assumed))); 18 } while (assumed != old); 19 return __longlong_as_double(old); 20 } 21 22 #endif 23 #endif
4.在PSPNet/src/caffe/layers/interp_layer.cpp 下添加代码,代码如下:
1 #include <vector> 2 3 #include "caffe/layer.hpp" 4 #include "caffe/util/math_functions.hpp" 5 #include "caffe/util/interp.hpp" 6 #include "caffe/layers/interp_layer.hpp" 7 8 namespace caffe { 9 10 template <typename Dtype> 11 void InterpLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom, 12 const vector<Blob<Dtype>*>& top) { 13 InterpParameter interp_param = this->layer_param_.interp_param(); 14 pad_beg_ = interp_param.pad_beg(); 15 pad_end_ = interp_param.pad_end(); 16 CHECK_LE(pad_beg_, 0) << "Only supports non-pos padding (cropping) for now"; 17 CHECK_LE(pad_end_, 0) << "Only supports non-pos padding (cropping) for now"; 18 } 19 20 template <typename Dtype> 21 void InterpLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom, 22 const vector<Blob<Dtype>*>& top) { 23 num_ = bottom[0]->num(); 24 channels_ = bottom[0]->channels(); 25 height_in_ = bottom[0]->height(); 26 width_in_ = bottom[0]->width(); 27 height_in_eff_ = height_in_ + pad_beg_ + pad_end_; 28 width_in_eff_ = width_in_ + pad_beg_ + pad_end_; 29 InterpParameter interp_param = this->layer_param_.interp_param(); 30 if (interp_param.has_shrink_factor() && 31 !interp_param.has_zoom_factor()) { 32 const int shrink_factor = interp_param.shrink_factor(); 33 CHECK_GE(shrink_factor, 1) << "Shrink factor must be positive"; 34 height_out_ = (height_in_eff_ - 1) / shrink_factor + 1; 35 width_out_ = (width_in_eff_ - 1) / shrink_factor + 1; 36 } else if (interp_param.has_zoom_factor() && 37 !interp_param.has_shrink_factor()) { 38 const int zoom_factor = interp_param.zoom_factor(); 39 CHECK_GE(zoom_factor, 1) << "Zoom factor must be positive"; 40 height_out_ = height_in_eff_ + (height_in_eff_ - 1) * (zoom_factor - 1); 41 width_out_ = width_in_eff_ + (width_in_eff_ - 1) * (zoom_factor - 1); 42 } else if (interp_param.has_height() && interp_param.has_width()) { 43 height_out_ = interp_param.height(); 44 width_out_ = interp_param.width(); 45 } else if (interp_param.has_shrink_factor() && 46 interp_param.has_zoom_factor()) { 47 const int shrink_factor = interp_param.shrink_factor(); 48 const int zoom_factor = interp_param.zoom_factor(); 49 CHECK_GE(shrink_factor, 1) << "Shrink factor must be positive"; 50 CHECK_GE(zoom_factor, 1) << "Zoom factor must be positive"; 51 height_out_ = (height_in_eff_ - 1) / shrink_factor + 1; 52 width_out_ = (width_in_eff_ - 1) / shrink_factor + 1; 53 height_out_ = height_out_ + (height_out_ - 1) * (zoom_factor - 1); 54 width_out_ = width_out_ + (width_out_ - 1) * (zoom_factor - 1); 55 } else { 56 LOG(FATAL); 57 } 58 CHECK_GT(height_in_eff_, 0) << "height should be positive"; 59 CHECK_GT(width_in_eff_, 0) << "width should be positive"; 60 CHECK_GT(height_out_, 0) << "height should be positive"; 61 CHECK_GT(width_out_, 0) << "width should be positive"; 62 top[0]->Reshape(num_, channels_, height_out_, width_out_); 63 } 64 65 template <typename Dtype> 66 void InterpLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom, 67 const vector<Blob<Dtype>*>& top) { 68 caffe_cpu_interp2<Dtype,false>(num_ * channels_, 69 bottom[0]->cpu_data(), - pad_beg_, - pad_beg_, height_in_eff_, width_in_eff_, height_in_, width_in_, 70 top[0]->mutable_cpu_data(), 0, 0, height_out_, width_out_, height_out_, width_out_); 71 } 72 73 template <typename Dtype> 74 void InterpLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top, 75 const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) { 76 if (!propagate_down[0]) { return; } 77 caffe_set(bottom[0]->count(), Dtype(0), bottom[0]->mutable_cpu_diff()); 78 caffe_cpu_interp2_backward<Dtype,false>(num_ * channels_, 79 bottom[0]->mutable_cpu_diff(), - pad_beg_, - pad_beg_, height_in_eff_, width_in_eff_, height_in_, width_in_, 80 top[0]->cpu_diff(), 0, 0, height_out_, width_out_, height_out_, width_out_); 81 } 82 83 #ifndef CPU_ONLY 84 template <typename Dtype> 85 void InterpLayer<Dtype>::Forward_gpu(const vector<Blob<Dtype>*>& bottom, 86 const vector<Blob<Dtype>*>& top) { 87 caffe_gpu_interp2<Dtype,false>(num_ * channels_, 88 bottom[0]->gpu_data(), - pad_beg_, - pad_beg_, height_in_eff_, width_in_eff_, height_in_, width_in_, 89 top[0]->mutable_gpu_data(), 0, 0, height_out_, width_out_, height_out_, width_out_); 90 } 91 92 template <typename Dtype> 93 void InterpLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top, 94 const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) { 95 if (!propagate_down[0]) { return; } 96 caffe_gpu_set(bottom[0]->count(), Dtype(0), bottom[0]->mutable_gpu_diff()); 97 caffe_gpu_interp2_backward<Dtype,false>(num_ * channels_, 98 bottom[0]->mutable_gpu_diff(), - pad_beg_, - pad_beg_, height_in_eff_, width_in_eff_, height_in_, width_in_, 99 top[0]->gpu_diff(), 0, 0, height_out_, width_out_, height_out_, width_out_); 100 } 101 #endif 102 103 #ifdef CPU_ONLY 104 STUB_GPU(InterpLayer); 105 #endif 106 107 INSTANTIATE_CLASS(InterpLayer); 108 REGISTER_LAYER_CLASS(Interp); 109 110 } // namespace caffe
4.在PSPNet/src/caffe/util/interp.cpp中添加代码,代码如下:
1 #include "caffe/common.hpp" 2 #include "caffe/util/interp.hpp" 3 #include <algorithm> 4 #include <cmath> 5 6 namespace caffe { 7 8 // Bi-linear interpolation 9 // IN : [channels height1 width1] cropped from a bigger [Height1 Width1] image 10 // OUT: [channels height2 width2] cropped from a bigger [Height2 Width2] image 11 template <typename Dtype, bool packed> 12 void caffe_cpu_interp2(const int channels, 13 const Dtype *data1, const int x1, const int y1, const int height1, const int width1, const int Height1, const int Width1, 14 Dtype *data2, const int x2, const int y2, const int height2, const int width2, const int Height2, const int Width2) { 15 CHECK(x1 >= 0 && y1 >= 0 && height1 > 0 && width1 > 0 && x2 >= 0 && y2 >= 0 && height2 > 0 && width2 > 0); 16 CHECK(Width1 >= width1 + x1 && Height1 >= height1 + y1 && Width2 >= width2 + x2 && Height2 >= height2 + y2); 17 // special case: just copy 18 if (height1 == height2 && width1 == width2) { 19 for (int h2 = 0; h2 < height2; ++h2) { 20 const int h1 = h2; 21 for (int w2 = 0; w2 < width2; ++w2) { 22 const int w1 = w2; 23 if (packed) { 24 const Dtype* pos1 = &data1[channels * ((y1 + h1) * Width1 + (x1 + w1))]; 25 Dtype* pos2 = &data2[channels * ((y2 + h2) * Width2 + (x2 + w2))]; 26 for (int c = 0; c < channels; ++c) { 27 pos2[0] = pos1[0]; 28 pos1++; 29 pos2++; 30 } 31 } 32 else { 33 const Dtype* pos1 = &data1[(y1 + h1) * Width1 + (x1 + w1)]; 34 Dtype* pos2 = &data2[(y2 + h2) * Width2 + (x2 + w2)]; 35 for (int c = 0; c < channels; ++c) { 36 pos2[0] = pos1[0]; 37 pos1 += Width1 * Height1; 38 pos2 += Width2 * Height2; 39 } 40 } 41 } 42 } 43 return; 44 } 45 const float rheight = (height2 > 1) ? static_cast<float>(height1 - 1) / (height2 - 1) : 0.f; 46 const float rwidth = (width2 > 1) ? static_cast<float>(width1 - 1) / (width2 - 1) : 0.f; 47 for (int h2 = 0; h2 < height2; ++h2) { 48 const float h1r = rheight * h2; 49 const int h1 = h1r; 50 const int h1p = (h1 < height1 - 1) ? 1 : 0; 51 const Dtype h1lambda = h1r - h1; 52 const Dtype h0lambda = Dtype(1.) - h1lambda; 53 for (int w2 = 0; w2 < width2; ++w2) { 54 const float w1r = rwidth * w2; 55 const int w1 = w1r; 56 const int w1p = (w1 < width1 - 1) ? 1 : 0; 57 const Dtype w1lambda = w1r - w1; 58 const Dtype w0lambda = Dtype(1.) - w1lambda; 59 if (packed) { 60 const Dtype* pos1 = &data1[channels * ((y1 + h1) * Width1 + (x1 + w1))]; 61 Dtype* pos2 = &data2[channels * ((y2 + h2) * Width2 + (x2 + w2))]; 62 for (int c = 0; c < channels; ++c) { 63 pos2[0] = 64 h0lambda * (w0lambda * pos1[0] + w1lambda * pos1[channels * w1p]) + 65 h1lambda * (w0lambda * pos1[channels * h1p * Width1] + w1lambda * pos1[channels * (h1p * Width1 + w1p)]); 66 pos1++; 67 pos2++; 68 } 69 } 70 else { 71 const Dtype* pos1 = &data1[(y1 + h1) * Width1 + (x1 + w1)]; 72 Dtype* pos2 = &data2[(y2 + h2) * Width2 + (x2 + w2)]; 73 for (int c = 0; c < channels; ++c) { 74 pos2[0] = 75 h0lambda * (w0lambda * pos1[0] + w1lambda * pos1[w1p]) + 76 h1lambda * (w0lambda * pos1[h1p * Width1] + w1lambda * pos1[h1p * Width1 + w1p]); 77 pos1 += Width1 * Height1; 78 pos2 += Width2 * Height2; 79 } 80 } 81 } 82 } 83 } 84 85 86 // Backward (adjoint) operation 1 <- 2 (accumulates) 87 template <typename Dtype, bool packed> 88 void caffe_cpu_interp2_backward(const int channels, 89 Dtype *data1, const int x1, const int y1, const int height1, const int width1, const int Height1, const int Width1, 90 const Dtype *data2, const int x2, const int y2, const int height2, const int width2, const int Height2, const int Width2) { 91 CHECK(x1 >= 0 && y1 >= 0 && height1 > 0 && width1 > 0 && x2 >= 0 && y2 >= 0 && height2 > 0 && width2 > 0); 92 CHECK(Width1 >= width1 + x1 && Height1 >= height1 + y1 && Width2 >= width2 + x2 && Height2 >= height2 + y2); 93 // special case: same-size matching grids 94 if (height1 == height2 && width1 == width2) { 95 for (int h2 = 0; h2 < height2; ++h2) { 96 const int h1 = h2; 97 for (int w2 = 0; w2 < width2; ++w2) { 98 const int w1 = w2; 99 if (packed) { 100 Dtype* pos1 = &data1[channels * ((y1 + h1) * Width1 + (x1 + w1))]; 101 const Dtype* pos2 = &data2[channels * ((y2 + h2) * Width2 + (x2 + w2))]; 102 for (int c = 0; c < channels; ++c) { 103 pos1[0] += pos2[0]; 104 pos1++; 105 pos2++; 106 } 107 } 108 else { 109 Dtype* pos1 = &data1[(y1 + h1) * Width1 + (x1 + w1)]; 110 const Dtype* pos2 = &data2[(y2 + h2) * Width2 + (x2 + w2)]; 111 for (int c = 0; c < channels; ++c) { 112 pos1[0] += pos2[0]; 113 pos1 += Width1 * Height1; 114 pos2 += Width2 * Height2; 115 } 116 } 117 } 118 } 119 return; 120 } 121 const float rheight = (height2 > 1) ? static_cast<float>(height1 - 1) / (height2 - 1) : 0.f; 122 const float rwidth = (width2 > 1) ? static_cast<float>(width1 - 1) / (width2 - 1) : 0.f; 123 for (int h2 = 0; h2 < height2; ++h2) { 124 const float h1r = rheight * h2; 125 const int h1 = h1r; 126 const int h1p = (h1 < height1 - 1) ? 1 : 0; 127 const Dtype h1lambda = h1r - h1; 128 const Dtype h0lambda = Dtype(1.) - h1lambda; 129 for (int w2 = 0; w2 < width2; ++w2) { 130 const float w1r = rwidth * w2; 131 const int w1 = w1r; 132 const int w1p = (w1 < width1 - 1) ? 1 : 0; 133 const Dtype w1lambda = w1r - w1; 134 const Dtype w0lambda = Dtype(1.) - w1lambda; 135 if (packed) { 136 Dtype* pos1 = &data1[channels * ((y1 + h1) * Width1 + (x1 + w1))]; 137 const Dtype* pos2 = &data2[channels * ((y2 + h2) * Width2 + (x2 + w2))]; 138 for (int c = 0; c < channels; ++c) { 139 pos1[0] += h0lambda * w0lambda * pos2[0]; 140 pos1[channels * w1p] += h0lambda * w1lambda * pos2[0]; 141 pos1[channels * h1p * Width1] += h1lambda * w0lambda * pos2[0]; 142 pos1[channels * (h1p * Width1 + w1p)] += h1lambda * w1lambda * pos2[0]; 143 pos1++; 144 pos2++; 145 } 146 } 147 else { 148 Dtype* pos1 = &data1[(y1 + h1) * Width1 + (x1 + w1)]; 149 const Dtype* pos2 = &data2[(y2 + h2) * Width2 + (x2 + w2)]; 150 for (int c = 0; c < channels; ++c) { 151 pos1[0] += h0lambda * w0lambda * pos2[0]; 152 pos1[w1p] += h0lambda * w1lambda * pos2[0]; 153 pos1[h1p * Width1] += h1lambda * w0lambda * pos2[0]; 154 pos1[h1p * Width1 + w1p] += h1lambda * w1lambda * pos2[0]; 155 pos1 += Width1 * Height1; 156 pos2 += Width2 * Height2; 157 } 158 } 159 } 160 } 161 } 162 163 // Create Gaussian pyramid of an image. Assume output space is pre-allocated. 164 // IN : [channels height width] 165 template <typename Dtype, bool packed> 166 void caffe_cpu_pyramid2(const int channels, 167 const Dtype *data, const int height, const int width, 168 Dtype *data_pyr, const int levels) { 169 CHECK(height > 0 && width > 0 && levels >= 0); 170 int height1 = height, width1 = width; 171 int height2 = height, width2 = width; 172 const Dtype *data1 = data; 173 Dtype *data2 = data_pyr; 174 for (int l = 0; l < levels; ++l) { 175 height2 /= 2; 176 width2 /= 2; 177 if (height2 == 0 || width2 == 0) { 178 break; 179 } 180 for (int h2 = 0; h2 < height2; ++h2) { 181 const int h1 = 2 * h2; 182 for (int w2 = 0; w2 < width2; ++w2) { 183 const int w1 = 2 * w2; 184 if (packed) { 185 const Dtype* pos1 = &data1[channels * (h1 * width1 + w1)]; 186 Dtype* pos2 = &data2[channels * (h2 * width2 + w2)]; 187 for (int c = 0; c < channels; ++c) { 188 pos2[0] = static_cast<Dtype>(.25) * 189 (pos1[0] + pos1[channels] + 190 pos1[channels * width1] + pos1[channels * (width1 + 1)]); 191 pos1++; 192 pos2++; 193 } 194 } 195 else { 196 const Dtype* pos1 = &data1[h1 * width1 + w1]; 197 Dtype* pos2 = &data2[h2 * width2 + w2]; 198 for (int c = 0; c < channels; ++c) { 199 pos2[0] = static_cast<Dtype>(.25) * 200 (pos1[0] + pos1[1] + 201 pos1[width1] + pos1[width1 + 1]); 202 pos1 += width1 * height1; 203 pos2 += width2 * height2; 204 } 205 } 206 } 207 } 208 data1 = data2; 209 height1 = height2; 210 width1 = width2; 211 data2 += channels * height2 * width2; 212 } 213 } 214 215 /* 216 template <typename Dtype, bool packed> 217 void caffe_cpu_mosaic(const int channels, 218 const Dtype *data1, const MosaicParameter mosaic_params1, 219 const Dtype *data_pyr, const int levels, 220 Dtype *data2, const MosaicParameter mosaic_params2) { 221 const int num1 = mosaic_params1.rects_size(); 222 const int num2 = mosaic_params2.rects_size(); 223 CHECK(num1 == num2 || (num1 == 1 && num2 > 1) || (num2 == 1 && num1 > 1)); 224 const int num = std::max(num1, num2); 225 for (int i = 0; i < num; ++i) { 226 const Rect rect1 = mosaic_params1.rects((i < num1) ? i : 0); 227 const Rect rect2 = mosaic_params2.rects((i < num2) ? i : 0); 228 int level = log2(sqrt((float)rect1.height() * rect1.width() / rect2.height() / rect2.width())); 229 level = std::max(0, std::min(levels, level)); 230 if (data_pyr == 0 || level == 0) { 231 caffe_cpu_interp2<Dtype,packed>(channels, 232 data1, rect1.x(), rect1.y(), rect1.height(), rect1.width(), mosaic_params1.height(), mosaic_params1.width(), 233 data2, rect2.x(), rect2.y(), rect2.height(), rect2.width(), mosaic_params2.height(), mosaic_params2.width()); 234 } 235 else { 236 const Dtype *data_pyr_l = data_pyr; 237 int factor = 2; 238 for (int l = 1; l < level; ++l) { 239 data_pyr_l += channels * (mosaic_params1.height() / factor) * (mosaic_params1.width() / factor); 240 factor *= 2; 241 } 242 caffe_cpu_interp2<Dtype,packed>(channels, 243 data_pyr_l, rect1.x() / factor, rect1.y() / factor, rect1.height() / factor, rect1.width() / factor, mosaic_params1.height() / factor, mosaic_params1.width() / factor, 244 data2, rect2.x(), rect2.y(), rect2.height(), rect2.width(), mosaic_params2.height(), mosaic_params2.width()); 245 } 246 } 247 } 248 template <typename Dtype, bool packed> 249 void caffe_gpu_mosaic(const int channels, 250 const Dtype *data1, const MosaicParameter mosaic_params1, 251 const Dtype *data_pyr, const int levels, 252 Dtype *data2, const MosaicParameter mosaic_params2) { 253 const int num1 = mosaic_params1.rects_size(); 254 const int num2 = mosaic_params2.rects_size(); 255 CHECK(num1 == num2 || (num1 == 1 && num2 > 1) || (num2 == 1 && num1 > 1)); 256 const int num = std::max(num1, num2); 257 for (int i = 0; i < num; ++i) { 258 const Rect rect1 = mosaic_params1.rects((i < num1) ? i : 0); 259 const Rect rect2 = mosaic_params2.rects((i < num2) ? i : 0); 260 int level = log2(sqrt((float)rect1.height() * rect1.width() / rect2.height() / rect2.width())); 261 level = std::max(0, std::min(levels, level)); 262 if (data_pyr == 0 || level == 0) { 263 caffe_gpu_interp2<Dtype,packed>(channels, 264 data1, rect1.x(), rect1.y(), rect1.height(), rect1.width(), mosaic_params1.height(), mosaic_params1.width(), 265 data2, rect2.x(), rect2.y(), rect2.height(), rect2.width(), mosaic_params2.height(), mosaic_params2.width()); 266 } 267 else { 268 const Dtype *data_pyr_l = data_pyr; 269 int factor = 2; 270 for (int l = 1; l < level; ++l) { 271 data_pyr_l += channels * (mosaic_params1.height() / factor) * (mosaic_params1.width() / factor); 272 factor *= 2; 273 } 274 caffe_gpu_interp2<Dtype,packed>(channels, 275 data_pyr_l, rect1.x() / factor, rect1.y() / factor, rect1.height() / factor, rect1.width() / factor, mosaic_params1.height() / factor, mosaic_params1.width() / factor, 276 data2, rect2.x(), rect2.y(), rect2.height(), rect2.width(), mosaic_params2.height(), mosaic_params2.width()); 277 } 278 } 279 } 280 */ 281 282 // Explicit instances 283 template void caffe_cpu_interp2<float,false>(const int, const float *, const int, const int, const int, const int, const int, const int, float *, const int, const int, const int, const int, const int, const int); 284 template void caffe_cpu_interp2<float,true>(const int, const float *, const int, const int, const int, const int, const int, const int, float *, const int, const int, const int, const int, const int, const int); 285 template void caffe_cpu_interp2<double,false>(const int, const double *, const int, const int, const int, const int, const int, const int, double *, const int, const int, const int, const int, const int, const int); 286 template void caffe_cpu_interp2<double,true>(const int, const double *, const int, const int, const int, const int, const int, const int, double *, const int, const int, const int, const int, const int, const int); 287 288 template void caffe_cpu_interp2_backward<float,false>(const int, float *, const int, const int, const int, const int, const int, const int, const float *, const int, const int, const int, const int, const int, const int); 289 template void caffe_cpu_interp2_backward<double,false>(const int, double *, const int, const int, const int, const int, const int, const int, const double *, const int, const int, const int, const int, const int, const int); 290 291 template void caffe_cpu_pyramid2<float,false>(const int, const float *, const int, const int, float *, const int); 292 template void caffe_cpu_pyramid2<float,true>(const int, const float *, const int, const int, float *, const int); 293 template void caffe_cpu_pyramid2<double,false>(const int, const double *, const int, const int, double *, const int); 294 template void caffe_cpu_pyramid2<double,true>(const int, const double *, const int, const int, double *, const int); 295 296 /* 297 template void caffe_cpu_mosaic<float,false>(const int, const float *, const MosaicParameter, const float *, const int, float *, const MosaicParameter); 298 template void caffe_cpu_mosaic<float,true>(const int, const float *, const MosaicParameter, const float *, const int, float *, const MosaicParameter); 299 template void caffe_cpu_mosaic<double,false>(const int, const double *, const MosaicParameter, const double *, const int, double *, const MosaicParameter); 300 template void caffe_cpu_mosaic<double,true>(const int, const double *, const MosaicParameter, const double *, const int, double *, const MosaicParameter); 301 template void caffe_gpu_mosaic<float,false>(const int, const float *, const MosaicParameter, const float *, const int, float *, const MosaicParameter); 302 template void caffe_gpu_mosaic<float,true>(const int, const float *, const MosaicParameter, const float *, const int, float *, const MosaicParameter); 303 template void caffe_gpu_mosaic<double,false>(const int, const double *, const MosaicParameter, const double *, const int, double *, const MosaicParameter); 304 template void caffe_gpu_mosaic<double,true>(const int, const double *, const MosaicParameter, const double *, const int, double *, const MosaicParameter); 305 */ 306 307 } // namespace caffe
5.在PSPNet/src/caffe/util/interp.cu中添加代码,代码如下:
1 #include "caffe/common.hpp" 2 #include "caffe/common.cuh" 3 #include "caffe/util/interp.hpp" 4 5 namespace caffe { 6 7 // Bi-linear interpolation 8 // IN : [channels height1 width1] cropped from a bigger [Height1 Width1] image 9 // OUT: [channels height2 width2] cropped from a bigger [Height2 Width2] image 10 template <typename Dtype, bool packed> 11 __global__ void caffe_gpu_interp2_kernel(const int n, const float rheight, const float rwidth, 12 const int channels, 13 const Dtype *data1, const int x1, const int y1, const int height1, const int width1, const int Height1, const int Width1, 14 Dtype *data2, const int x2, const int y2, const int height2, const int width2, const int Height2, const int Width2) { 15 int index = threadIdx.x + blockIdx.x * blockDim.x; 16 if (index < n) { 17 const int w2 = index % width2; // 0:width2-1 18 const int h2 = index / width2; // 0:height2-1 19 // special case: just copy 20 if (height1 == height2 && width1 == width2) { 21 const int h1 = h2; 22 const int w1 = w2; 23 if (packed) { 24 const Dtype* pos1 = &data1[channels * ((y1 + h1) * Width1 + (x1 + w1))]; 25 Dtype* pos2 = &data2[channels * ((y2 + h2) * Width2 + (x2 + w2))]; 26 for (int c = 0; c < channels; ++c) { 27 pos2[0] = pos1[0]; 28 pos1++; 29 pos2++; 30 } 31 } 32 else { 33 const Dtype* pos1 = &data1[(y1 + h1) * Width1 + (x1 + w1)]; 34 Dtype* pos2 = &data2[(y2 + h2) * Width2 + (x2 + w2)]; 35 for (int c = 0; c < channels; ++c) { 36 pos2[0] = pos1[0]; 37 pos1 += Width1 * Height1; 38 pos2 += Width2 * Height2; 39 } 40 } 41 return; 42 } 43 // 44 const float h1r = rheight * h2; 45 const int h1 = h1r; 46 const int h1p = (h1 < height1 - 1) ? 1 : 0; 47 const Dtype h1lambda = h1r - h1; 48 const Dtype h0lambda = Dtype(1.) - h1lambda; 49 // 50 const float w1r = rwidth * w2; 51 const int w1 = w1r; 52 const int w1p = (w1 < width1 - 1) ? 1 : 0; 53 const Dtype w1lambda = w1r - w1; 54 const Dtype w0lambda = Dtype(1.) - w1lambda; 55 // 56 if (packed) { 57 const Dtype* pos1 = &data1[channels * ((y1 + h1) * Width1 + (x1 + w1))]; 58 Dtype* pos2 = &data2[channels * ((y2 + h2) * Width2 + (x2 + w2))]; 59 for (int c = 0; c < channels; ++c) { 60 pos2[0] = 61 h0lambda * (w0lambda * pos1[0] + w1lambda * pos1[channels * w1p]) + 62 h1lambda * (w0lambda * pos1[channels * h1p * Width1] + w1lambda * pos1[channels * (h1p * Width1 + w1p)]); 63 pos1++; 64 pos2++; 65 } 66 } 67 else { 68 const Dtype* pos1 = &data1[(y1 + h1) * Width1 + (x1 + w1)]; 69 Dtype* pos2 = &data2[(y2 + h2) * Width2 + (x2 + w2)]; 70 for (int c = 0; c < channels; ++c) { 71 pos2[0] = 72 h0lambda * (w0lambda * pos1[0] + w1lambda * pos1[w1p]) + 73 h1lambda * (w0lambda * pos1[h1p * Width1] + w1lambda * pos1[h1p * Width1 + w1p]); 74 pos1 += Width1 * Height1; 75 pos2 += Width2 * Height2; 76 } 77 } 78 } 79 } 80 81 template <typename Dtype, bool packed> 82 void caffe_gpu_interp2(const int channels, 83 const Dtype *data1, const int x1, const int y1, const int height1, const int width1, const int Height1, const int Width1, 84 Dtype *data2, const int x2, const int y2, const int height2, const int width2, const int Height2, const int Width2) { 85 CHECK(x1 >= 0 && y1 >= 0 && height1 > 0 && width1 > 0 && x2 >= 0 && y2 >= 0 && height2 > 0 && width2 > 0); 86 CHECK(Width1 >= width1 + x1 && Height1 >= height1 + y1 && Width2 >= width2 + x2 && Height2 >= height2 + y2); 87 const float rheight = (height2 > 1) ? static_cast<float>(height1 - 1) / (height2 - 1) : 0.f; 88 const float rwidth = (width2 > 1) ? static_cast<float>(width1 - 1) / (width2 - 1) : 0.f; 89 const int num_kernels = height2 * width2; 90 caffe_gpu_interp2_kernel<Dtype,packed><<<CAFFE_GET_BLOCKS(num_kernels), CAFFE_CUDA_NUM_THREADS>>> 91 (num_kernels, rheight, rwidth, channels, 92 data1, x1, y1, height1, width1, Height1, Width1, 93 data2, x2, y2, height2, width2, Height2, Width2); 94 CUDA_POST_KERNEL_CHECK; 95 } 96 97 // Backward (adjoint) operation 1 <- 2 (accumulates) 98 template <typename Dtype, bool packed> 99 __global__ void caffe_gpu_interp2_kernel_backward(const int n, const float rheight, const float rwidth, 100 const int channels, 101 Dtype *data1, const int x1, const int y1, const int height1, const int width1, const int Height1, const int Width1, 102 const Dtype *data2, const int x2, const int y2, const int height2, const int width2, const int Height2, const int Width2) { 103 int index = threadIdx.x + blockIdx.x * blockDim.x; 104 if (index < n) { 105 const int w2 = index % width2; // 0:width2-1 106 const int h2 = index / width2; // 0:height2-1 107 // special case: just copy 108 if (height1 == height2 && width1 == width2) { 109 const int h1 = h2; 110 const int w1 = w2; 111 if (packed) { 112 Dtype* pos1 = &data1[channels * ((y1 + h1) * Width1 + (x1 + w1))]; 113 const Dtype* pos2 = &data2[channels * ((y2 + h2) * Width2 + (x2 + w2))]; 114 for (int c = 0; c < channels; ++c) { 115 pos1[0] += pos2[0]; 116 pos1++; 117 pos2++; 118 } 119 } 120 else { 121 Dtype* pos1 = &data1[(y1 + h1) * Width1 + (x1 + w1)]; 122 const Dtype* pos2 = &data2[(y2 + h2) * Width2 + (x2 + w2)]; 123 for (int c = 0; c < channels; ++c) { 124 pos1[0] += pos2[0]; 125 pos1 += Width1 * Height1; 126 pos2 += Width2 * Height2; 127 } 128 } 129 return; 130 } 131 // 132 const float h1r = rheight * h2; 133 const int h1 = h1r; 134 const int h1p = (h1 < height1 - 1) ? 1 : 0; 135 const Dtype h1lambda = h1r - h1; 136 const Dtype h0lambda = Dtype(1.) - h1lambda; 137 // 138 const float w1r = rwidth * w2; 139 const int w1 = w1r; 140 const int w1p = (w1 < width1 - 1) ? 1 : 0; 141 const Dtype w1lambda = w1r - w1; 142 const Dtype w0lambda = Dtype(1.) - w1lambda; 143 // 144 if (packed) { 145 Dtype* pos1 = &data1[channels * ((y1 + h1) * Width1 + (x1 + w1))]; 146 const Dtype* pos2 = &data2[channels * ((y2 + h2) * Width2 + (x2 + w2))]; 147 for (int c = 0; c < channels; ++c) { 148 atomicAdd(&pos1[0], h0lambda * w0lambda * pos2[0]); 149 atomicAdd(&pos1[channels * w1p], h0lambda * w1lambda * pos2[0]); 150 atomicAdd(&pos1[channels * h1p * Width1], h1lambda * w0lambda * pos2[0]); 151 atomicAdd(&pos1[channels * (h1p * Width1 + w1p)], h1lambda * w1lambda * pos2[0]); 152 pos1++; 153 pos2++; 154 } 155 } 156 else { 157 Dtype* pos1 = &data1[(y1 + h1) * Width1 + (x1 + w1)]; 158 const Dtype* pos2 = &data2[(y2 + h2) * Width2 + (x2 + w2)]; 159 for (int c = 0; c < channels; ++c) { 160 atomicAdd(&pos1[0], h0lambda * w0lambda * pos2[0]); 161 atomicAdd(&pos1[w1p], h0lambda * w1lambda * pos2[0]); 162 atomicAdd(&pos1[h1p * Width1], h1lambda * w0lambda * pos2[0]); 163 atomicAdd(&pos1[h1p * Width1 + w1p], h1lambda * w1lambda * pos2[0]); 164 pos1 += Width1 * Height1; 165 pos2 += Width2 * Height2; 166 } 167 } 168 } 169 } 170 171 template <typename Dtype, bool packed> 172 void caffe_gpu_interp2_backward(const int channels, 173 Dtype *data1, const int x1, const int y1, const int height1, const int width1, const int Height1, const int Width1, 174 const Dtype *data2, const int x2, const int y2, const int height2, const int width2, const int Height2, const int Width2) { 175 CHECK(x1 >= 0 && y1 >= 0 && height1 > 0 && width1 > 0 && x2 >= 0 && y2 >= 0 && height2 > 0 && width2 > 0); 176 CHECK(Width1 >= width1 + x1 && Height1 >= height1 + y1 && Width2 >= width2 + x2 && Height2 >= height2 + y2); 177 const float rheight = (height2 > 1) ? static_cast<float>(height1 - 1) / (height2 - 1) : 0.f; 178 const float rwidth = (width2 > 1) ? static_cast<float>(width1 - 1) / (width2 - 1) : 0.f; 179 const int num_kernels = height2 * width2; 180 caffe_gpu_interp2_kernel_backward<Dtype,packed><<<CAFFE_GET_BLOCKS(num_kernels), CAFFE_CUDA_NUM_THREADS>>> 181 (num_kernels, rheight, rwidth, channels, 182 data1, x1, y1, height1, width1, Height1, Width1, 183 data2, x2, y2, height2, width2, Height2, Width2); 184 CUDA_POST_KERNEL_CHECK; 185 } 186 187 188 // Create Gaussian pyramid of an image. Assume output space is pre-allocated. 189 // IN : [channels height width] 190 template <typename Dtype, bool packed> 191 __global__ void caffe_gpu_pyramid2_kernel(const int n, const int channels, 192 const Dtype *data1, const int height1, const int width1, 193 Dtype *data2, const int height2, const int width2) { 194 int index = threadIdx.x + blockIdx.x * blockDim.x; 195 if (index < n) { 196 const int w2 = index % width2; // 0:width2-1 197 const int h2 = index / width2; // 0:height2-1 198 const int w1 = 2 * w2; 199 const int h1 = 2 * h2; 200 if (packed) { 201 const Dtype* pos1 = &data1[channels * (h1 * width1 + w1)]; 202 Dtype* pos2 = &data2[channels * (h2 * width2 + w2)]; 203 for (int c = 0; c < channels; ++c) { 204 pos2[0] = static_cast<Dtype>(.25) * 205 (pos1[0] + pos1[channels] + 206 pos1[channels * width1] + pos1[channels * (width1 + 1)]); 207 pos1++; 208 pos2++; 209 } 210 } 211 else { 212 const Dtype* pos1 = &data1[h1 * width1 + w1]; 213 Dtype* pos2 = &data2[h2 * width2 + w2]; 214 for (int c = 0; c < channels; ++c) { 215 pos2[0] = static_cast<Dtype>(.25) * 216 (pos1[0] + pos1[1] + 217 pos1[width1] + pos1[width1 + 1]); 218 pos1 += width1 * height1; 219 pos2 += width2 * height2; 220 } 221 } 222 } 223 } 224 225 template <typename Dtype, bool packed> 226 void caffe_gpu_pyramid2(const int channels, 227 const Dtype *data, const int height, const int width, 228 Dtype *data_pyr, const int levels) { 229 CHECK(height > 0 && width > 0 && levels >= 0); 230 int height1 = height, width1 = width; 231 int height2 = height, width2 = width; 232 const Dtype *data1 = data; 233 Dtype *data2 = data_pyr; 234 for (int l = 0; l < levels; ++l) { 235 height2 /= 2; 236 width2 /= 2; 237 if (height2 == 0 || width2 == 0) { 238 break; 239 } 240 const int num_kernels = height2 * width2; 241 caffe_gpu_pyramid2_kernel<Dtype,packed><<<CAFFE_GET_BLOCKS(num_kernels), CAFFE_CUDA_NUM_THREADS>>> 242 (num_kernels, channels, data1, height1, width1, data2, height2, width2); 243 CUDA_POST_KERNEL_CHECK; 244 data1 = data2; 245 height1 = height2; 246 width1 = width2; 247 data2 += channels * height2 * width2; 248 } 249 } 250 251 252 // Explicit instances 253 template void caffe_gpu_interp2<float,false>(const int, const float *, const int, const int, const int, const int, const int, const int, float *, const int, const int, const int, const int, const int, const int); 254 template void caffe_gpu_interp2<float,true>(const int, const float *, const int, const int, const int, const int, const int, const int, float *, const int, const int, const int, const int, const int, const int); 255 template void caffe_gpu_interp2<double,false>(const int, const double *, const int, const int, const int, const int, const int, const int, double *, const int, const int, const int, const int, const int, const int); 256 template void caffe_gpu_interp2<double,true>(const int, const double *, const int, const int, const int, const int, const int, const int, double *, const int, const int, const int, const int, const int, const int); 257 258 template void caffe_gpu_interp2_backward<float,false>(const int, float *, const int, const int, const int, const int, const int, const int, const float *, const int, const int, const int, const int, const int, const int); 259 template void caffe_gpu_interp2_backward<double,false>(const int, double *, const int, const int, const int, const int, const int, const int, const double *, const int, const int, const int, const int, const int, const int); 260 261 template void caffe_gpu_pyramid2<float,false>(const int, const float *, const int, const int, float *, const int); 262 template void caffe_gpu_pyramid2<float,true>(const int, const float *, const int, const int, float *, const int); 263 template void caffe_gpu_pyramid2<double,false>(const int, const double *, const int, const int, double *, const int); 264 template void caffe_gpu_pyramid2<double,true>(const int, const double *, const int, const int, double *, const int); 265 266 } // namespace caffe
6.在PSPNet/src/caffe/proto/caffe.proto中添加代码,代码如下:
1 message LayerParameter { 2 optional string name = 1; // the layer name 3 optional string type = 2; // the layer type 4 repeated string bottom = 3; // the name of each bottom blob 5 repeated string top = 4; // the name of each top blob 6 7 // The train / test phase for computation. 8 optional Phase phase = 10; 9 10 // The amount of weight to assign each top blob in the objective. 11 // Each layer assigns a default value, usually of either 0 or 1, 12 // to each top blob. 13 repeated float loss_weight = 5; 14 15 // Specifies training parameters (multipliers on global learning constants, 16 // and the name and other settings used for weight sharing). 17 repeated ParamSpec param = 6; 18 19 // The blobs containing the numeric parameters of the layer. 20 repeated BlobProto blobs = 7; 21 22 // Specifies on which bottoms the backpropagation should be skipped. 23 // The size must be either 0 or equal to the number of bottoms. 24 repeated bool propagate_down = 11; 25 26 // Rules controlling whether and when a layer is included in the network, 27 // based on the current NetState. You may specify a non-zero number of rules 28 // to include OR exclude, but not both. If no include or exclude rules are 29 // specified, the layer is always included. If the current NetState meets 30 // ANY (i.e., one or more) of the specified rules, the layer is 31 // included/excluded. 32 repeated NetStateRule include = 8; 33 repeated NetStateRule exclude = 9; 34 35 // Parameters for data pre-processing. 36 optional TransformationParameter transform_param = 100; 37 38 // Parameters shared by loss layers. 39 optional LossParameter loss_param = 101; 40 41 // Layer type-specific parameters. 42 // 43 // Note: certain layers may have more than one computational engine 44 // for their implementation. These layers include an Engine type and 45 // engine parameter for selecting the implementation. 46 // The default for the engine is set by the ENGINE switch at compile-time. 47 optional AccuracyParameter accuracy_param = 102; 48 optional AdaptiveBiasChannelParameter adaptive_bias_channel_param = 148; 49 optional ArgMaxParameter argmax_param = 103; 50 optional BatchNormParameter batch_norm_param = 139; 51 optional BNParameter bn_param = 152; 52 optional BiasParameter bias_param = 141; 53 optional BiasChannelParameter bias_channel_param = 149; 54 optional ConcatParameter concat_param = 104; 55 optional ContrastiveLossParameter contrastive_loss_param = 105; 56 optional ConvolutionParameter convolution_param = 106; 57 optional DataParameter data_param = 107; 58 optional DenseCRFParameter dense_crf_param = 146; 59 optional DomainTransformParameter domain_transform_param = 147; 60 optional DropoutParameter dropout_param = 108; 61 optional DummyDataParameter dummy_data_param = 109; 62 optional EltwiseParameter eltwise_param = 110; 63 optional ELUParameter elu_param = 140; 64 optional EmbedParameter embed_param = 137; 65 optional ExpParameter exp_param = 111; 66 optional FlattenParameter flatten_param = 135; 67 optional HDF5DataParameter hdf5_data_param = 112; 68 optional HDF5OutputParameter hdf5_output_param = 113; 69 optional HingeLossParameter hinge_loss_param = 114; 70 optional ImageDataParameter image_data_param = 115; 71 optional InfogainLossParameter infogain_loss_param = 116; 72 optional InnerProductParameter inner_product_param = 117; 73 optional InterpParameter interp_param = 143; //注意143不能和其他的数字重复,可以自己情况调整 74 optional LogParameter log_param = 134; 75 optional LRNParameter lrn_param = 118; 76 optional MatReadParameter mat_read_param = 151; 77 optional MatWriteParameter mat_write_param = 145; 78 optional MemoryDataParameter memory_data_param = 119; 79 optional MVNParameter mvn_param = 120; 80 optional PoolingParameter pooling_param = 121; 81 optional PowerParameter power_param = 122; 82 optional PReLUParameter prelu_param = 131; 83 optional PythonParameter python_param = 130; 84 optional ReductionParameter reduction_param = 136; 85 optional ReLUParameter relu_param = 123; 86 optional ReshapeParameter reshape_param = 133; 87 optional ScaleParameter scale_param = 142; 88 optional SegAccuracyParameter seg_accuracy_param = 144; 89 optional SigmoidParameter sigmoid_param = 124; 90 optional SoftmaxParameter softmax_param = 125; 91 optional SPPParameter spp_param = 132; 92 optional SliceParameter slice_param = 126; 93 optional TanHParameter tanh_param = 127; 94 optional ThresholdParameter threshold_param = 128; 95 optional TileParameter tile_param = 138; 96 optional UniqueLabelParameter unique_label_param = 150; 97 optional WindowDataParameter window_data_param = 129; 98 }
1 message InterpParameter { 2 optional int32 height = 1 [default = 0]; // Height of output 3 optional int32 width = 2 [default = 0]; // Width of output 4 optional int32 zoom_factor = 3 [default = 1]; // zoom factor 5 optional int32 shrink_factor = 4 [default = 1]; // shrink factor 6 optional int32 pad_beg = 5 [default = 0]; // padding at begin of input 7 optional int32 pad_end = 6 [default = 0]; // padding at end of input 8 }
7.在网络结构中添加Interp层,代码如下:
1 layer{ 2 bottom:"input" 3 top:"output" 4 name:"interp_layer" 5 type:"Interp" 6 interp_param{ //注意可按需求改为interp_param{height:60 width:60}(即固定特征图的尺寸),也可以不需要这个interp_param参数 7 shrink_factor:4 8 zoom_factor:3 9 pad_beg:0 10 pad_end:0 11 } 12 }
第二步,添加完相应的代码,则进行编译
1.因为修改过caffe.proto,所以需要重新编译proto,需要先安装protobuf,安装之后需要编译caffe.proto文件,生成caffe.pb.h和caffe.pb.cc文件。编译过程如下:
1 # 确定protobuf的版本 2 $ protoc --version 3 libprotoc 2.5.0 4 5 # 编译caffe.proto,需要先进入src/caffe/proto目录下,也可以不进入,指定路径 6 $ protoc -I=./ --cpp_out=./ ./caffe.proto 7 8 # 查看编译结果 9 $ ls 10 caffe.pb.cc caffe.pb.h caffe.proto
2.编译caffe,退到caffe路径下,编译:
1 //确保每一步都成功执行 2 make clean 3 make -j8 4 make pycaffe
...大体上是这样一个流程,编译过程中遇到相应问题再百度,有错误的地方欢迎大家指正。
版权声明:
作者:王老头
出处:http://www.cnblogs.com/wmr95/p/8715607.html
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,并在文章页面明显位置给出原文链接,否则,作者将保留追究法律责任的权利。