Skip to content

Commit b755679

Browse files
committed
implementation MirrorPad of TF for both mode=REFLECT and mode=SYMMETRIC
1 parent 1776fe7 commit b755679

File tree

3 files changed

+179
-1
lines changed

3 files changed

+179
-1
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#ifndef CAFFE_MIRROR_PAD_LAYER_HPP_
2+
#define CAFFE_MIRROR_PAD_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+
template <typename Dtype>
13+
class MirrorPadLayer : public Layer<Dtype> {
14+
public:
15+
16+
explicit MirrorPadLayer(const LayerParameter& param)
17+
: Layer<Dtype>(param) {}
18+
virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom,
19+
const vector<Blob<Dtype>*>& top);
20+
virtual void Reshape(const vector<Blob<Dtype>*>& bottom,
21+
const vector<Blob<Dtype>*>& top);
22+
23+
virtual inline const char* type() const { return "MirrorPad"; }
24+
virtual inline int ExactNumBottomBlobs() const { return 1; }
25+
virtual inline int ExactNumTopBlobs() const { return 1; }
26+
27+
protected:
28+
29+
virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom,
30+
const vector<Blob<Dtype>*>& top);
31+
/// @brief Not implemented (non-differentiable function)
32+
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
33+
const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {
34+
NOT_IMPLEMENTED;
35+
}
36+
inline vector<int> indices(int offset, const vector<int> & shape) const;
37+
inline int offset(const vector<int>& indices, const vector<int> & shape) const;
38+
39+
vector<int> paddings_;
40+
float constant_values_;
41+
string mode_;
42+
};
43+
44+
} // namespace caffe
45+
46+
#endif // CAFFE_MIRROR_PAD_LAYER_HPP_
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#include <algorithm>
2+
#include <functional>
3+
#include <utility>
4+
#include <vector>
5+
6+
#include "caffe/layers/mirror_pad_layer.hpp"
7+
8+
namespace caffe {
9+
using namespace std;
10+
template <typename Dtype>
11+
void MirrorPadLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype> *> &bottom,
12+
const vector<Blob<Dtype> *> &top) {
13+
const MirrorPadParameter &mirror_pad_param =
14+
this->layer_param_.mirror_pad_param();
15+
constant_values_ = mirror_pad_param.constant_values();
16+
mode_ = mirror_pad_param.mode();
17+
paddings_.clear();
18+
std::copy(mirror_pad_param.paddings().begin(),
19+
mirror_pad_param.paddings().end(), std::back_inserter(paddings_));
20+
int pad_dim = paddings_.size();
21+
CHECK_EQ(pad_dim % 2, 0)
22+
<< "Paddings for each dimension should have 2 values!";
23+
CHECK_EQ(pad_dim / 2, bottom[0]->num_axes())
24+
<< "Paddings' num should be 2 times of bottom dimension!";
25+
// CHECK_LE(bottom[0]->num_axes(), 4) << "Not support more than 4D paddings!";
26+
}
27+
28+
template <typename Dtype>
29+
void MirrorPadLayer<Dtype>::Reshape(const vector<Blob<Dtype> *> &bottom,
30+
const vector<Blob<Dtype> *> &top) {
31+
int num_top_axes = bottom[0]->num_axes();
32+
std::vector<int> shape(num_top_axes, 1);
33+
shape = bottom[0]->shape();
34+
for (int i = 0; i < num_top_axes; i++) {
35+
shape[i] = shape[i] + paddings_[2 * i] + paddings_[2 * i + 1];
36+
}
37+
top[0]->Reshape(shape);
38+
}
39+
40+
template <typename Dtype>
41+
inline vector<int>
42+
MirrorPadLayer<Dtype>::indices(int offset, const vector<int> &shape) const {
43+
vector<int> indices(shape.size());
44+
int r = offset;
45+
for (int i = shape.size() - 1; i >= 0; i--) {
46+
indices[i] = r % shape[i];
47+
r /= shape[i];
48+
}
49+
return indices;
50+
}
51+
52+
template <typename Dtype>
53+
inline int MirrorPadLayer<Dtype>::offset(const vector<int> &indices,
54+
const vector<int> &shape) const {
55+
int offset = 0;
56+
for (int i = 0; i < shape.size(); ++i) {
57+
offset *= shape[i];
58+
offset += indices[i];
59+
}
60+
return offset;
61+
}
62+
63+
template <typename Dtype>
64+
void MirrorPadLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype> *> &bottom,
65+
const vector<Blob<Dtype> *> &top) {
66+
const Dtype *bottom_data = bottom[0]->cpu_data();
67+
Dtype *top_data = top[0]->mutable_cpu_data();
68+
auto bottom_shape = bottom[0]->shape();
69+
auto top_shape = top[0]->shape();
70+
int strides = bottom_shape.back();
71+
72+
caffe_set(top[0]->count(), Dtype(constant_values_), top_data);
73+
74+
for (int position = 0; position < bottom[0]->count() / strides; position++) {
75+
vector<int> coord_bottom = indices(position * strides, bottom_shape);
76+
vector<int> coord_pad(coord_bottom);
77+
for (int i = 0; i < top_shape.size(); i++)
78+
coord_pad[i] += paddings_[2 * i];
79+
int position_top = offset(coord_pad, top_shape);
80+
copy_n(bottom_data + position * strides, strides, top_data + position_top);
81+
}
82+
if (mode_ == "REFLECT") {
83+
strides = 1;
84+
for (int i = top_shape.size() - 1; i >= 0; i--) {
85+
int inner_strides = strides;
86+
strides *= top_shape[i];
87+
for (int position = 0; position < top[0]->count() / strides; position++) {
88+
for (int j = 1; j <= paddings_[2 * i]; j++) {
89+
copy_n(top_data + position*strides + inner_strides * (paddings_[2 * i] + j),
90+
inner_strides,
91+
top_data + position*strides + inner_strides * (paddings_[2 * i] - j));
92+
}
93+
for (int j = 1; j <= paddings_[2 * i + 1]; j++) {
94+
copy_n(top_data + position*strides + inner_strides * (bottom_shape[i] + paddings_[2 * i] - 1 - j),
95+
inner_strides,
96+
top_data + position*strides + inner_strides * (bottom_shape[i] + paddings_[2 * i] - 1 + j));
97+
}
98+
}
99+
}
100+
101+
} else if (mode_ == "SYMMETRIC") {
102+
strides = 1;
103+
for (int i = top_shape.size() - 1; i >= 0; i--) {
104+
int inner_strides = strides;
105+
strides *= top_shape[i];
106+
for (int position = 0; position < top[0]->count() / strides; position++) {
107+
for (int j = 0; j < paddings_[2 * i]; j++) {
108+
copy_n(top_data + position*strides + inner_strides * (paddings_[2 * i] + j),
109+
inner_strides,
110+
top_data + position*strides + inner_strides * (paddings_[2 * i] - j - 1));
111+
}
112+
for (int j = 0; j < paddings_[2 * i + 1]; j++) {
113+
copy_n(top_data + position*strides + inner_strides * (bottom_shape[i] + paddings_[2 * i] - 1 - j),
114+
inner_strides,
115+
top_data + position*strides + inner_strides * (bottom_shape[i] + paddings_[2 * i] + j));
116+
}
117+
}
118+
}
119+
}
120+
}
121+
122+
INSTANTIATE_CLASS(MirrorPadLayer);
123+
REGISTER_LAYER_CLASS(MirrorPad);
124+
125+
} // namespace caffe

src/caffe/proto/caffe.proto

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ message ParamSpec {
460460
// NOTE
461461
// Update the next available ID when you add a new LayerParameter field.
462462
//
463-
// LayerParameter next available layer-specific ID: 237 (last added: xlu_param)
463+
// LayerParameter next available layer-specific ID: 238 (last added: mirror_pad_param)
464464
message LayerParameter {
465465
optional string name = 1; // the layer name
466466
optional string type = 2; // the layer type
@@ -641,6 +641,7 @@ message LayerParameter {
641641
optional UnstackParameter unstack_param = 234;
642642
optional BatchToSpaceNDParameter batch_to_space_nd_param = 235;
643643
optional SpaceToBatchNDParameter space_to_batch_nd_param = 236;
644+
optional MirrorPadParameter mirror_pad_param = 238;
644645
}
645646

646647
message AccumParameter {
@@ -2983,6 +2984,12 @@ message PadParameter{
29832984
optional float constant_values = 2 [default = 0.0];
29842985
}
29852986

2987+
message MirrorPadParameter{
2988+
repeated uint32 paddings = 1;
2989+
optional float constant_values = 2 [default = 0.0];
2990+
optional string mode = 3 [default = "CONSTANT"];
2991+
}
2992+
29862993
message StackParameter{
29872994
optional int32 axis = 1 [default = 0];
29882995
}

0 commit comments

Comments
 (0)