You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
931 lines
39 KiB
931 lines
39 KiB
/* Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License. */
|
|
|
|
#include <algorithm>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
#include "paddle/fluid/framework/op_registry.h"
|
|
#include "paddle/fluid/operators/math/math_function.h"
|
|
|
|
namespace paddle {
|
|
namespace operators {
|
|
|
|
using framework::Tensor;
|
|
|
|
template <typename T>
|
|
void ConstPad3DFuncNCDHW(const T* in_data, T* out_data, const int in_depth,
|
|
const int in_height, const int in_width,
|
|
const int out_depth, const int out_height,
|
|
const int out_width, const int pad_front,
|
|
const int pad_top, const int pad_left, const int out_d,
|
|
const int out_h, const int out_w, const T value) {
|
|
int in_d = out_d - pad_front;
|
|
int in_h = out_h - pad_top;
|
|
int in_w = out_w - pad_left;
|
|
out_data[out_d * out_height * out_width + out_h * out_width + out_w] =
|
|
(in_d < 0 || in_h < 0 || in_w < 0 || in_d >= in_depth ||
|
|
in_h >= in_height || in_w >= in_width)
|
|
? value
|
|
: in_data[in_d * in_height * in_width + in_h * in_width + in_w];
|
|
}
|
|
|
|
template <typename T>
|
|
void ConstPad3DFuncNDHWC(const T* in_data, T* out_data, const int channels,
|
|
const int in_depth, const int in_height,
|
|
const int in_width, const int out_depth,
|
|
const int out_height, const int out_width,
|
|
const int pad_front, const int pad_top,
|
|
const int pad_left, const int out_d, const int out_h,
|
|
const int out_w, const T value) {
|
|
int in_d = out_d - pad_front;
|
|
int in_h = out_h - pad_top;
|
|
int in_w = out_w - pad_left;
|
|
const int out_index =
|
|
(out_d * out_height * out_width + out_h * out_width + out_w) * channels;
|
|
if (in_d < 0 || in_h < 0 || in_w < 0 || in_d >= in_depth ||
|
|
in_h >= in_height || in_w >= in_width) {
|
|
for (int c = 0; c < channels; ++c) {
|
|
out_data[out_index + c] = value;
|
|
}
|
|
} else {
|
|
const int in_index =
|
|
(in_d * in_height * in_width + in_h * in_width + in_w) * channels;
|
|
for (int c = 0; c < channels; ++c) {
|
|
out_data[out_index + c] = in_data[in_index + c];
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
void ReflectPad3DFuncNCDHW(const T* in_data, T* out_data, const int in_depth,
|
|
const int in_height, const int in_width,
|
|
const int out_depth, const int out_height,
|
|
const int out_width, const int pad_front,
|
|
const int pad_top, const int pad_left,
|
|
const int out_d, const int out_h, const int out_w,
|
|
const T value) {
|
|
int in_d = out_d - pad_front;
|
|
int in_h = out_h - pad_top;
|
|
int in_w = out_w - pad_left;
|
|
|
|
in_d = std::max(in_d, -in_d); // reflect by 0
|
|
in_d = std::min(in_d, 2 * in_depth - in_d - 2); // reflect by in_depth
|
|
in_h = std::max(in_h, -in_h); // reflect by 0
|
|
in_h = std::min(in_h, 2 * in_height - in_h - 2); // reflect by in_height
|
|
in_w = std::max(in_w, -in_w); // reflect by 0
|
|
in_w = std::min(in_w, 2 * in_width - in_w - 2); // reflect by in_width
|
|
|
|
out_data[out_d * out_height * out_width + out_h * out_width + out_w] =
|
|
in_data[in_d * in_height * in_width + in_h * in_width + in_w];
|
|
}
|
|
|
|
template <typename T>
|
|
void ReflectPad3DFuncNDHWC(const T* in_data, T* out_data, const int channels,
|
|
const int in_depth, const int in_height,
|
|
const int in_width, const int out_depth,
|
|
const int out_height, const int out_width,
|
|
const int pad_front, const int pad_top,
|
|
const int pad_left, const int out_d, const int out_h,
|
|
const int out_w, const T value) {
|
|
int in_d = out_d - pad_front;
|
|
int in_h = out_h - pad_top;
|
|
int in_w = out_w - pad_left;
|
|
|
|
in_d = std::max(in_d, -in_d);
|
|
in_d = std::min(in_d, 2 * in_depth - in_d - 2);
|
|
in_h = std::max(in_h, -in_h);
|
|
in_h = std::min(in_h, 2 * in_height - in_h - 2);
|
|
in_w = std::max(in_w, -in_w);
|
|
in_w = std::min(in_w, 2 * in_width - in_w - 2);
|
|
|
|
const int out_index =
|
|
(out_d * out_height * out_width + out_h * out_width + out_w) * channels;
|
|
const int in_index =
|
|
(in_d * in_height * in_width + in_h * in_width + in_w) * channels;
|
|
for (int c = 0; c < channels; ++c) {
|
|
out_data[out_index + c] = in_data[in_index + c];
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
void ReplicatePad3DFuncNCDHW(const T* in_data, T* out_data, const int in_depth,
|
|
const int in_height, const int in_width,
|
|
const int out_depth, const int out_height,
|
|
const int out_width, const int pad_front,
|
|
const int pad_top, const int pad_left,
|
|
const int out_d, const int out_h, const int out_w,
|
|
const T value) {
|
|
int in_d = std::min(in_depth - 1, std::max(out_d - pad_front, 0));
|
|
int in_h = std::min(in_height - 1, std::max(out_h - pad_top, 0));
|
|
int in_w = std::min(in_width - 1, std::max(out_w - pad_left, 0));
|
|
|
|
out_data[out_d * out_height * out_width + out_h * out_width + out_w] =
|
|
in_data[in_d * in_height * in_width + in_h * in_width + in_w];
|
|
}
|
|
|
|
template <typename T>
|
|
void ReplicatePad3DFuncNDHWC(const T* in_data, T* out_data, const int channels,
|
|
const int in_depth, const int in_height,
|
|
const int in_width, const int out_depth,
|
|
const int out_height, const int out_width,
|
|
const int pad_front, const int pad_top,
|
|
const int pad_left, const int out_d,
|
|
const int out_h, const int out_w, const T value) {
|
|
int in_d = std::min(in_depth - 1, std::max(out_d - pad_front, 0));
|
|
int in_h = std::min(in_height - 1, std::max(out_h - pad_top, 0));
|
|
int in_w = std::min(in_width - 1, std::max(out_w - pad_left, 0));
|
|
|
|
const int out_index =
|
|
(out_d * out_height * out_width + out_h * out_width + out_w) * channels;
|
|
const int in_index =
|
|
(in_d * in_height * in_width + in_h * in_width + in_w) * channels;
|
|
for (int c = 0; c < channels; ++c) {
|
|
out_data[out_index + c] = in_data[in_index + c];
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
void CircularPad3DFuncNCDHW(const T* in_data, T* out_data, const int in_depth,
|
|
const int in_height, const int in_width,
|
|
const int out_depth, const int out_height,
|
|
const int out_width, const int pad_front,
|
|
const int pad_top, const int pad_left,
|
|
const int out_d, const int out_h, const int out_w,
|
|
const T value) {
|
|
int in_d = ((out_d - pad_front) % in_depth + in_depth) % in_depth;
|
|
int in_h = ((out_h - pad_top) % in_height + in_height) % in_height;
|
|
int in_w = ((out_w - pad_left) % in_width + in_width) % in_width;
|
|
|
|
out_data[out_d * out_height * out_width + out_h * out_width + out_w] =
|
|
in_data[in_d * in_height * in_width + in_h * in_width + in_w];
|
|
}
|
|
|
|
template <typename T>
|
|
void CircularPad3DFuncNDHWC(const T* in_data, T* out_data, const int channels,
|
|
const int in_depth, const int in_height,
|
|
const int in_width, const int out_depth,
|
|
const int out_height, const int out_width,
|
|
const int pad_front, const int pad_top,
|
|
const int pad_left, const int out_d,
|
|
const int out_h, const int out_w, const T value) {
|
|
int in_d = ((out_d - pad_front) % in_depth + in_depth) % in_depth;
|
|
int in_h = ((out_h - pad_top) % in_height + in_height) % in_height;
|
|
int in_w = ((out_w - pad_left) % in_width + in_width) % in_width;
|
|
|
|
const int out_index =
|
|
(out_d * out_height * out_width + out_h * out_width + out_w) * channels;
|
|
const int in_index =
|
|
(in_d * in_height * in_width + in_h * in_width + in_w) * channels;
|
|
for (int c = 0; c < channels; ++c) {
|
|
out_data[out_index + c] = in_data[in_index + c];
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
void Pad3DNCDHW(const T* in_data, const int num, const int channels,
|
|
const int in_depth, const int in_height, const int in_width,
|
|
const int out_depth, const int out_height, const int out_width,
|
|
const int pad_front, const int pad_top, const int pad_left,
|
|
T value, T* out_data,
|
|
void (*pad_func)(const T*, T*, const int, const int, const int,
|
|
const int, const int, const int, const int,
|
|
const int, const int, const int, const int,
|
|
const int, const T)) {
|
|
for (int n = 0; n < num; ++n) {
|
|
for (int c = 0; c < channels; ++c) {
|
|
for (int out_d = 0; out_d < out_depth; ++out_d) {
|
|
for (int out_h = 0; out_h < out_height; ++out_h) {
|
|
for (int out_w = 0; out_w < out_width; ++out_w) {
|
|
pad_func(in_data, out_data, in_depth, in_height, in_width,
|
|
out_depth, out_height, out_width, pad_front, pad_top,
|
|
pad_left, out_d, out_h, out_w, value);
|
|
}
|
|
}
|
|
}
|
|
in_data += in_depth * in_height * in_width;
|
|
out_data += out_depth * out_height * out_width;
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
void Pad3DNDHWC(const T* in_data, const int num, const int channels,
|
|
const int in_depth, const int in_height, const int in_width,
|
|
const int out_depth, const int out_height, const int out_width,
|
|
const int pad_front, const int pad_top, const int pad_left,
|
|
T value, T* out_data,
|
|
void (*pad_func)(const T*, T*, const int, const int, const int,
|
|
const int, const int, const int, const int,
|
|
const int, const int, const int, const int,
|
|
const int, const int, const T)) {
|
|
for (int n = 0; n < num; ++n) {
|
|
for (int out_d = 0; out_d < out_depth; ++out_d) {
|
|
for (int out_h = 0; out_h < out_height; ++out_h) {
|
|
for (int out_w = 0; out_w < out_width; ++out_w) {
|
|
pad_func(in_data, out_data, channels, in_depth, in_height, in_width,
|
|
out_depth, out_height, out_width, pad_front, pad_top,
|
|
pad_left, out_d, out_h, out_w, value);
|
|
}
|
|
}
|
|
}
|
|
in_data += in_depth * in_height * in_width * channels;
|
|
out_data += out_depth * out_height * out_width * channels;
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
void ConstPad3DGradNCDHW(T* d_in_data, const T* d_out_data, const int in_depth,
|
|
const int in_height, const int in_width,
|
|
const int out_depth, const int out_height,
|
|
const int out_width, const int pad_front,
|
|
const int pad_top, const int pad_left, const int out_d,
|
|
const int out_h, const int out_w) {
|
|
int in_d = out_d - pad_front;
|
|
int in_h = out_h - pad_top;
|
|
int in_w = out_w - pad_left;
|
|
if (!(in_d < 0 || in_h < 0 || in_w < 0 || in_d >= in_depth ||
|
|
in_h >= in_height || in_w >= in_width)) {
|
|
d_in_data[in_d * in_height * in_width + in_h * in_width + in_w] =
|
|
d_out_data[out_d * out_height * out_width + out_h * out_width + out_w];
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
void ConstPad3DGradNDHWC(T* d_in_data, const T* d_out_data, const int channels,
|
|
const int in_depth, const int in_height,
|
|
const int in_width, const int out_depth,
|
|
const int out_height, const int out_width,
|
|
const int pad_front, const int pad_top,
|
|
const int pad_left, const int out_d, const int out_h,
|
|
const int out_w) {
|
|
int in_d = out_d - pad_front;
|
|
int in_h = out_h - pad_top;
|
|
int in_w = out_w - pad_left;
|
|
|
|
const int out_index =
|
|
(out_d * out_height * out_width + out_h * out_width + out_w) * channels;
|
|
if (!(in_d < 0 || in_h < 0 || in_w < 0 || in_d >= in_depth ||
|
|
in_h >= in_height || in_w >= in_width)) {
|
|
const int in_index =
|
|
(in_d * in_height * in_width + in_h * in_width + in_w) * channels;
|
|
for (int c = 0; c < channels; ++c) {
|
|
d_in_data[in_index + c] = d_out_data[out_index + c];
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
void ReflectPad3DGradNCDHW(T* d_in_data, const T* d_out_data,
|
|
const int in_depth, const int in_height,
|
|
const int in_width, const int out_depth,
|
|
const int out_height, const int out_width,
|
|
const int pad_front, const int pad_top,
|
|
const int pad_left, const int out_d, const int out_h,
|
|
const int out_w) {
|
|
int in_d = out_d - pad_front;
|
|
int in_h = out_h - pad_top;
|
|
int in_w = out_w - pad_left;
|
|
|
|
in_d = std::max(in_d, -in_d); // reflect by 0
|
|
in_d = std::min(in_d, 2 * in_depth - in_d - 2); // reflect by in_depth
|
|
in_h = std::max(in_h, -in_h); // reflect by 0
|
|
in_h = std::min(in_h, 2 * in_height - in_h - 2); // reflect by in_height
|
|
in_w = std::max(in_w, -in_w); // reflect by 0
|
|
in_w = std::min(in_w, 2 * in_width - in_w - 2); // reflect by in_width
|
|
|
|
d_in_data[in_d * in_height * in_width + in_h * in_width + in_w] +=
|
|
d_out_data[out_d * out_height * out_width + out_h * out_width + out_w];
|
|
}
|
|
|
|
template <typename T>
|
|
void ReflectPad3DGradNDHWC(T* d_in_data, const T* d_out_data,
|
|
const int channels, const int in_depth,
|
|
const int in_height, const int in_width,
|
|
const int out_depth, const int out_height,
|
|
const int out_width, const int pad_front,
|
|
const int pad_top, const int pad_left,
|
|
const int out_d, const int out_h, const int out_w) {
|
|
int in_d = out_d - pad_front;
|
|
int in_h = out_h - pad_top;
|
|
int in_w = out_w - pad_left;
|
|
|
|
in_d = std::max(in_d, -in_d);
|
|
in_d = std::min(in_d, 2 * in_depth - in_d - 2);
|
|
in_h = std::max(in_h, -in_h);
|
|
in_h = std::min(in_h, 2 * in_height - in_h - 2);
|
|
in_w = std::max(in_w, -in_w);
|
|
in_w = std::min(in_w, 2 * in_width - in_w - 2);
|
|
|
|
const int out_index =
|
|
(out_d * out_height * out_width + out_h * out_width + out_w) * channels;
|
|
const int in_index =
|
|
(in_d * in_height * in_width + in_h * in_width + in_w) * channels;
|
|
for (int c = 0; c < channels; ++c) {
|
|
d_in_data[in_index + c] += d_out_data[out_index + c];
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
void ReplicatePad3DGradNCDHW(T* d_in_data, const T* d_out_data,
|
|
const int in_depth, const int in_height,
|
|
const int in_width, const int out_depth,
|
|
const int out_height, const int out_width,
|
|
const int pad_front, const int pad_top,
|
|
const int pad_left, const int out_d,
|
|
const int out_h, const int out_w) {
|
|
int in_d = std::min(in_depth - 1, std::max(out_d - pad_front, 0));
|
|
int in_h = std::min(in_height - 1, std::max(out_h - pad_top, 0));
|
|
int in_w = std::min(in_width - 1, std::max(out_w - pad_left, 0));
|
|
|
|
d_in_data[in_d * in_height * in_width + in_h * in_width + in_w] +=
|
|
d_out_data[out_d * out_height * out_width + out_h * out_width + out_w];
|
|
}
|
|
|
|
template <typename T>
|
|
void ReplicatePad3DGradNDHWC(T* d_in_data, const T* d_out_data,
|
|
const int channels, const int in_depth,
|
|
const int in_height, const int in_width,
|
|
const int out_depth, const int out_height,
|
|
const int out_width, const int pad_front,
|
|
const int pad_top, const int pad_left,
|
|
const int out_d, const int out_h,
|
|
const int out_w) {
|
|
int in_d = std::min(in_depth - 1, std::max(out_d - pad_front, 0));
|
|
int in_h = std::min(in_height - 1, std::max(out_h - pad_top, 0));
|
|
int in_w = std::min(in_width - 1, std::max(out_w - pad_left, 0));
|
|
|
|
const int out_index =
|
|
(out_d * out_height * out_width + out_h * out_width + out_w) * channels;
|
|
const int in_index =
|
|
(in_d * in_height * in_width + in_h * in_width + in_w) * channels;
|
|
for (int c = 0; c < channels; ++c) {
|
|
d_in_data[in_index + c] += d_out_data[out_index + c];
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
void CircularPad3DGradNCDHW(T* d_in_data, const T* d_out_data,
|
|
const int in_depth, const int in_height,
|
|
const int in_width, const int out_depth,
|
|
const int out_height, const int out_width,
|
|
const int pad_front, const int pad_top,
|
|
const int pad_left, const int out_d,
|
|
const int out_h, const int out_w) {
|
|
int in_d = ((out_d - pad_front) % in_depth + in_depth) % in_depth;
|
|
int in_h = ((out_h - pad_top) % in_height + in_height) % in_height;
|
|
int in_w = ((out_w - pad_left) % in_width + in_width) % in_width;
|
|
d_in_data[in_d * in_height * in_width + in_h * in_width + in_w] +=
|
|
d_out_data[out_d * out_height * out_width + out_h * out_width + out_w];
|
|
}
|
|
|
|
template <typename T>
|
|
void CircularPad3DGradNDHWC(T* d_in_data, const T* d_out_data,
|
|
const int channels, const int in_depth,
|
|
const int in_height, const int in_width,
|
|
const int out_depth, const int out_height,
|
|
const int out_width, const int pad_front,
|
|
const int pad_top, const int pad_left,
|
|
const int out_d, const int out_h, const int out_w) {
|
|
int in_d = ((out_d - pad_front) % in_depth + in_depth) % in_depth;
|
|
int in_h = ((out_h - pad_top) % in_height + in_height) % in_height;
|
|
int in_w = ((out_w - pad_left) % in_width + in_width) % in_width;
|
|
|
|
const int out_index =
|
|
(out_d * out_height * out_width + out_h * out_width + out_w) * channels;
|
|
const int in_index =
|
|
(in_d * in_height * in_width + in_h * in_width + in_w) * channels;
|
|
for (int c = 0; c < channels; ++c) {
|
|
d_in_data[in_index + c] += d_out_data[out_index + c];
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
void Pad3DGradNCDHW(T* d_in_data, const int num, const int channels,
|
|
const int in_depth, const int in_height, const int in_width,
|
|
const int out_depth, const int out_height,
|
|
const int out_width, const int pad_front, const int pad_top,
|
|
const int pad_left, const T* d_out_data,
|
|
void (*pad_func)(T*, const T*, const int, const int,
|
|
const int, const int, const int, const int,
|
|
const int, const int, const int, const int,
|
|
const int, const int)) {
|
|
for (int n = 0; n < num; ++n) {
|
|
for (int c = 0; c < channels; ++c) {
|
|
for (int out_d = 0; out_d < out_depth; ++out_d) {
|
|
for (int out_h = 0; out_h < out_height; ++out_h) {
|
|
for (int out_w = 0; out_w < out_width; ++out_w) {
|
|
pad_func(d_in_data, d_out_data, in_depth, in_height, in_width,
|
|
out_depth, out_height, out_width, pad_front, pad_top,
|
|
pad_left, out_d, out_h, out_w);
|
|
}
|
|
}
|
|
}
|
|
d_in_data += in_depth * in_height * in_width;
|
|
d_out_data += out_depth * out_height * out_width;
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
void Pad3DGradNDHWC(T* d_in_data, const int num, const int channels,
|
|
const int in_depth, const int in_height, const int in_width,
|
|
const int out_depth, const int out_height,
|
|
const int out_width, const int pad_front, const int pad_top,
|
|
const int pad_left, const T* d_out_data,
|
|
void (*pad_func)(T*, const T*, const int, const int,
|
|
const int, const int, const int, const int,
|
|
const int, const int, const int, const int,
|
|
const int, const int, const int)) {
|
|
for (int n = 0; n < num; ++n) {
|
|
for (int out_d = 0; out_d < out_depth; ++out_d) {
|
|
for (int out_h = 0; out_h < out_height; ++out_h) {
|
|
for (int out_w = 0; out_w < out_width; ++out_w) {
|
|
pad_func(d_in_data, d_out_data, channels, in_depth, in_height,
|
|
in_width, out_depth, out_height, out_width, pad_front,
|
|
pad_top, pad_left, out_d, out_h, out_w);
|
|
}
|
|
}
|
|
}
|
|
d_in_data += in_depth * in_height * in_width * channels;
|
|
d_out_data += out_depth * out_height * out_width * channels;
|
|
}
|
|
}
|
|
|
|
static inline std::vector<int> GetPaddings(
|
|
const framework::ExecutionContext& context) {
|
|
std::vector<int> paddings(6);
|
|
auto* paddings_t = context.Input<Tensor>("Paddings");
|
|
if (paddings_t) {
|
|
auto paddings_data = paddings_t->data<int>();
|
|
std::memcpy(paddings.data(), paddings_data, paddings.size() * sizeof(int));
|
|
} else {
|
|
auto pads = context.Attr<std::vector<int>>("paddings");
|
|
std::copy(pads.begin(), pads.end(), paddings.data());
|
|
}
|
|
return paddings;
|
|
}
|
|
|
|
template <typename T>
|
|
class Pad3dCPUKernel : public framework::OpKernel<T> {
|
|
public:
|
|
void Compute(const framework::ExecutionContext& context) const override {
|
|
std::vector<int> pads = GetPaddings(context);
|
|
auto mode = context.Attr<std::string>("mode");
|
|
auto data_format = context.Attr<std::string>("data_format");
|
|
T value = static_cast<T>(context.Attr<float>("value"));
|
|
|
|
auto* x = context.Input<Tensor>("X");
|
|
auto in_dims = x->dims();
|
|
const T* in_data = x->data<T>();
|
|
|
|
auto* out = context.Output<Tensor>("Out");
|
|
if (data_format == "NCDHW") {
|
|
out->Resize({in_dims[0], in_dims[1], in_dims[2] + pads[4] + pads[5],
|
|
in_dims[3] + pads[2] + pads[3],
|
|
in_dims[4] + pads[0] + pads[1]});
|
|
} else {
|
|
out->Resize({in_dims[0], in_dims[1] + pads[4] + pads[5],
|
|
in_dims[2] + pads[2] + pads[3],
|
|
in_dims[3] + pads[0] + pads[1], in_dims[4]});
|
|
}
|
|
auto out_dims = out->dims();
|
|
T* out_data = out->mutable_data<T>(context.GetPlace());
|
|
|
|
int channels = in_dims[1];
|
|
int in_depth = in_dims[2];
|
|
int in_height = in_dims[3];
|
|
int in_width = in_dims[4];
|
|
int out_depth = out_dims[2];
|
|
int out_height = out_dims[3];
|
|
int out_width = out_dims[4];
|
|
if (data_format == "NDHWC") {
|
|
channels = in_dims[4];
|
|
in_depth = in_dims[1];
|
|
in_height = in_dims[2];
|
|
in_width = in_dims[3];
|
|
out_depth = out_dims[1];
|
|
out_height = out_dims[2];
|
|
out_width = out_dims[3];
|
|
}
|
|
|
|
if (mode == "reflect") {
|
|
PADDLE_ENFORCE_GT(in_depth, pads[4],
|
|
platform::errors::InvalidArgument(
|
|
"The depth of Input(X)'s dimension should be "
|
|
"greater than pad_front"
|
|
" in reflect mode"
|
|
", but received depth(%d) and pad_front(%d).",
|
|
in_depth, pads[4]));
|
|
PADDLE_ENFORCE_GT(in_depth, pads[5],
|
|
platform::errors::InvalidArgument(
|
|
"The depth of Input(X)'s dimension should be "
|
|
"greater than pad_back"
|
|
" in reflect mode"
|
|
", but received depth(%d) and pad_back(%d).",
|
|
in_depth, pads[5]));
|
|
|
|
PADDLE_ENFORCE_GT(in_height, pads[2],
|
|
platform::errors::InvalidArgument(
|
|
"The height of Input(X)'s dimension should be "
|
|
"greater than pad_top"
|
|
" in reflect mode"
|
|
", but received depth(%d) and pad_top(%d).",
|
|
in_height, pads[2]));
|
|
PADDLE_ENFORCE_GT(in_height, pads[3],
|
|
platform::errors::InvalidArgument(
|
|
"The height of Input(X)'s dimension should be "
|
|
"greater than pad_bottom"
|
|
" in reflect mode"
|
|
", but received depth(%d) and pad_bottom(%d).",
|
|
in_height, pads[3]));
|
|
|
|
PADDLE_ENFORCE_GT(in_width, pads[0],
|
|
platform::errors::InvalidArgument(
|
|
"The width of Input(X)'s dimension should be "
|
|
"greater than pad_left"
|
|
" in reflect mode"
|
|
", but received depth(%d) and pad_left(%d).",
|
|
in_width, pads[0]));
|
|
PADDLE_ENFORCE_GT(in_width, pads[1],
|
|
platform::errors::InvalidArgument(
|
|
"The width of Input(X)'s dimension should be "
|
|
"greater than pad_right"
|
|
" in reflect mode"
|
|
", but received depth(%d) and pad_right(%d).",
|
|
in_width, pads[1]));
|
|
}
|
|
|
|
const int pad_left = pads[0];
|
|
const int pad_top = pads[2];
|
|
const int pad_front = pads[4];
|
|
const int num = in_dims[0];
|
|
if (data_format == "NCDHW") {
|
|
std::map<std::string,
|
|
void (*)(const T*, T*, const int, const int, const int,
|
|
const int, const int, const int, const int, const int,
|
|
const int, const int, const int, const int, const T)>
|
|
func_map;
|
|
|
|
func_map["reflect"] = ReflectPad3DFuncNCDHW;
|
|
func_map["replicate"] = ReplicatePad3DFuncNCDHW;
|
|
func_map["circular"] = CircularPad3DFuncNCDHW;
|
|
func_map["constant"] = ConstPad3DFuncNCDHW;
|
|
Pad3DNCDHW(in_data, num, channels, in_depth, in_height, in_width,
|
|
out_depth, out_height, out_width, pad_front, pad_top, pad_left,
|
|
value, out_data, func_map[mode]);
|
|
} else {
|
|
std::map<std::string, void (*)(const T*, T*, const int, const int,
|
|
const int, const int, const int, const int,
|
|
const int, const int, const int, const int,
|
|
const int, const int, const int, const T)>
|
|
func_map;
|
|
|
|
func_map["reflect"] = ReflectPad3DFuncNDHWC;
|
|
func_map["replicate"] = ReplicatePad3DFuncNDHWC;
|
|
func_map["circular"] = CircularPad3DFuncNDHWC;
|
|
func_map["constant"] = ConstPad3DFuncNDHWC;
|
|
Pad3DNDHWC(in_data, num, channels, in_depth, in_height, in_width,
|
|
out_depth, out_height, out_width, pad_front, pad_top, pad_left,
|
|
value, out_data, func_map[mode]);
|
|
}
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
class Pad3dGradCPUKernel : public framework::OpKernel<T> {
|
|
public:
|
|
void Compute(const framework::ExecutionContext& context) const override {
|
|
std::vector<int> pads = GetPaddings(context);
|
|
auto mode = context.Attr<std::string>("mode");
|
|
auto data_format = context.Attr<std::string>("data_format");
|
|
auto* d_out = context.Input<Tensor>(framework::GradVarName("Out"));
|
|
auto* d_in = context.Output<Tensor>(framework::GradVarName("X"));
|
|
auto d_in_dims = d_in->dims();
|
|
auto d_out_dims = d_out->dims();
|
|
const T* d_out_data = d_out->data<T>();
|
|
T* d_in_data = d_in->mutable_data<T>(context.GetPlace());
|
|
math::SetConstant<platform::CPUDeviceContext, T> set_zero;
|
|
set_zero(context.template device_context<platform::CPUDeviceContext>(),
|
|
d_in, static_cast<T>(0));
|
|
const int pad_left = pads[0];
|
|
const int pad_top = pads[2];
|
|
const int pad_front = pads[4];
|
|
const int num = d_in_dims[0];
|
|
if (data_format == "NCDHW") {
|
|
const int channels = d_in_dims[1];
|
|
const int in_depth = d_in_dims[2];
|
|
const int in_height = d_in_dims[3];
|
|
const int in_width = d_in_dims[4];
|
|
const int out_depth = d_out_dims[2];
|
|
const int out_height = d_out_dims[3];
|
|
const int out_width = d_out_dims[4];
|
|
|
|
std::map<std::string,
|
|
void (*)(T*, const T*, const int, const int, const int,
|
|
const int, const int, const int, const int, const int,
|
|
const int, const int, const int, const int)>
|
|
func_map;
|
|
|
|
func_map["reflect"] = ReflectPad3DGradNCDHW;
|
|
func_map["replicate"] = ReplicatePad3DGradNCDHW;
|
|
func_map["circular"] = CircularPad3DGradNCDHW;
|
|
func_map["constant"] = ConstPad3DGradNCDHW;
|
|
|
|
Pad3DGradNCDHW(d_in_data, num, channels, in_depth, in_height, in_width,
|
|
out_depth, out_height, out_width, pad_front, pad_top,
|
|
pad_left, d_out_data, func_map[mode]);
|
|
} else {
|
|
const int channels = d_in_dims[4];
|
|
const int in_depth = d_in_dims[1];
|
|
const int in_height = d_in_dims[2];
|
|
const int in_width = d_in_dims[3];
|
|
const int out_depth = d_out_dims[1];
|
|
const int out_height = d_out_dims[2];
|
|
const int out_width = d_out_dims[3];
|
|
|
|
std::map<std::string,
|
|
void (*)(T*, const T*, const int, const int, const int,
|
|
const int, const int, const int, const int, const int,
|
|
const int, const int, const int, const int, const int)>
|
|
func_map;
|
|
|
|
func_map["reflect"] = ReflectPad3DGradNDHWC;
|
|
func_map["replicate"] = ReplicatePad3DGradNDHWC;
|
|
func_map["circular"] = CircularPad3DGradNDHWC;
|
|
func_map["constant"] = ConstPad3DGradNDHWC;
|
|
|
|
Pad3DGradNDHWC(d_in_data, num, channels, in_depth, in_height, in_width,
|
|
out_depth, out_height, out_width, pad_front, pad_top,
|
|
pad_left, d_out_data, func_map[mode]);
|
|
}
|
|
}
|
|
};
|
|
|
|
class Pad3dOp : public framework::OperatorWithKernel {
|
|
public:
|
|
using framework::OperatorWithKernel::OperatorWithKernel;
|
|
|
|
void InferShape(framework::InferShapeContext* ctx) const override {
|
|
OP_INOUT_CHECK(ctx->HasInput("X"), "Input", "X", "Pad3d");
|
|
OP_INOUT_CHECK(ctx->HasOutput("Out"), "Output", "Out", "Pad3d");
|
|
|
|
auto x_dim = ctx->GetInputDim("X");
|
|
PADDLE_ENFORCE_EQ(x_dim.size(), 5,
|
|
platform::errors::InvalidArgument(
|
|
"The size of Input(X)'s dimension should be equal to "
|
|
"5, but received %d. ",
|
|
x_dim.size()));
|
|
|
|
std::vector<int64_t> out_dims(x_dim.size());
|
|
auto data_format = ctx->Attrs().Get<std::string>("data_format");
|
|
out_dims[0] = x_dim[0];
|
|
if (ctx->HasInput("Paddings")) {
|
|
auto paddings_dim = ctx->GetInputDim("Paddings");
|
|
PADDLE_ENFORCE_EQ(paddings_dim.size(), 1,
|
|
platform::errors::InvalidArgument(
|
|
"Size of Input(Paddings)'s dimension should be "
|
|
"equal to 1, but received %d.",
|
|
paddings_dim.size()));
|
|
if (ctx->IsRuntime()) {
|
|
PADDLE_ENFORCE_EQ(paddings_dim[0], 6,
|
|
platform::errors::InvalidArgument(
|
|
"Shape of Input(Paddings) should be equal to "
|
|
"[6], but received [%d].",
|
|
paddings_dim[0]));
|
|
}
|
|
out_dims[1] = x_dim[1];
|
|
out_dims[2] = x_dim[2];
|
|
out_dims[3] = x_dim[3];
|
|
} else {
|
|
auto paddings = ctx->Attrs().Get<std::vector<int>>("paddings");
|
|
PADDLE_ENFORCE_EQ(
|
|
paddings.size(), 6,
|
|
platform::errors::InvalidArgument(
|
|
"Size of paddings should be equal to 4, but received %d.",
|
|
static_cast<int>(paddings.size())));
|
|
if (data_format == "NCDHW") {
|
|
out_dims[1] = x_dim[1]; // channel
|
|
out_dims[2] = ((!ctx->IsRuntime()) && (x_dim[2] < 0))
|
|
? x_dim[2]
|
|
: (x_dim[2] + paddings[4] + paddings[5]); // depth
|
|
|
|
out_dims[3] = ((!ctx->IsRuntime()) && (x_dim[3] < 0))
|
|
? x_dim[3]
|
|
: (x_dim[3] + paddings[2] + paddings[3]); // height
|
|
|
|
out_dims[4] = ((!ctx->IsRuntime()) && (x_dim[4] < 0))
|
|
? x_dim[4]
|
|
: (x_dim[4] + paddings[0] + paddings[1]); // width
|
|
} else { // NDHWC
|
|
out_dims[4] = x_dim[4]; // channel
|
|
|
|
out_dims[1] = ((!ctx->IsRuntime()) && (x_dim[1] < 0))
|
|
? x_dim[1]
|
|
: (x_dim[1] + paddings[4] + paddings[5]); // depth
|
|
out_dims[2] = ((!ctx->IsRuntime()) && (x_dim[2] < 0))
|
|
? x_dim[2]
|
|
: (x_dim[2] + paddings[2] + paddings[3]); // height
|
|
out_dims[3] = ((!ctx->IsRuntime()) && (x_dim[3] < 0))
|
|
? x_dim[3]
|
|
: (x_dim[3] + paddings[0] + paddings[1]); // width
|
|
}
|
|
}
|
|
|
|
ctx->SetOutputDim("Out", framework::make_ddim(out_dims));
|
|
ctx->ShareLoD("X", /*->*/ "Out");
|
|
}
|
|
|
|
protected:
|
|
framework::OpKernelType GetExpectedKernelType(
|
|
const framework::ExecutionContext& ctx) const override {
|
|
return framework::OpKernelType(
|
|
OperatorWithKernel::IndicateVarDataType(ctx, "X"), ctx.GetPlace());
|
|
}
|
|
};
|
|
|
|
class Pad3dOpMaker : public framework::OpProtoAndCheckerMaker {
|
|
public:
|
|
void Make() override {
|
|
AddInput("X",
|
|
"The input of pad3d op. "
|
|
"The input should be a 5-D tensor with formate NCDHW or NDHWC.");
|
|
AddOutput("Out",
|
|
"The output of pad3d op. "
|
|
"A tensor with the same shape as X.");
|
|
AddInput("Paddings",
|
|
"A 1-D tensor to describe the padding rules."
|
|
"paddings=[0, 1, 2, 3, 4, 5] means "
|
|
"padding 0 column to left, 1 column to right, "
|
|
"2 row to top, 3 row to bottom, 4 depth to front "
|
|
"and 5 depth to back. Size of paddings must be 6.")
|
|
.AsDispensable();
|
|
AddAttr<std::vector<int>>(
|
|
"paddings",
|
|
"(vector<int>) "
|
|
"A list<int> to describe the padding rules."
|
|
"paddings=[0, 1, 2, 3, 4, 5] means "
|
|
"padding 0 column to left, 1 column to right, "
|
|
"2 row to top, 3 row to bottom, 4 depth to front "
|
|
"and 5 depth to back. Size of paddings must be 6.");
|
|
AddAttr<float>("value",
|
|
"(float, default 0.0) "
|
|
"The value to fill the padded areas in constant mode.")
|
|
.SetDefault(0.0f);
|
|
AddAttr<std::string>(
|
|
"mode",
|
|
"(string, default constant) "
|
|
"Four modes: constant(default), reflect, replicate, circular.")
|
|
.SetDefault("constant");
|
|
AddAttr<std::string>(
|
|
"data_format",
|
|
"(string, default NCDHW) Only used in "
|
|
"An optional string from: \"NDHWC\", \"NCDHW\". "
|
|
"Defaults to \"NDHWC\". Specify the data format of the input data.")
|
|
.SetDefault("NCDHW");
|
|
AddComment(R"DOC(
|
|
Pad3d Operator.
|
|
Pad 3-d images according to 'paddings' and 'mode'.
|
|
If mode is 'reflect', paddings[0] and paddings[1] must be no greater
|
|
than width-1. The height and depth dimension have the same condition.
|
|
|
|
Given that X is a channel of image from input:
|
|
|
|
X = [[[[[1, 2, 3],
|
|
[4, 5, 6]]]]]
|
|
|
|
Case 0:
|
|
|
|
paddings = [2, 2, 1, 1, 0, 0],
|
|
mode = 'constant'
|
|
pad_value = 0
|
|
|
|
Out = [[[[[0. 0. 0. 0. 0. 0. 0.]
|
|
[0. 0. 1. 2. 3. 0. 0.]
|
|
[0. 0. 4. 5. 6. 0. 0.]
|
|
[0. 0. 0. 0. 0. 0. 0.]]]]]
|
|
|
|
Case 1:
|
|
|
|
paddings = [2, 2, 1, 1, 0, 0],
|
|
mode = 'reflect'
|
|
|
|
Out = [[[[[6. 5. 4. 5. 6. 5. 4.]
|
|
[3. 2. 1. 2. 3. 2. 1.]
|
|
[6. 5. 4. 5. 6. 5. 4.]
|
|
[3. 2. 1. 2. 3. 2. 1.]]]]]
|
|
|
|
Case 2:
|
|
|
|
paddings = [2, 2, 1, 1, 0, 0],
|
|
mode = 'replicate'
|
|
|
|
Out = [[[[[1. 1. 1. 2. 3. 3. 3.]
|
|
[1. 1. 1. 2. 3. 3. 3.]
|
|
[4. 4. 4. 5. 6. 6. 6.]
|
|
[4. 4. 4. 5. 6. 6. 6.]]]]]
|
|
|
|
Case 3:
|
|
|
|
paddings = [2, 2, 1, 1, 0, 0],
|
|
mode = 'circular'
|
|
|
|
Out = [[[[[5. 6. 4. 5. 6. 4. 5.]
|
|
[2. 3. 1. 2. 3. 1. 2.]
|
|
[5. 6. 4. 5. 6. 4. 5.]
|
|
[2. 3. 1. 2. 3. 1. 2.]]]]]
|
|
|
|
)DOC");
|
|
}
|
|
};
|
|
|
|
class Pad3dOpGrad : public framework::OperatorWithKernel {
|
|
public:
|
|
using framework::OperatorWithKernel::OperatorWithKernel;
|
|
|
|
void InferShape(framework::InferShapeContext* ctx) const override {
|
|
OP_INOUT_CHECK(ctx->HasInput("X"), "Input", "X", "Pad3d@Grad");
|
|
OP_INOUT_CHECK(ctx->HasInput(framework::GradVarName("Out")), "Input",
|
|
framework::GradVarName("Out"), "Pad3d@Grad");
|
|
|
|
auto x_dims = ctx->GetInputDim("X");
|
|
auto x_grad_name = framework::GradVarName("X");
|
|
if (ctx->HasOutput(x_grad_name)) {
|
|
ctx->SetOutputDim(x_grad_name, x_dims);
|
|
}
|
|
}
|
|
|
|
protected:
|
|
framework::OpKernelType GetExpectedKernelType(
|
|
const framework::ExecutionContext& ctx) const override {
|
|
return framework::OpKernelType(OperatorWithKernel::IndicateVarDataType(
|
|
ctx, framework::GradVarName("Out")),
|
|
ctx.GetPlace());
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
class Pad3dOpGradMaker : public framework::SingleGradOpMaker<T> {
|
|
public:
|
|
using framework::SingleGradOpMaker<T>::SingleGradOpMaker;
|
|
|
|
protected:
|
|
void Apply(GradOpPtr<T> bind) const override {
|
|
bind->SetInput("X", this->Input("X"));
|
|
if (this->HasInput("Paddings")) {
|
|
bind->SetInput("Paddings", this->Input("Paddings"));
|
|
}
|
|
bind->SetInput(framework::GradVarName("Out"), this->OutputGrad("Out"));
|
|
bind->SetOutput(framework::GradVarName("X"), this->InputGrad("X"));
|
|
bind->SetAttrMap(this->Attrs());
|
|
bind->SetType("pad3d_grad");
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
class Pad3dOpDoubleGradMaker : public framework::SingleGradOpMaker<T> {
|
|
public:
|
|
using framework::SingleGradOpMaker<T>::SingleGradOpMaker;
|
|
|
|
void Apply(GradOpPtr<T> grad_op) const override {
|
|
if (this->HasInput("Paddings")) {
|
|
grad_op->SetInput("Paddings", this->Input("Paddings"));
|
|
}
|
|
grad_op->SetType("pad3d");
|
|
grad_op->SetInput("X", this->OutputGrad(framework::GradVarName("X")));
|
|
grad_op->SetOutput("Out", this->InputGrad(framework::GradVarName("Out")));
|
|
grad_op->SetAttrMap(this->Attrs());
|
|
}
|
|
};
|
|
|
|
DECLARE_NO_NEED_BUFFER_VARS_INFERER(Pad3dOpGradNoNeedBufferVarsInferer, "X");
|
|
|
|
} // namespace operators
|
|
} // namespace paddle
|
|
|
|
namespace ops = paddle::operators;
|
|
|
|
REGISTER_OPERATOR(pad3d, ops::Pad3dOp, ops::Pad3dOpMaker,
|
|
ops::Pad3dOpGradMaker<paddle::framework::OpDesc>,
|
|
ops::Pad3dOpGradMaker<paddle::imperative::OpBase>);
|
|
REGISTER_OPERATOR(pad3d_grad, ops::Pad3dOpGrad,
|
|
ops::Pad3dOpDoubleGradMaker<paddle::framework::OpDesc>,
|
|
ops::Pad3dOpDoubleGradMaker<paddle::imperative::OpBase>,
|
|
ops::Pad3dOpGradNoNeedBufferVarsInferer);
|
|
REGISTER_OP_CPU_KERNEL(pad3d, ops::Pad3dCPUKernel<float>,
|
|
ops::Pad3dCPUKernel<double>, ops::Pad3dCPUKernel<int>,
|
|
ops::Pad3dCPUKernel<int64_t>);
|
|
REGISTER_OP_CPU_KERNEL(pad3d_grad, ops::Pad3dGradCPUKernel<float>,
|
|
ops::Pad3dGradCPUKernel<double>);
|