From c8a1c14dec60177bd034f52f4b26dcd61ca98c26 Mon Sep 17 00:00:00 2001 From: cyberslack_lee Date: Tue, 12 Nov 2024 10:31:48 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90Paddle=20Tensor=20No.2=E3=80=91?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=20Tensor.=5F=5Frfloordiv=5F=5F=09=E5=A4=8D?= =?UTF-8?q?=E7=94=A8=E5=B7=B2=E6=9C=89=E6=8E=A5=E5=8F=A3=20Tensor.=5F=5Ffl?= =?UTF-8?q?oordiv=5F=5F=20(#69222)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix * add dygraph test * add dygraph test --- paddle/fluid/pybind/eager_math_op_patch.cc | 94 +++++++++++++++++++++ python/paddle/base/dygraph/math_op_patch.py | 1 + python/paddle/base/layers/math_op_patch.py | 8 ++ python/paddle/pir/math_op_patch.py | 7 ++ python/paddle/tensor/tensor.prototype.pyi | 3 +- test/legacy_test/test_math_op_patch.py | 13 +++ test/legacy_test/test_math_op_patch_pir.py | 7 +- 7 files changed, 130 insertions(+), 3 deletions(-) diff --git a/paddle/fluid/pybind/eager_math_op_patch.cc b/paddle/fluid/pybind/eager_math_op_patch.cc index 6696d77ee61f9..65288b0445425 100644 --- a/paddle/fluid/pybind/eager_math_op_patch.cc +++ b/paddle/fluid/pybind/eager_math_op_patch.cc @@ -1558,6 +1558,96 @@ static PyObject* tensor__floordiv__method(TensorObject* self, EAGER_CATCH_AND_THROW_RETURN_NULL } +static PyObject* tensor__rfloordiv__method(TensorObject* self, + PyObject* args, + PyObject* kwargs) { + phi::RecordEvent pythonc_record_event( + "__rfloordiv__ pybind_patch_func", phi::TracerEventType::UserDefined, 1); + EAGER_TRY + VLOG(6) << "Running Eager tensor__rfloordiv__method"; + + // Set Device ID + auto place = egr::Controller::Instance().GetExpectedPlace(); + SetDevice(place); + + paddle::Tensor ret; + paddle::Tensor self_tensor = self->tensor; + + PyObject* other_obj = PyTuple_GET_ITEM(args, 0); + + // 1. scalar exists cases or not + // there is no scalar case for rfloordiv, but alse need to cast self_tensor + // in need. + if (PyFloat_Check(other_obj) || PyCheckInteger(other_obj) || + IsNumpyType(other_obj)) { + if (PyFloat_Check(other_obj)) { + if (_supported_int_dtype_.find(self_tensor.dtype()) != + _supported_int_dtype_.end()) { + eager_gil_scoped_release guard; + self_tensor = cast_ad_func(self_tensor, DataType::FLOAT32); + } + } else if (PyCheckInteger(other_obj) && + self_tensor.dtype() == DataType::BOOL) { + eager_gil_scoped_release guard; + self_tensor = cast_ad_func(self_tensor, DataType::INT64); + } + } else if (PyComplex_Check(other_obj)) { + if (is_support_complex(self_tensor.dtype()) == false) { + eager_gil_scoped_release guard; + self_tensor = cast_ad_func( + self_tensor, promoteTypes(self_tensor.dtype(), DataType::COMPLEX64)); + } + } + + // 2. create or get tensor for other_obj + paddle::Tensor other_tensor; + if (PyCheckTensor(other_obj)) { + auto& self_tensor_ref_addr = self->tensor; + auto& other_tensor_ref_addr = CastPyArg2Tensor(other_obj, 0); + const phi::distributed::ProcessMesh* mesh = nullptr; + if (InputsContainDistTensor( + &mesh, self_tensor_ref_addr, other_tensor_ref_addr)) { + ConvertAllInputsToDistTensor( + mesh, self_tensor_ref_addr, other_tensor_ref_addr); + } + self_tensor = self_tensor_ref_addr; + other_tensor = other_tensor_ref_addr; + } else { + if (IsNumpyArray(other_obj)) { + py::object numpy_value = + py::reinterpret_borrow(py::handle(other_obj)); + other_tensor = paddle::empty({}, phi::DataType::FLOAT32, place); + InitTensorWithNumpyValue(numpy_value, place, &other_tensor); + } else { + paddle::experimental::Scalar value = + CastPyArg2Scalar(other_obj, "__rfloordiv__", 0); + if (PyComplex_Check(other_obj)) { + eager_gil_scoped_release guard; + other_tensor = + full_ad_func({1}, value, DataType::COMPLEX64, self_tensor.place()); + } else { + eager_gil_scoped_release guard; + other_tensor = + full_ad_func({1}, value, self_tensor.dtype(), self_tensor.place()); + } + } + const phi::distributed::ProcessMesh* mesh = nullptr; + if (InputsContainDistTensor(&mesh, self_tensor, other_tensor)) { + ConvertAllInputsToDistTensor(mesh, self_tensor, other_tensor); + } + } + + // 3. calculation + VLOG(6) << "Calling floor_divide_ad_func in tensor__rfloordiv__method"; + { + eager_gil_scoped_release guard; + ret = floor_divide_ad_func(other_tensor, self_tensor); + } + + return ToPyObject(ret); + EAGER_CATCH_AND_THROW_RETURN_NULL +} + static PyObject* tensor__pow__method(TensorObject* self, PyObject* args, PyObject* kwargs) { @@ -1973,6 +2063,10 @@ PyMethodDef math_op_patch_methods[] = { // NOLINT (PyCFunction)(void (*)())tensor__floordiv__method, METH_VARARGS | METH_KEYWORDS, nullptr}, + {"__rfloordiv__", + (PyCFunction)(void (*)())tensor__rfloordiv__method, + METH_VARARGS | METH_KEYWORDS, + nullptr}, {"__pow__", (PyCFunction)(void (*)())tensor__pow__method, METH_VARARGS | METH_KEYWORDS, diff --git a/python/paddle/base/dygraph/math_op_patch.py b/python/paddle/base/dygraph/math_op_patch.py index fc1c60d9f611c..739efb84f20c9 100644 --- a/python/paddle/base/dygraph/math_op_patch.py +++ b/python/paddle/base/dygraph/math_op_patch.py @@ -238,6 +238,7 @@ def _mT_(var: Tensor) -> Tensor: '__lt__', '__le__', '__floordiv__', + '__rfloordiv__', '__pow__', '__rpow__', '__eq__', diff --git a/python/paddle/base/layers/math_op_patch.py b/python/paddle/base/layers/math_op_patch.py index c5998120c9e77..f5185688f1aaa 100644 --- a/python/paddle/base/layers/math_op_patch.py +++ b/python/paddle/base/layers/math_op_patch.py @@ -54,6 +54,7 @@ "__truediv__", "__rtruediv__", "__floordiv__", + "__rfloordiv__", "__pow__", "__rpow__", "__eq__", @@ -78,6 +79,7 @@ "__pow__": "A ** B", "__rpow__": "A **= B", "__floordiv__": "A //B", + "__rfloordiv__": "A //=B", "__mod__": "A % B", "__rmod__": "A %= B", "__matmul__": "A @ B", @@ -860,6 +862,12 @@ def to_dense(var): '__floordiv__', 'elementwise_floordiv', False, None ), ), + ( + '__rfloordiv__', + _binary_creator_( + '__rfloordiv__', 'elementwise_floordiv', True, None + ), + ), ( '__mod__', _binary_creator_('__mod__', 'elementwise_mod', False, None), diff --git a/python/paddle/pir/math_op_patch.py b/python/paddle/pir/math_op_patch.py index 4842c1418a5fc..f17d210377462 100644 --- a/python/paddle/pir/math_op_patch.py +++ b/python/paddle/pir/math_op_patch.py @@ -50,6 +50,7 @@ "__truediv__", "__rtruediv__", "__floordiv__", + "__rfloordiv__", "__pow__", "__rpow__", "__eq__", @@ -1092,6 +1093,12 @@ def register_hook(self, hook): '__floordiv__', paddle.tensor.floor_divide, False, None ), ), + ( + '__rfloordiv__', + _binary_creator_( + '__rfloordiv__', paddle.tensor.floor_divide, True, None + ), + ), ( '__mod__', _binary_creator_('__mod__', paddle.tensor.remainder, False, None), diff --git a/python/paddle/tensor/tensor.prototype.pyi b/python/paddle/tensor/tensor.prototype.pyi index 8f9816b7cabd2..da473b8b145c9 100644 --- a/python/paddle/tensor/tensor.prototype.pyi +++ b/python/paddle/tensor/tensor.prototype.pyi @@ -178,7 +178,8 @@ class AbstractTensor: def __rtruediv__(self, y: _typing.TensorLike) -> Tensor: ... # type: ignore def __rmod__(self, y: _typing.TensorLike) -> Tensor: ... # type: ignore def __rpow__(self, y: _typing.TensorLike) -> Tensor: ... # type: ignore - def __rdiv__(self, y: _typing.TensorLike) -> Tensor: ... + def __rdiv__(self, y: _typing.TensorLike) -> Tensor: ... # type: ignore + def __rfloordiv__(self, y: _typing.TensorLike) -> Tensor: ... # type: ignore # type cast def __bool__(self) -> bool: ... diff --git a/test/legacy_test/test_math_op_patch.py b/test/legacy_test/test_math_op_patch.py index 803c3954c1199..22034acf2d392 100644 --- a/test/legacy_test/test_math_op_patch.py +++ b/test/legacy_test/test_math_op_patch.py @@ -484,6 +484,19 @@ def test_dygraph_floor_divide(self): np.testing.assert_equal(actual_out, expect_out) paddle.enable_static() + def test_dygraph_rfloordiv(self): + paddle.disable_static() + np_a = np.random.random((2, 3, 4)).astype(np.int32) + np_b = np.random.random((2, 3, 4)).astype(np.int32) + np_b[np.abs(np_b) < 1] = 2 + # normal case: nparray // tensor + tensor_a = paddle.to_tensor(np_a, dtype="int32") + tensor_b = paddle.to_tensor(np_b, dtype="int32") + expect_out = np_b // np_a + actual_out = tensor_b.__rfloordiv__(np_a) + np.testing.assert_equal(actual_out, expect_out) + paddle.enable_static() + def test_dygraph_elementwise_pow(self): paddle.disable_static() self.init_data() diff --git a/test/legacy_test/test_math_op_patch_pir.py b/test/legacy_test/test_math_op_patch_pir.py index 551a99eaa432a..7b2d39ab7ea03 100644 --- a/test/legacy_test/test_math_op_patch_pir.py +++ b/test/legacy_test/test_math_op_patch_pir.py @@ -143,6 +143,7 @@ def test_floordiv(self): paddle.to_tensor(x_np), paddle.to_tensor(y_np) ) res_np_d = x_np.__floordiv__(y_np) + res_np_e = x_np.__rfloordiv__(y_np) paddle.enable_static() with paddle.pir_utils.IrGuard(): main_program, exe, program_guard = new_program() @@ -156,14 +157,16 @@ def test_floordiv(self): b = x // y c = x.floor_divide(y) d = x.__floordiv__(y) - (b_np, c_np, d_np) = exe.run( + e = x.__rfloordiv__(y) + (b_np, c_np, d_np, e_np) = exe.run( main_program, feed={"x": x_np, "y": y_np}, - fetch_list=[b, c, d], + fetch_list=[b, c, d, e], ) np.testing.assert_allclose(res_np_b, b_np, atol=1e-05) np.testing.assert_allclose(res_np_c, c_np, atol=1e-05) np.testing.assert_allclose(res_np_d, d_np, atol=1e-05) + np.testing.assert_allclose(res_np_e, e_np, rtol=1e-05) def test_bitwise_not(self): paddle.disable_static()