From 2ff00ff7a07ead0f7968da11dd8e9c231cb57d97 Mon Sep 17 00:00:00 2001 From: tink2123 Date: Tue, 11 Aug 2020 07:59:15 +0000 Subject: [PATCH 1/7] support list in interp scale_factor --- paddle/fluid/operators/interpolate_op.cc | 57 +++++++---- paddle/fluid/operators/interpolate_op.cu | 97 ++++++++++++------ paddle/fluid/operators/interpolate_op.h | 98 +++++++++++++------ .../tests/unittests/test_bicubic_interp_op.py | 29 +++++- .../unittests/test_bilinear_interp_op.py | 27 ++++- .../tests/unittests/test_linear_interp_op.py | 17 +++- .../tests/unittests/test_nearest_interp_op.py | 26 ++++- .../unittests/test_trilinear_interp_op.py | 84 ++++++++++++---- python/paddle/nn/functional/common.py | 38 +++++-- python/paddle/nn/layer/common.py | 6 +- 10 files changed, 362 insertions(+), 117 deletions(-) diff --git a/paddle/fluid/operators/interpolate_op.cc b/paddle/fluid/operators/interpolate_op.cc index 1e99e22e12b2a..e889324345aad 100644 --- a/paddle/fluid/operators/interpolate_op.cc +++ b/paddle/fluid/operators/interpolate_op.cc @@ -63,14 +63,18 @@ static void Interpolate1DInferShapeCheck(framework::InferShapeContext* ctx) { platform::errors::InvalidArgument( "Scale's dimension size must be 1, but got dimension = %d .", scale_tensor.size())); + PADDLE_ENFORCE_EQ( + scale_tensor[0], 1, + platform::errors::InvalidArgument( + "Scale's shape must be 1, but got shape = %d .", scale_tensor[0])); out_w = -1; } else { - float scale = ctx->Attrs().Get("scale"); - if (scale > 0) { + float scale_w = ctx->Attrs().Get("scale_w"); + if (scale_w > 0) { // round down out_w = (data_layout == DataLayout::kNCHW - ? static_cast(dim_x[2] * scale) - : static_cast(dim_x[1] * scale)); + ? static_cast(dim_x[2] * scale_w) + : static_cast(dim_x[1] * scale_w)); // protect when input shape is -1 out_w = out_w > 0 ? out_w : -1; } else { @@ -144,18 +148,22 @@ static void Interpolate2DInferShapeCheck(framework::InferShapeContext* ctx) { platform::errors::InvalidArgument( "Scale's dimension size must be 1, but got dimension = %d .", scale_tensor.size())); + PADDLE_ENFORCE(scale_tensor[0] == 2 || scale_tensor[0] == 1, + "Scale's shape must be 2 or 1, but got shape = %d .", + scale_tensor[0]); out_h = -1; out_w = -1; } else { - float scale = ctx->Attrs().Get("scale"); - if (scale > 0) { + float scale_h = ctx->Attrs().Get("scale_h"); + float scale_w = ctx->Attrs().Get("scale_w"); + if (scale_h > 0 && scale_w > 0) { // round down out_h = (data_layout == DataLayout::kNCHW - ? static_cast(dim_x[2] * scale) - : static_cast(dim_x[1] * scale)); + ? static_cast(dim_x[2] * scale_h) + : static_cast(dim_x[1] * scale_h)); out_w = (data_layout == DataLayout::kNCHW - ? static_cast(dim_x[3] * scale) - : static_cast(dim_x[2] * scale)); + ? static_cast(dim_x[3] * scale_w) + : static_cast(dim_x[2] * scale_w)); // protect when input shape is -1 out_h = out_h > 0 ? out_h : -1; out_w = out_w > 0 ? out_w : -1; @@ -235,22 +243,28 @@ static void Interpolate3DInferShapeCheck(framework::InferShapeContext* ctx) { platform::errors::InvalidArgument( "Scale's dimension size must be 1, but got size = %d .", scale_tensor.size())); + PADDLE_ENFORCE(scale_tensor[0] == 3 || scale_tensor[0] == 1, + "Scale's shape must be 3 or 1, but got shape = %d .", + scale_tensor[0]); out_d = -1; out_h = -1; out_w = -1; } else { - float scale = ctx->Attrs().Get("scale"); - if (scale > 0) { + float scale_d = ctx->Attrs().Get("scale_d"); + float scale_h = ctx->Attrs().Get("scale_h"); + float scale_w = ctx->Attrs().Get("scale_w"); + + if (scale_d > 0 && scale_h > 0 && scale_w > 0) { // round down out_d = (data_layout == DataLayout::kNCHW - ? static_cast(dim_x[2] * scale) - : static_cast(dim_x[1] * scale)); + ? static_cast(dim_x[2] * scale_d) + : static_cast(dim_x[1] * scale_d)); out_h = (data_layout == DataLayout::kNCHW - ? static_cast(dim_x[3] * scale) - : static_cast(dim_x[2] * scale)); + ? static_cast(dim_x[3] * scale_h) + : static_cast(dim_x[2] * scale_h)); out_w = (data_layout == DataLayout::kNCHW - ? static_cast(dim_x[4] * scale) - : static_cast(dim_x[3] * scale)); + ? static_cast(dim_x[4] * scale_w) + : static_cast(dim_x[3] * scale_w)); // protect when input shape is -1 out_d = out_d > 0 ? out_d : -1; out_h = out_h > 0 ? out_h : -1; @@ -370,7 +384,12 @@ class InterpolateOpMaker : public framework::OpProtoAndCheckerMaker { AddAttr("out_d", "output depth of interpolate op.").SetDefault(0); AddAttr("out_h", "output height of interpolate op.").SetDefault(0); AddAttr("out_w", "output width of interpolate op.").SetDefault(0); - AddAttr("scale", "scale factor of interpolate op.").SetDefault(0.); + AddAttr("scale_w", "scale_w factor of interpolate op.") + .SetDefault(0.); + AddAttr("scale_h", "scale_h factor of interpolate op.") + .SetDefault(0.); + AddAttr("scale_d", "scale_d factor of interpolate op.") + .SetDefault(0.); AddAttr("interp_method", "(string, default \"bilinear\"), interpolation " "method, can be \"linear\" for linear interpolation" diff --git a/paddle/fluid/operators/interpolate_op.cu b/paddle/fluid/operators/interpolate_op.cu index 5f17f2960573c..78ccaa9e2f943 100644 --- a/paddle/fluid/operators/interpolate_op.cu +++ b/paddle/fluid/operators/interpolate_op.cu @@ -847,7 +847,7 @@ static void Interpolate1DCUDAFwd(const framework::ExecutionContext& ctx, auto scale_data = get_new_data_from_tensor(scale_tensor); scale = scale_data[0]; } else { - scale = ctx.Attr("scale"); + scale = ctx.Attr("scale_w"); } if (scale > 0) { out_w = static_cast(in_w * scale); @@ -921,17 +921,25 @@ static void Interpolate2DCUDAFwd(const framework::ExecutionContext& ctx, out_h = new_size[0]; out_w = new_size[1]; } else { - float scale; + float scale_h; + float scale_w; auto scale_tensor = ctx.Input("Scale"); if (scale_tensor != nullptr) { auto scale_data = get_new_data_from_tensor(scale_tensor); - scale = scale_data[0]; + if (scale_data.size() > 1) { + scale_h = scale_data[0]; + scale_w = scale_data[1]; + } else { + scale_h = scale_data[0]; + scale_w = scale_data[0]; + } } else { - scale = ctx.Attr("scale"); + scale_w = ctx.Attr("scale_w"); + scale_h = ctx.Attr("scale_h"); } - if (scale > 0) { - out_h = static_cast(in_h * scale); - out_w = static_cast(in_w * scale); + if (scale_w > 0 && scale_h > 0) { + out_h = static_cast(in_h * scale_h); + out_w = static_cast(in_w * scale_w); } auto out_size = ctx.Input("OutSize"); if (out_size != nullptr) { @@ -1027,18 +1035,30 @@ static void Interpolate3DCUDAFwd(const framework::ExecutionContext& ctx, out_h = new_size[1]; out_w = new_size[2]; } else { - float scale; + float scale_d; + float scale_h; + float scale_w; auto scale_tensor = ctx.Input("Scale"); if (scale_tensor != nullptr) { auto scale_data = get_new_data_from_tensor(scale_tensor); - scale = scale_data[0]; + if (scale_data.size() > 1) { + scale_d = scale_data[0]; + scale_h = scale_data[1]; + scale_w = scale_data[2]; + } else { + scale_d = scale_data[0]; + scale_h = scale_data[0]; + scale_w = scale_data[0]; + } } else { - scale = ctx.Attr("scale"); + scale_d = ctx.Attr("scale_d"); + scale_h = ctx.Attr("scale_h"); + scale_w = ctx.Attr("scale_w"); } - if (scale > 0) { - out_d = static_cast(in_d * scale); - out_h = static_cast(in_h * scale); - out_w = static_cast(in_w * scale); + if (scale_d > 0 && scale_h > 0 && scale_w > 0) { + out_d = static_cast(in_d * scale_d); + out_h = static_cast(in_h * scale_h); + out_w = static_cast(in_w * scale_w); } auto out_size = ctx.Input("OutSize"); if (out_size != nullptr) { @@ -1128,7 +1148,7 @@ static void Interpolate1DCUDABwd(const framework::ExecutionContext& ctx, auto scale_data = get_new_data_from_tensor(scale_tensor); scale = scale_data[0]; } else { - scale = ctx.Attr("scale"); + scale = ctx.Attr("scale_w"); } if (scale > 0) { out_w = static_cast(in_w * scale); @@ -1201,17 +1221,25 @@ static void Interpolate2DCUDABwd(const framework::ExecutionContext& ctx, int out_h = ctx.Attr("out_h"); int out_w = ctx.Attr("out_w"); - float scale; + float scale_h; + float scale_w; auto scale_tensor = ctx.Input("Scale"); if (scale_tensor != nullptr) { auto scale_data = get_new_data_from_tensor(scale_tensor); - scale = scale_data[0]; + if (scale_data.size() > 1) { + scale_h = scale_data[0]; + scale_w = scale_data[1]; + } else { + scale_h = scale_data[0]; + scale_w = scale_data[0]; + } } else { - scale = ctx.Attr("scale"); + scale_w = ctx.Attr("scale_w"); + scale_h = ctx.Attr("scale_h"); } - if (scale > 0) { - out_h = static_cast(in_h * scale); - out_w = static_cast(in_w * scale); + if (scale_w > 0 && scale_h > 0) { + out_h = static_cast(in_h * scale_h); + out_w = static_cast(in_w * scale_w); } auto out_size = ctx.Input("OutSize"); @@ -1305,18 +1333,30 @@ static void Interpolate3DCUDABwd(const framework::ExecutionContext& ctx, int out_d = ctx.Attr("out_d"); int out_h = ctx.Attr("out_h"); int out_w = ctx.Attr("out_w"); - float scale; + float scale_d; + float scale_h; + float scale_w; auto scale_tensor = ctx.Input("Scale"); if (scale_tensor != nullptr) { auto scale_data = get_new_data_from_tensor(scale_tensor); - scale = scale_data[0]; + if (scale_data.size() > 1) { + scale_d = scale_data[0]; + scale_h = scale_data[1]; + scale_w = scale_data[2]; + } else { + scale_d = scale_data[0]; + scale_h = scale_data[0]; + scale_w = scale_data[0]; + } } else { - scale = ctx.Attr("scale"); + scale_d = ctx.Attr("scale_d"); + scale_h = ctx.Attr("scale_h"); + scale_w = ctx.Attr("scale_w"); } - if (scale > 0) { - out_d = static_cast(in_d * scale); - out_h = static_cast(in_h * scale); - out_w = static_cast(in_w * scale); + if (scale_d > 0 && scale_h > 0 && scale_w > 0) { + out_d = static_cast(in_d * scale_d); + out_h = static_cast(in_h * scale_h); + out_w = static_cast(in_w * scale_w); } auto out_size = ctx.Input("OutSize"); @@ -1435,6 +1475,7 @@ class InterpolateGradOpCUDAKernel : public framework::OpKernel { } // namespace paddle namespace ops = paddle::operators; +namespace plat = paddle::platform; REGISTER_OP_CUDA_KERNEL(bilinear_interp, ops::InterpolateOpCUDAKernel, ops::InterpolateOpCUDAKernel, ops::InterpolateOpCUDAKernel); diff --git a/paddle/fluid/operators/interpolate_op.h b/paddle/fluid/operators/interpolate_op.h index 5fbde701fcef6..b6c6d135abe12 100644 --- a/paddle/fluid/operators/interpolate_op.h +++ b/paddle/fluid/operators/interpolate_op.h @@ -794,7 +794,7 @@ static void Interpolate1DCPUFwd(const framework::ExecutionContext& ctx, auto scale_data = get_new_data_from_tensor(scale_tensor); scale = scale_data[0]; } else { - scale = ctx.Attr("scale"); + scale = ctx.Attr("scale_w"); } if (scale > 0) { out_w = static_cast(in_w * scale); @@ -854,17 +854,25 @@ static void Interpolate2DCPUFwd(const framework::ExecutionContext& ctx, out_h = new_size[0]; out_w = new_size[1]; } else { - float scale; + float scale_h; + float scale_w; auto scale_tensor = ctx.Input("Scale"); if (scale_tensor != nullptr) { auto scale_data = get_new_data_from_tensor(scale_tensor); - scale = scale_data[0]; + if (scale_data.size() > 1) { + scale_h = scale_data[0]; + scale_w = scale_data[1]; + } else { + scale_h = scale_data[0]; + scale_w = scale_data[0]; + } } else { - scale = ctx.Attr("scale"); + scale_w = ctx.Attr("scale_w"); + scale_h = ctx.Attr("scale_h"); } - if (scale > 0) { - out_h = static_cast(in_h * scale); - out_w = static_cast(in_w * scale); + if (scale_h > 0 && scale_w > 0) { + out_h = static_cast(in_h * scale_h); + out_w = static_cast(in_w * scale_w); } auto out_size = ctx.Input("OutSize"); if (out_size != nullptr) { @@ -940,18 +948,30 @@ static void Interpolate3DCPUFwd(const framework::ExecutionContext& ctx, out_h = new_size[1]; out_w = new_size[2]; } else { - float scale; + float scale_d; + float scale_h; + float scale_w; auto scale_tensor = ctx.Input("Scale"); if (scale_tensor != nullptr) { auto scale_data = get_new_data_from_tensor(scale_tensor); - scale = scale_data[0]; + if (scale_data.size() > 1) { + scale_d = scale_data[0]; + scale_h = scale_data[1]; + scale_w = scale_data[2]; + } else { + scale_d = scale_data[0]; + scale_h = scale_data[0]; + scale_w = scale_data[0]; + } } else { - scale = ctx.Attr("scale"); + scale_d = ctx.Attr("scale_d"); + scale_h = ctx.Attr("scale_h"); + scale_w = ctx.Attr("scale_w"); } - if (scale > 0) { - out_d = static_cast(in_d * scale); - out_h = static_cast(in_h * scale); - out_w = static_cast(in_w * scale); + if (scale_w > 0 && scale_h > 0 && scale_d > 0) { + out_d = static_cast(in_d * scale_d); + out_h = static_cast(in_h * scale_h); + out_w = static_cast(in_w * scale_w); } auto out_size = ctx.Input("OutSize"); if (out_size != nullptr) { @@ -1028,7 +1048,7 @@ static void Interpolate1DCPUBwd(const framework::ExecutionContext& ctx, auto scale_data = get_new_data_from_tensor(scale_tensor); scale = scale_data[0]; } else { - scale = ctx.Attr("scale"); + scale = ctx.Attr("scale_w"); } if (scale > 0) { out_w = static_cast(in_w * scale); @@ -1088,17 +1108,25 @@ static void Interpolate2DCPUBwd(const framework::ExecutionContext& ctx, int out_h = ctx.Attr("out_h"); int out_w = ctx.Attr("out_w"); - float scale; + float scale_h; + float scale_w; auto scale_tensor = ctx.Input("Scale"); if (scale_tensor != nullptr) { auto scale_data = get_new_data_from_tensor(scale_tensor); - scale = scale_data[0]; + if (scale_data.size() > 1) { + scale_h = scale_data[0]; + scale_w = scale_data[1]; + } else { + scale_w = scale_data[0]; + scale_h = scale_data[0]; + } } else { - scale = ctx.Attr("scale"); + scale_h = ctx.Attr("scale_h"); + scale_w = ctx.Attr("scale_w"); } - if (scale > 0) { - out_h = static_cast(in_h * scale); - out_w = static_cast(in_w * scale); + if (scale_h > 0 && scale_w > 0) { + out_h = static_cast(in_h * scale_h); + out_w = static_cast(in_w * scale_w); } auto out_size = ctx.Input("OutSize"); if (out_size != nullptr) { @@ -1173,18 +1201,30 @@ static void Interpolate3DCPUBwd(const framework::ExecutionContext& ctx, int out_d = ctx.Attr("out_d"); int out_h = ctx.Attr("out_h"); int out_w = ctx.Attr("out_w"); - float scale; + float scale_d; + float scale_h; + float scale_w; auto scale_tensor = ctx.Input("Scale"); if (scale_tensor != nullptr) { auto scale_data = get_new_data_from_tensor(scale_tensor); - scale = scale_data[0]; + if (scale_data.size() > 1) { + scale_d = scale_data[0]; + scale_h = scale_data[1]; + scale_w = scale_data[2]; + } else { + scale_d = scale_data[0]; + scale_h = scale_data[0]; + scale_w = scale_data[0]; + } } else { - scale = ctx.Attr("scale"); - } - if (scale > 0) { - out_d = static_cast(in_d * scale); - out_h = static_cast(in_h * scale); - out_w = static_cast(in_w * scale); + scale_d = ctx.Attr("scale_d"); + scale_h = ctx.Attr("scale_h"); + scale_w = ctx.Attr("scale_w"); + } + if (scale_d > 0 && scale_h > 0 && scale_w > 0) { + out_d = static_cast(in_d * scale_d); + out_h = static_cast(in_h * scale_h); + out_w = static_cast(in_w * scale_w); } auto out_size = ctx.Input("OutSize"); if (out_size != nullptr) { diff --git a/python/paddle/fluid/tests/unittests/test_bicubic_interp_op.py b/python/paddle/fluid/tests/unittests/test_bicubic_interp_op.py index f3f3431c9fb3e..b50d9e7b7c7df 100644 --- a/python/paddle/fluid/tests/unittests/test_bicubic_interp_op.py +++ b/python/paddle/fluid/tests/unittests/test_bicubic_interp_op.py @@ -125,6 +125,8 @@ def setUp(self): self.out_size = None self.actual_shape = None self.data_layout = 'NCHW' + self.scale_w = -1 + self.scale_h = -1 self.init_test_case() self.op_type = "bicubic_interp" input_np = np.random.random(self.input_shape).astype("float64") @@ -137,12 +139,18 @@ def setUp(self): in_w = self.input_shape[2] if self.scale > 0: - out_h = int(in_h * self.scale) - out_w = int(in_w * self.scale) + if isinstance(self.scale, list) and len(self.scale) > 1: + self.scale_w = self.scale[1] + self.scale_h = self.scale[0] + elif self.scale > 0: + self.scale_w = self.scale_h = self.scale + + if self.scale_w > 0 and self.scale_h > 0: + out_h = int(in_h * self.scale_h) + out_w = int(in_w * self.scale_w) else: out_h = self.out_h out_w = self.out_w - output_np = bicubic_interp_np(input_np, out_h, out_w, self.out_size, self.actual_shape, self.align_corners, self.data_layout) @@ -155,7 +163,8 @@ def setUp(self): self.attrs = { 'out_h': self.out_h, 'out_w': self.out_w, - 'scale': self.scale, + 'scale_w': self.scale_w, + 'scale_h': self.scale_h, 'interp_method': self.interp_method, 'align_corners': self.align_corners, 'data_layout': self.data_layout @@ -241,6 +250,16 @@ def init_test_case(self): self.align_corners = False +class TestBicubicInterpCase7(TestBicubicInterpOp): + def init_test_case(self): + self.interp_method = 'bicubic' + self.input_shape = [1, 1, 32, 64] + self.out_h = 64 + self.out_w = 32 + self.scale = [0.5, 0.5] + self.align_corners = False + + class TestBicubicInterpSame(TestBicubicInterpOp): def init_test_case(self): self.interp_method = 'bicubic' @@ -289,7 +308,7 @@ def test_case(self): scale_tensor = fluid.data( name="scale_tensor", shape=[1], dtype="float32") - out1 = interpolate( + out1 = paddle.nn.functional.common.interpolate( x, size=[12, 12], mode='bicubic', align_corners=False) out2 = interpolate( x, size=[12, dim], mode='bicubic', align_corners=False) diff --git a/python/paddle/fluid/tests/unittests/test_bilinear_interp_op.py b/python/paddle/fluid/tests/unittests/test_bilinear_interp_op.py index 287e85cb271f8..fcbb456a6ae51 100755 --- a/python/paddle/fluid/tests/unittests/test_bilinear_interp_op.py +++ b/python/paddle/fluid/tests/unittests/test_bilinear_interp_op.py @@ -97,6 +97,8 @@ class TestBilinearInterpOp(OpTest): def setUp(self): self.out_size = None self.actual_shape = None + self.scale_w = -1 + self.scale_h = -1 self.data_layout = 'NCHW' self.init_test_case() self.op_type = "bilinear_interp" @@ -110,8 +112,15 @@ def setUp(self): in_w = self.input_shape[2] if self.scale > 0: - out_h = int(in_h * self.scale) - out_w = int(in_w * self.scale) + if isinstance(self.scale, list) and len(self.scale) > 1: + self.scale_w = self.scale[1] + self.scale_h = self.scale[0] + elif self.scale > 0: + self.scale_w = self.scale_h = self.scale + + if self.scale_w > 0 and self.scale_h > 0: + out_h = int(in_h * self.scale_h) + out_w = int(in_w * self.scale_w) else: out_h = self.out_h out_w = self.out_w @@ -128,7 +137,8 @@ def setUp(self): self.attrs = { 'out_h': self.out_h, 'out_w': self.out_w, - 'scale': self.scale, + 'scale_w': self.scale_w, + 'sclae_h': self.scale_h, 'interp_method': self.interp_method, 'align_corners': self.align_corners, 'align_mode': self.align_mode, @@ -378,6 +388,17 @@ def init_test_case(self): self.align_mode = 1 +class TestBilinearInterpScale4(TestBilinearInterpOp): + def init_test_case(self): + self.interp_method = 'bilinear' + self.input_shape = [2, 3, 5, 7] + self.out_h = 60 + self.out_w = 25 + self.scale = [1.5, 2.5] + self.align_corners = True + self.align_mode = 1 + + class TestBilinearInterpZero(TestBilinearInterpOp): def init_test_case(self): self.interp_method = 'bilinear' diff --git a/python/paddle/fluid/tests/unittests/test_linear_interp_op.py b/python/paddle/fluid/tests/unittests/test_linear_interp_op.py index 98f7cd5b6b2dc..ebb268a2bddb2 100755 --- a/python/paddle/fluid/tests/unittests/test_linear_interp_op.py +++ b/python/paddle/fluid/tests/unittests/test_linear_interp_op.py @@ -32,7 +32,7 @@ def linear_interp_np(input, align_mode=0, data_layout='NCHW'): if data_layout == "NHWC": - input = np.transpose(input, (0, 2, 1)) # NHWC => NCHW + input = np.transpose(input, (0, 2, 1)) # NWC => NCW if out_size is not None: out_w = out_size[0] if actual_shape is not None: @@ -87,6 +87,8 @@ def setUp(self): in_w = self.input_shape[1] if self.scale > 0: + if isinstance(self.scale, list) and len(self.scale) > 0: + self.scale = self.scale[0] out_w = int(in_w * self.scale) else: out_w = self.out_w @@ -102,7 +104,7 @@ def setUp(self): self.attrs = { 'out_w': self.out_w, - 'scale': self.scale, + 'scale_w': self.scale, 'interp_method': self.interp_method, 'align_corners': self.align_corners, 'align_mode': self.align_mode, @@ -163,6 +165,17 @@ def init_test_case(self): self.align_mode = 0 +class TestLinearInterpOpScale(TestLinearInterpOp): + def init_test_case(self): + self.interp_method = 'linear' + self.input_shape = [1, 3, 100] + self.out_w = 50 + self.scale = [0.5] + self.out_size = np.array([50, ]).astype("int32") + self.align_corners = False + self.align_mode = 0 + + class TestLinearInterpOpSizeTensor(TestLinearInterpOp): def setUp(self): self.out_size = None diff --git a/python/paddle/fluid/tests/unittests/test_nearest_interp_op.py b/python/paddle/fluid/tests/unittests/test_nearest_interp_op.py index eda530f30df26..77a4f457041b1 100755 --- a/python/paddle/fluid/tests/unittests/test_nearest_interp_op.py +++ b/python/paddle/fluid/tests/unittests/test_nearest_interp_op.py @@ -76,6 +76,8 @@ class TestNearestInterpOp(OpTest): def setUp(self): self.out_size = None self.actual_shape = None + self.scale_w = -1 + self.scale_h = -1 self.data_layout = 'NCHW' self.init_test_case() self.op_type = "nearest_interp" @@ -89,8 +91,15 @@ def setUp(self): in_w = self.input_shape[2] if self.scale > 0: - out_h = int(in_h * self.scale) - out_w = int(in_w * self.scale) + if isinstance(self.scale, list) and len(self.scale) > 1: + self.scale_w = self.scale[1] + self.scale_h = self.scale[0] + elif self.scale > 0: + self.scale_w = self.scale_h = self.scale + + if self.scale_w > 0 and self.scale_h > 0: + out_h = int(in_h * self.scale_h) + out_w = int(in_w * self.scale_w) else: out_h = self.out_h out_w = self.out_w @@ -106,7 +115,8 @@ def setUp(self): self.attrs = { 'out_h': self.out_h, 'out_w': self.out_w, - 'scale': self.scale, + 'scale_w': self.scale_w, + 'scale_h': self.scale_h, 'interp_method': self.interp_method, 'align_corners': self.align_corners, 'data_layout': self.data_layout @@ -327,6 +337,16 @@ def init_test_case(self): self.align_corners = True +class TestNearestNeighborInterpScale4(TestNearestInterpOp): + def init_test_case(self): + self.interp_method = 'nearest' + self.input_shape = [3, 2, 7, 5] + self.out_h = 64 + self.out_w = 32 + self.scale = [1., 2.] + self.align_corners = True + + class TestNearestInterpOp_attr_tensor(OpTest): def setUp(self): self.out_size = None diff --git a/python/paddle/fluid/tests/unittests/test_trilinear_interp_op.py b/python/paddle/fluid/tests/unittests/test_trilinear_interp_op.py index 2778fa0c6ace4..2d5d89cd9e421 100755 --- a/python/paddle/fluid/tests/unittests/test_trilinear_interp_op.py +++ b/python/paddle/fluid/tests/unittests/test_trilinear_interp_op.py @@ -20,6 +20,7 @@ import paddle.fluid.core as core import paddle.fluid as fluid from paddle.nn.functional import interpolate +np.random.seed(2000) def trilinear_interp_np(input, @@ -128,6 +129,9 @@ class TestTrilinearInterpOp(OpTest): def setUp(self): self.out_size = None self.actual_shape = None + self.scale_w = -1 + self.scale_h = -1 + self.scale_d = -1 self.data_layout = 'NCDHW' self.init_test_case() self.op_type = "trilinear_interp" @@ -143,9 +147,16 @@ def setUp(self): in_w = self.input_shape[3] if self.scale > 0: - out_d = int(in_d * self.scale) - out_h = int(in_h * self.scale) - out_w = int(in_w * self.scale) + if isinstance(self.scale, list) and len(self.scale) > 1: + self.scale_w = self.scale[2] + self.scale_h = self.scale[1] + self.scale_d = self.scale[0] + elif self.scale > 0: + self.scale_w = self.scale_h = self.scale_d = self.scale + if self.scale_w > 0 and self.scale_h > 0 and self.scale_d > 0: + out_h = int(in_h * self.scale_h) + out_w = int(in_w * self.scale_w) + out_d = int(in_d * self.scale_d) else: out_d = self.out_d out_h = self.out_h @@ -168,7 +179,9 @@ def setUp(self): 'out_d': self.out_d, 'out_h': self.out_h, 'out_w': self.out_w, - 'scale': self.scale, + 'scale_d': self.scale_d, + 'scale_h': self.scale_h, + 'scale_w': self.scale_w, 'interp_method': self.interp_method, 'align_corners': self.align_corners, 'align_mode': self.align_mode, @@ -449,6 +462,18 @@ def init_test_case(self): self.align_mode = 1 +class TestTrilinearInterpScale4(TestTrilinearInterpOp): + def init_test_case(self): + self.interp_method = 'trilinear' + self.input_shape = [2, 3, 5, 7, 9] + self.out_d = 60 + self.out_h = 40 + self.out_w = 25 + self.scale = [1.5, 2.5, 2.0] + self.align_corners = True + self.align_mode = 1 + + class TestTrilinearInterpZero(TestTrilinearInterpOp): def init_test_case(self): self.interp_method = 'trilinear' @@ -588,11 +613,33 @@ def test_case(self): x, out_shape=[4, 4, 8], actual_shape=actual_size) out5 = fluid.layers.resize_trilinear(x, scale=scale_tensor) out6 = interpolate( - x, scale_factor=scale_tensor, mode='trilinear', data_format="NCDHW") + x, + scale_factor=[2.0, 2.0, 2.0], + mode='trilinear', + align_mode=1, + align_corners=True, + data_format="NCDHW") out7 = interpolate( - x, size=[4, 4, 8], mode='trilinear', data_format="NCDHW") + x, + size=[12, 18, 8], + mode='trilinear', + align_mode=1, + align_corners=True, + data_format="NCDHW") out8 = interpolate( - x, size=shape_tensor, mode='trilinear', data_format="NCDHW") + x, + size=shape_tensor, + mode='trilinear', + align_mode=1, + align_corners=True, + data_format="NCDHW") + out9 = interpolate( + x, + scale_factor=scale_tensor, + mode='trilinear', + align_mode=1, + align_corners=True, + data_format="NCDHW") x_data = np.random.random((2, 3, 6, 9, 4)).astype("float32") dim_data = np.array([18]).astype("int32") @@ -606,17 +653,18 @@ def test_case(self): place = core.CPUPlace() exe = fluid.Executor(place) exe.run(fluid.default_startup_program()) - results = exe.run(fluid.default_main_program(), - feed={ - "x": x_data, - "y": np.transpose(x_data, (0, 2, 3, 4, 1)), - "dim": dim_data, - "shape_tensor": shape_data, - "actual_size": actual_size_data, - "scale_tensor": scale_data - }, - fetch_list=[out1, out2, out3, out4, out5], - return_numpy=True) + results = exe.run( + fluid.default_main_program(), + feed={ + "x": x_data, + "y": np.transpose(x_data, (0, 2, 3, 4, 1)), + "dim": dim_data, + "shape_tensor": shape_data, + "actual_size": actual_size_data, + "scale_tensor": scale_data + }, + fetch_list=[out1, out2, out3, out4, out5, out6, out7, out8, out9], + return_numpy=True) expect_res = trilinear_interp_np( x_data, out_d=12, out_h=18, out_w=8, align_mode=1) diff --git a/python/paddle/nn/functional/common.py b/python/paddle/nn/functional/common.py index fe41cb6e64c34..14f0d0f777735 100644 --- a/python/paddle/nn/functional/common.py +++ b/python/paddle/nn/functional/common.py @@ -49,7 +49,7 @@ def interpolate(input, scale_factor=None, mode='nearest', align_corners=False, - align_mode=1, + align_mode=0, data_format='NCHW', name=None): """ @@ -194,15 +194,15 @@ def interpolate(input, when input is a 4-D Tensor and is (out_d, out_h, out_w) when input is a 5-D Tensor. Default: None. If a list, each element can be an integer or a Tensor Variable of shape: [1]. If a Tensor Variable, its dimensions size should be a 1. - scale_factor (float|Variable|None): The multiplier for the input height or width. At + scale_factor (float|Variable|list|None): The multiplier for the input height or width. At least one of :attr:`out_shape` or :attr:`scale_factor` must be set. - And :attr:`out_shape` has a higher priority than :attr:`scale_factor`. + And :attr:`out_shape` has a higher priority than :attr:`scale_factor`.Has to match input size if it is a list. Default: None. mode (str): The resample method. It supports 'linear', 'nearest', 'bilinear', 'bicubic' and 'trilinear' currently. Default: 'nearest' align_corners(bool) : An optional bool, If True, the centers of the 4 corner pixels of the input and output tensors are aligned, preserving the values at the - corner pixels. + corner pixels.This only has an effect when 'linear', 'bilinear', 'bicubic' or 'trilinear'. Default: False align_mode(int) : An optional for linear/bilinear/trilinear interpolation. Refer to the formula in the example above, it can be \'0\' for src_idx = scale_factor*(dst_indx+0.5)-0.5 , can be \'1\' for @@ -319,7 +319,10 @@ def interpolate(input, if align_mode != 0 and align_mode != 1: raise ValueError("align_mode can only be 0 or 1") - + if align_corners != 0 and resample == 'NEAREST': + raise ValueError( + "align_corners option can only be set with the interpolating modes: linear | bilinear | bicubic | trilinear" + ) helper = LayerHelper('{}_interp'.format(resample_type), **locals()) dtype = helper.input_dtype() @@ -349,6 +352,9 @@ def _is_list_or_turple_(data): "out_d": -1, "out_h": -1, "out_w": -1, + "scale_w": -1, + "scale_h": -1, + "scale_d": -1, "interp_method": resample_type, "align_corners": align_corners, "align_mode": align_mode, @@ -434,10 +440,28 @@ def _is_list_or_turple_(data): elif isinstance(scale, float) or isinstance(scale, int): if scale <= 0: raise ValueError("Attr(scale) should be greater than zero.") - attrs['scale'] = float(scale) + attrs['scale_w'], attrs['scale_h'], attrs['scale_d'] = float(scale) + elif isinstance(scale, list): + print(len(input.shape)) + if len(scale) != len(input.shape) - 2: + raise ValueError("scale_shape length should be {} for " + "input {}-D tensor.".format( + len(input.shape) - 2, len(input.shape))) + for value in scale: + if value <= 0: + raise ValueError("Attr(scale) should be greater than zero.") + if len(scale) == 1: + attrs['scale_w'] = scale[0] + elif len(scale) == 2: + attrs['scale_h'] = scale[0] + attrs['scale_w'] = scale[1] + elif len(scale) == 3: + attrs['scale_d'] = scale[0] + attrs['scale_h'] = scale[1] + attrs['scale_w'] = scale[2] else: raise TypeError( - "Attr(scale)'s type should be float, int or Variable.") + "Attr(scale)'s type should be float, int, list or Variable.") out = helper.create_variable_for_type_inference(dtype) helper.append_op( diff --git a/python/paddle/nn/layer/common.py b/python/paddle/nn/layer/common.py index 8125e528b195b..1a02d53b9c695 100644 --- a/python/paddle/nn/layer/common.py +++ b/python/paddle/nn/layer/common.py @@ -169,9 +169,9 @@ class UpSample(layers.Layer): when input is a 4-D Tensor and is (out_d, out_h, out_w) when input is a 5-D Tensor. Default: None. If a list, each element can be an integer or a Tensor Variable of shape: [1]. If a Tensor Variable, its dimensions size should be a 1. - scale_factor (float|Variable|None): The multiplier for the input height or width. At + scale_factor (float|Variable|list|None): The multiplier for the input height or width. At least one of :attr:`out_shape` or :attr:`scale_factor` must be set. - And :attr:`out_shape` has a higher priority than :attr:`scale_factor`. + And :attr:`out_shape` has a higher priority than :attr:`scale_factor`.Has to match input size if it is a list. Default: None. mode (str): The resample method. It supports 'linear', 'nearst', 'bilinear', 'bicubic' and 'trilinear' currently. Default: 'nearest' @@ -230,7 +230,7 @@ def __init__(self, scale_factor=None, mode='nearest', align_corners=False, - align_mode=1, + align_mode=0, data_format='NCHW'): super(UpSample, self).__init__() self.size = size From 8ea8c081686107939d5d5a1140029c7ef184ba9e Mon Sep 17 00:00:00 2001 From: tink2123 Date: Tue, 11 Aug 2020 10:14:56 +0000 Subject: [PATCH 2/7] change PADDLE_ENFORCE to PADDLE_ENFORCE_EQ --- paddle/fluid/operators/interpolate_op.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/paddle/fluid/operators/interpolate_op.cc b/paddle/fluid/operators/interpolate_op.cc index e889324345aad..e2e1543acb992 100644 --- a/paddle/fluid/operators/interpolate_op.cc +++ b/paddle/fluid/operators/interpolate_op.cc @@ -148,9 +148,10 @@ static void Interpolate2DInferShapeCheck(framework::InferShapeContext* ctx) { platform::errors::InvalidArgument( "Scale's dimension size must be 1, but got dimension = %d .", scale_tensor.size())); - PADDLE_ENFORCE(scale_tensor[0] == 2 || scale_tensor[0] == 1, - "Scale's shape must be 2 or 1, but got shape = %d .", - scale_tensor[0]); + PADDLE_ENFORCE_EQ(scale_tensor[0] == 2 || scale_tensor[0] == 1, true, + platform::errors::InvalidArgument( + "Scale's shape must be 2 or 1, but got shape = %d .", + scale_tensor[0])); out_h = -1; out_w = -1; } else { @@ -244,8 +245,9 @@ static void Interpolate3DInferShapeCheck(framework::InferShapeContext* ctx) { "Scale's dimension size must be 1, but got size = %d .", scale_tensor.size())); PADDLE_ENFORCE(scale_tensor[0] == 3 || scale_tensor[0] == 1, - "Scale's shape must be 3 or 1, but got shape = %d .", - scale_tensor[0]); + platform::errors::InvalidArgument( + "Scale's shape must be 3 or 1, but got shape = %d .", + scale_tensor[0])); out_d = -1; out_h = -1; out_w = -1; From c2f46e833cbcefdb1f1c42718b583f6831798801 Mon Sep 17 00:00:00 2001 From: tink2123 Date: Tue, 11 Aug 2020 11:53:12 +0000 Subject: [PATCH 3/7] change PADDLE_ENFORCE to PADDLE_ENFORCE_EQ --- paddle/fluid/operators/interpolate_op.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/paddle/fluid/operators/interpolate_op.cc b/paddle/fluid/operators/interpolate_op.cc index e2e1543acb992..e5c8525f9efca 100644 --- a/paddle/fluid/operators/interpolate_op.cc +++ b/paddle/fluid/operators/interpolate_op.cc @@ -244,10 +244,10 @@ static void Interpolate3DInferShapeCheck(framework::InferShapeContext* ctx) { platform::errors::InvalidArgument( "Scale's dimension size must be 1, but got size = %d .", scale_tensor.size())); - PADDLE_ENFORCE(scale_tensor[0] == 3 || scale_tensor[0] == 1, - platform::errors::InvalidArgument( - "Scale's shape must be 3 or 1, but got shape = %d .", - scale_tensor[0])); + PADDLE_ENFORCE_EQ(scale_tensor[0] == 3 || scale_tensor[0] == 1, true, + platform::errors::InvalidArgument( + "Scale's shape must be 3 or 1, but got shape = %d .", + scale_tensor[0])); out_d = -1; out_h = -1; out_w = -1; From f6ac45c0d855accd784830c2448601cf5df91e93 Mon Sep 17 00:00:00 2001 From: tink2123 Date: Wed, 12 Aug 2020 03:33:53 +0000 Subject: [PATCH 4/7] Adapt to python3 --- python/paddle/fluid/tests/unittests/test_bicubic_interp_op.py | 2 +- .../paddle/fluid/tests/unittests/test_bilinear_interp_op.py | 4 ++-- python/paddle/fluid/tests/unittests/test_linear_interp_op.py | 2 +- python/paddle/fluid/tests/unittests/test_nearest_interp_op.py | 2 +- .../paddle/fluid/tests/unittests/test_trilinear_interp_op.py | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/python/paddle/fluid/tests/unittests/test_bicubic_interp_op.py b/python/paddle/fluid/tests/unittests/test_bicubic_interp_op.py index b50d9e7b7c7df..156783acbd164 100644 --- a/python/paddle/fluid/tests/unittests/test_bicubic_interp_op.py +++ b/python/paddle/fluid/tests/unittests/test_bicubic_interp_op.py @@ -138,7 +138,7 @@ def setUp(self): in_h = self.input_shape[1] in_w = self.input_shape[2] - if self.scale > 0: + if self.scale: if isinstance(self.scale, list) and len(self.scale) > 1: self.scale_w = self.scale[1] self.scale_h = self.scale[0] diff --git a/python/paddle/fluid/tests/unittests/test_bilinear_interp_op.py b/python/paddle/fluid/tests/unittests/test_bilinear_interp_op.py index fcbb456a6ae51..890ea12282876 100755 --- a/python/paddle/fluid/tests/unittests/test_bilinear_interp_op.py +++ b/python/paddle/fluid/tests/unittests/test_bilinear_interp_op.py @@ -111,7 +111,7 @@ def setUp(self): in_h = self.input_shape[1] in_w = self.input_shape[2] - if self.scale > 0: + if self.scale: if isinstance(self.scale, list) and len(self.scale) > 1: self.scale_w = self.scale[1] self.scale_h = self.scale[0] @@ -138,7 +138,7 @@ def setUp(self): 'out_h': self.out_h, 'out_w': self.out_w, 'scale_w': self.scale_w, - 'sclae_h': self.scale_h, + 'scale_h': self.scale_h, 'interp_method': self.interp_method, 'align_corners': self.align_corners, 'align_mode': self.align_mode, diff --git a/python/paddle/fluid/tests/unittests/test_linear_interp_op.py b/python/paddle/fluid/tests/unittests/test_linear_interp_op.py index ebb268a2bddb2..1a770d7be3a41 100755 --- a/python/paddle/fluid/tests/unittests/test_linear_interp_op.py +++ b/python/paddle/fluid/tests/unittests/test_linear_interp_op.py @@ -86,7 +86,7 @@ def setUp(self): else: in_w = self.input_shape[1] - if self.scale > 0: + if self.scale: if isinstance(self.scale, list) and len(self.scale) > 0: self.scale = self.scale[0] out_w = int(in_w * self.scale) diff --git a/python/paddle/fluid/tests/unittests/test_nearest_interp_op.py b/python/paddle/fluid/tests/unittests/test_nearest_interp_op.py index 77a4f457041b1..5eba483bdaaef 100755 --- a/python/paddle/fluid/tests/unittests/test_nearest_interp_op.py +++ b/python/paddle/fluid/tests/unittests/test_nearest_interp_op.py @@ -90,7 +90,7 @@ def setUp(self): in_h = self.input_shape[1] in_w = self.input_shape[2] - if self.scale > 0: + if self.scale: if isinstance(self.scale, list) and len(self.scale) > 1: self.scale_w = self.scale[1] self.scale_h = self.scale[0] diff --git a/python/paddle/fluid/tests/unittests/test_trilinear_interp_op.py b/python/paddle/fluid/tests/unittests/test_trilinear_interp_op.py index 2d5d89cd9e421..e3e79339089e5 100755 --- a/python/paddle/fluid/tests/unittests/test_trilinear_interp_op.py +++ b/python/paddle/fluid/tests/unittests/test_trilinear_interp_op.py @@ -146,7 +146,7 @@ def setUp(self): in_h = self.input_shape[2] in_w = self.input_shape[3] - if self.scale > 0: + if self.scale: if isinstance(self.scale, list) and len(self.scale) > 1: self.scale_w = self.scale[2] self.scale_h = self.scale[1] From a2a22f516dec9b4361b22f95066ad4f78525f69b Mon Sep 17 00:00:00 2001 From: tink2123 Date: Thu, 13 Aug 2020 03:08:09 +0000 Subject: [PATCH 5/7] fix test_layers, test=develop --- python/paddle/fluid/layers/nn.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/paddle/fluid/layers/nn.py b/python/paddle/fluid/layers/nn.py index 46fb61745aeb4..d77730d78214e 100644 --- a/python/paddle/fluid/layers/nn.py +++ b/python/paddle/fluid/layers/nn.py @@ -7475,7 +7475,8 @@ def _is_list_or_turple_(data): elif isinstance(scale, float) or isinstance(scale, int): if scale <= 0: raise ValueError("Attr(scale) should be greater than zero.") - attrs['scale'] = float(scale) + attrs['scale_w'] = attrs['scale_h'] = attrs['scale_d'] = float( + scale) else: raise TypeError( "Attr(scale)'s type should be float, int or Variable.") From 0a2aad05555169861b7b7d02982718d83d23bdc2 Mon Sep 17 00:00:00 2001 From: tink2123 Date: Thu, 20 Aug 2020 12:43:57 +0000 Subject: [PATCH 6/7] add PADDLE_ENFORCE_EQ,test=develop --- paddle/fluid/operators/interpolate_op.cc | 12 +- paddle/fluid/operators/interpolate_op.cu | 44 +++++ paddle/fluid/operators/interpolate_op.h | 60 ++++++- python/paddle/nn/functional/common.py | 209 +++++++++++++++++++++-- python/paddle/nn/layer/common.py | 158 ++++++++++++++++- 5 files changed, 460 insertions(+), 23 deletions(-) diff --git a/paddle/fluid/operators/interpolate_op.cc b/paddle/fluid/operators/interpolate_op.cc index e5c8525f9efca..643fa28023018 100644 --- a/paddle/fluid/operators/interpolate_op.cc +++ b/paddle/fluid/operators/interpolate_op.cc @@ -70,6 +70,9 @@ static void Interpolate1DInferShapeCheck(framework::InferShapeContext* ctx) { out_w = -1; } else { float scale_w = ctx->Attrs().Get("scale_w"); + PADDLE_ENFORCE_EQ(scale_w > 0, true, platform::errors::InvalidArgument( + "scale of Op(interpolate) " + "should be greater than 0.")); if (scale_w > 0) { // round down out_w = (data_layout == DataLayout::kNCHW @@ -157,6 +160,10 @@ static void Interpolate2DInferShapeCheck(framework::InferShapeContext* ctx) { } else { float scale_h = ctx->Attrs().Get("scale_h"); float scale_w = ctx->Attrs().Get("scale_w"); + PADDLE_ENFORCE_EQ( + scale_w > 0 && scale_h > 0, true, + platform::errors::InvalidArgument("scale of Op(interpolate) " + "should be greater than 0.")); if (scale_h > 0 && scale_w > 0) { // round down out_h = (data_layout == DataLayout::kNCHW @@ -255,7 +262,10 @@ static void Interpolate3DInferShapeCheck(framework::InferShapeContext* ctx) { float scale_d = ctx->Attrs().Get("scale_d"); float scale_h = ctx->Attrs().Get("scale_h"); float scale_w = ctx->Attrs().Get("scale_w"); - + PADDLE_ENFORCE_EQ( + scale_w > 0 && scale_h > 0 && scale_d > 0, true, + platform::errors::InvalidArgument("scale of Op(interpolate) " + "should be greater than 0.")); if (scale_d > 0 && scale_h > 0 && scale_w > 0) { // round down out_d = (data_layout == DataLayout::kNCHW diff --git a/paddle/fluid/operators/interpolate_op.cu b/paddle/fluid/operators/interpolate_op.cu index 78ccaa9e2f943..bb8a5186c8b64 100644 --- a/paddle/fluid/operators/interpolate_op.cu +++ b/paddle/fluid/operators/interpolate_op.cu @@ -846,8 +846,14 @@ static void Interpolate1DCUDAFwd(const framework::ExecutionContext& ctx, if (scale_tensor != nullptr) { auto scale_data = get_new_data_from_tensor(scale_tensor); scale = scale_data[0]; + PADDLE_ENFORCE_EQ(scale_w > 0, true, platform::errors::InvalidArgument( + "scale of Op(interpolate) " + "should be greater than 0.")); } else { scale = ctx.Attr("scale_w"); + PADDLE_ENFORCE_EQ(scale_w > 0, true, platform::errors::InvalidArgument( + "scale of Op(interpolate) " + "should be greater than 0.")); } if (scale > 0) { out_w = static_cast(in_w * scale); @@ -933,9 +939,17 @@ static void Interpolate2DCUDAFwd(const framework::ExecutionContext& ctx, scale_h = scale_data[0]; scale_w = scale_data[0]; } + PADDLE_ENFORCE_EQ( + scale_w > 0 && scale_h > 0, true, + platform::errors::InvalidArgument("scale of Op(interpolate) " + "should be greater than 0.")); } else { scale_w = ctx.Attr("scale_w"); scale_h = ctx.Attr("scale_h"); + PADDLE_ENFORCE_EQ( + scale_w > 0 && scale_h > 0, true, + platform::errors::InvalidArgument("scale of Op(interpolate) " + "should be greater than 0.")); } if (scale_w > 0 && scale_h > 0) { out_h = static_cast(in_h * scale_h); @@ -1050,10 +1064,18 @@ static void Interpolate3DCUDAFwd(const framework::ExecutionContext& ctx, scale_h = scale_data[0]; scale_w = scale_data[0]; } + PADDLE_ENFORCE_EQ( + scale_w > 0 && scale_h > 0 && scale_d > 0, true, + platform::errors::InvalidArgument("scale of Op(interpolate) " + "should be greater than 0.")); } else { scale_d = ctx.Attr("scale_d"); scale_h = ctx.Attr("scale_h"); scale_w = ctx.Attr("scale_w"); + PADDLE_ENFORCE_EQ( + scale_w > 0 && scale_h > 0 && scale_d > 0, true, + platform::errors::InvalidArgument("scale of Op(interpolate) " + "should be greater than 0.")); } if (scale_d > 0 && scale_h > 0 && scale_w > 0) { out_d = static_cast(in_d * scale_d); @@ -1147,8 +1169,14 @@ static void Interpolate1DCUDABwd(const framework::ExecutionContext& ctx, if (scale_tensor != nullptr) { auto scale_data = get_new_data_from_tensor(scale_tensor); scale = scale_data[0]; + PADDLE_ENFORCE_EQ(scale_w > 0, true, platform::errors::InvalidArgument( + "scale of Op(interpolate) " + "should be greater than 0.")); } else { scale = ctx.Attr("scale_w"); + PADDLE_ENFORCE_EQ(scale_w > 0, true, platform::errors::InvalidArgument( + "scale of Op(interpolate) " + "should be greater than 0.")); } if (scale > 0) { out_w = static_cast(in_w * scale); @@ -1233,9 +1261,17 @@ static void Interpolate2DCUDABwd(const framework::ExecutionContext& ctx, scale_h = scale_data[0]; scale_w = scale_data[0]; } + PADDLE_ENFORCE_EQ( + scale_w > 0 && scale_h > 0, true, + platform::errors::InvalidArgument("scale of Op(interpolate) " + "should be greater than 0.")); } else { scale_w = ctx.Attr("scale_w"); scale_h = ctx.Attr("scale_h"); + PADDLE_ENFORCE_EQ( + scale_w > 0 && scale_h > 0, true, + platform::errors::InvalidArgument("scale of Op(interpolate) " + "should be greater than 0.")); } if (scale_w > 0 && scale_h > 0) { out_h = static_cast(in_h * scale_h); @@ -1348,10 +1384,18 @@ static void Interpolate3DCUDABwd(const framework::ExecutionContext& ctx, scale_h = scale_data[0]; scale_w = scale_data[0]; } + PADDLE_ENFORCE_EQ( + scale_w > 0 && scale_h > 0 && scale_d > 0, true, + platform::errors::InvalidArgument("scale of Op(interpolate) " + "should be greater than 0.")); } else { scale_d = ctx.Attr("scale_d"); scale_h = ctx.Attr("scale_h"); scale_w = ctx.Attr("scale_w"); + PADDLE_ENFORCE_EQ( + scale_w > 0 && scale_h > 0 && scale_d > 0, true, + platform::errors::InvalidArgument("scale of Op(interpolate) " + "should be greater than 0.")); } if (scale_d > 0 && scale_h > 0 && scale_w > 0) { out_d = static_cast(in_d * scale_d); diff --git a/paddle/fluid/operators/interpolate_op.h b/paddle/fluid/operators/interpolate_op.h index b6c6d135abe12..512a24804fd33 100644 --- a/paddle/fluid/operators/interpolate_op.h +++ b/paddle/fluid/operators/interpolate_op.h @@ -792,12 +792,18 @@ static void Interpolate1DCPUFwd(const framework::ExecutionContext& ctx, auto scale_tensor = ctx.Input("Scale"); if (scale_tensor != nullptr) { auto scale_data = get_new_data_from_tensor(scale_tensor); - scale = scale_data[0]; + scale_w = scale_data[0]; + PADDLE_ENFORCE_EQ(scale_w > 0, true, platform::errors::InvalidArgument( + "scale of Op(interpolate) " + "should be greater than 0.")); } else { - scale = ctx.Attr("scale_w"); + scale_w = ctx.Attr("scale_w"); + PADDLE_ENFORCE_EQ(scale_w > 0, true, platform::errors::InvalidArgument( + "scale of Op(interpolate) " + "should be greater than 0.")); } - if (scale > 0) { - out_w = static_cast(in_w * scale); + if (scale_w > 0) { + out_w = static_cast(in_w * scale_w); } auto out_size = ctx.Input("OutSize"); if (out_size != nullptr) { @@ -866,9 +872,17 @@ static void Interpolate2DCPUFwd(const framework::ExecutionContext& ctx, scale_h = scale_data[0]; scale_w = scale_data[0]; } + PADDLE_ENFORCE_EQ( + scale_w > 0 && scale_h > 0, true, + platform::errors::InvalidArgument("scale of Op(interpolate) " + "should be greater than 0.")); } else { scale_w = ctx.Attr("scale_w"); scale_h = ctx.Attr("scale_h"); + PADDLE_ENFORCE_EQ( + scale_w > 0 && scale_h > 0, true, + platform::errors::InvalidArgument("scale of Op(interpolate) " + "should be greater than 0.")); } if (scale_h > 0 && scale_w > 0) { out_h = static_cast(in_h * scale_h); @@ -963,10 +977,18 @@ static void Interpolate3DCPUFwd(const framework::ExecutionContext& ctx, scale_h = scale_data[0]; scale_w = scale_data[0]; } + PADDLE_ENFORCE_EQ( + scale_w > 0 && scale_h > 0 && scale_d, true, + platform::errors::InvalidArgument("scale of Op(interpolate) " + "should be greater than 0.")); } else { scale_d = ctx.Attr("scale_d"); scale_h = ctx.Attr("scale_h"); scale_w = ctx.Attr("scale_w"); + PADDLE_ENFORCE_EQ( + scale_w > 0 && scale_h > 0 && scale_d, true, + platform::errors::InvalidArgument("scale of Op(interpolate) " + "should be greater than 0.")); } if (scale_w > 0 && scale_h > 0 && scale_d > 0) { out_d = static_cast(in_d * scale_d); @@ -1046,12 +1068,18 @@ static void Interpolate1DCPUBwd(const framework::ExecutionContext& ctx, auto scale_tensor = ctx.Input("Scale"); if (scale_tensor != nullptr) { auto scale_data = get_new_data_from_tensor(scale_tensor); - scale = scale_data[0]; + scale_w = scale_data[0]; + PADDLE_ENFORCE_EQ(scale_w > 0, true, platform::errors::InvalidArgument( + "scale of Op(interpolate) " + "should be greater than 0.")); } else { - scale = ctx.Attr("scale_w"); + scale_w = ctx.Attr("scale_w"); + PADDLE_ENFORCE_EQ(scale_w > 0, true, platform::errors::InvalidArgument( + "scale of Op(interpolate) " + "should be greater than 0.")); } - if (scale > 0) { - out_w = static_cast(in_w * scale); + if (scale_w > 0) { + out_w = static_cast(in_w * scale_w); } auto out_size = ctx.Input("OutSize"); if (out_size != nullptr) { @@ -1120,9 +1148,17 @@ static void Interpolate2DCPUBwd(const framework::ExecutionContext& ctx, scale_w = scale_data[0]; scale_h = scale_data[0]; } + PADDLE_ENFORCE_EQ( + scale_w > 0 && scale_h > 0, true, + platform::errors::InvalidArgument("scale of Op(interpolate) " + "should be greater than 0.")); } else { scale_h = ctx.Attr("scale_h"); scale_w = ctx.Attr("scale_w"); + PADDLE_ENFORCE_EQ( + scale_w > 0 && scale_h > 0, true, + platform::errors::InvalidArgument("scale of Op(interpolate) " + "should be greater than 0.")); } if (scale_h > 0 && scale_w > 0) { out_h = static_cast(in_h * scale_h); @@ -1216,10 +1252,18 @@ static void Interpolate3DCPUBwd(const framework::ExecutionContext& ctx, scale_h = scale_data[0]; scale_w = scale_data[0]; } + PADDLE_ENFORCE_EQ( + scale_w > 0 && scale_h > 0 && scale_d > 0, true, + platform::errors::InvalidArgument("scale of Op(interpolate) " + "should be greater than 0.")); } else { scale_d = ctx.Attr("scale_d"); scale_h = ctx.Attr("scale_h"); scale_w = ctx.Attr("scale_w"); + PADDLE_ENFORCE_EQ( + scale_w > 0 && scale_h > 0 && scale_d > 0, true, + platform::errors::InvalidArgument("scale of Op(interpolate) " + "should be greater than 0.")); } if (scale_d > 0 && scale_h > 0 && scale_w > 0) { out_d = static_cast(in_d * scale_d); diff --git a/python/paddle/nn/functional/common.py b/python/paddle/nn/functional/common.py index 14f0d0f777735..f5bc54d29267c 100644 --- a/python/paddle/nn/functional/common.py +++ b/python/paddle/nn/functional/common.py @@ -40,7 +40,8 @@ 'unfold', # 'bilinear_tensor_product', 'assign', - 'interpolate' + 'interpolate', + 'upsample' ] @@ -117,18 +118,11 @@ def interpolate(input, W_out = W_{in} * scale_{factor} Nearest neighbor interpolation: - if: - align_corners = False + input : (N,C,H_in,W_in) output: (N,C,H_out,W_out) where: H_out = floor (H_{in} * scale_{factor}) W_out = floor (W_{in} * scale_{factor}) - else: - align_corners = True - input : (N,C,H_in,W_in) - output: (N,C,H_out,W_out) where: - H_out = round(H_{in} * scale_{factor}) - W_out = round(W_{in} * scale_{factor}) Bilinear interpolation: if: @@ -352,9 +346,6 @@ def _is_list_or_turple_(data): "out_d": -1, "out_h": -1, "out_w": -1, - "scale_w": -1, - "scale_h": -1, - "scale_d": -1, "interp_method": resample_type, "align_corners": align_corners, "align_mode": align_mode, @@ -470,3 +461,197 @@ def _is_list_or_turple_(data): outputs={"Out": out}, attrs=attrs) return out + + +def upsample(input, + size=None, + scale_factor=None, + mode='nearest', + align_corners=False, + align_mode=0, + data_format='NCHW', + name=None): + """ + This op resizes a batch of images. + The input must be a 3-D Tensor of the shape (num_batches, channels, in_w) + or 4-D (num_batches, channels, in_h, in_w), or a 5-D Tensor of the shape + (num_batches, channels, in_d, in_h, in_w) or (num_batches, in_d, in_h, in_w, channels), + and the resizing only applies on the three dimensions(depth, height and width). + **Warning:** the parameter :attr:`actual_shape` will be deprecated in the + future and only use :attr:`out_shape` instead. + Supporting resample methods: + 'linear' : Linear interpolation + 'bilinear' : Bilinear interpolation + 'trilinear' : Trilinear interpolation + 'nearest' : Nearest neighbor interpolation + 'bicubic' : Bicubic interpolation + Linear interpolation is the method of using a line connecting two known quantities + to determine the value of an unknown quantity between the two known quantities. + + Nearest neighbor interpolation is to perform nearest neighbor interpolation + in both the 3rd dimension(in height direction) and the 4th dimension(in width + direction) on input tensor. + Bilinear interpolation is an extension of linear interpolation for + interpolating functions of two variables (e.g. H-direction and + W-direction in this op) on a rectilinear 2D grid. The key idea is + to perform linear interpolation first in one direction, and then + again in the other direction. + + Bicubic interpolation is an extension of cubic interpolation for interpolating + data points on a two-dimensional regular grid. The interpolated surface is + smoother than corresponding surfaces obtained by bilinear interpolation or + nearest-neighbor interpolation. + Trilinear interpolation is an extension of linear interpolation for + interpolating functions of three variables (e.g. D-direction, + H-direction and W-direction in this op) on a rectilinear 3D grid. + The linear interpolation is performed on three directions. + Align_corners and align_mode are optional parameters,the calculation method + of interpolation can be selected by them. + Example: + .. code-block:: text + For scale_factor: + if align_corners = True && out_size > 1 : + scale_factor = (in_size-1.0)/(out_size-1.0) + else: + scale_factor = float(in_size/out_size) + Linear interpolation: + if: + align_corners = False , align_mode = 0 + input : (N,C,W_in) + output: (N,C,W_out) where: + W_out = (W_{in}+0.5) * scale_{factor} - 0.5 + else: + input : (N,C,W_in) + output: (N,C,W_out) where: + W_out = W_{in} * scale_{factor} + Nearest neighbor interpolation: + if: + align_corners = False + input : (N,C,H_in,W_in) + output: (N,C,H_out,W_out) where: + H_out = floor (H_{in} * scale_{factor}) + W_out = floor (W_{in} * scale_{factor}) + else: + align_corners = True + input : (N,C,H_in,W_in) + output: (N,C,H_out,W_out) where: + H_out = round(H_{in} * scale_{factor}) + W_out = round(W_{in} * scale_{factor}) + + Bilinear interpolation: + if: + align_corners = False , align_mode = 0 + input : (N,C,H_in,W_in) + output: (N,C,H_out,W_out) where: + H_out = (H_{in}+0.5) * scale_{factor} - 0.5 + W_out = (W_{in}+0.5) * scale_{factor} - 0.5 + else: + input : (N,C,H_in,W_in) + output: (N,C,H_out,W_out) where: + H_out = H_{in} * scale_{factor} + W_out = W_{in} * scale_{factor} + Bicubic interpolation: + if: + align_corners = False + input : (N,C,H_in,W_in) + output: (N,C,H_out,W_out) where: + H_out = (H_{in}+0.5) * scale_{factor} - 0.5 + W_out = (W_{in}+0.5) * scale_{factor} - 0.5 + else: + input : (N,C,H_in,W_in) + output: (N,C,H_out,W_out) where: + H_out = H_{in} * scale_{factor} + W_out = W_{in} * scale_{factor} + Trilinear interpolation: + if: + align_corners = False , align_mode = 0 + input : (N,C,D_in,H_in,W_in) + output: (N,C,D_out,H_out,W_out) where: + D_out = (D_{in}+0.5) * scale_{factor} - 0.5 + H_out = (H_{in}+0.5) * scale_{factor} - 0.5 + W_out = (W_{in}+0.5) * scale_{factor} - 0.5 + else: + input : (N,C,D_in,H_in,W_in) + output: (N,C,D_out,H_out,W_out) where: + D_out = D_{in} * scale_{factor} + H_out = H_{in} * scale_{factor} + W_out = W_{in} * scale_{factor} + https://en.wikipedia.org/wiki/Linear_interpolation. + For details of linear interpolation, please refer to Wikipedia: + + For details of nearest neighbor interpolation, please refer to Wikipedia: + https://en.wikipedia.org/wiki/Nearest-neighbor_interpolation. + + For details of bilinear interpolation, please refer to Wikipedia: + https://en.wikipedia.org/wiki/Bilinear_interpolation. + + For details of bicubic interpolation, please refer to Wikipedia: + https://en.wikipedia.org/wiki/Bicubic_interpolation + + For details of trilinear interpolation, please refer to Wikipedia: + https://en.wikipedia.org/wiki/Trilinear_interpolation. + + Parameters: + input (Variable): 3-D, 4-D or 5-D Tensor, its data type is float32, float64, or uint8, + its data format is specified by :attr:`data_format`. + size (list|tuple|Variable|None): Output shape of image resize + layer, the shape is (out_w, ) when input is a 3-D Tensor, the shape is (out_h, out_w) + when input is a 4-D Tensor and is (out_d, out_h, out_w) when input is a 5-D Tensor. + Default: None. If a list, each element can be an integer or a Tensor Variable of shape: [1]. + If a Tensor Variable, its dimensions size should be a 1. + scale_factor (float|Variable|None): The multiplier for the input height or width. At + least one of :attr:`out_shape` or :attr:`scale_factor` must be set. + And :attr:`out_shape` has a higher priority than :attr:`scale_factor`. + Default: None. + mode (str): The resample method. It supports 'linear', 'nearest', 'bilinear', + 'bicubic' and 'trilinear' currently. Default: 'nearest' + align_corners(bool) : An optional bool, If True, the centers of the 4 corner pixels of the + input and output tensors are aligned, preserving the values at the + corner pixels. + Default: False + align_mode(int) : An optional for linear/bilinear/trilinear interpolation. Refer to the formula in the example above, + it can be \'0\' for src_idx = scale_factor*(dst_indx+0.5)-0.5 , can be \'1\' for + src_idx = scale_factor*dst_index. + data_format (str, optional): Specify the data format of the input, and the data format of the output + will be consistent with that of the input. An optional string from:`NCW`, `NWC`, `"NCHW"`, `"NHWC"`, `"NCDHW"`, + `"NDHWC"`. The default is `"NCHW"`. When it is `"NCHW"`, the data is stored in the order of: + `[batch_size, input_channels, input_height, input_width]`. When it is `"NCHW"`, the data is stored + in the order of: `[batch_size, input_channels, input_depth, input_height, input_width]`. + name(str, optional): The default value is None. + Normally there is no need for user to set this property. + For more information, please refer to :ref:`api_guide_Name` + Returns: + A 3-D Tensor of the shape (num_batches, channels, out_w) or (num_batches, out_w, channels), + A 4-D Tensor of the shape (num_batches, channels, out_h, out_w) or (num_batches, out_h, out_w, channels), + or 5-D Tensor of the shape (num_batches, channels, out_d, out_h, out_w) or (num_batches, out_d, out_h, out_w, channels). + Raises: + TypeError: size should be a list or tuple or Variable. + ValueError: The 'mode' of image_resize can only be 'linear', 'bilinear', + 'trilinear', 'bicubic', or 'nearest' currently. + ValueError: 'linear' only support 3-D tensor. + ValueError: 'bilinear', 'bicubic' and 'nearest' only support 4-D tensor. + ValueError: 'trilinear' only support 5-D tensor. + ValueError: One of size and scale_factor must not be None. + ValueError: size length should be 1 for input 3-D tensor. + ValueError: size length should be 2 for input 4-D tensor. + ValueError: size length should be 3 for input 5-D tensor. + ValueError: scale_factor should be greater than zero. + TypeError: align_corners should be a bool value + ValueError: align_mode can only be '0' or '1' + ValueError: data_format can only be 'NCW', 'NWC', 'NCHW', 'NHWC', 'NCDHW' or 'NDHWC'. + Examples: + .. code-block:: python + import paddle + import numpy as np + import paddle.fluid.dygraph as dg + upsample_op = paddle.nn.UpSample(size=[12,12]) + input_data = np.random.rand(2,3,6,10).astype("float32") + place = paddle.fluid.CPUPlace() + with dg.guard(place) as g: + input = dg.to_variable(input_data) + output = upsample_op(input=input) + print(output.shape) + # [2L, 3L, 12L, 12L] + """ + return interpolate(input, size, scale_factor, mode, align_corners, + align_mode, data_format) diff --git a/python/paddle/nn/layer/common.py b/python/paddle/nn/layer/common.py index 1a02d53b9c695..197420e45d7ff 100644 --- a/python/paddle/nn/layer/common.py +++ b/python/paddle/nn/layer/common.py @@ -22,7 +22,7 @@ __all__ = [ 'BilinearTensorProduct', 'Pool2D', 'Embedding', 'Linear', 'UpSample', - 'Pad2D' + 'Pad2D', 'UpsamplingNearest2d', 'UpsamplingBilinear2d' ] @@ -219,7 +219,7 @@ class UpSample(layers.Layer): input_data = np.random.rand(2,3,6,10).astype("float32") place = paddle.fluid.CPUPlace() with dg.guard(place) as g: - input = dg.to_variable(input_data) + input = paddle.to_tensor(input_data) output = upsample_op(input=input) print(output.shape) # [2L, 3L, 12L, 12L] @@ -253,6 +253,160 @@ def forward(self, input): return out +class UpsamplingNearest2d(layers.Layer): + """ + This op upsamples a batch of images, using nearest neighbours' pixel values. + The input must be a 4-D Tensor of the shape (num_batches, channels, in_h, in_w), + and the upsampling only applies on the two dimensions(height and width). + **Warning:** the parameter :attr:`actual_shape` will be deprecated in the + future and only use :attr:`out_shape` instead. + Nearest neighbor interpolation is to perform nearest neighbor interpolation + in both the 3rd dimension(in height direction) and the 4th dimension(in width + direction) on input tensor. + + For details of nearest neighbor interpolation, please refer to Wikipedia: + https://en.wikipedia.org/wiki/Nearest-neighbor_interpolation. + + input (Variable): 4-D Tensor, its data type is float32, float64, or uint8, + its data format is specified by :attr:`data_format`. + size (list|tuple|Variable|None): Output shape of image resize + layer, the shape is (out_h, out_w) when input is a 4-D Tensor. + Default: None. If a list, each element can be an integer or a Tensor Variable of shape: [1]. + If a Tensor Variable, its dimensions size should be a 1. + scale_factor (float|int|list|Variable|None): The multiplier for the input height or width. At + least one of :attr:`out_shape` or :attr:`scale_factor` must be set. + And :attr:`out_shape` has a higher priority than :attr:`scale_factor`. + Default: None. Has to match input size if it is a list. + data_format (str, optional): Specify the data format of the input, and the data format of the output + will be consistent with that of the input. An optional string from:`NCW`, `NWC`, `"NCHW"`, `"NHWC"`, `"NCDHW"`, + `"NDHWC"`. The default is `"NCHW"`. When it is `"NCHW"`, the data is stored in the order of: + `[batch_size, input_channels, input_height, input_width]`. When it is `"NCHW"`, the data is stored + in the order of: `[batch_size, input_channels, input_depth, input_height, input_width]`. + name(str, optional): The default value is None. + Normally there is no need for user to set this property. + For more information, please refer to :ref:`api_guide_Name` + Returns: + A 4-D Tensor of the shape (num_batches, channels, out_h, out_w) or (num_batches, out_h, out_w, channels), + Raises: + TypeError: size should be a list or tuple or Variable. + ValueError: 'nearest' only support 4-D tensor. + ValueError: One of size and scale_factor must not be None. + ValueError: size length should be 2 for input 4-D tensor. + ValueError: scale_factor should be greater than zero. + ValueError: data_format can only be 'NCHW', 'NHWC'. + Examples: + .. code-block:: python + import paddle + import numpy as np + import paddle.fluid.dygraph as dg + upsample_op = paddle.nn.UpsamplingNearest2d(size=[12,12]) + input_data = np.random.rand(2,3,6,10).astype("float32") + place = paddle.fluid.CPUPlace() + with dg.guard(place) as g: + input = paddle.to_tensor(input_data) + output = upsample_op(input=input) + print(output.shape) + # [2L, 3L, 12L, 12L] + """ + + def __init__(self, size=None, scale_factor=None, data_format='NCHW'): + super(UpSample, self).__init__() + self.size = size + self.scale_factor = scale_factor + self.mode = mode.lower() + self.data_format = data_format + + def forward(self, input): + out = F.interpolate( + input, + size=self.size, + scale_factor=self.scale_factor, + mode='nearest', + align_corners=False, + align_mode=0, + data_format=self.data_format) + + return out + + +class UpsamplingBilinear2d(layers.Layer): + """ + This op upsamples a batch of images, using bilinear' pixel values. + The input must be a 4-D Tensor of the shape (num_batches, channels, in_h, in_w), + and the upsampling only applies on the two dimensions(height and width). + **Warning:** the parameter :attr:`actual_shape` will be deprecated in the + future and only use :attr:`out_shape` instead. + Bilinear interpolation is an extension of linear interpolation for + interpolating functions of two variables (e.g. H-direction and + W-direction in this op) on a rectilinear 2D grid. The key idea is + to perform linear interpolation first in one direction, and then + again in the other direction. + + For details of bilinear interpolation, please refer to Wikipedia: + https://en.wikipedia.org/wiki/Bilinear_interpolation. + + input (Variable): 4-D Tensor, its data type is float32, float64, or uint8, + its data format is specified by :attr:`data_format`. + size (list|tuple|Variable|None): Output shape of image resize + layer, the shape is (out_h, out_w) when input is a 4-D Tensor. + Default: None. If a list, each element can be an integer or a Tensor Variable of shape: [1]. + If a Tensor Variable, its dimensions size should be a 1. + scale_factor (float|int|list|Variable|None): The multiplier for the input height or width. At + least one of :attr:`out_shape` or :attr:`scale_factor` must be set. + And :attr:`out_shape` has a higher priority than :attr:`scale_factor`. + Default: None. Has to match input size if it is a list. + data_format (str, optional): Specify the data format of the input, and the data format of the output + will be consistent with that of the input. An optional string from:`NCW`, `NWC`, `"NCHW"`, `"NHWC"`, `"NCDHW"`, + `"NDHWC"`. The default is `"NCHW"`. When it is `"NCHW"`, the data is stored in the order of: + `[batch_size, input_channels, input_height, input_width]`. When it is `"NCHW"`, the data is stored + in the order of: `[batch_size, input_channels, input_depth, input_height, input_width]`. + name(str, optional): The default value is None. + Normally there is no need for user to set this property. + For more information, please refer to :ref:`api_guide_Name` + Returns: + A 4-D Tensor of the shape (num_batches, channels, out_h, out_w) or (num_batches, out_h, out_w, channels), + Raises: + TypeError: size should be a list or tuple or Variable. + ValueError: 'bilinear' only support 4-D tensor. + ValueError: One of size and scale_factor must not be None. + ValueError: size length should be 2 for input 4-D tensor. + ValueError: scale_factor should be greater than zero. + ValueError: data_format can only be 'NCHW', 'NHWC'. + Examples: + .. code-block:: python + import paddle + import numpy as np + import paddle.fluid.dygraph as dg + upsample_op = paddle.nn.UpsamplingBilinear2d(size=[12,12]) + input_data = np.random.rand(2,3,6,10).astype("float32") + place = paddle.fluid.CPUPlace() + with dg.guard(place) as g: + input = paddle.to_tensor(input_data) + output = upsample_op(input=input) + print(output.shape) + # [2L, 3L, 12L, 12L] + """ + + def __init__(self, size=None, scale_factor=None, data_format='NCHW'): + super(UpSample, self).__init__() + self.size = size + self.scale_factor = scale_factor + self.mode = mode.lower() + self.data_format = data_format + + def forward(self, input): + out = F.interpolate( + input, + size=self.size, + scale_factor=self.scale_factor, + mode='bilinear', + align_corners=True, + align_mode=0, + data_format=self.data_format) + + return out + + class Pad2D(layers.Layer): """ :alias_main: paddle.nn.Pad2D From ec633aa672e585e21892bf9fead81297e4ffeec1 Mon Sep 17 00:00:00 2001 From: tink2123 Date: Thu, 20 Aug 2020 13:04:02 +0000 Subject: [PATCH 7/7] rename scale to scale_w --- paddle/fluid/operators/interpolate_op.cu | 20 ++++++++++---------- paddle/fluid/operators/interpolate_op.h | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/paddle/fluid/operators/interpolate_op.cu b/paddle/fluid/operators/interpolate_op.cu index bb8a5186c8b64..788109880f969 100644 --- a/paddle/fluid/operators/interpolate_op.cu +++ b/paddle/fluid/operators/interpolate_op.cu @@ -841,22 +841,22 @@ static void Interpolate1DCUDAFwd(const framework::ExecutionContext& ctx, auto new_size = get_new_shape(list_new_shape_tensor); out_w = new_size[0]; } else { - float scale; + float scale_w; auto scale_tensor = ctx.Input("Scale"); if (scale_tensor != nullptr) { auto scale_data = get_new_data_from_tensor(scale_tensor); - scale = scale_data[0]; + scale_w = scale_data[0]; PADDLE_ENFORCE_EQ(scale_w > 0, true, platform::errors::InvalidArgument( "scale of Op(interpolate) " "should be greater than 0.")); } else { - scale = ctx.Attr("scale_w"); + scale_w = ctx.Attr("scale_w"); PADDLE_ENFORCE_EQ(scale_w > 0, true, platform::errors::InvalidArgument( "scale of Op(interpolate) " "should be greater than 0.")); } - if (scale > 0) { - out_w = static_cast(in_w * scale); + if (scale_w > 0) { + out_w = static_cast(in_w * scale_w); } auto out_size = ctx.Input("OutSize"); if (out_size != nullptr) { @@ -1164,22 +1164,22 @@ static void Interpolate1DCUDABwd(const framework::ExecutionContext& ctx, int align_mode = ctx.Attr("align_mode"); int out_w = ctx.Attr("out_w"); - float scale; + float scale_w; auto scale_tensor = ctx.Input("Scale"); if (scale_tensor != nullptr) { auto scale_data = get_new_data_from_tensor(scale_tensor); - scale = scale_data[0]; + scale_w = scale_data[0]; PADDLE_ENFORCE_EQ(scale_w > 0, true, platform::errors::InvalidArgument( "scale of Op(interpolate) " "should be greater than 0.")); } else { - scale = ctx.Attr("scale_w"); + scale_w = ctx.Attr("scale_w"); PADDLE_ENFORCE_EQ(scale_w > 0, true, platform::errors::InvalidArgument( "scale of Op(interpolate) " "should be greater than 0.")); } - if (scale > 0) { - out_w = static_cast(in_w * scale); + if (scale_w > 0) { + out_w = static_cast(in_w * scale_w); } auto out_size = ctx.Input("OutSize"); diff --git a/paddle/fluid/operators/interpolate_op.h b/paddle/fluid/operators/interpolate_op.h index 512a24804fd33..fe0e1d9c30d38 100644 --- a/paddle/fluid/operators/interpolate_op.h +++ b/paddle/fluid/operators/interpolate_op.h @@ -788,7 +788,7 @@ static void Interpolate1DCPUFwd(const framework::ExecutionContext& ctx, auto new_size = get_new_shape(list_new_size_tensor); out_w = new_size[0]; } else { - float scale; + float scale_w; auto scale_tensor = ctx.Input("Scale"); if (scale_tensor != nullptr) { auto scale_data = get_new_data_from_tensor(scale_tensor); @@ -1064,7 +1064,7 @@ static void Interpolate1DCPUBwd(const framework::ExecutionContext& ctx, int align_mode = ctx.Attr("align_mode"); int out_w = ctx.Attr("out_w"); - float scale; + float scale_w; auto scale_tensor = ctx.Input("Scale"); if (scale_tensor != nullptr) { auto scale_data = get_new_data_from_tensor(scale_tensor);