1 #include "caffe2/operators/pad_op.h" 7 PadMode StringToPadMode(
const string& mode) {
8 if (mode ==
"constant") {
9 return PadMode::CONSTANT;
10 }
else if (mode ==
"reflect") {
11 return PadMode::REFLECT;
12 }
else if (mode ==
"edge") {
15 CAFFE_THROW(
"Unknown padding mode: " + mode);
23 bool PadImageOp<float, CPUContext>::RunOnDeviceWithOrderNCHW() {
26 int channels = X.dim32(1);
27 int height = X.dim32(2);
28 int width = X.dim32(3);
29 ConvPoolOpBase::SetOutputSize(X, Y, channels);
31 const float* Xdata = X.data<
float>();
32 float* Ydata = Y->mutable_data<
float>();
34 int padded_height = Y->dim32(2);
35 int padded_width = Y->dim32(3);
38 case PadMode::CONSTANT:
39 for (
int n = 0; n < X.dim32(0); ++n) {
40 for (
int c = 0; c < channels; ++c) {
41 for (
int ph = 0; ph < padded_height; ++ph) {
42 for (
int pw = 0; pw < padded_width; ++pw) {
45 Ydata[ph * padded_width + pw] =
46 (h < 0 || w < 0 || h >= height || w >= width)
48 : Xdata[h * width + w];
52 Xdata += height * width;
53 Ydata += padded_height * padded_width;
57 case PadMode::REFLECT:
58 if (pad_r() >= 0 && pad_t() >= 0 && pad_l() >= 0 && pad_b() >= 0) {
59 for (
int n = 0; n < X.dim32(0); ++n) {
60 for (
int c = 0; c < channels; ++c) {
63 auto* Ystart = Ydata + pad_t() * padded_width + pad_l();
64 math::CopyMatrix<CPUContext>(
76 int h = ph - pad_t(); \ 77 int w = pw - pad_l(); \ 79 h = min(h, 2 * height - h - 2); \ 81 w = min(w, 2 * width - w - 2); \ 82 Ydata[ph * padded_width + pw] = Xdata[h * width + w] 85 for (
int ph = 0; ph < pad_t(); ++ph) {
86 for (
int pw = 0; pw < padded_width; ++pw) {
92 for (
int ph = padded_height - pad_b(); ph < padded_height; ++ph) {
93 for (
int pw = 0; pw < padded_width; ++pw) {
99 for (
int ph = pad_t(); ph < padded_height - pad_b(); ++ph) {
101 for (
int pw = 0; pw < pad_l(); ++pw) {
105 for (
int pw = padded_width - pad_r(); pw < padded_width; ++pw) {
112 Xdata += height * width;
113 Ydata += padded_height * padded_width;
117 for (
int n = 0; n < X.dim32(0); ++n) {
118 for (
int c = 0; c < channels; ++c) {
119 for (
int ph = 0; ph < padded_height; ++ph) {
120 for (
int pw = 0; pw < padded_width; ++pw) {
121 int h = ph - pad_t();
122 int w = pw - pad_l();
126 h = min(h, 2 * height - h - 2);
128 w = min(w, 2 * width - w - 2);
129 Ydata[ph * padded_width + pw] = Xdata[h * width + w];
133 Xdata += height * width;
134 Ydata += padded_height * padded_width;
140 for (
int n = 0; n < X.dim32(0); ++n) {
141 for (
int c = 0; c < channels; ++c) {
142 for (
int ph = 0; ph < padded_height; ++ph) {
143 for (
int pw = 0; pw < padded_width; ++pw) {
145 int h = min(height - 1, max(ph - pad_t(), 0));
146 int w = min(width - 1, max(pw - pad_l(), 0));
147 Ydata[ph * padded_width + pw] = Xdata[h * width + w];
151 Xdata += height * width;
152 Ydata += padded_height * padded_width;
161 bool PadImageOp<float, CPUContext>::RunOnDeviceWithOrderNHWC() {
164 int height = X.dim32(1);
165 int width = X.dim32(2);
166 int channels = X.dim32(3);
167 ConvPoolOpBase::SetOutputSize(X, Y, channels);
168 const float* Xdata = X.data<
float>();
169 float* Ydata = Y->mutable_data<
float>();
172 int padded_height = Y->dim32(1);
173 int padded_width = Y->dim32(2);
176 case PadMode::CONSTANT:
177 for (
int n = 0; n < X.dim32(0); ++n) {
178 for (
int ph = 0; ph < padded_height; ++ph) {
179 for (
int pw = 0; pw < padded_width; ++pw) {
180 int h = ph - pad_t();
181 int w = pw - pad_l();
182 const int pad_index = (ph * padded_width + pw) * channels;
183 if (h < 0 || w < 0 || h >= height || w >= width) {
184 for (
int c = 0; c < channels; ++c) {
185 Ydata[pad_index + c] = value_;
188 const int input_index = (h * width + w) * channels;
189 for (
int c = 0; c < channels; ++c) {
190 Ydata[pad_index + c] = Xdata[input_index + c];
196 Xdata += X.size() / X.dim32(0);
197 Ydata += Y->size() / Y->dim32(0);
200 case PadMode::REFLECT:
201 for (
int n = 0; n < X.dim32(0); ++n) {
202 for (
int ph = 0; ph < padded_height; ++ph) {
203 for (
int pw = 0; pw < padded_width; ++pw) {
204 const int pad_index = (ph * padded_width + pw) * channels;
205 int h = ph - pad_t();
206 int w = pw - pad_l();
210 h = min(h, 2 * height - h - 2);
212 w = min(w, 2 * width - w - 2);
213 const int input_index = (h * width + w) * channels;
214 for (
int c = 0; c < channels; ++c) {
215 Ydata[pad_index + c] = Xdata[input_index + c];
220 Xdata += X.size() / X.dim32(0);
221 Ydata += Y->size() / Y->dim32(0);
225 for (
int n = 0; n < X.dim32(0); ++n) {
226 for (
int ph = 0; ph < padded_height; ++ph) {
227 for (
int pw = 0; pw < padded_width; ++pw) {
228 const int pad_index = (ph * padded_width + pw) * channels;
229 int h = min(height - 1, max(ph - pad_t(), 0));
230 int w = min(width - 1, max(pw - pad_l(), 0));
231 const int input_index = (h * width + w) * channels;
232 for (
int c = 0; c < channels; ++c) {
233 Ydata[pad_index + c] = Xdata[input_index + c];
238 Xdata += X.size() / X.dim32(0);
239 Ydata += Y->size() / Y->dim32(0);
247 bool PadImageGradientOp<float, CPUContext>::RunOnDeviceWithOrderNCHW() {
249 auto* dX = Output(0);
253 dY.dim32(2) - pad_t() - pad_b(),
254 dY.dim32(3) - pad_l() - pad_r());
255 int padded_height = dY.dim32(2);
256 int padded_width = dY.dim32(3);
257 int channels = dX->dim32(1);
258 int height = dX->dim32(2);
259 int width = dX->dim32(3);
261 const float* dYdata = dY.data<
float>();
262 float* dXdata = dX->mutable_data<
float>();
263 math::Set<float, CPUContext>(dX->size(), 0, dXdata, &context_);
266 case PadMode::CONSTANT:
267 for (
int n = 0; n < dY.dim32(0); ++n) {
268 for (
int c = 0; c < channels; ++c) {
269 for (
int ph = 0; ph < padded_height; ++ph) {
270 for (
int pw = 0; pw < padded_width; ++pw) {
271 int h = ph - pad_t();
272 int w = pw - pad_l();
273 if (!(h < 0 || w < 0 || h >= height || w >= width)) {
274 dXdata[h * width + w] += dYdata[ph * padded_width + pw];
279 dXdata += height * width;
280 dYdata += padded_height * padded_width;
284 case PadMode::REFLECT:
285 for (
int n = 0; n < dY.dim32(0); ++n) {
286 for (
int c = 0; c < channels; ++c) {
287 for (
int ph = 0; ph < padded_height; ++ph) {
288 for (
int pw = 0; pw < padded_width; ++pw) {
289 int h = ph - pad_t();
290 int w = pw - pad_l();
294 h = min(h, 2 * height - h - 2);
296 w = min(w, 2 * width - w - 2);
297 dXdata[h * width + w] += dYdata[ph * padded_width + pw];
301 dXdata += height * width;
302 dYdata += padded_height * padded_width;
307 for (
int n = 0; n < dY.dim32(0); ++n) {
308 for (
int c = 0; c < channels; ++c) {
309 for (
int ph = 0; ph < padded_height; ++ph) {
310 for (
int pw = 0; pw < padded_width; ++pw) {
311 int h = min(height - 1, max(ph - pad_t(), 0));
312 int w = min(width - 1, max(pw - pad_l(), 0));
313 dXdata[h * width + w] += dYdata[ph * padded_width + pw];
317 dXdata += height * width;
318 dYdata += padded_height * padded_width;
327 bool PadImageGradientOp<float, CPUContext>::RunOnDeviceWithOrderNHWC() {
329 auto* dX = Output(0);
332 dY.dim32(1) - pad_t() - pad_b(),
333 dY.dim32(2) - pad_l() - pad_r(),
335 int padded_height = dY.dim32(1);
336 int padded_width = dY.dim32(2);
337 int channels = dY.dim32(3);
338 int height = dX->dim32(1);
339 int width = dX->dim32(2);
341 const float* dYdata = dY.data<
float>();
342 float* dXdata = dX->mutable_data<
float>();
343 math::Set<float, CPUContext>(dX->size(), 0, dXdata, &context_);
346 case PadMode::CONSTANT:
347 for (
int n = 0; n < dY.dim32(0); ++n) {
348 for (
int ph = 0; ph < padded_height; ++ph) {
349 for (
int pw = 0; pw < padded_width; ++pw) {
350 int h = ph - pad_t();
351 int w = pw - pad_l();
352 const int pad_index = (ph * padded_width + pw) * channels;
353 if (!(h < 0 || w < 0 || h >= height || w >= width)) {
354 const int input_index = (h * width + w) * channels;
355 for (
int c = 0; c < channels; ++c) {
356 dXdata[input_index + c] += dYdata[pad_index + c];
362 dXdata += dX->size() / dX->dim32(0);
363 dYdata += dY.size() / dY.dim32(0);
366 case PadMode::REFLECT:
367 for (
int n = 0; n < dY.dim32(0); ++n) {
368 for (
int ph = 0; ph < padded_height; ++ph) {
369 for (
int pw = 0; pw < padded_width; ++pw) {
370 const int pad_index = (ph * padded_width + pw) * channels;
371 int h = ph - pad_t();
372 int w = pw - pad_l();
376 h = min(h, 2 * height - h - 2);
378 w = min(w, 2 * width - w - 2);
379 const int input_index = (h * width + w) * channels;
380 for (
int c = 0; c < channels; ++c) {
381 dXdata[input_index + c] += dYdata[pad_index + c];
386 dXdata += dX->size() / dX->dim32(0);
387 dYdata += dY.size() / dY.dim32(0);
391 for (
int n = 0; n < dY.dim32(0); ++n) {
392 for (
int ph = 0; ph < padded_height; ++ph) {
393 for (
int pw = 0; pw < padded_width; ++pw) {
394 const int pad_index = (ph * padded_width + pw) * channels;
396 int h = min(height - 1, max(ph - pad_t(), 0));
397 int w = min(width - 1, max(pw - pad_l(), 0));
398 const int input_index = (h * width + w) * channels;
399 for (
int c = 0; c < channels; ++c) {
400 dXdata[input_index + c] += dYdata[pad_index + c];
405 dXdata += dX->size() / dX->dim32(0);
406 dYdata += dY.size() / dY.dim32(0);
414 std::vector<TensorShape> PadImageOp<float, CPUContext>::PadTensorInference(
415 const OperatorDef& def,
416 const vector<TensorShape>& in) {
417 return ConvPoolOpBase::TensorInferenceForPool(def, in);
420 REGISTER_CPU_OPERATOR(PadImage, PadImageOp<float, CPUContext>);
421 REGISTER_CPU_OPERATOR(PadImageGradient, PadImageGradientOp<float, CPUContext>);
423 OPERATOR_SCHEMA(PadImage)
426 .TensorInferenceFunction(PadImageOp<float, CPUContext>::PadTensorInference)
428 PadImage pads values around the boundary of an image according to the pad 429 values and stride sizes defined by the ConvPoolOpBase operator. 434 "Input data tensor from the previous operator; dimensions " 435 "depend on whether the NCHW or NHWC operators are being used. For example, " 436 "in the former, the input has size (N x C x H x W), where N is the batch " 437 "size, C is the number of channels, and H and W are the height and the width " 438 "of the data. The corresponding permutation of dimensions is used in the " 443 "Output data tensor from padding the H and W dimensions on " 444 "the tensor. Dimensions will vary based on various pad and stride " 447 OPERATOR_SCHEMA(PadImageGradient).NumInputs(1).NumOutputs(1);
450 using GradientMakerBase::GradientMakerBase;
451 vector<OperatorDef> GetGradientDefs()
override {
453 "PadImageGradient",
"", vector<string>{GO(0)}, vector<string>{GI(0)});
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...
static vector< OperatorDef > SingleGradientDef(const Args &...args)
a helper function to allow one to create one single operator def, which is usually the case for many ...