diff --git a/paddle/fluid/operators/interpolate_op.cc b/paddle/fluid/operators/interpolate_op.cc index 1e99e22e12b2a..643fa28023018 100644 --- a/paddle/fluid/operators/interpolate_op.cc +++ b/paddle/fluid/operators/interpolate_op.cc @@ -63,14 +63,21 @@ 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"); + 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 - ? 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 +151,27 @@ 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_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 { - 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"); + 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 - ? 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 +251,32 @@ 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_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; } 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"); + 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 - ? 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 +396,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..788109880f969 100644 --- a/paddle/fluid/operators/interpolate_op.cu +++ b/paddle/fluid/operators/interpolate_op.cu @@ -841,16 +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"); + 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) { @@ -921,17 +927,33 @@ 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]; + } + PADDLE_ENFORCE_EQ( + scale_w > 0 && scale_h > 0, true, + platform::errors::InvalidArgument("scale of Op(interpolate) " + "should be greater than 0.")); } else { - scale = ctx.Attr("scale"); + 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 > 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 +1049,38 @@ 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]; + } + 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 = ctx.Attr("scale"); + 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 > 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) { @@ -1122,16 +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"); + 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"); @@ -1201,17 +1249,33 @@ 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]; + } + PADDLE_ENFORCE_EQ( + scale_w > 0 && scale_h > 0, true, + platform::errors::InvalidArgument("scale of Op(interpolate) " + "should be greater than 0.")); } else { - scale = ctx.Attr("scale"); + 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 > 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 +1369,38 @@ 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]; + } + 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 = ctx.Attr("scale"); + 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 > 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 +1519,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..fe0e1d9c30d38 100644 --- a/paddle/fluid/operators/interpolate_op.h +++ b/paddle/fluid/operators/interpolate_op.h @@ -788,16 +788,22 @@ 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); - 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"); + 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) { @@ -854,17 +860,33 @@ 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]; + } + PADDLE_ENFORCE_EQ( + scale_w > 0 && scale_h > 0, true, + platform::errors::InvalidArgument("scale of Op(interpolate) " + "should be greater than 0.")); } else { - scale = ctx.Attr("scale"); + 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 > 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 +962,38 @@ 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]; + } + 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 = ctx.Attr("scale"); + 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 > 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) { @@ -1022,16 +1064,22 @@ 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); - 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"); + 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) { @@ -1088,17 +1136,33 @@ 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]; + } + PADDLE_ENFORCE_EQ( + scale_w > 0 && scale_h > 0, true, + platform::errors::InvalidArgument("scale of Op(interpolate) " + "should be greater than 0.")); } else { - scale = ctx.Attr("scale"); + 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 > 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 +1237,38 @@ 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]; + } + 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 = 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"); + 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); + 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/layers/nn.py b/python/paddle/fluid/layers/nn.py index 985db80a22297..74f3860a2f113 100644 --- a/python/paddle/fluid/layers/nn.py +++ b/python/paddle/fluid/layers/nn.py @@ -7461,7 +7461,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.") 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..156783acbd164 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") @@ -136,13 +138,19 @@ def setUp(self): in_h = self.input_shape[1] 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 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..890ea12282876 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" @@ -109,9 +111,16 @@ def setUp(self): in_h = self.input_shape[1] 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 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, + 'scale_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..1a770d7be3a41 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: @@ -86,7 +86,9 @@ 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) 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..5eba483bdaaef 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" @@ -88,9 +90,16 @@ def setUp(self): in_h = self.input_shape[1] 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 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..e3e79339089e5 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" @@ -142,10 +146,17 @@ def setUp(self): in_h = self.input_shape[2] 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 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 cc5ff8de5e99d..7ab810dad4b54 100644 --- a/python/paddle/nn/functional/common.py +++ b/python/paddle/nn/functional/common.py @@ -48,6 +48,7 @@ # 'bilinear_tensor_product', 'assign', 'interpolate', + 'upsample' 'cosine_similarity', ] @@ -57,7 +58,7 @@ def interpolate(input, scale_factor=None, mode='nearest', align_corners=False, - align_mode=1, + align_mode=0, data_format='NCHW', name=None): """ @@ -125,18 +126,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: @@ -202,15 +196,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 @@ -327,7 +321,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() @@ -442,10 +439,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( @@ -455,7 +470,199 @@ def _is_list_or_turple_(data): 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) + def pad(x, pad, mode='constant', value=0, data_format="NCHW", name=None): """ Pad tensor according to 'pad' and 'mode'. diff --git a/python/paddle/nn/layer/common.py b/python/paddle/nn/layer/common.py index c4823298f2035..aedf71e5d74c3 100644 --- a/python/paddle/nn/layer/common.py +++ b/python/paddle/nn/layer/common.py @@ -184,9 +184,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' @@ -234,7 +234,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] @@ -245,7 +245,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 @@ -268,6 +268,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