From fe2bfe1587a76acddaf4a2e939a944121f75a658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=AD=E4=B8=AA=E9=AA=A8=E5=A4=B4?= <46243324+zrr1999@users.noreply.github.com> Date: Wed, 31 Aug 2022 14:27:37 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90PaddlePaddle=20Hackathon=203=20No.14?= =?UTF-8?q?=E3=80=91=E4=B8=BA=20Paddle=20=E6=96=B0=E5=A2=9E=20remainder=5F?= =?UTF-8?q?=20API=20(#45266)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../elementwise/elementwise_mod_op.cc | 3 +- python/paddle/__init__.py | 1 + .../unittests/test_elementwise_mod_op.py | 46 ++++++++++++++++++- .../fluid/tests/unittests/test_inplace.py | 23 ++++++++++ python/paddle/tensor/__init__.py | 2 + python/paddle/tensor/math.py | 18 ++++++++ 6 files changed, 90 insertions(+), 3 deletions(-) diff --git a/paddle/fluid/operators/elementwise/elementwise_mod_op.cc b/paddle/fluid/operators/elementwise/elementwise_mod_op.cc index 55d6e214d6c12..4caeaf4180f29 100644 --- a/paddle/fluid/operators/elementwise/elementwise_mod_op.cc +++ b/paddle/fluid/operators/elementwise/elementwise_mod_op.cc @@ -56,7 +56,8 @@ class ElementwiseModOpMaker : public ElementwiseOpMaker { namespace ops = paddle::operators; REGISTER_OP_WITHOUT_GRADIENT(elementwise_mod, ops::ElementwiseOp, - ops::ElementwiseModOpMaker); + ops::ElementwiseModOpMaker, + ops::ElementwiseOpInplaceInferer); REGISTER_OP_VERSION(elementwise_mod) .AddCheckpoint( diff --git a/python/paddle/__init__.py b/python/paddle/__init__.py index 61b9674ca730d..b39f4161eee97 100755 --- a/python/paddle/__init__.py +++ b/python/paddle/__init__.py @@ -239,6 +239,7 @@ from .tensor.math import divide # noqa: F401 from .tensor.math import floor_divide # noqa: F401 from .tensor.math import remainder # noqa: F401 +from .tensor.math import remainder_ # noqa: F401 from .tensor.math import mod # noqa: F401 from .tensor.math import floor_mod # noqa: F401 from .tensor.math import multiply # noqa: F401 diff --git a/python/paddle/fluid/tests/unittests/test_elementwise_mod_op.py b/python/paddle/fluid/tests/unittests/test_elementwise_mod_op.py index f51d101224366..eeccd8b976271 100644 --- a/python/paddle/fluid/tests/unittests/test_elementwise_mod_op.py +++ b/python/paddle/fluid/tests/unittests/test_elementwise_mod_op.py @@ -97,12 +97,15 @@ def init_dtype(self): class TestRemainderOp(unittest.TestCase): + def _executed_api(self, x, y, name=None): + return paddle.remainder(x, y, name) + def test_name(self): with fluid.program_guard(fluid.Program()): x = fluid.data(name="x", shape=[2, 3], dtype="int64") y = fluid.data(name='y', shape=[2, 3], dtype='int64') - y_1 = paddle.remainder(x, y, name='div_res') + y_1 = self._executed_api(x, y, name='div_res') self.assertEqual(('div_res' in y_1.name), True) def test_dygraph(self): @@ -111,7 +114,7 @@ def test_dygraph(self): np_y = np.array([1, 5, 3, 3]).astype('int64') x = paddle.to_tensor(np_x) y = paddle.to_tensor(np_y) - z = paddle.remainder(x, y) + z = self._executed_api(x, y) np_z = z.numpy() z_expected = np.array([0, 3, 2, 1]) self.assertEqual((np_z == z_expected).all(), True) @@ -133,5 +136,44 @@ def test_dygraph(self): np.testing.assert_allclose(z_expected, z.numpy(), rtol=1e-05) +class TestRemainderInplaceOp(TestRemainderOp): + + def _executed_api(self, x, y, name=None): + return x.remainder_(y, name) + + +class TestRemainderInplaceBroadcastSuccess(unittest.TestCase): + + def init_data(self): + self.x_numpy = np.random.rand(2, 3, 4).astype('float') + self.y_numpy = np.random.rand(3, 4).astype('float') + + def test_broadcast_success(self): + paddle.disable_static() + self.init_data() + x = paddle.to_tensor(self.x_numpy) + y = paddle.to_tensor(self.y_numpy) + inplace_result = x.remainder_(y) + numpy_result = self.x_numpy % self.y_numpy + self.assertEqual((inplace_result.numpy() == numpy_result).all(), True) + paddle.enable_static() + + +class TestRemainderInplaceBroadcastSuccess2(TestRemainderInplaceBroadcastSuccess + ): + + def init_data(self): + self.x_numpy = np.random.rand(1, 2, 3, 1).astype('float') + self.y_numpy = np.random.rand(3, 1).astype('float') + + +class TestRemainderInplaceBroadcastSuccess3(TestRemainderInplaceBroadcastSuccess + ): + + def init_data(self): + self.x_numpy = np.random.rand(2, 3, 1, 5).astype('float') + self.y_numpy = np.random.rand(1, 3, 1, 5).astype('float') + + if __name__ == '__main__': unittest.main() diff --git a/python/paddle/fluid/tests/unittests/test_inplace.py b/python/paddle/fluid/tests/unittests/test_inplace.py index 7588339e95e1c..ce086024dc9a6 100644 --- a/python/paddle/fluid/tests/unittests/test_inplace.py +++ b/python/paddle/fluid/tests/unittests/test_inplace.py @@ -494,6 +494,29 @@ def inplace_api_processing(self, var): return var.subtract_(input_var_2) +class TestDygraphInplaceRemainder(TestDygraphInplaceAdd): + + def non_inplace_api_processing(self, var): + input_var_2 = paddle.to_tensor(self.input_var_numpy_2) + return var.remainder(input_var_2) + + def inplace_api_processing(self, var): + input_var_2 = paddle.to_tensor(self.input_var_numpy_2) + return var.remainder_(input_var_2) + + def test_leaf_inplace_var_error(self): + pass + + def test_backward_error(self): + pass + + def test_backward_success_1(self): + pass + + def test_backward_success_2(self): + pass + + class TestLossIsInplaceVar(unittest.TestCase): def func_test_loss_is_inplace_var(self): diff --git a/python/paddle/tensor/__init__.py b/python/paddle/tensor/__init__.py index 93decb4278efa..58dfa26cfe377 100755 --- a/python/paddle/tensor/__init__.py +++ b/python/paddle/tensor/__init__.py @@ -184,6 +184,7 @@ from .math import divide # noqa: F401 from .math import floor_divide # noqa: F401 from .math import remainder # noqa: F401 +from .math import remainder_ # noqa: F401 from .math import mod # noqa: F401 from .math import floor_mod # noqa: F401 from .math import multiply # noqa: F401 @@ -367,6 +368,7 @@ 'divide', 'floor_divide', 'remainder', + 'remainder_', 'mod', 'floor_mod', 'multiply', diff --git a/python/paddle/tensor/math.py b/python/paddle/tensor/math.py index 1d8b6a126152e..3c7e9424a3ba6 100644 --- a/python/paddle/tensor/math.py +++ b/python/paddle/tensor/math.py @@ -784,6 +784,24 @@ def remainder(x, y, name=None): return _elementwise_op(LayerHelper(op_type, **locals())) +@inplace_apis_in_dygraph_only +def remainder_(x, y, name=None): + r""" + Inplace version of ``remainder`` API, the output Tensor will be inplaced with input ``x``. + Please refer to :ref:`api_tensor_remainder`. + """ + op_type = 'elementwise_mod_' + axis = -1 + + out_shape = broadcast_shape(x.shape, y.shape) + if out_shape != x.shape: + raise ValueError( + "The shape of broadcast output {} is different from that of inplace tensor {} in the Inplace operation.".format( + out_shape, x.shape)) + + return _elementwise_op_in_dygraph(x, y, axis=axis, op_name=op_type) + + mod = remainder # noqa: F841 floor_mod = remainder # noqa: F841