From 36b55f7bea3c44a85a2392f2556f7c5d1663104a Mon Sep 17 00:00:00 2001 From: yaoxuefeng6 Date: Wed, 1 Jul 2020 17:53:11 +0800 Subject: [PATCH 1/4] modify flip test=develop --- paddle/fluid/operators/flip_op.cc | 80 ++++++++++--------- .../paddle/fluid/tests/unittests/test_flip.py | 30 ++++--- python/paddle/tensor/manipulation.py | 13 ++- 3 files changed, 70 insertions(+), 53 deletions(-) diff --git a/paddle/fluid/operators/flip_op.cc b/paddle/fluid/operators/flip_op.cc index 7d0df5ffbd894..8888b206a6be8 100644 --- a/paddle/fluid/operators/flip_op.cc +++ b/paddle/fluid/operators/flip_op.cc @@ -39,43 +39,49 @@ class FlipOp : public framework::OperatorWithKernel { auto flip_dims = ctx->Attrs().Get>("dims"); size_t flip_dims_size = flip_dims.size(); - // check if dims axis within range - auto min_max_d = std::minmax_element(flip_dims.begin(), flip_dims.end()); - PADDLE_ENFORCE_LT(*min_max_d.first, x_dims.size(), - platform::errors::InvalidArgument( - "min(dims) should be less than the input tensor X's " - "dimensions of FlipOp. But received min(dims) = %d, " - "X's dimensions = %d, X's shape = [%s]", - *min_max_d.first, x_dims.size(), x_dims)); - PADDLE_ENFORCE_GE( - *min_max_d.first, x_dims.size() * -1, - platform::errors::InvalidArgument( - "min(dims) should be greater than or equal to the input tensor X's " - "dimensions of FlipOp times -1. But received min(dims) = %d, X's " - "dimensions = %d, X's shape = [%s]", - *min_max_d.first, x_dims.size() * -1, x_dims)); - PADDLE_ENFORCE_LT(*min_max_d.second, x_dims.size(), - platform::errors::InvalidArgument( - "max(dims) should be less than the input tensor X's " - "dimensions of FlipOp. But received max(dims) = %d, " - "X's dimensions = %d, X's shape = [%s]", - *min_max_d.second, x_dims.size(), x_dims)); - PADDLE_ENFORCE_GE( - *min_max_d.second, x_dims.size() * -1, - platform::errors::InvalidArgument( - "max(dims) should be greater than or equal to the input tensor X's " - "dimensions of FlipOp times -1. But received max(dims) = %d, X's " - "dimensions = %d, X's shape = [%s]", - *min_max_d.second, x_dims.size() * -1, x_dims)); - - // check duplicates in dims - flip_dims.erase(std::unique(flip_dims.begin(), flip_dims.end()), - flip_dims.end()); - PADDLE_ENFORCE_EQ(flip_dims.size(), flip_dims_size, - platform::errors::InvalidArgument( - "dims has duplicates, original flip dims size=%d, " - "but unique flip dims size=%d.)", - flip_dims_size, flip_dims.size())); + if (flip_dims_size > 0) { + // check if dims axis within range + auto min_max_d = std::minmax_element(flip_dims.begin(), flip_dims.end()); + PADDLE_ENFORCE_LT( + *min_max_d.first, x_dims.size(), + platform::errors::InvalidArgument( + "min(dims) should be less than the input tensor X's " + "dimensions of FlipOp. But received min(dims) = %d, " + "X's dimensions = %d, X's shape = [%s]", + *min_max_d.first, x_dims.size(), x_dims)); + PADDLE_ENFORCE_GE(*min_max_d.first, x_dims.size() * -1, + platform::errors::InvalidArgument( + "min(dims) should be greater than or equal to the " + "input tensor X's " + "dimensions of FlipOp times -1. But received " + "min(dims) = %d, X's " + "dimensions = %d, X's shape = [%s]", + *min_max_d.first, x_dims.size() * -1, x_dims)); + PADDLE_ENFORCE_LT( + *min_max_d.second, x_dims.size(), + platform::errors::InvalidArgument( + "max(dims) should be less than the input tensor X's " + "dimensions of FlipOp. But received max(dims) = %d, " + "X's dimensions = %d, X's shape = [%s]", + *min_max_d.second, x_dims.size(), x_dims)); + PADDLE_ENFORCE_GE(*min_max_d.second, x_dims.size() * -1, + platform::errors::InvalidArgument( + "max(dims) should be greater than or equal to the " + "input tensor X's " + "dimensions of FlipOp times -1. But received " + "max(dims) = %d, X's " + "dimensions = %d, X's shape = [%s]", + *min_max_d.second, x_dims.size() * -1, x_dims)); + + // check duplicates in dims + flip_dims.erase(std::unique(flip_dims.begin(), flip_dims.end()), + flip_dims.end()); + PADDLE_ENFORCE_EQ(flip_dims.size(), flip_dims_size, + platform::errors::InvalidArgument( + "dims has duplicates, original flip dims size=%d, " + "but unique flip dims size=%d.)", + flip_dims_size, flip_dims.size())); + } VLOG(3) << "flip operator x.shape=" << x_dims; diff --git a/python/paddle/fluid/tests/unittests/test_flip.py b/python/paddle/fluid/tests/unittests/test_flip.py index 77e416e5e6a73..777deb1b7f7ec 100644 --- a/python/paddle/fluid/tests/unittests/test_flip.py +++ b/python/paddle/fluid/tests/unittests/test_flip.py @@ -30,9 +30,9 @@ def test_static_graph(self): startup_program = fluid.Program() train_program = fluid.Program() with fluid.program_guard(train_program, startup_program): - dims = [0] + axis = [0] input = fluid.data(name='input', dtype='float32', shape=[2, 3]) - output = paddle.flip(input, dims) + output = paddle.flip(input, axis) place = fluid.CPUPlace() if fluid.core.is_compiled_with_cuda(): place = fluid.CUDAPlace(0) @@ -68,7 +68,7 @@ def setUp(self): self.outputs = {'Out': self.calc_ref_res()} def init_attrs(self): - self.attrs = {"dims": self.dims} + self.attrs = {"dims": self.axis} def test_check_output(self): self.check_output() @@ -78,11 +78,11 @@ def test_check_grad(self): def init_test_case(self): self.in_shape = (6, 4, 2, 3) - self.dims = [0, 1] + self.axis = [0, 1] def calc_ref_res(self): res = self.inputs['X'] - for axis in self.dims: + for axis in self.axis: res = np.flip(res, axis) return res @@ -90,25 +90,37 @@ def calc_ref_res(self): class TestFlipOpAxis1(TestFlipOp): def init_test_case(self): self.in_shape = (2, 4, 4) - self.dims = [0] + self.axis = [0] class TestFlipOpAxis2(TestFlipOp): def init_test_case(self): self.in_shape = (4, 4, 6, 3) - self.dims = [0, 2] + self.axis = [0, 2] class TestFlipOpAxis3(TestFlipOp): def init_test_case(self): self.in_shape = (4, 3, 1) - self.dims = [0, 1, 2] + self.axis = [0, 1, 2] class TestFlipOpAxis4(TestFlipOp): def init_test_case(self): self.in_shape = (6, 4, 2, 2) - self.dims = [0, 1, 2, 3] + self.axis = [0, 1, 2, 3] + + +class TestFlipOpEmptyAxis(TestFlipOp): + def init_test_case(self): + self.in_shape = (6, 4, 2, 2) + self.axis = [] + + +class TestFlipOpNegAxis(TestFlipOp): + def init_test_case(self): + self.in_shape = (6, 4, 2, 2) + self.axis = [-1] if __name__ == "__main__": diff --git a/python/paddle/tensor/manipulation.py b/python/paddle/tensor/manipulation.py index a888b78ea9146..afd644803f0cf 100644 --- a/python/paddle/tensor/manipulation.py +++ b/python/paddle/tensor/manipulation.py @@ -51,18 +51,18 @@ ] -def flip(input, dims, name=None): +def flip(input, axis, name=None): """ :alias_main: paddle.flip :alias: paddle.flip,paddle.tensor.flip,paddle.tensor.manipulation.flip - Reverse the order of a n-D tensor along given axis in dims. + Reverse the order of a n-D tensor along given axis in axis. Args: input (Variable): A Tensor(or LoDTensor) with shape :math:`[N_1, N_2,..., N_k]` . The data type of the input Tensor should be float32, float64, int32, int64, bool. - dims (list): The axis to flip on. + axis (list): The axis to flip on. 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` . @@ -76,7 +76,7 @@ def flip(input, dims, name=None): import paddle.fluid as fluid import numpy as np input = fluid.data(name="x", shape=[-1, 2, 2], dtype='float32') - output = paddle.flip(input, dims=[0, 1]) + output = paddle.flip(input, axis=[0, 1]) exe = fluid.Executor(fluid.CPUPlace()) exe.run(fluid.default_startup_program()) img = np.arange(12).reshape((3,2,2)).astype(np.float32) @@ -89,8 +89,7 @@ def flip(input, dims, name=None): check_dtype(dtype, 'X', ['float16', 'float32', 'float64', 'int32', 'int64', 'bool'], 'flip') - check_type(dims, 'dims', (list, tuple), 'flip') - assert len(dims) > 0, 'len(dims) must be greater than 0.' + check_type(axis, 'axis', (list, tuple), 'flip') if name is None: out = helper.create_variable_for_type_inference(dtype) else: @@ -100,7 +99,7 @@ def flip(input, dims, name=None): type="flip", inputs={"X": input}, outputs={"Out": out}, - attrs={"dims": dims}) + attrs={"dims": axis}) return out From 281e6c32d674111adfc9d0680450db2670f02a95 Mon Sep 17 00:00:00 2001 From: yaoxuefeng6 Date: Mon, 6 Jul 2020 13:38:24 +0800 Subject: [PATCH 2/4] change attr name test=develop --- paddle/fluid/operators/flip_op.cc | 4 ++-- paddle/fluid/operators/flip_op.cu | 2 +- paddle/fluid/operators/flip_op.h | 2 +- python/paddle/fluid/tests/unittests/test_flip.py | 2 +- python/paddle/tensor/manipulation.py | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/paddle/fluid/operators/flip_op.cc b/paddle/fluid/operators/flip_op.cc index 8888b206a6be8..b198dbc1cc0db 100644 --- a/paddle/fluid/operators/flip_op.cc +++ b/paddle/fluid/operators/flip_op.cc @@ -36,7 +36,7 @@ class FlipOp : public framework::OperatorWithKernel { platform::errors::NotFound( "Output(Out) of FlipOp should not be null.")); auto x_dims = ctx->GetInputDim("X"); - auto flip_dims = ctx->Attrs().Get>("dims"); + auto flip_dims = ctx->Attrs().Get>("axis"); size_t flip_dims_size = flip_dims.size(); if (flip_dims_size > 0) { @@ -110,7 +110,7 @@ class FlipOpMaker : public framework::OpProtoAndCheckerMaker { void Make() override { AddInput("X", "(Tensor), The input tensor of flip op."); AddOutput("Out", "(Tensor), The output tensor of flip op."); - AddAttr>("dims", "The axes to flip on."); + AddAttr>("axis", "The axes to flip on."); AddComment(R"DOC( Flip Operator. Reverse the order of a n-D tensor along given axis in dims. diff --git a/paddle/fluid/operators/flip_op.cu b/paddle/fluid/operators/flip_op.cu index 41aae1e1f35a6..581a994ba84b5 100644 --- a/paddle/fluid/operators/flip_op.cu +++ b/paddle/fluid/operators/flip_op.cu @@ -81,7 +81,7 @@ class FlipKernel Tensor* out = ctx.Output("Out"); auto* in_data = x->data(); auto* out_data = out->mutable_data(ctx.GetPlace()); - auto flip_dims = ctx.template Attr>("dims"); + auto flip_dims = ctx.template Attr>("axis"); const int flip_dims_size = static_cast(flip_dims.size()); auto x_dims = x->dims(); diff --git a/paddle/fluid/operators/flip_op.h b/paddle/fluid/operators/flip_op.h index 73d73f5d0f2e0..b77827b782b1a 100644 --- a/paddle/fluid/operators/flip_op.h +++ b/paddle/fluid/operators/flip_op.h @@ -41,7 +41,7 @@ class FlipKernel void Compute(const framework::ExecutionContext& ctx) const override { const Tensor* x = ctx.Input("X"); Tensor* out = ctx.Output("Out"); - auto flip_dims = ctx.template Attr>("dims"); + auto flip_dims = ctx.template Attr>("axis"); auto x_dims = x->dims(); const int total_dims = x_dims.size(); diff --git a/python/paddle/fluid/tests/unittests/test_flip.py b/python/paddle/fluid/tests/unittests/test_flip.py index 777deb1b7f7ec..6feee9ce57306 100644 --- a/python/paddle/fluid/tests/unittests/test_flip.py +++ b/python/paddle/fluid/tests/unittests/test_flip.py @@ -68,7 +68,7 @@ def setUp(self): self.outputs = {'Out': self.calc_ref_res()} def init_attrs(self): - self.attrs = {"dims": self.axis} + self.attrs = {"axis": self.axis} def test_check_output(self): self.check_output() diff --git a/python/paddle/tensor/manipulation.py b/python/paddle/tensor/manipulation.py index afd644803f0cf..254c4abab464f 100644 --- a/python/paddle/tensor/manipulation.py +++ b/python/paddle/tensor/manipulation.py @@ -99,7 +99,7 @@ def flip(input, axis, name=None): type="flip", inputs={"X": input}, outputs={"Out": out}, - attrs={"dims": axis}) + attrs={"axis": axis}) return out From a300d7add0af342e7b33d183c1b0408939f70242 Mon Sep 17 00:00:00 2001 From: yaoxuefeng6 Date: Wed, 8 Jul 2020 17:28:11 +0800 Subject: [PATCH 3/4] bug fix test=develop --- paddle/fluid/operators/flip_op.cc | 34 ++++++++++++++-------------- python/paddle/tensor/manipulation.py | 32 ++++++++++++++------------ 2 files changed, 34 insertions(+), 32 deletions(-) diff --git a/paddle/fluid/operators/flip_op.cc b/paddle/fluid/operators/flip_op.cc index b198dbc1cc0db..fc17657594b7a 100644 --- a/paddle/fluid/operators/flip_op.cc +++ b/paddle/fluid/operators/flip_op.cc @@ -45,32 +45,32 @@ class FlipOp : public framework::OperatorWithKernel { PADDLE_ENFORCE_LT( *min_max_d.first, x_dims.size(), platform::errors::InvalidArgument( - "min(dims) should be less than the input tensor X's " - "dimensions of FlipOp. But received min(dims) = %d, " - "X's dimensions = %d, X's shape = [%s]", + "min(axes) should be less than the input tensor X's " + "axes of FlipOp. But received min(axes) = %d, " + "X's axes = %d, X's shape = [%s]", *min_max_d.first, x_dims.size(), x_dims)); PADDLE_ENFORCE_GE(*min_max_d.first, x_dims.size() * -1, platform::errors::InvalidArgument( - "min(dims) should be greater than or equal to the " + "min(axes) should be greater than or equal to the " "input tensor X's " - "dimensions of FlipOp times -1. But received " - "min(dims) = %d, X's " - "dimensions = %d, X's shape = [%s]", + "axes of FlipOp times -1. But received " + "min(axes) = %d, X's " + "axes = %d, X's shape = [%s]", *min_max_d.first, x_dims.size() * -1, x_dims)); PADDLE_ENFORCE_LT( *min_max_d.second, x_dims.size(), platform::errors::InvalidArgument( - "max(dims) should be less than the input tensor X's " - "dimensions of FlipOp. But received max(dims) = %d, " - "X's dimensions = %d, X's shape = [%s]", + "max(axes) should be less than the input tensor X's " + "axes of FlipOp. But received max(axes) = %d, " + "X's axes = %d, X's shape = [%s]", *min_max_d.second, x_dims.size(), x_dims)); PADDLE_ENFORCE_GE(*min_max_d.second, x_dims.size() * -1, platform::errors::InvalidArgument( - "max(dims) should be greater than or equal to the " + "max(axes) should be greater than or equal to the " "input tensor X's " - "dimensions of FlipOp times -1. But received " - "max(dims) = %d, X's " - "dimensions = %d, X's shape = [%s]", + "axes of FlipOp times -1. But received " + "max(axes) = %d, X's " + "axes = %d, X's shape = [%s]", *min_max_d.second, x_dims.size() * -1, x_dims)); // check duplicates in dims @@ -78,8 +78,8 @@ class FlipOp : public framework::OperatorWithKernel { flip_dims.end()); PADDLE_ENFORCE_EQ(flip_dims.size(), flip_dims_size, platform::errors::InvalidArgument( - "dims has duplicates, original flip dims size=%d, " - "but unique flip dims size=%d.)", + "axes has duplicates, original flip axes size=%d, " + "but unique flip axes size=%d.)", flip_dims_size, flip_dims.size())); } @@ -113,7 +113,7 @@ class FlipOpMaker : public framework::OpProtoAndCheckerMaker { AddAttr>("axis", "The axes to flip on."); AddComment(R"DOC( Flip Operator. - Reverse the order of a n-D tensor along given axis in dims. + Reverse the order of a n-D tensor along given axis in axes. )DOC"); } }; diff --git a/python/paddle/tensor/manipulation.py b/python/paddle/tensor/manipulation.py index 254c4abab464f..7ea7a4c869f74 100644 --- a/python/paddle/tensor/manipulation.py +++ b/python/paddle/tensor/manipulation.py @@ -51,7 +51,7 @@ ] -def flip(input, axis, name=None): +def flip(x, axis, name=None): """ :alias_main: paddle.flip :alias: paddle.flip,paddle.tensor.flip,paddle.tensor.manipulation.flip @@ -60,32 +60,34 @@ def flip(input, axis, name=None): Reverse the order of a n-D tensor along given axis in axis. Args: - input (Variable): A Tensor(or LoDTensor) with shape :math:`[N_1, N_2,..., N_k]` . The data type of the input Tensor + x (Variable): A Tensor(or LoDTensor) with shape :math:`[N_1, N_2,..., N_k]` . The data type of the input Tensor x should be float32, float64, int32, int64, bool. - axis (list): The axis to flip on. + axis (list): The axis(axes) to flip on. 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: - Variable: Tensor or LoDTensor calculated by flip layer. The data type is same with input. + Variable: Tensor or LoDTensor calculated by flip layer. The data type is same with input x. Examples: .. code-block:: python import paddle - import paddle.fluid as fluid import numpy as np - input = fluid.data(name="x", shape=[-1, 2, 2], dtype='float32') - output = paddle.flip(input, axis=[0, 1]) - exe = fluid.Executor(fluid.CPUPlace()) - exe.run(fluid.default_startup_program()) - img = np.arange(12).reshape((3,2,2)).astype(np.float32) - res = exe.run(fluid.default_main_program(), feed={'x':img}, fetch_list=[output]) - print(res) # [[[10,11][8, 9]],[[6, 7],[4, 5]] [[2, 3],[0, 1]]] + + paddle.enable_imperative() + + image_shape=(3, 2, 2) + x = np.arange(image_shape[0] * image_shape[1] * image_shape[2]).reshape(image_shape) + x = x.astype('float32') + img = paddle.imperative.to_variable(x) + out = paddle.flip(img, [0,1]) + + print(out) # [[[10,11][8, 9]],[[6, 7],[4, 5]] [[2, 3],[0, 1]]] """ helper = LayerHelper("flip", **locals()) - check_type(input, 'X', (Variable), 'flip') - dtype = helper.input_dtype() + check_type(x, 'X', (Variable), 'flip') + dtype = helper.input_dtype('x') check_dtype(dtype, 'X', ['float16', 'float32', 'float64', 'int32', 'int64', 'bool'], 'flip') @@ -97,7 +99,7 @@ def flip(input, axis, name=None): helper.append_op( type="flip", - inputs={"X": input}, + inputs={"X": x}, outputs={"Out": out}, attrs={"axis": axis}) return out From dfc3d125683c2cde8d89826d8b321749db9b78eb Mon Sep 17 00:00:00 2001 From: yaoxuefeng6 Date: Thu, 9 Jul 2020 18:23:33 +0800 Subject: [PATCH 4/4] modify flip on comments test=develop --- python/paddle/__init__.py | 2 +- python/paddle/tensor/__init__.py | 2 +- python/paddle/tensor/manipulation.py | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/python/paddle/__init__.py b/python/paddle/__init__.py index 9862ef8ac0692..d50be4498a314 100644 --- a/python/paddle/__init__.py +++ b/python/paddle/__init__.py @@ -107,7 +107,7 @@ from .tensor.manipulation import gather #DEFINE_ALIAS from .tensor.manipulation import gather_nd #DEFINE_ALIAS from .tensor.manipulation import reshape #DEFINE_ALIAS -from .tensor.manipulation import reverse #DEFINE_ALIAS +from .tensor.manipulation import flip as reverse #DEFINE_ALIAS from .tensor.manipulation import scatter #DEFINE_ALIAS from .tensor.manipulation import scatter_nd_add #DEFINE_ALIAS from .tensor.manipulation import scatter_nd #DEFINE_ALIAS diff --git a/python/paddle/tensor/__init__.py b/python/paddle/tensor/__init__.py index a96d112c8ea3b..62afe63471693 100644 --- a/python/paddle/tensor/__init__.py +++ b/python/paddle/tensor/__init__.py @@ -81,7 +81,7 @@ from .manipulation import gather #DEFINE_ALIAS from .manipulation import gather_nd #DEFINE_ALIAS from .manipulation import reshape #DEFINE_ALIAS -from .manipulation import reverse #DEFINE_ALIAS +from .manipulation import flip as reverse #DEFINE_ALIAS from .manipulation import scatter #DEFINE_ALIAS from .manipulation import scatter_nd_add #DEFINE_ALIAS from .manipulation import scatter_nd #DEFINE_ALIAS diff --git a/python/paddle/tensor/manipulation.py b/python/paddle/tensor/manipulation.py index 7ea7a4c869f74..5c42984f86915 100644 --- a/python/paddle/tensor/manipulation.py +++ b/python/paddle/tensor/manipulation.py @@ -28,7 +28,6 @@ from ..fluid.layers import expand_as #DEFINE_ALIAS from ..fluid.layers import flatten #DEFINE_ALIAS from ..fluid.layers import reshape #DEFINE_ALIAS -from ..fluid.layers import reverse #DEFINE_ALIAS from ..fluid.layers import scatter #DEFINE_ALIAS from ..fluid.layers import slice #DEFINE_ALIAS from ..fluid.layers import strided_slice #DEFINE_ALIAS @@ -62,7 +61,7 @@ def flip(x, axis, name=None): Args: x (Variable): A Tensor(or LoDTensor) with shape :math:`[N_1, N_2,..., N_k]` . The data type of the input Tensor x should be float32, float64, int32, int64, bool. - axis (list): The axis(axes) to flip on. + axis (list): The axis(axes) to flip on. Negative indices for indexing from the end are accepted. 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` . @@ -105,6 +104,9 @@ def flip(x, axis, name=None): return out +reverse = flip #DEFINE_ALIAS + + def roll(input, shifts, dims=None): """ :alias_main: paddle.roll