From ad50fa710bf530d7289823a0859426f674180f57 Mon Sep 17 00:00:00 2001 From: littletomatodonkey <2120160898@bit.edu.cn> Date: Thu, 25 Feb 2021 20:40:23 +0800 Subject: [PATCH] add int pad support for Pad1D/2D/3D (#31209) * add int pad support for Pad1D/2D/3D * fix type * fix format --- .../fluid/tests/unittests/test_pad3d_op.py | 33 +++++++++++++++++++ python/paddle/nn/layer/common.py | 24 ++++++++++---- 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/python/paddle/fluid/tests/unittests/test_pad3d_op.py b/python/paddle/fluid/tests/unittests/test_pad3d_op.py index 88d3d80a14..8dc825e60b 100644 --- a/python/paddle/fluid/tests/unittests/test_pad3d_op.py +++ b/python/paddle/fluid/tests/unittests/test_pad3d_op.py @@ -467,12 +467,15 @@ class TestPad1dAPI(unittest.TestCase): for place in self.places: input_shape = (3, 4, 5) pad = [1, 2] + pad_int = 1 value = 100 input_data = np.random.rand(*input_shape).astype(np.float32) pad_reflection = nn.Pad1D(padding=pad, mode="reflect") pad_replication = nn.Pad1D(padding=pad, mode="replicate") pad_constant = nn.Pad1D(padding=pad, mode="constant", value=value) + pad_constant_int = nn.Pad1D( + padding=pad_int, mode="constant", value=value) pad_circular = nn.Pad1D(padding=pad, mode="circular") data = paddle.to_tensor(input_data) @@ -492,6 +495,14 @@ class TestPad1dAPI(unittest.TestCase): input_data, pad, "constant", value=value, data_format="NCL") self.assertTrue(np.allclose(output.numpy(), np_out)) + output = pad_constant_int(data) + np_out = self._get_numpy_out( + input_data, [pad_int] * 2, + "constant", + value=value, + data_format="NCL") + self.assertTrue(np.allclose(output.numpy(), np_out)) + output = pad_circular(data) np_out = self._get_numpy_out( input_data, pad, "circular", value=value, data_format="NCL") @@ -541,12 +552,15 @@ class TestPad2dAPI(unittest.TestCase): for place in self.places: input_shape = (3, 4, 5, 6) pad = [1, 2, 2, 1] + pad_int = 1 value = 100 input_data = np.random.rand(*input_shape).astype(np.float32) pad_reflection = nn.Pad2D(padding=pad, mode="reflect") pad_replication = nn.Pad2D(padding=pad, mode="replicate") pad_constant = nn.Pad2D(padding=pad, mode="constant", value=value) + pad_constant_int = nn.Pad2D( + padding=pad_int, mode="constant", value=value) pad_circular = nn.Pad2D(padding=pad, mode="circular") data = paddle.to_tensor(input_data) @@ -566,6 +580,14 @@ class TestPad2dAPI(unittest.TestCase): input_data, pad, "constant", value=value, data_format="NCHW") self.assertTrue(np.allclose(output.numpy(), np_out)) + output = pad_constant_int(data) + np_out = self._get_numpy_out( + input_data, [pad_int] * 4, + "constant", + value=value, + data_format="NCHW") + self.assertTrue(np.allclose(output.numpy(), np_out)) + output = pad_circular(data) np_out = self._get_numpy_out( input_data, pad, "circular", data_format="NCHW") @@ -617,12 +639,15 @@ class TestPad3dAPI(unittest.TestCase): for place in self.places: input_shape = (3, 4, 5, 6, 7) pad = [1, 2, 2, 1, 1, 0] + pad_int = 1 value = 100 input_data = np.random.rand(*input_shape).astype(np.float32) pad_reflection = nn.Pad3D(padding=pad, mode="reflect") pad_replication = nn.Pad3D(padding=pad, mode="replicate") pad_constant = nn.Pad3D(padding=pad, mode="constant", value=value) + pad_constant_int = nn.Pad3D( + padding=pad_int, mode="constant", value=value) pad_circular = nn.Pad3D(padding=pad, mode="circular") data = paddle.to_tensor(input_data) @@ -642,6 +667,14 @@ class TestPad3dAPI(unittest.TestCase): input_data, pad, "constant", value=value, data_format="NCDHW") self.assertTrue(np.allclose(output.numpy(), np_out)) + output = pad_constant_int(data) + np_out = self._get_numpy_out( + input_data, [pad_int] * 6, + "constant", + value=value, + data_format="NCDHW") + self.assertTrue(np.allclose(output.numpy(), np_out)) + output = pad_circular(data) np_out = self._get_numpy_out( input_data, pad, "circular", data_format="NCDHW") diff --git a/python/paddle/nn/layer/common.py b/python/paddle/nn/layer/common.py index 05d619bd72..d0f97625bc 100644 --- a/python/paddle/nn/layer/common.py +++ b/python/paddle/nn/layer/common.py @@ -38,6 +38,13 @@ __all__ = [ ] +def _npairs(x, n): + if isinstance(x, (paddle.Tensor, list)): + return x + x = [x] * (n * 2) + return x + + class Linear(layers.Layer): r""" @@ -915,7 +922,8 @@ class Pad1D(layers.Layer): If mode is 'reflect', pad[0] and pad[1] must be no greater than width-1. Parameters: - padding (Tensor | List[int32]): The padding size with data type int32. [len(padding)/2] dimensions + padding (Tensor | List[int] | int): The padding size with data type int. If is int, use the + same padding in both dimensions. Else [len(padding)/2] dimensions of input will be padded. The pad has the form (pad_left, pad_right). mode (str): Four modes: 'constant' (default), 'reflect', 'replicate', 'circular'. When in 'constant' mode, this op uses a constant value to pad the input tensor. @@ -968,7 +976,7 @@ class Pad1D(layers.Layer): data_format="NCL", name=None): super(Pad1D, self).__init__() - self._pad = padding + self._pad = _npairs(padding, 1) self._mode = mode self._value = value self._data_format = data_format @@ -996,8 +1004,9 @@ class Pad2D(layers.Layer): than width-1. The height dimension has the same condition. Parameters: - padding (Tensor | List[int32]): The padding size with data type int32. [len(padding)/2] dimensions - of input will be padded. The pad has the form (pad_left, pad_right, pad_top, pad_bottom). + padding (Tensor | List[int] | int): The padding size with data type int. If is int, use the + same padding in all dimensions. Else [len(padding)/2] dimensions of input will be padded. + The pad has the form (pad_left, pad_right, pad_top, pad_bottom). 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. @@ -1051,7 +1060,7 @@ class Pad2D(layers.Layer): data_format="NCHW", name=None): super(Pad2D, self).__init__() - self._pad = padding + self._pad = _npairs(padding, 2) self._mode = mode self._value = value self._data_format = data_format @@ -1079,7 +1088,8 @@ class Pad3D(layers.Layer): than width-1. The height and depth dimension has the same condition. Parameters: - padding (Tensor | List[int32]): The padding size with data type int32. [len(padding)/2] dimensions + padding (Tensor | List[int] | int): The padding size with data type int. If is int, use the + same padding in all dimensions. Else [len(padding)/2] dimensions of input will be padded. 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. @@ -1134,7 +1144,7 @@ class Pad3D(layers.Layer): data_format="NCDHW", name=None): super(Pad3D, self).__init__() - self._pad = padding + self._pad = _npairs(padding, 3) self._mode = mode self._value = value self._data_format = data_format -- GitLab