From 248e27b7c27db12df71bc85dd8138ded3e635f6d Mon Sep 17 00:00:00 2001 From: littletomatodonkey Date: Wed, 18 Aug 2021 18:50:47 +0800 Subject: [PATCH] fix pad outliers err (#34979) * fix pad outliers err * fix pad api input type and doc * fix example of pad * add unittest for pad3d * fix unittest * fix error format * fix pad doc --- paddle/fluid/operators/pad3d_op.cc | 7 ++ paddle/fluid/operators/pad3d_op.cu | 7 ++ .../fluid/tests/unittests/test_pad3d_op.py | 64 ++++++++++++------- python/paddle/nn/functional/common.py | 32 ++++++++-- python/paddle/nn/layer/common.py | 2 +- 5 files changed, 81 insertions(+), 31 deletions(-) diff --git a/paddle/fluid/operators/pad3d_op.cc b/paddle/fluid/operators/pad3d_op.cc index 0751cf25587..c2be9ac97ff 100644 --- a/paddle/fluid/operators/pad3d_op.cc +++ b/paddle/fluid/operators/pad3d_op.cc @@ -567,6 +567,13 @@ class Pad3dCPUKernel : public framework::OpKernel { in_width, pads[1])); } + if (mode == "circular") { + PADDLE_ENFORCE_NE( + in_depth * in_height * in_width, 0, + platform::errors::InvalidArgument( + "The input tensor size can not be 0 for circular padding mode.")); + } + const int pad_left = pads[0]; const int pad_top = pads[2]; const int pad_front = pads[4]; diff --git a/paddle/fluid/operators/pad3d_op.cu b/paddle/fluid/operators/pad3d_op.cu index 672a75389cc..ed936c10755 100644 --- a/paddle/fluid/operators/pad3d_op.cu +++ b/paddle/fluid/operators/pad3d_op.cu @@ -620,6 +620,13 @@ class Pad3dCUDAKernel : public framework::OpKernel { in_width, pads[1])); } + if (mode == "circular") { + PADDLE_ENFORCE_NE( + in_depth * in_height * in_width, 0, + platform::errors::InvalidArgument( + "The input tensor size can not be 0 for circular padding mode.")); + } + const int pad_left = pads[0]; const int pad_top = pads[2]; const int pad_front = pads[4]; diff --git a/python/paddle/fluid/tests/unittests/test_pad3d_op.py b/python/paddle/fluid/tests/unittests/test_pad3d_op.py index 8dc825e60bc..5ec7bdc66fe 100644 --- a/python/paddle/fluid/tests/unittests/test_pad3d_op.py +++ b/python/paddle/fluid/tests/unittests/test_pad3d_op.py @@ -682,46 +682,64 @@ class TestPad3dAPI(unittest.TestCase): class TestPad3dOpError(unittest.TestCase): + def setUp(self): + self.places = [paddle.CPUPlace()] + if core.is_compiled_with_cuda(): + self.places.append(paddle.CUDAPlace(0)) + def test_errors(self): def test_variable(): input_shape = (1, 2, 3, 4, 5) data = np.random.rand(*input_shape).astype(np.float32) - F.pad(x=data, paddings=[1, 1, 1, 1, 1, 1]) + y = F.pad(x=data, pad=[1, 1, 1, 1, 1, 1], data_format="NCDHW") def test_reflect_1(): input_shape = (1, 2, 3, 4, 5) data = np.random.rand(*input_shape).astype(np.float32) - x = paddle.fluid.data(name="x", shape=input_shape) - y = F.pad(x, pad=[5, 6, 1, 1, 1, 1], value=1, mode='reflect') - place = paddle.CPUPlace() - exe = Executor(place) - outputs = exe.run(feed={'x': data}, fetch_list=[y.name]) + x = paddle.to_tensor(data) + y = F.pad(x, + pad=[5, 6, 1, 1, 1, 1], + value=1, + mode='reflect', + data_format="NCDHW") def test_reflect_2(): input_shape = (1, 2, 3, 4, 5) data = np.random.rand(*input_shape).astype(np.float32) - x = paddle.fluid.data(name="x", shape=input_shape) - y = F.pad(x, pad=[1, 1, 4, 3, 1, 1], value=1, mode='reflect') - place = paddle.CPUPlace() - exe = Executor(place) - outputs = exe.run(feed={'x': data}, fetch_list=[y.name]) + x = paddle.to_tensor(data) + y = F.pad(x, + pad=[1, 1, 4, 3, 1, 1], + value=1, + mode='reflect', + data_format="NCDHW") def test_reflect_3(): input_shape = (1, 2, 3, 4, 5) data = np.random.rand(*input_shape).astype(np.float32) - x = paddle.fluid.data(name="x", shape=input_shape) - y = F.pad(x, pad=[1, 1, 1, 1, 2, 3], value=1, mode='reflect') - place = paddle.CPUPlace() - exe = Executor(place) - outputs = exe.run(feed={'x': data}, fetch_list=[y.name]) - - self.assertRaises(TypeError, test_variable) - - self.assertRaises(Exception, test_reflect_1) - - self.assertRaises(Exception, test_reflect_2) + x = paddle.to_tensor(data) + y = F.pad(x, + pad=[1, 1, 1, 1, 2, 3], + value=1, + mode='reflect', + data_format="NCDHW") + + def test_circular_1(): + input_shape = (1, 2, 0, 4, 5) + data = np.random.rand(*input_shape).astype(np.float32) + x = paddle.to_tensor(data) + y = F.pad(x, + pad=[1, 1, 1, 1, 2, 3], + mode='circular', + data_format="NCDHW") - self.assertRaises(Exception, test_reflect_3) + paddle.disable_static() + for place in self.places: + self.assertRaises(ValueError, test_variable) + self.assertRaises(Exception, test_reflect_1) + self.assertRaises(Exception, test_reflect_2) + self.assertRaises(Exception, test_reflect_3) + self.assertRaises(Exception, test_circular_1) + paddle.enable_static() class TestPadDataformatError(unittest.TestCase): diff --git a/python/paddle/nn/functional/common.py b/python/paddle/nn/functional/common.py index aee8ea2a3cc..4ead5f49d40 100644 --- a/python/paddle/nn/functional/common.py +++ b/python/paddle/nn/functional/common.py @@ -1160,12 +1160,13 @@ def pad(x, pad, mode='constant', value=0, data_format="NCHW", name=None): Parameters: x (Tensor): The input tensor with data type float32/double/int32/int64_t. - pad (Tensor | List[int32]): The padding size with data type int32. [len(padding)/2] dimensions - of input will be padded. 1. If input dimension is 3, then the pad has the form (pad_left, + pad (Tensor | List[int] | Tuple[int]): The padding size with data type int. + If mode is 'constant' and length of pad is twice as length of x dimension, then x will + be padded from the first dimension to the last dimension. + Else: 1. If input dimension is 3, then the pad has the form (pad_left, pad_right). 2. If the input dimension is 4, then the pad has the form (pad_left, pad_right, pad_top, pad_bottom). 3. If the input dimension is 5, then the pad has the form (pad_left, pad_right, pad_top, pad_bottom, pad_front, pad_back). - mode (str): Four modes: 'constant' (default), 'reflect', 'replicate', 'circular'. When in 'constant' mode, this op uses a constant value to pad the input tensor. When in 'reflect' mode, uses reflection of the input boundaries to pad the input tensor. @@ -1189,6 +1190,15 @@ def pad(x, pad, mode='constant', value=0, data_format="NCHW", name=None): [4., 5., 6.]]]]] Case 0: + pad = [0, 0, 0, 0, 0, 0, 1, 1, 0, 0], + mode = 'constant' + value = 0 + Out = [[[[[0., 0., 0.], + [1., 2., 3.], + [4., 5., 6.], + [0., 0., 0.]]]]] + + Case 1: pad = [2, 2, 1, 1, 0, 0], mode = 'constant' value = 0 @@ -1197,7 +1207,7 @@ def pad(x, pad, mode='constant', value=0, data_format="NCHW", name=None): [0. 0. 4. 5. 6. 0. 0.] [0. 0. 0. 0. 0. 0. 0.]]]]] - Case 1: + Case 2: pad = [2, 2, 1, 1, 0, 0], mode = 'reflect' Out = [[[[[6. 5. 4. 5. 6. 5. 4.] @@ -1205,7 +1215,7 @@ def pad(x, pad, mode='constant', value=0, data_format="NCHW", name=None): [6. 5. 4. 5. 6. 5. 4.] [3. 2. 1. 2. 3. 2. 1.]]]]] - Case 2: + Case 3: pad = [2, 2, 1, 1, 0, 0], mode = 'replicate' Out = [[[[[1. 1. 1. 2. 3. 3. 3.] @@ -1213,7 +1223,7 @@ def pad(x, pad, mode='constant', value=0, data_format="NCHW", name=None): [4. 4. 4. 5. 6. 6. 6.] [4. 4. 4. 5. 6. 6. 6.]]]]] - Case 3: + Case 4: pad = [2, 2, 1, 1, 0, 0], mode = 'circular' Out = [[[[[5. 6. 4. 5. 6. 4. 5.] @@ -1231,11 +1241,18 @@ def pad(x, pad, mode='constant', value=0, data_format="NCHW", name=None): # example 1 x_shape = (1, 1, 3) x = paddle.arange(np.prod(x_shape), dtype="float32").reshape(x_shape) + 1 - y = F.pad(x, [2, 3], value=1, mode='constant', data_format="NCL") + y = F.pad(x, [0, 0, 0, 0, 2, 3], value=1, mode='constant', data_format="NCL") print(y) # [[[1. 1. 1. 2. 3. 1. 1. 1.]]] # example 2 + x_shape = (1, 1, 3) + x = paddle.arange(np.prod(x_shape), dtype="float32").reshape(x_shape) + 1 + y = F.pad(x, [2, 3], value=1, mode='constant', data_format="NCL") + print(y) + # [[[1. 1. 1. 2. 3. 1. 1. 1.]]] + + # example 3 x_shape = (1, 1, 2, 3) x = paddle.arange(np.prod(x_shape), dtype="float32").reshape(x_shape) + 1 y = F.pad(x, [1, 2, 1, 1], value=1, mode='circular') @@ -1295,6 +1312,7 @@ def pad(x, pad, mode='constant', value=0, data_format="NCHW", name=None): unsqueezed_dim = [1] x = unsqueeze(x, axis=unsqueezed_dim) else: + pad = list(pad) if data_format in ["NCL", "NCHW", "NCDHW"]: data_format = "NCDHW" if x_dim == 3: diff --git a/python/paddle/nn/layer/common.py b/python/paddle/nn/layer/common.py index b88dc4bfe95..357c9bc7d40 100644 --- a/python/paddle/nn/layer/common.py +++ b/python/paddle/nn/layer/common.py @@ -24,7 +24,7 @@ __all__ = [] def _npairs(x, n): - if isinstance(x, (paddle.Tensor, list)): + if isinstance(x, (paddle.Tensor, list, tuple)): return x x = [x] * (n * 2) return x -- GitLab