From 8ac0344a4ba3f291fa170145504cbfd9ead03d2c Mon Sep 17 00:00:00 2001 From: Tao Luo Date: Wed, 1 Dec 2021 10:36:47 +0800 Subject: [PATCH] Add paddle.rad2deg and paddle.deg2rad (#37598) --- python/paddle/__init__.py | 4 + .../fluid/tests/unittests/test_deg2rad.py | 75 ++++++++++++ .../fluid/tests/unittests/test_rad2deg.py | 92 ++++++++++++++ python/paddle/tensor/__init__.py | 2 + python/paddle/tensor/math.py | 114 +++++++++++++++++- 5 files changed, 285 insertions(+), 2 deletions(-) create mode 100644 python/paddle/fluid/tests/unittests/test_deg2rad.py create mode 100644 python/paddle/fluid/tests/unittests/test_rad2deg.py diff --git a/python/paddle/__init__.py b/python/paddle/__init__.py index af42cbfc88e..73b186efed3 100755 --- a/python/paddle/__init__.py +++ b/python/paddle/__init__.py @@ -223,6 +223,8 @@ from .tensor.math import trunc # noqa: F401 from .tensor.math import digamma # noqa: F401 from .tensor.math import neg # noqa: F401 from .tensor.math import lgamma # noqa: F401 +from .tensor.math import rad2deg # noqa: F401 +from .tensor.math import deg2rad # noqa: F401 from .tensor.math import diff # noqa: F401 from .tensor.random import multinomial # noqa: F401 @@ -458,6 +460,8 @@ __all__ = [ # noqa 'ceil', 'atan', 'atan2', + 'rad2deg', + 'deg2rad', 'expand', 'broadcast_to', 'ones_like', diff --git a/python/paddle/fluid/tests/unittests/test_deg2rad.py b/python/paddle/fluid/tests/unittests/test_deg2rad.py new file mode 100644 index 00000000000..31219d5ab97 --- /dev/null +++ b/python/paddle/fluid/tests/unittests/test_deg2rad.py @@ -0,0 +1,75 @@ +# Copyright (c) 2019 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 +from op_test import OpTest + +paddle.enable_static() + + +class TestDeg2radAPI(unittest.TestCase): + def setUp(self): + self.x_dtype = 'float64' + self.x_np = np.array( + [180.0, -180.0, 360.0, -360.0, 90.0, -90.0]).astype(np.float64) + self.x_shape = [6] + self.out_np = np.deg2rad(self.x_np) + + def test_static_graph(self): + startup_program = fluid.Program() + train_program = fluid.Program() + with fluid.program_guard(startup_program, train_program): + x = fluid.data(name='input', dtype=self.x_dtype, shape=self.x_shape) + out = paddle.deg2rad(x) + + place = fluid.CUDAPlace(0) if core.is_compiled_with_cuda( + ) else fluid.CPUPlace() + exe = fluid.Executor(place) + res = exe.run(fluid.default_main_program(), + feed={'input': self.x_np}, + fetch_list=[out]) + self.assertTrue((np.array(out[0]) == self.out_np).all()) + + def test_dygraph(self): + paddle.disable_static() + x1 = paddle.to_tensor([180.0, -180.0, 360.0, -360.0, 90.0, -90.0]) + result1 = paddle.deg2rad(x1) + self.assertEqual(np.allclose(self.out_np, result1.numpy()), True) + + paddle.enable_static() + + +class TestDeg2radAPI2(TestDeg2radAPI): + # Test input data type is int + def setUp(self): + self.x_np = 180 + self.x_shape = [1] + self.out_np = np.pi + self.x_dtype = 'int64' + + def test_dygraph(self): + paddle.disable_static() + + x2 = paddle.to_tensor(180) + result2 = paddle.deg2rad(x2) + self.assertEqual(np.allclose(np.pi, result2.numpy()), True) + + paddle.enable_static() diff --git a/python/paddle/fluid/tests/unittests/test_rad2deg.py b/python/paddle/fluid/tests/unittests/test_rad2deg.py new file mode 100644 index 00000000000..9f117cbab9a --- /dev/null +++ b/python/paddle/fluid/tests/unittests/test_rad2deg.py @@ -0,0 +1,92 @@ +# Copyright (c) 2019 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 +from op_test import OpTest + +paddle.enable_static() + + +class TestRad2degAPI(unittest.TestCase): + def setUp(self): + self.x_dtype = 'float64' + self.x_np = np.array( + [3.142, -3.142, 6.283, -6.283, 1.570, -1.570]).astype(np.float64) + self.x_shape = [6] + self.out_np = np.rad2deg(self.x_np) + + def test_static_graph(self): + startup_program = fluid.Program() + train_program = fluid.Program() + with fluid.program_guard(startup_program, train_program): + x = fluid.data(name='input', dtype=self.x_dtype, shape=self.x_shape) + out = paddle.rad2deg(x) + + place = fluid.CUDAPlace(0) if core.is_compiled_with_cuda( + ) else fluid.CPUPlace() + exe = fluid.Executor(place) + res = exe.run(fluid.default_main_program(), + feed={'input': self.x_np}, + fetch_list=[out]) + self.assertTrue((np.array(out[0]) == self.out_np).all()) + + def test_dygraph(self): + paddle.disable_static() + x1 = paddle.to_tensor([3.142, -3.142, 6.283, -6.283, 1.570, -1.570]) + result1 = paddle.rad2deg(x1) + self.assertEqual(np.allclose(self.out_np, result1.numpy()), True) + + paddle.enable_static() + + +class TestRad2degAPI2(TestRad2degAPI): + def setUp(self): + self.x_np = np.pi / 2 + self.x_shape = [1] + self.out_np = 90 + self.x_dtype = 'float32' + + def test_dygraph(self): + paddle.disable_static() + + x2 = paddle.to_tensor(np.pi / 2) + result2 = paddle.rad2deg(x2) + self.assertEqual(np.allclose(90, result2.numpy()), True) + + paddle.enable_static() + + +class TestRad2degAPI3(TestRad2degAPI): + # Test input data type is int + def setUp(self): + self.x_np = 1 + self.x_shape = [1] + self.out_np = 180 / np.pi + self.x_dtype = 'int64' + + def test_dygraph(self): + paddle.disable_static() + + x2 = paddle.to_tensor(1) + result2 = paddle.rad2deg(x2) + self.assertEqual(np.allclose(180 / np.pi, result2.numpy()), True) + + paddle.enable_static() diff --git a/python/paddle/tensor/__init__.py b/python/paddle/tensor/__init__.py index 23e956b6590..d8acb946a6d 100755 --- a/python/paddle/tensor/__init__.py +++ b/python/paddle/tensor/__init__.py @@ -189,6 +189,8 @@ from .math import digamma # noqa: F401 from .math import neg # noqa: F401 from .math import lgamma # noqa: F401 from .math import diagonal # noqa: F401 +from .math import rad2deg # noqa: F401 +from .math import deg2rad # noqa: F401 from .math import diff # noqa: F401 from .random import multinomial # noqa: F401 diff --git a/python/paddle/tensor/math.py b/python/paddle/tensor/math.py index 0a5930d91ad..66c3eaece76 100755 --- a/python/paddle/tensor/math.py +++ b/python/paddle/tensor/math.py @@ -2612,6 +2612,117 @@ def atan2(x, y, name=None): type='atan2', inputs=inputs, outputs={'Out': out}) return out +def rad2deg(x, name=None): + """ + Convert each of the elements of input x from angles in radians to degrees. + + Equation: + .. math:: + + rad2deg(x)=180/ \pi * x + + Args: + x (Tensor): An N-D Tensor, the data type is float32, float64, int32, int64. + name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`. + + Returns: + out (Tensor): An N-D Tensor, the shape and data type is the same with input (The output data type is float32 when the input data type is int). + + Examples: + .. code-block:: python + + import paddle + import numpy as np + + x1 = paddle.to_tensor([3.142, -3.142, 6.283, -6.283, 1.570, -1.570]) + result1 = paddle.rad2deg(x1) + print(result1) + # Tensor(shape=[6], dtype=float32, place=CUDAPlace(0), stop_gradient=True, + # [180.02334595, -180.02334595, 359.98937988, -359.98937988, + # 9.95437622 , -89.95437622]) + + x2 = paddle.to_tensor(np.pi/2) + result2 = paddle.rad2deg(x2) + print(result2) + # Tensor(shape=[1], dtype=float32, place=CUDAPlace(0), stop_gradient=True, + # [90.]) + + x3 = paddle.to_tensor(1) + result3 = paddle.rad2deg(x3) + print(result3) + # Tensor(shape=[1], dtype=float32, place=CUDAPlace(0), stop_gradient=True, + # [57.29578018]) + """ + rad2deg_scale = 180 / np.pi + if in_dygraph_mode(): + if convert_dtype(x.dtype) in ['int32', 'int64']: + x = cast(x, dtype="float32") + return _C_ops.scale(x, 'scale', rad2deg_scale) + else: + check_variable_and_dtype(x, 'x', ['int32', 'int64', 'float32', 'float64'], 'rad2deg') + helper = LayerHelper('rad2deg', **locals()) + out_cast = x + if convert_dtype(x.dtype) in ['int32', 'int64']: + out_cast = helper.create_variable_for_type_inference(dtype=paddle.float32) + helper.append_op( + type='cast', inputs={'X':x}, outputs={'Out': out_cast}, attrs={'in_dtype': x.dtype,'out_dtype': paddle.float32}) + out = helper.create_variable_for_type_inference(dtype=out_cast.dtype) + helper.append_op( + type='scale', inputs={'X':out_cast}, outputs={'Out': out}, attrs={'scale': rad2deg_scale}) + return out + +def deg2rad(x, name=None): + """ + Convert each of the elements of input x from degrees to angles in radians. + + Equation: + .. math:: + + deg2rad(x)=\pi * x / 180 + + Args: + x (Tensor): An N-D Tensor, the data type is float32, float64, int32, int64. + name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`. + + Returns: + out (Tensor): An N-D Tensor, the shape and data type is the same with input (The output data type is float32 when the input data type is int). + + Examples: + .. code-block:: python + + import paddle + import numpy as np + + x1 = paddle.to_tensor([180.0, -180.0, 360.0, -360.0, 90.0, -90.0]) + result1 = paddle.deg2rad(x1) + print(result1) + # Tensor(shape=[6], dtype=float32, place=CUDAPlace(0), stop_gradient=True, + # [3.14159274, -3.14159274, 6.28318548, -6.28318548, 1.57079637, + # -1.57079637]) + + x2 = paddle.to_tensor(180) + result2 = paddle.deg2rad(x2) + print(result2) + # Tensor(shape=[1], dtype=float32, place=CUDAPlace(0), stop_gradient=True, + # [3.14159274]) + """ + deg2rad_scale = np.pi / 180.0 + if in_dygraph_mode(): + if convert_dtype(x.dtype) in ['int32', 'int64']: + x = cast(x, dtype="float32") + return _C_ops.scale(x, 'scale', deg2rad_scale) + else: + check_variable_and_dtype(x, 'x', ['int32', 'int64', 'float32', 'float64'], 'deg2rad') + helper = LayerHelper('deg2rad', **locals()) + out_cast = x + if convert_dtype(x.dtype) in ['int32', 'int64']: + out_cast = helper.create_variable_for_type_inference(dtype=paddle.float32) + helper.append_op( + type='cast', inputs={'X':x}, outputs={'Out': out_cast}, attrs={'in_dtype': x.dtype,'out_dtype': paddle.float32}) + out = helper.create_variable_for_type_inference(dtype=out_cast.dtype) + helper.append_op( + type='scale', inputs={'X':out_cast}, outputs={'Out': out}, attrs={'scale': deg2rad_scale}) + return out def diff(x, n=1, axis=-1, prepend=None, append=None, name=None): r""" @@ -2646,6 +2757,7 @@ def diff(x, n=1, axis=-1, prepend=None, append=None, name=None): .. code-block:: python import paddle + x = paddle.to_tensor([1, 4, 5, 2]) out = paddle.diff(x) print(out) @@ -2667,8 +2779,6 @@ def diff(x, n=1, axis=-1, prepend=None, append=None, name=None): print(out) # out: # [[1, 1], [1, 1]] - - """ if axis < 0: -- GitLab