From 186682febb3e331a1bb77814026bb2e11bb9ca90 Mon Sep 17 00:00:00 2001 From: FNRE <287246233@qq.com> Date: Tue, 20 Apr 2021 19:41:30 +0800 Subject: [PATCH] add paddle.nn.unfold #32297 (#32298) * add paddle.nn.unfold * update Parameters of Unfold --- .../fluid/tests/unittests/test_unfold_op.py | 28 ++++++++ python/paddle/nn/__init__.py | 1 + python/paddle/nn/layer/common.py | 71 +++++++++++++++++++ 3 files changed, 100 insertions(+) diff --git a/python/paddle/fluid/tests/unittests/test_unfold_op.py b/python/paddle/fluid/tests/unittests/test_unfold_op.py index e24368e052..7295cb8381 100644 --- a/python/paddle/fluid/tests/unittests/test_unfold_op.py +++ b/python/paddle/fluid/tests/unittests/test_unfold_op.py @@ -18,6 +18,9 @@ import math import numpy as np import unittest from op_test import OpTest +import paddle +import paddle.fluid as fluid +from paddle.fluid import core class TestUnfoldOp(OpTest): @@ -98,5 +101,30 @@ class TestUnfoldOp(OpTest): self.check_grad(['X'], 'Y') +class TestUnfoldAPI(TestUnfoldOp): + """ + This is for test on paddle.nn.Unfold + """ + + def setUp(self): + self.op_type = 'unfold' + self.set_data() + self.places = [fluid.CPUPlace()] + if core.is_compiled_with_cuda(): + self.places.append(fluid.CUDAPlace(0)) + + def test_dygraph(self): + for place in self.places: + with fluid.dygraph.guard(place): + input = fluid.dygraph.to_variable(self.inputs['X']) + m = paddle.nn.Unfold(**self.attrs) + m.eval() + result = m(input) + self.assertTrue(np.allclose(result.numpy(), self.outputs['Y'])) + + def test_info(self): + str(paddle.nn.Unfold(**self.attrs)) + + if __name__ == '__main__': unittest.main() diff --git a/python/paddle/nn/__init__.py b/python/paddle/nn/__init__.py index 79f21aadae..27d8f35234 100644 --- a/python/paddle/nn/__init__.py +++ b/python/paddle/nn/__init__.py @@ -83,6 +83,7 @@ from .layer.common import Dropout #DEFINE_ALIAS from .layer.common import Dropout2D #DEFINE_ALIAS from .layer.common import Dropout3D #DEFINE_ALIAS from .layer.common import AlphaDropout #DEFINE_ALIAS +from .layer.common import Unfold #DEFINE_ALIAS from .layer.pooling import AvgPool1D #DEFINE_ALIAS from .layer.pooling import AvgPool2D #DEFINE_ALIAS diff --git a/python/paddle/nn/layer/common.py b/python/paddle/nn/layer/common.py index 86a6fae0d6..2f71e5470f 100644 --- a/python/paddle/nn/layer/common.py +++ b/python/paddle/nn/layer/common.py @@ -35,6 +35,7 @@ __all__ = [ 'Dropout3D', 'Bilinear', 'AlphaDropout', + 'Unfold', ] @@ -1380,3 +1381,73 @@ class Embedding(layers.Layer): if self._name is not None: main_str += ', name={_name}' return main_str.format(**self.__dict__) + + +class Unfold(layers.Layer): + """ + This op returns a col buffer of sliding local blocks of input x, also known + as im2col for batched 2D image tensors. For each block under the convolution filter, + all element will be rearranged as a column. While the convolution filter sliding over + the input feature map, a series of such columns will be formed. + + For each input :math:`x` with shape [N, C, H, W], the output shape [N, Cout, Lout] + can be calculated as following. + + See ``paddle.nn.functional.unfold`` for more details. + + + Parameters: + kernel_sizes(int|list): The size of convolution kernel, should be [k_h, k_w] + or an integer k treated as [k, k]. + strides(int|list): The strides, should be [stride_h, stride_w] + or an integer stride treated as [sride, stride]. + For default, strides will be [1, 1]. + paddings(int|list): The paddings of each dimension, should be + [padding_top, padding_left, padding_bottom, padding_right] + or [padding_h, padding_w] or an integer padding. + If [padding_h, padding_w] was given, it will expanded to + [padding_h, padding_w, padding_h, padding_w]. If an integer + padding was given, [padding, padding, padding, padding] will + be used. For default, paddings will be [0, 0, 0, 0] + dilations(int|list): the dilations of convolution kernel, should be + [dilation_h, dilation_w], or an integer dilation treated as + [dilation, dilation]. For default, it will be [1, 1]. + 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` + + + Examples: + .. code-block:: python + + import paddle + import paddle.nn as nn + + x = paddle.randn((100,3,224,224)) + unfold = nn.Unfold(kernel_sizes=[3, 3]) + result = unfold(x) + print(result) + """ + + def __init__(self, + kernel_sizes, + dilations=1, + paddings=0, + strides=1, + name=None): + super(Unfold, self).__init__() + + self.kernel_sizes = kernel_sizes + self.dilations = dilations + self.paddings = paddings + self.strides = strides + self.name = name + + def forward(self, input): + return F.unfold(input, self.kernel_sizes, self.dilations, self.paddings, + self.strides, self.name) + + def extra_repr(self): + name_str = ', name={}'.format(self.name) if self.name else '' + return 'kernel_size={}, dilation={}, padding={}, stride={}{}'.\ + format(self.kernel_sizes, self.dilations, self.paddings, self.strides, name_str) -- GitLab