Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PaddlePaddle Hackathon] add paddle.zeropad2d #36383

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions python/paddle/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
from .tensor.creation import ones_like # noqa: F401
from .tensor.creation import zeros # noqa: F401
from .tensor.creation import zeros_like # noqa: F401
from .tensor.creation import zeropad2d # noqa: F401
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

需要添加到all列表中,另外需要实现paddle.nn.ZeroPad2d

from .tensor.creation import arange # noqa: F401
from .tensor.creation import full # noqa: F401
from .tensor.creation import full_like # noqa: F401
Expand Down Expand Up @@ -426,6 +427,7 @@
'tril',
'pow',
'zeros_like',
'zeropad2d',
'maximum',
'topk',
'index_select',
Expand Down
132 changes: 132 additions & 0 deletions python/paddle/fluid/tests/unittests/test_zeropad2d.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import numpy as np
import paddle
import unittest
from paddle import zeropad2d


class TestZeroPad2dError(unittest.TestCase):
"""
test paddle.zeropad2d error.
"""

def setUp(self):
"""
unsupport dtypes
"""
self.shape = [4, 3, 224, 224]
self.unsupport_dtypes = ['bool', 'int8']

def test_unsupport_dtypes(self):
"""
test unsupport dtypes.
"""
for dtype in self.unsupport_dtypes:
pad = 2
x = np.random.randint(-255, 255, size=self.shape)
x_tensor = paddle.to_tensor(x).astype(dtype)
self.assertRaises(RuntimeError, zeropad2d, x=x_tensor, pad=pad)

def test_unsupport_pad1(self):
"""
test length of 'pad' not equal 4.
"""
pad = [2, 2]
x = np.random.randint(-255, 255, size=self.shape)
x_tensor = paddle.to_tensor(x)
self.assertRaises(AssertionError, zeropad2d, x=x_tensor, pad=pad)


class TestZeroPad2d(unittest.TestCase):
"""
test paddle.zeropad2d
"""

def setUp(self):
"""
support dtypes
"""
self.shape = [4, 3, 224, 224]
self.support_dtypes = ['float32', 'float64', 'int32', 'int64']

def test_support_dtypes(self):
"""
test support types
"""
for dtype in self.support_dtypes:
pad = 2
x = np.random.randint(-255, 255, size=self.shape).astype(dtype)
expect_res = np.pad(x, [[0, 0], [0, 0], [pad, pad], [pad, pad]])

x_tensor = paddle.to_tensor(x).astype(dtype)
ret_res = paddle.zeropad2d(x_tensor, [pad, pad, pad, pad]).numpy()
self.assertTrue(np.allclose(expect_res, ret_res))

def test_support_pad1(self):
"""
test the type of 'pad' is int.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

int在上一个测例已经测过了,这里重复了吧

"""
pad = 2
x = np.random.randint(-255, 255, size=self.shape)
expect_res = np.pad(x, [[0, 0], [0, 0], [pad, pad], [pad, pad]])

x_tensor = paddle.to_tensor(x)
ret_res = paddle.zeropad2d(x_tensor, pad).numpy()
self.assertTrue(np.allclose(expect_res, ret_res))

def test_support_pad2(self):
"""
test the type of 'pad' is list.
"""
pad = [1, 2, 3, 4]
x = np.random.randint(-255, 255, size=self.shape)
expect_res = np.pad(
x, [[0, 0], [0, 0], [pad[2], pad[3]], [pad[0], pad[1]]])

x_tensor = paddle.to_tensor(x)
ret_res = paddle.zeropad2d(x_tensor, pad).numpy()
self.assertTrue(np.allclose(expect_res, ret_res))

def test_support_pad3(self):
"""
test the type of 'pad' is tuple.
"""
pad = (1, 2, 3, 4)
x = np.random.randint(-255, 255, size=self.shape)
expect_res = np.pad(
x, [[0, 0], [0, 0], [pad[2], pad[3]], [pad[0], pad[1]]])

x_tensor = paddle.to_tensor(x)
ret_res = paddle.zeropad2d(x_tensor, pad).numpy()
self.assertTrue(np.allclose(expect_res, ret_res))

def test_support_pad4(self):
"""
test the type of 'pad' is paddle.Tensor.
"""
pad = [1, 2, 3, 4]
x = np.random.randint(-255, 255, size=self.shape)
expect_res = np.pad(
x, [[0, 0], [0, 0], [pad[2], pad[3]], [pad[0], pad[1]]])

x_tensor = paddle.to_tensor(x)
pad_tensor = paddle.to_tensor(pad)
ret_res = paddle.zeropad2d(x_tensor, pad_tensor).numpy()
self.assertTrue(np.allclose(expect_res, ret_res))


if __name__ == '__main__':
unittest.main()
1 change: 1 addition & 0 deletions python/paddle/tensor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from .creation import ones_like # noqa: F401
from .creation import zeros # noqa: F401
from .creation import zeros_like # noqa: F401
from .creation import zeropad2d # noqa: F401
from .creation import arange # noqa: F401
from .creation import full # noqa: F401
from .creation import full_like # noqa: F401
Expand Down
62 changes: 62 additions & 0 deletions python/paddle/tensor/creation.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,68 @@ def zeros_like(x, dtype=None, name=None):
return full_like(x=x, fill_value=0, dtype=dtype, name=name)


def zeropad2d(x, pad, data_format="NCHW", name=None):
"""
Pads the input tensor boundaries with zero according to 'pad'.

Args:
x(Tensor): The input tensor with data type float32/float64/int32/int64.
pad(int | Tensor | List[int] | Tuple[int]): The padding size with data type int.
The input dimension should be 4 and pad has the form (pad_left, pad_right,
pad_top, pad_bottom).
data_format(str): An string from: "NHWC", "NCHW". Specify the data format of
the input data. Default: "NCHW".
name(str, optional): The default value is None. Normally there is no need for user
to set this property.

Returns: A Tensor padded according to pad and data type is same as input.
Returns: Tensor

Examples:
.. code-block:: python

import paddle
import numpy as np

x_shape = (1, 1, 2, 3)
x = paddle.arange(np.prod(x_shape), dtype="float32").reshape(x_shape) + 1
y = paddle.zeropad2d(x, [1, 2, 1, 1])
# [[[[0. 0. 0. 0. 0. 0.]
# [0. 1. 2. 3. 0. 0.]
# [0. 4. 5. 6. 0. 0.]
# [0. 0. 0. 0. 0. 0.]]]]
"""
data_format = data_format.upper()
assert data_format in [
"NCHW", "NHWC"
], "data_format should be in one of [NCHW, NHWC], bug got {}".format(
data_format)

x_dim = len(x.shape)

assert x_dim == 4, "input tensor dimension should be 4, but got {}".format(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

输入Tensor一定要是4维吗

x_dim)

if isinstance(pad, int):
pad = [pad] * 4

assert isinstance(
pad, (paddle.Tensor, list, tuple)
), "pad type should be one of [paddle.Tensor, list, tuple], but got {}".format(
type(x))

if isinstance(pad, Variable):
pad = pad.numpy()
assert len(
pad
) == 4, "when the type of 'pad' is not int, the length of 'pad' shoud be 4."
pad = [pad[2], pad[3], pad[0], pad[1]]
out = core.ops.pad2d(x, "paddings", pad, "value", 0, "data_format",
data_format, "name", name)

return out


def eye(num_rows, num_columns=None, dtype=None, name=None):
"""

Expand Down