Skip to content

Commit f63ad7e

Browse files
committed
Added Simplified Crop Layer, with fix for 0 crop.
1 parent b9b47e3 commit f63ad7e

File tree

4 files changed

+228
-1
lines changed

4 files changed

+228
-1
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#ifndef CAFFE_CROP_LAYER_HPP_
2+
#define CAFFE_CROP_LAYER_HPP_
3+
4+
#include <utility>
5+
#include <vector>
6+
7+
#include "caffe/blob.hpp"
8+
#include "caffe/layer.hpp"
9+
#include "caffe/proto/caffe.pb.h"
10+
11+
namespace caffe {
12+
13+
/**
14+
* @brief Takes a Blob and crop it along either the width or height dimension,
15+
* outputting a cropped Blob.
16+
*
17+
* TODO(dox): thorough documentation for Forward, Backward, and proto params.
18+
*/
19+
20+
template <typename Dtype>
21+
class CropLayer : public Layer<Dtype> {
22+
public:
23+
explicit CropLayer(const LayerParameter& param)
24+
: Layer<Dtype>(param) {}
25+
virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom,
26+
const vector<Blob<Dtype>*>& top);
27+
virtual void Reshape(const vector<Blob<Dtype>*>& bottom,
28+
const vector<Blob<Dtype>*>& top);
29+
30+
virtual inline const char* type() const { return "Crop"; }
31+
virtual inline int ExactNumBottomBlobs() const { return 2; }
32+
virtual inline int ExactNumTopBlobs() const { return 1; }
33+
34+
protected:
35+
virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom,
36+
const vector<Blob<Dtype>*>& top);
37+
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
38+
const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);
39+
virtual void Forward_gpu(const vector<Blob<Dtype>*>& bottom,
40+
const vector<Blob<Dtype>*>& top);
41+
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
42+
const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);
43+
44+
int crop_h_, crop_w_;
45+
};
46+
47+
} // namespace caffe
48+
49+
#endif // CAFFE_CROP_LAYER_HPP_

src/caffe/layers/crop_layer.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#include <algorithm>
2+
#include <map>
3+
#include <set>
4+
#include <vector>
5+
6+
#include "caffe/layer.hpp"
7+
#include "caffe/layers/crop_layer.hpp"
8+
#include "caffe/net.hpp"
9+
10+
11+
namespace caffe {
12+
13+
template <typename Dtype>
14+
void CropLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom,
15+
const vector<Blob<Dtype>*>& top) {
16+
const CropParameter& param = this->layer_param_.crop_param();
17+
CHECK_EQ(bottom.size(), 2) << "Wrong number of bottom blobs.";
18+
CHECK_EQ(bottom[0]->num_axes(), 4) << "Only works with 4D blobs.";
19+
CHECK_EQ(bottom[1]->num_axes(), 4) << "Only works with 4D blobs.";
20+
crop_h_ = param.offset_height();
21+
crop_w_ = param.offset_width();
22+
}
23+
24+
template <typename Dtype>
25+
void CropLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom,
26+
const vector<Blob<Dtype>*>& top) {
27+
// Check that the image we are cropping minus the margin is bigger than the
28+
// destination image.
29+
CHECK_GE(bottom[0]->height()-crop_h_, bottom[1]->height())
30+
<< "invalid offset";
31+
CHECK_GE(bottom[0]->width()-crop_w_, bottom[1]->width()) << "invalid offset";
32+
top[0]->Reshape(bottom[0]->num(), bottom[0]->channels(), bottom[1]->height(),
33+
bottom[1]->width());
34+
}
35+
36+
template <typename Dtype>
37+
void CropLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
38+
const vector<Blob<Dtype>*>& top) {
39+
const Dtype* bottom_data = bottom[0]->cpu_data();
40+
Dtype* top_data = top[0]->mutable_cpu_data();
41+
for (int n = 0; n < top[0]->num(); ++n) {
42+
for (int c = 0; c < top[0]->channels(); ++c) {
43+
for (int h = 0; h < top[0]->height(); ++h) {
44+
caffe_copy(top[0]->width(),
45+
bottom_data + bottom[0]->offset(n, c, crop_h_ + h, crop_w_),
46+
top_data + top[0]->offset(n, c, h));
47+
}
48+
}
49+
}
50+
}
51+
52+
template <typename Dtype>
53+
void CropLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
54+
const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {
55+
const Dtype* top_diff = top[0]->cpu_diff();
56+
Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();
57+
if (propagate_down[0]) {
58+
caffe_set(bottom[0]->count(), static_cast<Dtype>(0), bottom_diff);
59+
for (int n = 0; n < top[0]->num(); ++n) {
60+
for (int c = 0; c < top[0]->channels(); ++c) {
61+
for (int h = 0; h < top[0]->height(); ++h) {
62+
caffe_copy(top[0]->width(),
63+
top_diff + top[0]->offset(n, c, h),
64+
bottom_diff + bottom[0]->offset(n, c, crop_h_ + h, crop_w_));
65+
}
66+
}
67+
}
68+
}
69+
}
70+
71+
#ifdef CPU_ONLY
72+
STUB_GPU(CropLayer);
73+
#endif
74+
75+
INSTANTIATE_CLASS(CropLayer);
76+
REGISTER_LAYER_CLASS(Crop);
77+
78+
} // namespace caffe

src/caffe/layers/crop_layer.cu

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#include <vector>
2+
3+
#include "caffe/layers/crop_layer.hpp"
4+
5+
namespace caffe {
6+
7+
// Copy (one line per thread) from one array to another, with arbitrary
8+
// strides in the last two dimensions.
9+
template <typename Dtype>
10+
__global__ void copy_kernel(const int n, const int height, const int width,
11+
const int src_outer_stride, const int src_inner_stride,
12+
const int dest_outer_stride, const int dest_inner_stride,
13+
const Dtype* src, Dtype* dest) {
14+
CUDA_KERNEL_LOOP(index, n) {
15+
int src_start = index / height * src_outer_stride
16+
+ index % height * src_inner_stride;
17+
int dest_start = index / height * dest_outer_stride
18+
+ index % height * dest_inner_stride;
19+
for (int i = 0; i < width; ++i) {
20+
dest[dest_start + i] = src[src_start + i];
21+
}
22+
}
23+
}
24+
25+
template <typename Dtype>
26+
void CropLayer<Dtype>::Forward_gpu(const vector<Blob<Dtype>*>& bottom,
27+
const vector<Blob<Dtype>*>& top) {
28+
const Dtype* bottom_data = bottom[0]->gpu_data();
29+
Dtype* top_data = top[0]->mutable_gpu_data();
30+
const int lines = top[0]->count() / top[0]->width();
31+
32+
// NOLINT_NEXT_LINE(whitespace/operators)
33+
copy_kernel<<<CAFFE_GET_BLOCKS(lines), CAFFE_CUDA_NUM_THREADS>>>(
34+
lines, top[0]->height(), top[0]->width(),
35+
bottom[0]->height() * bottom[0]->width(), bottom[0]->width(),
36+
top[0]->height() * top[0]->width(), top[0]->width(),
37+
bottom_data + bottom[0]->offset(0, 0, crop_h_, crop_w_), top_data);
38+
}
39+
40+
template <typename Dtype>
41+
void CropLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
42+
const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {
43+
const Dtype* top_diff = top[0]->gpu_diff();
44+
Dtype* bottom_diff = bottom[0]->mutable_gpu_diff();
45+
const int lines = top[0]->count() / top[0]->width();
46+
47+
if (propagate_down[0]) {
48+
caffe_gpu_set(bottom[0]->count(), static_cast<Dtype>(0), bottom_diff);
49+
// NOLINT_NEXT_LINE(whitespace/operators)
50+
copy_kernel<<<CAFFE_GET_BLOCKS(lines), CAFFE_CUDA_NUM_THREADS>>>(
51+
lines, top[0]->height(), top[0]->width(),
52+
top[0]->height() * top[0]->width(), top[0]->width(),
53+
bottom[0]->height() * bottom[0]->width(), bottom[0]->width(),
54+
top_diff, bottom_diff + bottom[0]->offset(0, 0, crop_h_, crop_w_));
55+
}
56+
}
57+
58+
INSTANTIATE_LAYER_GPU_FUNCS(CropLayer);
59+
60+
} // namespace caffe

src/caffe/proto/caffe.proto

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ message ParamSpec {
309309
// NOTE
310310
// Update the next available ID when you add a new LayerParameter field.
311311
//
312-
// LayerParameter next available layer-specific ID: 147 (last added: parse_evaluate_param)
312+
// LayerParameter next available layer-specific ID: 148 (last added: crop_param)
313313
message LayerParameter {
314314
optional string name = 1; // the layer name
315315
optional string type = 2; // the layer type
@@ -363,6 +363,7 @@ message LayerParameter {
363363
optional ConcatParameter concat_param = 104;
364364
optional ContrastiveLossParameter contrastive_loss_param = 105;
365365
optional ConvolutionParameter convolution_param = 106;
366+
optional CropParameter crop_param = 147;
366367
optional DataParameter data_param = 107;
367368
optional DropoutParameter dropout_param = 108;
368369
optional DummyDataParameter dummy_data_param = 109;
@@ -539,6 +540,38 @@ message BiasParameter {
539540
optional FillerParameter filler = 3;
540541
}
541542

543+
// Message that stores parameters used by PoolingLayer
544+
message BinPoolingParameter {
545+
enum PoolMethod {
546+
MAX = 0;
547+
AVE = 1;
548+
STOCHASTIC = 2;
549+
}
550+
optional PoolMethod pool = 1 [default = MAX]; // The pooling method
551+
// Pad, kernel size, and stride are all given as a single value for equal
552+
// dimensions in height and width or as Y, X pairs.
553+
optional uint32 pad = 4 [default = 0]; // The padding size (equal in Y, X)
554+
optional uint32 pad_h = 9 [default = 0]; // The padding height
555+
optional uint32 pad_w = 10 [default = 0]; // The padding width
556+
optional uint32 kernel_size = 2; // The kernel size (square)
557+
optional uint32 kernel_h = 5; // The kernel height
558+
optional uint32 kernel_w = 6; // The kernel width
559+
optional uint32 stride = 3 [default = 1]; // The stride (equal in Y, X)
560+
optional uint32 stride_h = 7; // The stride height
561+
optional uint32 stride_w = 8; // The stride width
562+
optional uint32 bin_size = 13; // The spatial bin #
563+
optional uint32 bin_h = 14; // The spatial bin # in height direction
564+
optional uint32 bin_w = 15; // The spatial bin # in width direction
565+
enum Engine {
566+
DEFAULT = 0;
567+
CAFFE = 1;
568+
CUDNN = 2;
569+
}
570+
optional Engine engine = 11 [default = DEFAULT];
571+
// If global_pooling then it will pool over the size of the bottom by doing
572+
// kernel_h = bottom->height and kernel_w = bottom->width
573+
optional bool global_pooling = 12 [default = false];
574+
}
542575
message ContrastiveLossParameter {
543576
// margin for dissimilar pair
544577
optional float margin = 1 [default = 1.0];
@@ -604,6 +637,13 @@ message ConvolutionParameter {
604637
optional bool force_nd_im2col = 17 [default = false];
605638
}
606639

640+
message CropParameter {
641+
// Assumes standard dimensions: ( N,C,H,W )
642+
// This could possibly be extended to use "optional BlobShape offsets"
643+
optional uint32 offset_height = 1[default = 0];
644+
optional uint32 offset_width = 2[default = 0];
645+
}
646+
607647
message DataParameter {
608648
enum DB {
609649
LEVELDB = 0;

0 commit comments

Comments
 (0)