From 6ff19d6678f30bd1fc5307fb24a58ff554d38e42 Mon Sep 17 00:00:00 2001 From: zmxdream Date: Mon, 6 Dec 2021 17:27:42 +0800 Subject: [PATCH] [New API]add rot90 api (#37634) * update * update. test=develop * fix. test=develop * fix ut. test=develop * fix ut. test=develop * fix ut. test=develop * update. test=develop * fix ut. test=develop * fix ut. test=develop * fix sample code. test=develop * fix ut. test=develop * fix ut. test=develop * fix ut. test=develop * fix ut. test=develop * fix paddle.rot90 doc. test=develop * update ut. test=develop * fix. test=develop * fix .test=develop * fix .test=develop * fix doc. test=develop --- .../framework/heter_pipeline_trainer_test.cc | 2 - python/paddle/__init__.py | 2 + .../fluid/tests/unittests/test_rot90_op.py | 262 ++++++++++++++++++ python/paddle/tensor/__init__.py | 2 + python/paddle/tensor/manipulation.py | 86 ++++++ 5 files changed, 352 insertions(+), 2 deletions(-) create mode 100644 python/paddle/fluid/tests/unittests/test_rot90_op.py diff --git a/paddle/fluid/framework/heter_pipeline_trainer_test.cc b/paddle/fluid/framework/heter_pipeline_trainer_test.cc index af8eca32ee2..417c7685bcb 100644 --- a/paddle/fluid/framework/heter_pipeline_trainer_test.cc +++ b/paddle/fluid/framework/heter_pipeline_trainer_test.cc @@ -115,8 +115,6 @@ TEST(HeterPipelineTrainerTest, GPU) { t3.add_trainers(1); t3.add_trainers(1); t3.add_trainers(1); - t3.add_dump_fields("hello"); - t3.add_dump_param("fc_0"); auto* heter_section_param3 = t3.mutable_heter_section_param(); heter_section_param3->set_num_pipeline_stages(3); heter_section_param3->set_pipeline_stage(2); diff --git a/python/paddle/__init__.py b/python/paddle/__init__.py index c37c331bae4..661cd495b53 100755 --- a/python/paddle/__init__.py +++ b/python/paddle/__init__.py @@ -150,6 +150,7 @@ from .tensor.manipulation import unsqueeze # noqa: F401 from .tensor.manipulation import unsqueeze_ # noqa: F401 from .tensor.manipulation import unstack # noqa: F401 from .tensor.manipulation import flip # noqa: F401 +from .tensor.manipulation import rot90 # noqa: F401 from .tensor.manipulation import unbind # noqa: F401 from .tensor.manipulation import roll # noqa: F401 from .tensor.manipulation import chunk # noqa: F401 @@ -408,6 +409,7 @@ __all__ = [ # noqa 'bitwise_not', 'mm', 'flip', + 'rot90', 'bincount', 'histogram', 'multiplex', diff --git a/python/paddle/fluid/tests/unittests/test_rot90_op.py b/python/paddle/fluid/tests/unittests/test_rot90_op.py new file mode 100644 index 00000000000..4ab7c4f14f9 --- /dev/null +++ b/python/paddle/fluid/tests/unittests/test_rot90_op.py @@ -0,0 +1,262 @@ +# 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. + +from __future__ import print_function + +import unittest +import numpy as np +import paddle +import paddle.fluid as fluid +import paddle.fluid.core as core +from paddle.fluid import Program, program_guard + + +class TestRot90_API(unittest.TestCase): + """Test rot90 api.""" + + def test_static_graph(self): + paddle.enable_static() + startup_program = fluid.Program() + train_program = fluid.Program() + with fluid.program_guard(train_program, startup_program): + input = fluid.data(name='input', dtype='float32', shape=[2, 3]) + output = paddle.rot90(input, k=1, axes=[0, 1]) + output = paddle.rot90(output, k=1, axes=[0, 1]) + output = output.rot90(k=1, axes=[0, 1]) + place = fluid.CPUPlace() + if fluid.core.is_compiled_with_cuda(): + place = fluid.CUDAPlace(0) + exe = fluid.Executor(place) + exe.run(startup_program) + + img = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.float32) + res = exe.run(train_program, + feed={'input': img}, + fetch_list=[output]) + + out_np = np.array(res[0]) + out_ref = np.array([[4, 1], [5, 2], [6, 3]]).astype(np.float32) + + self.assertTrue( + (out_np == out_ref).all(), + msg='rot90 output is wrong, out =' + str(out_np)) + + def test_static_k_0(self): + paddle.enable_static() + input = fluid.data(name='input', dtype='float32', shape=[2, 3]) + startup_program = fluid.Program() + train_program = fluid.Program() + with fluid.program_guard(train_program, startup_program): + input = fluid.data(name='input', dtype='float32', shape=[2, 3]) + output = paddle.rot90(input, k=0, axes=[0, 1]) + place = fluid.CPUPlace() + if fluid.core.is_compiled_with_cuda(): + place = fluid.CUDAPlace(0) + exe = fluid.Executor(place) + exe.run(startup_program) + + img = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.float32) + res = exe.run(train_program, + feed={'input': img}, + fetch_list=[output]) + + out_np = np.array(res[0]) + out_ref = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.float32) + + self.assertTrue( + (out_np == out_ref).all(), + msg='rot90 output is wrong, out =' + str(out_np)) + + def test_static_k_2(self): + paddle.enable_static() + input = fluid.data(name='input', dtype='float32', shape=[2, 3]) + startup_program = fluid.Program() + train_program = fluid.Program() + with fluid.program_guard(train_program, startup_program): + input = fluid.data(name='input', dtype='float32', shape=[2, 3]) + output = paddle.rot90(input, k=2, axes=[0, 1]) + place = fluid.CPUPlace() + if fluid.core.is_compiled_with_cuda(): + place = fluid.CUDAPlace(0) + exe = fluid.Executor(place) + exe.run(startup_program) + + img = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.float32) + res = exe.run(train_program, + feed={'input': img}, + fetch_list=[output]) + + out_np = np.array(res[0]) + out_ref = np.array([[6, 5, 4], [3, 2, 1]]).astype(np.float32) + + self.assertTrue( + (out_np == out_ref).all(), + msg='rot90 output is wrong, out =' + str(out_np)) + + def test_static_k_3(self): + paddle.enable_static() + input = fluid.data(name='input', dtype='float32', shape=[2, 3]) + startup_program = fluid.Program() + train_program = fluid.Program() + with fluid.program_guard(train_program, startup_program): + input = fluid.data(name='input', dtype='float32', shape=[2, 3]) + output = paddle.rot90(input, k=3, axes=[0, 1]) + place = fluid.CPUPlace() + if fluid.core.is_compiled_with_cuda(): + place = fluid.CUDAPlace(0) + exe = fluid.Executor(place) + exe.run(startup_program) + + img = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.float32) + res = exe.run(train_program, + feed={'input': img}, + fetch_list=[output]) + + out_np = np.array(res[0]) + out_ref = np.array([[4, 1], [5, 2], [6, 3]]).astype(np.float32) + + self.assertTrue( + (out_np == out_ref).all(), + msg='rot90 output is wrong, out =' + str(out_np)) + + def test_static_neg_k_1(self): + paddle.enable_static() + input = fluid.data(name='input', dtype='float32', shape=[2, 3]) + startup_program = fluid.Program() + train_program = fluid.Program() + with fluid.program_guard(train_program, startup_program): + input = fluid.data(name='input', dtype='float32', shape=[2, 3]) + output = paddle.rot90(input, k=-1, axes=[0, 1]) + place = fluid.CPUPlace() + if fluid.core.is_compiled_with_cuda(): + place = fluid.CUDAPlace(0) + exe = fluid.Executor(place) + exe.run(startup_program) + + img = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.float32) + res = exe.run(train_program, + feed={'input': img}, + fetch_list=[output]) + + out_np = np.array(res[0]) + out_ref = np.array([[4, 1], [5, 2], [6, 3]]).astype(np.float32) + + self.assertTrue( + (out_np == out_ref).all(), + msg='rot90 output is wrong, out =' + str(out_np)) + + def test_static_neg_k_2(self): + paddle.enable_static() + input = fluid.data(name='input', dtype='float32', shape=[2, 3]) + startup_program = fluid.Program() + train_program = fluid.Program() + with fluid.program_guard(train_program, startup_program): + input = fluid.data(name='input', dtype='float32', shape=[2, 3]) + output = paddle.rot90(input, k=-2, axes=[0, 1]) + place = fluid.CPUPlace() + if fluid.core.is_compiled_with_cuda(): + place = fluid.CUDAPlace(0) + exe = fluid.Executor(place) + exe.run(startup_program) + + img = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.float32) + res = exe.run(train_program, + feed={'input': img}, + fetch_list=[output]) + + out_np = np.array(res[0]) + out_ref = np.array([[6, 5, 4], [3, 2, 1]]).astype(np.float32) + + self.assertTrue( + (out_np == out_ref).all(), + msg='rot90 output is wrong, out =' + str(out_np)) + + def test_static_neg_k_3(self): + paddle.enable_static() + input = fluid.data(name='input', dtype='float32', shape=[2, 3]) + startup_program = fluid.Program() + train_program = fluid.Program() + with fluid.program_guard(train_program, startup_program): + input = fluid.data(name='input', dtype='float32', shape=[2, 3]) + output = paddle.rot90(input, k=-3, axes=[0, 1]) + place = fluid.CPUPlace() + if fluid.core.is_compiled_with_cuda(): + place = fluid.CUDAPlace(0) + exe = fluid.Executor(place) + exe.run(startup_program) + + img = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.float32) + res = exe.run(train_program, + feed={'input': img}, + fetch_list=[output]) + + out_np = np.array(res[0]) + out_ref = np.array([[3, 6], [2, 5], [1, 4]]).astype(np.float32) + + self.assertTrue( + (out_np == out_ref).all(), + msg='rot90 output is wrong, out =' + str(out_np)) + + def test_error_api(self): + paddle.enable_static() + + ## dims error + def run1(): + input = fluid.data(name='input', dtype='float32', shape=[2, 3]) + output = paddle.rot90(input, k=1, axes=[0]) + + self.assertRaises(ValueError, run1) + + ## input dims error + def run2(): + input = fluid.data(name='input', dtype='float32', shape=[2]) + output = paddle.rot90(input, k=1, axes=[0, 1]) + + self.assertRaises(ValueError, run2) + + def run3(): + input = fluid.data(name='input', dtype='float32', shape=[2, 3]) + output = paddle.rot90(input, k=1, axes=[0, 0]) + + self.assertRaises(ValueError, run3) + + def run4(): + input = fluid.data(name='input', dtype='float32', shape=[2, 3]) + output = paddle.rot90(input, k=1, axes=[3, 1]) + + self.assertRaises(ValueError, run4) + + def run5(): + input = fluid.data(name='input', dtype='float32', shape=[2, 3]) + output = paddle.rot90(input, k=1, axes=[0, 3]) + + self.assertRaises(ValueError, run5) + + def test_dygraph(self): + img = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.float32) + with fluid.dygraph.guard(): + inputs = fluid.dygraph.to_variable(img) + + ret = paddle.rot90(inputs, k=1, axes=[0, 1]) + ret = ret.rot90(1, axes=[0, 1]) + ret = paddle.rot90(ret, k=1, axes=[0, 1]) + out_ref = np.array([[4, 1], [5, 2], [6, 3]]).astype(np.float32) + + self.assertTrue( + (ret.numpy() == out_ref).all(), + msg='rot90 output is wrong, out =' + str(ret.numpy())) + + +if __name__ == "__main__": + unittest.main() diff --git a/python/paddle/tensor/__init__.py b/python/paddle/tensor/__init__.py index 7cc2c7623a9..793fdb89d06 100755 --- a/python/paddle/tensor/__init__.py +++ b/python/paddle/tensor/__init__.py @@ -106,6 +106,7 @@ from .manipulation import unsqueeze # noqa: F401 from .manipulation import unsqueeze_ # noqa: F401 from .manipulation import unstack # noqa: F401 from .manipulation import flip # noqa: F401 +from .manipulation import rot90 # noqa: F401 from .manipulation import unbind # noqa: F401 from .manipulation import roll # noqa: F401 from .manipulation import chunk # noqa: F401 @@ -370,6 +371,7 @@ tensor_method_func = [ #noqa 'unsqueeze_', 'unstack', 'flip', + 'rot90', 'unbind', 'roll', 'tile', diff --git a/python/paddle/tensor/manipulation.py b/python/paddle/tensor/manipulation.py index 9b9b2d9431e..f48e5a3a764 100644 --- a/python/paddle/tensor/manipulation.py +++ b/python/paddle/tensor/manipulation.py @@ -495,6 +495,92 @@ def flip(x, axis, name=None): return out +def rot90(x, k=1, axes=[0, 1], name=None): + """ + Rotate a n-D tensor by 90 degrees in the plane specified by dims axis. Rotation direction is from the first towards the second axis if k > 0, and from the second towards the first for k < 0. + + Args: + x (Tensor): The input Tensor(or LoDTensor). The data type of the input Tensor x + should be float32, float64, int32, int64, bool. + k (int): Number of times to rotate + axes (list|tuple): Axis to rotate + 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: + Tensor: Tensor or LoDTensor calculated by rot90 layer. The data type is same with input x. + + Raises: + TypeError: If the data type of ``x`` is not Variable + TypeError: If the dtype of ``x`` is not float16, float32, float64, int32, int64, bool + TypeError: If the data type of ``dims`` is not list, tuple + + Examples: + .. code-block:: python + + import paddle + import numpy as np + + data = paddle.arange(4) + data = paddle.reshape(data, (2, 2)) + print(data) ## [[0, 1],[2, 3]] + y = paddle.rot90(data, 1, [0, 1]) + print(y) #[[1, 3],[0, 2]] + y= paddle.rot90(data, -1, [0, 1]) + print(y) #[[2, 0],[3, 1]] + data2 = paddle.arange(8) + data2 = paddle.reshape(data2, (2,2,2)) + print(data2) ###[[[0, 1],[2, 3]],[[4, 5],[6, 7]]] + y = paddle.rot90(data2, 1, [1, 2]) + print(y) ### [[[1, 3],[0, 2]],[[5, 7],[4, 6]]] + """ + + helper = LayerHelper("rot90", **locals()) + check_type(x, 'X', (Variable), 'rot90') + dtype = helper.input_dtype('x') + check_dtype(dtype, 'X', + ['float16', 'float32', 'float64', 'int32', 'int64', 'bool'], + 'rot90') + check_type(axes, 'axes', (list, tuple), 'rot90') + + input_total_dims = len(x.shape) + total_rot_dims = len(axes) + if total_rot_dims != 2: + raise ValueError("expected total rotation axes == 2, but got axes = {}". + format(total_rot_dims)) + if input_total_dims < 2: + raise ValueError("expected total dims >= 2, but got total dims = {}". + format(input_total_dims)) + + if not (axes[0] != axes[1] and abs(axes[0] - axes[1]) != input_total_dims): + raise ValueError( + "expected rotation axes to be different, but got axis0 = {}, and axis1 = {}". + format(axes[0], axes[1])) + + if not (axes[0] < input_total_dims and axes[0] >= -input_total_dims): + raise ValueError("Rotation axis0 out of range, axis0 = {}".format(axes[ + 0])) + if not (axes[1] < input_total_dims and axes[1] >= -input_total_dims): + raise ValueError("Rotation axis1 out of range, axis1 = {}".format(axes[ + 1])) + + ## k % 4 + k = k % 4 if k >= 0 else 4 - (-k % 4) + if k == 0: + return x + if k == 2: + return flip(flip(x, axes[0]), axes[1]) + + axes_list = list(range(0, input_total_dims)) + (axes_list[axes[0]], axes_list[axes[1]]) = (axes_list[axes[1]], + axes_list[axes[0]]) + if k == 1: + return transpose(flip(x, axes[1]), axes_list) + else: + # k == 3 + return flip(transpose(x, axes_list), axes[1]) + + def flatten(x, start_axis=0, stop_axis=-1, name=None): r""" **Flatten op** -- GitLab