2568 lines
90 KiB
C++
2568 lines
90 KiB
C++
/* Copyright (c) 2022 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. */
|
|
// disable numpy compile error
|
|
|
|
#if defined(_MSC_VER)
|
|
#include <BaseTsd.h>
|
|
typedef SSIZE_T ssize_t;
|
|
#endif
|
|
|
|
#include <Python.h>
|
|
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
#include "paddle/fluid/eager/api/all.h"
|
|
#include "paddle/fluid/eager/grad_node_info.h"
|
|
#include "paddle/fluid/eager/hooks.h"
|
|
#include "paddle/fluid/eager/utils.h"
|
|
#include "paddle/fluid/framework/convert_utils.h"
|
|
#include "paddle/fluid/platform/enforce.h"
|
|
#include "paddle/fluid/pybind/eager.h"
|
|
#include "paddle/fluid/pybind/eager_utils.h"
|
|
#include "paddle/fluid/pybind/exception.h"
|
|
#include "paddle/phi/api/include/api.h"
|
|
#include "paddle/phi/common/data_type.h"
|
|
#include "paddle/phi/core/compat/convert_utils.h"
|
|
#include "paddle/phi/core/dense_tensor.h"
|
|
#include "paddle/phi/core/memory/allocation/allocator.h"
|
|
#include "paddle/phi/core/memory/memcpy.h"
|
|
#include "pybind11/detail/internals.h"
|
|
#include "pybind11/numpy.h"
|
|
#include "pybind11/pybind11.h"
|
|
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
|
#include "paddle/common/ddim.h"
|
|
#include "paddle/common/flags.h"
|
|
#include "paddle/fluid/eager/api/generated/eager_generated/forwards/dygraph_functions.h"
|
|
#include "paddle/fluid/framework/data_type.h"
|
|
#include "paddle/fluid/framework/python_headers.h"
|
|
#include "paddle/fluid/pybind/op_function_common.h"
|
|
#include "paddle/fluid/pybind/tensor_py.h"
|
|
#include "paddle/phi/common/type_promotion.h"
|
|
#include "paddle/phi/core/memory/allocation/mmap_allocator.h"
|
|
#include "paddle/phi/kernels/funcs/math_function.h"
|
|
|
|
COMMON_DECLARE_bool(use_accuracy_compatible_kernel);
|
|
|
|
using egr::ConvertAllInputsToDistTensor;
|
|
using egr::InputsContainDistTensor;
|
|
|
|
namespace paddle::pybind {
|
|
|
|
static bool PyCheckInteger(PyObject* obj) {
|
|
return PyLong_Check(obj) && !PyBool_Check(obj);
|
|
}
|
|
|
|
static bool IsNumpyType(PyObject* obj) {
|
|
// It is not a good way to judge the type of obj by its type'name. Maybe using
|
|
// `PyArray_IsScalar` will be better. However, this interface cannot be used
|
|
// by including pybind11, and it needs to compile with numpy.
|
|
auto type_name = std::string(Py_TYPE(obj)->tp_name);
|
|
return type_name == "numpy.int64" || type_name == "numpy.longlong" ||
|
|
type_name == "numpy.int32" || type_name == "numpy.int16";
|
|
}
|
|
|
|
static bool IsNumpyArray(PyObject* obj) {
|
|
auto type_name = std::string(Py_TYPE(obj)->tp_name);
|
|
return type_name == "numpy.ndarray";
|
|
}
|
|
|
|
void InitTensorWithNumpyValue(const py::object& array,
|
|
const Place& place,
|
|
Tensor* self,
|
|
bool zero_copy = false) {
|
|
PADDLE_ENFORCE_EQ(
|
|
self->defined(),
|
|
true,
|
|
common::errors::Fatal(
|
|
"Calling InitTensorWithNumpyValue of Eager Tensor without "
|
|
"EmptyTensorInitializer is "
|
|
"forbidden. Please check your code and make sure you new a "
|
|
"eager tensor before init it with NumPy."));
|
|
phi::DenseTensor* impl_ptr =
|
|
static_cast<phi::DenseTensor*>(self->impl().get());
|
|
if (phi::is_cpu_place(place)) {
|
|
SetTensorFromPyArray<CPUPlace>(impl_ptr, array, place, zero_copy);
|
|
} else if (phi::is_xpu_place(place)) {
|
|
SetTensorFromPyArray<phi::XPUPlace>(impl_ptr, array, place, zero_copy);
|
|
} else if (phi::is_xpu_pinned_place(place)) {
|
|
SetTensorFromPyArray<phi::XPUPinnedPlace>(
|
|
impl_ptr, array, place, zero_copy);
|
|
} else if (phi::is_gpu_place(place)) {
|
|
SetTensorFromPyArray<GPUPlace>(impl_ptr, array, place, zero_copy);
|
|
} else if (phi::is_cuda_pinned_place(place)) {
|
|
SetTensorFromPyArray<phi::GPUPinnedPlace>(
|
|
impl_ptr, array, place, zero_copy);
|
|
} else if (phi::is_custom_place(place)) {
|
|
SetTensorFromPyArray<phi::CustomPlace>(impl_ptr, array, place, zero_copy);
|
|
} else {
|
|
PADDLE_THROW(common::errors::InvalidArgument(
|
|
"Place should be one of "
|
|
"CPUPlace/XPUPlace/CUDAPlace/CUDAPinnedPlace/CustomPlace"));
|
|
}
|
|
}
|
|
|
|
std::set<DataType> _supported_int_dtype_{DataType::UINT8,
|
|
DataType::INT8,
|
|
DataType::INT16,
|
|
DataType::INT32,
|
|
DataType::INT64,
|
|
DataType::BOOL};
|
|
std::set<DataType> _complex_dtypes{
|
|
DataType::COMPLEX64,
|
|
DataType::COMPLEX128,
|
|
};
|
|
|
|
// _supported_promote_complex_types_
|
|
// '__add__',
|
|
// '__radd__',
|
|
// '__sub__',
|
|
// '__rsub__',
|
|
// '__mul__',
|
|
// '__rmul__',
|
|
// '__div__',
|
|
// '__truediv__',
|
|
// '__rdiv__',
|
|
// '__rtruediv__',
|
|
// '__floordiv__',
|
|
// '__pow__',
|
|
// '__rpow__',
|
|
// '__mod__',
|
|
// '__rmod__',
|
|
// '__matmul__',
|
|
// '__gt__',
|
|
// '__ge__',
|
|
// '__lt__',
|
|
// '__le__',
|
|
// '__eq__',
|
|
// '__ne__'
|
|
|
|
void SetDevice(Place place) {
|
|
if (phi::is_gpu_place(place)) {
|
|
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
|
phi::backends::gpu::SetDeviceId(place.device);
|
|
VLOG(6) << "CurrentDeviceId: " << phi::backends::gpu::GetCurrentDeviceId()
|
|
<< " from " << static_cast<int>(place.device);
|
|
#else
|
|
PADDLE_THROW(common::errors::PreconditionNotMet(
|
|
"PaddlePaddle should compile with GPU if use CUDAPlace."));
|
|
#endif
|
|
}
|
|
|
|
if (phi::is_custom_place(place)) {
|
|
#if defined(PADDLE_WITH_CUSTOM_DEVICE)
|
|
phi::DeviceManager::SetDevice(place);
|
|
VLOG(6) << "CurrentDeviceId: "
|
|
<< phi::DeviceManager::GetDevice(place.GetDeviceType()) << " from "
|
|
<< static_cast<int>(place.device);
|
|
#else
|
|
PADDLE_THROW(common::errors::PreconditionNotMet(
|
|
"PaddlePaddle should compile with CUSTOM_DEVICE if use "
|
|
"CustomPlace."));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// scalar func only support add, radd, sub, rsub, mul, rmul, div, truediv.
|
|
// this function will update gradually.
|
|
Tensor CallScalarFunction(const Tensor& self_tensor,
|
|
double other,
|
|
std::string op_type) {
|
|
Tensor ret;
|
|
SetPythonStack();
|
|
// scale_ad_func need scalar and bias with float type.
|
|
if (op_type == "add" || op_type == "radd") {
|
|
ret = scale_ad_func(self_tensor, phi::Scalar(1.0), other, true);
|
|
} else if (op_type == "sub") {
|
|
ret = scale_ad_func(self_tensor, phi::Scalar(1.0), -other, true);
|
|
} else if (op_type == "rsub") {
|
|
ret = scale_ad_func(self_tensor, phi::Scalar(-1.0), other, true);
|
|
} else if (op_type == "mul") {
|
|
ret = scale_ad_func(self_tensor, phi::Scalar(other), 0.0, true);
|
|
} else if (op_type == "div") {
|
|
auto MPType = (self_tensor.dtype() == DataType::FLOAT16 ||
|
|
self_tensor.dtype() == DataType::BFLOAT16 ||
|
|
self_tensor.dtype() == DataType::FLOAT8_E5M2 ||
|
|
self_tensor.dtype() == DataType::FLOAT8_E4M3FN)
|
|
? DataType::FLOAT32
|
|
: self_tensor.dtype();
|
|
#if !defined(PADDLE_WITH_XPU)
|
|
PD_VISIT_BOOL_AND_FLOATING_AND_INTEGRAL_AND_COMPLEX_TYPES(
|
|
MPType, "CallScalarFunction", ([&] {
|
|
ret = div_scale_ad_func(self_tensor,
|
|
phi::Scalar(static_cast<data_t>(other)));
|
|
}));
|
|
#else
|
|
PD_VISIT_BOOL_AND_FLOATING_AND_INTEGRAL_AND_COMPLEX_TYPES(
|
|
MPType, "CallScalarFunction", ([&] {
|
|
ret = scale_ad_func(
|
|
self_tensor,
|
|
phi::Scalar(static_cast<data_t>(static_cast<data_t>(1.0) /
|
|
static_cast<data_t>(other))),
|
|
0.0,
|
|
true);
|
|
}));
|
|
#endif
|
|
} else if (op_type == "pow") {
|
|
ret = pow_ad_func(self_tensor, other);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void TypePromotionForZeroDimTensor(std::string func,
|
|
Tensor& self_tensor, // NOLINT
|
|
Tensor& other_tensor // NOLINT
|
|
) {
|
|
if ((self_tensor.shape().size() == 0 || other_tensor.shape().size() == 0) &&
|
|
self_tensor.dtype() != other_tensor.dtype()) {
|
|
VLOG(5) << "got 0-d tensor and need to do type promotion, x: "
|
|
<< self_tensor.dtype() << " y: " << other_tensor.dtype();
|
|
|
|
DataType promote_type;
|
|
// different major types or both 0-d tensor follow with T+T rule.
|
|
if (!is_common_dtype_for_scalar(self_tensor.dtype(),
|
|
other_tensor.dtype()) ||
|
|
(self_tensor.shape().size() == 0 && other_tensor.shape().size() == 0)) {
|
|
promote_type =
|
|
GetPromoteDtype(func, self_tensor.dtype(), other_tensor.dtype());
|
|
} else {
|
|
// common major types follow with tensor: int32(tensor) + int64(scalar)
|
|
// = int32
|
|
if (self_tensor.shape().size() == 0) {
|
|
promote_type = other_tensor.dtype();
|
|
} else {
|
|
promote_type = self_tensor.dtype();
|
|
}
|
|
}
|
|
SetPythonStack();
|
|
if (self_tensor.dtype() != promote_type) {
|
|
eager_gil_scoped_release guard;
|
|
self_tensor = cast_ad_func(self_tensor, promote_type);
|
|
}
|
|
if (other_tensor.dtype() != promote_type) {
|
|
eager_gil_scoped_release guard;
|
|
other_tensor = cast_ad_func(other_tensor, promote_type);
|
|
}
|
|
}
|
|
}
|
|
|
|
static PyObject* tensor__add__method(TensorObject* self,
|
|
PyObject* args,
|
|
PyObject* kwargs) {
|
|
phi::RecordEvent pythonc_record_event("__add__ or __radd_ pybind_patch_func",
|
|
phi::TracerEventType::UserDefined,
|
|
1);
|
|
|
|
EAGER_TRY
|
|
VLOG(6) << "Running Eager tensor__add__method";
|
|
|
|
SetPythonStack();
|
|
|
|
// Set Device ID
|
|
auto place = egr::Controller::Instance().GetExpectedPlace();
|
|
SetDevice(place);
|
|
|
|
Tensor ret;
|
|
Tensor self_tensor = self->tensor;
|
|
PyObject* other_obj = PyTuple_GET_ITEM(args, 0);
|
|
|
|
// 1. scalar exists cases
|
|
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);
|
|
}
|
|
|
|
double other = CastPyArg2Double(other_obj, "__add__", 0);
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = CallScalarFunction(self_tensor, other, "add");
|
|
}
|
|
return ToPyObject(ret);
|
|
} 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
|
|
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::object>(py::handle(other_obj));
|
|
other_tensor = paddle::empty({}, DataType::FLOAT32, place);
|
|
InitTensorWithNumpyValue(numpy_value, place, &other_tensor);
|
|
} else {
|
|
paddle::experimental::Scalar value;
|
|
// NOTE: call reflected method of other_obj if cast failed
|
|
try {
|
|
value = CastPyArg2Scalar(other_obj, "__add__", 0);
|
|
} catch (...) {
|
|
PyObject* radd = PyObject_GetAttrString(other_obj, "__radd__");
|
|
if (radd) {
|
|
bool has_callable_radd = PyCallable_Check(radd);
|
|
Py_DECREF(radd);
|
|
if (has_callable_radd) {
|
|
Py_INCREF(Py_NotImplemented);
|
|
return Py_NotImplemented;
|
|
}
|
|
}
|
|
throw;
|
|
}
|
|
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
other_tensor = full_ad_func(self_tensor.shape(),
|
|
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 add_ad_func in tensor__add__method";
|
|
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = add_ad_func(self_tensor, other_tensor);
|
|
}
|
|
|
|
return ToPyObject(ret);
|
|
|
|
EAGER_CATCH_AND_THROW_RETURN_NULL
|
|
}
|
|
|
|
static PyObject* tensor__sub__method(TensorObject* self,
|
|
PyObject* args,
|
|
PyObject* kwargs) {
|
|
phi::RecordEvent pythonc_record_event(
|
|
"__sub__ pybind_patch_func", phi::TracerEventType::UserDefined, 1);
|
|
|
|
EAGER_TRY
|
|
VLOG(6) << "Running Eager tensor__sub__method";
|
|
|
|
SetPythonStack();
|
|
|
|
// Set Device ID
|
|
auto place = egr::Controller::Instance().GetExpectedPlace();
|
|
SetDevice(place);
|
|
|
|
Tensor ret;
|
|
|
|
Tensor self_tensor = self->tensor;
|
|
PyObject* other_obj = PyTuple_GET_ITEM(args, 0);
|
|
// 1. scalar exists cases
|
|
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);
|
|
}
|
|
|
|
double other = CastPyArg2Double(other_obj, "__sub__", 0);
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = CallScalarFunction(self_tensor, other, "sub");
|
|
}
|
|
|
|
return ToPyObject(ret);
|
|
} 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
|
|
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::object>(py::handle(other_obj));
|
|
other_tensor = paddle::empty({}, DataType::FLOAT32, place);
|
|
InitTensorWithNumpyValue(numpy_value, place, &other_tensor);
|
|
} else {
|
|
paddle::experimental::Scalar value;
|
|
// NOTE: call reflected method of other_obj if cast failed
|
|
try {
|
|
value = CastPyArg2Scalar(other_obj, "__sub__", 0);
|
|
} catch (...) {
|
|
PyObject* rsub = PyObject_GetAttrString(other_obj, "__rsub__");
|
|
if (rsub) {
|
|
bool has_callable_rsub = PyCallable_Check(rsub);
|
|
Py_DECREF(rsub);
|
|
if (has_callable_rsub) {
|
|
Py_INCREF(Py_NotImplemented);
|
|
return Py_NotImplemented;
|
|
}
|
|
}
|
|
throw;
|
|
}
|
|
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
other_tensor = full_ad_func(self_tensor.shape(),
|
|
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 subtract_ad_func in tensor__sub__method";
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = subtract_ad_func(self_tensor, other_tensor);
|
|
}
|
|
|
|
return ToPyObject(ret);
|
|
EAGER_CATCH_AND_THROW_RETURN_NULL
|
|
}
|
|
|
|
static PyObject* tensor__rsub__method(TensorObject* self,
|
|
PyObject* args,
|
|
PyObject* kwargs) {
|
|
phi::RecordEvent pythonc_record_event(
|
|
"__rsub__ pybind_patch_func", phi::TracerEventType::UserDefined, 1);
|
|
|
|
EAGER_TRY
|
|
VLOG(4) << "Running Eager tensor__rsub__method";
|
|
|
|
SetPythonStack();
|
|
|
|
// Set Device ID
|
|
auto place = egr::Controller::Instance().GetExpectedPlace();
|
|
SetDevice(place);
|
|
|
|
Tensor ret;
|
|
Tensor self_tensor = self->tensor;
|
|
PyObject* other_obj = PyTuple_GET_ITEM(args, 0);
|
|
|
|
// 1. scalar exists cases
|
|
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);
|
|
}
|
|
|
|
double other = CastPyArg2Double(other_obj, "__rsub__", 0);
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = CallScalarFunction(self_tensor, other, "rsub");
|
|
}
|
|
return ToPyObject(ret);
|
|
} 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
|
|
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::object>(py::handle(other_obj));
|
|
other_tensor = paddle::empty({}, DataType::FLOAT32, place);
|
|
InitTensorWithNumpyValue(numpy_value, place, &other_tensor);
|
|
} else {
|
|
paddle::experimental::Scalar value =
|
|
CastPyArg2Scalar(other_obj, "__rsub__", 0);
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
other_tensor = full_ad_func(self_tensor.shape(),
|
|
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 subtract_ad_func in tensor__rsub__method";
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = subtract_ad_func(other_tensor, self_tensor);
|
|
}
|
|
|
|
return ToPyObject(ret);
|
|
EAGER_CATCH_AND_THROW_RETURN_NULL
|
|
}
|
|
|
|
static PyObject* tensor__mul__method(TensorObject* self,
|
|
PyObject* args,
|
|
PyObject* kwargs) {
|
|
phi::RecordEvent pythonc_record_event(
|
|
"__mul__ pybind_patch_func", phi::TracerEventType::UserDefined, 1);
|
|
|
|
EAGER_TRY
|
|
VLOG(6) << "Running Eager tensor__mul__method";
|
|
|
|
SetPythonStack();
|
|
|
|
// Set Device ID
|
|
auto place = egr::Controller::Instance().GetExpectedPlace();
|
|
SetDevice(place);
|
|
|
|
Tensor ret;
|
|
|
|
Tensor self_tensor = self->tensor;
|
|
PyObject* other_obj = PyTuple_GET_ITEM(args, 0);
|
|
|
|
// 1. scalar exists cases
|
|
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);
|
|
}
|
|
|
|
double other = CastPyArg2Double(other_obj, "__mul__", 0);
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = CallScalarFunction(self_tensor, other, "mul");
|
|
}
|
|
return ToPyObject(ret);
|
|
} 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
|
|
// if lhs or rhs input is tensor, we need to inplace cast it to dist_tensor
|
|
// if one of the input is numpy or scalar, no need to do inplace cast.
|
|
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::object>(py::handle(other_obj));
|
|
other_tensor = paddle::empty({}, DataType::FLOAT32, place);
|
|
InitTensorWithNumpyValue(numpy_value, place, &other_tensor);
|
|
} else {
|
|
// NOTE: For string types, return NotImplemented to allow Python to try to
|
|
// reflected method. This is the expected behavior per Python's data
|
|
// model: when the left operand doesn't support the operation with the
|
|
// right operand type, it should return NotImplemented so that the right
|
|
// operand's reflected method can be attempted. This avoids unintended
|
|
// string-to-number conversions (e.g., "a" -> 0) in the Scalar
|
|
// constructor.
|
|
if (PyObject_CheckString(other_obj)) {
|
|
Py_INCREF(Py_NotImplemented);
|
|
return Py_NotImplemented;
|
|
}
|
|
|
|
paddle::experimental::Scalar value;
|
|
|
|
// NOTE: call reflected method of other_obj if cast failed
|
|
try {
|
|
value = CastPyArg2Scalar(other_obj, "__mul__", 0);
|
|
} catch (...) {
|
|
PyObject* rmul = PyObject_GetAttrString(other_obj, "__rmul__");
|
|
if (rmul) {
|
|
bool has_callable_rmul = PyCallable_Check(rmul);
|
|
Py_DECREF(rmul);
|
|
if (has_callable_rmul) {
|
|
Py_INCREF(Py_NotImplemented);
|
|
return Py_NotImplemented;
|
|
}
|
|
}
|
|
throw;
|
|
}
|
|
|
|
if (PyComplex_Check(other_obj)) {
|
|
eager_gil_scoped_release guard;
|
|
other_tensor = full_ad_func(self_tensor.shape(),
|
|
value,
|
|
DataType::COMPLEX64,
|
|
self_tensor.place());
|
|
} else {
|
|
eager_gil_scoped_release guard;
|
|
other_tensor = full_ad_func(self_tensor.shape(),
|
|
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 multiply_ad_func in tensor__mul__method";
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = multiply_ad_func(self_tensor, other_tensor);
|
|
}
|
|
|
|
return ToPyObject(ret);
|
|
|
|
EAGER_CATCH_AND_THROW_RETURN_NULL
|
|
}
|
|
|
|
static PyObject* tensor__div__method(TensorObject* self,
|
|
PyObject* args,
|
|
PyObject* kwargs) {
|
|
phi::RecordEvent pythonc_record_event(
|
|
"__div__ pybind_patch_func", phi::TracerEventType::UserDefined, 1);
|
|
|
|
EAGER_TRY
|
|
|
|
VLOG(6) << "Running Eager tensor__div__method";
|
|
|
|
SetPythonStack();
|
|
|
|
// Set Device ID
|
|
auto place = egr::Controller::Instance().GetExpectedPlace();
|
|
SetDevice(place);
|
|
|
|
Tensor ret;
|
|
|
|
Tensor self_tensor = self->tensor;
|
|
PyObject* other_obj = PyTuple_GET_ITEM(args, 0);
|
|
|
|
// 1. scalar exists cases
|
|
if (PyFloat_Check(other_obj) || PyCheckInteger(other_obj) ||
|
|
IsNumpyType(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);
|
|
}
|
|
|
|
double other = CastPyArg2Double(other_obj, "__div__", 0);
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = CallScalarFunction(self_tensor, other, "div");
|
|
}
|
|
return ToPyObject(ret);
|
|
} 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
|
|
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::object>(py::handle(other_obj));
|
|
other_tensor = paddle::empty({}, DataType::FLOAT32, place);
|
|
InitTensorWithNumpyValue(numpy_value, place, &other_tensor);
|
|
} else {
|
|
paddle::experimental::Scalar value;
|
|
|
|
// NOTE: call reflected method of other_obj if cast failed
|
|
try {
|
|
value = CastPyArg2Scalar(other_obj, "__div__", 0);
|
|
} catch (...) {
|
|
PyObject* rdiv = PyObject_GetAttrString(other_obj, "__rdiv__");
|
|
if (rdiv) {
|
|
bool has_callable_rdiv = PyCallable_Check(rdiv);
|
|
Py_DECREF(rdiv);
|
|
if (has_callable_rdiv) {
|
|
Py_INCREF(Py_NotImplemented);
|
|
return Py_NotImplemented;
|
|
}
|
|
}
|
|
throw;
|
|
}
|
|
|
|
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(self_tensor.shape(),
|
|
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 divide_ad_func in tensor__div__method";
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = divide_ad_func(self_tensor, other_tensor);
|
|
}
|
|
|
|
return ToPyObject(ret);
|
|
EAGER_CATCH_AND_THROW_RETURN_NULL
|
|
}
|
|
|
|
static PyObject* tensor__rdiv__method(TensorObject* self,
|
|
PyObject* args,
|
|
PyObject* kwargs) {
|
|
phi::RecordEvent pythonc_record_event(
|
|
"__rdiv__ pybind_patch_func", phi::TracerEventType::UserDefined, 1);
|
|
EAGER_TRY
|
|
|
|
VLOG(6) << "Running Eager tensor__rdiv__method";
|
|
|
|
SetPythonStack();
|
|
|
|
// Set Device ID
|
|
auto place = egr::Controller::Instance().GetExpectedPlace();
|
|
SetDevice(place);
|
|
|
|
Tensor ret;
|
|
|
|
Tensor self_tensor = self->tensor;
|
|
PyObject* other_obj = PyTuple_GET_ITEM(args, 0);
|
|
|
|
// Use the torch-aligned rule (`other / self == self.reciprocal() * other`)
|
|
// only when FLAGS_use_accuracy_compatible_kernel is on and the backend is not
|
|
// XPU (XPU has no float reciprocal kernel). torch's Tensor.__rtruediv__ is
|
|
// `self.reciprocal() * other` on both CPU and GPU. Otherwise keep the
|
|
// original single-divide behavior. The two implementations are the two
|
|
// branches below.
|
|
if (FLAGS_use_accuracy_compatible_kernel && !phi::is_xpu_place(place)) {
|
|
// ===================== torch-aligned implementation =====================
|
|
// 1. scalar exists cases
|
|
// scalar / tensor is computed as tensor.reciprocal() * scalar. The scalar
|
|
// is kept in higher precision (MPType in ScaleFunctor, same as torch's
|
|
// opmath scalar) instead of being rounded to the tensor dtype by
|
|
// materializing a full tensor.
|
|
if (PyFloat_Check(other_obj) || PyCheckInteger(other_obj) ||
|
|
IsNumpyType(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);
|
|
}
|
|
double other = CastPyArg2Double(other_obj, "__rdiv__", 0);
|
|
VLOG(6) << "Calling reciprocal_ad_func and scale_ad_func in "
|
|
"tensor__rdiv__method";
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
Tensor recip = reciprocal_ad_func(self_tensor);
|
|
// bias is -0.0f so that `scale * x + bias` keeps the sign of negative
|
|
// zeros produced by the multiplication (a 0.0f bias would turn -0.0
|
|
// into +0.0), matching torch's `reciprocal() * scalar` bitwise.
|
|
ret = scale_ad_func(recip, phi::Scalar(other), -0.0f, true);
|
|
}
|
|
return ToPyObject(ret);
|
|
} 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
|
|
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::object>(py::handle(other_obj));
|
|
other_tensor = paddle::empty({}, DataType::FLOAT32, place);
|
|
InitTensorWithNumpyValue(numpy_value, place, &other_tensor);
|
|
} else {
|
|
paddle::experimental::Scalar value =
|
|
CastPyArg2Scalar(other_obj, "__rdiv__", 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(self_tensor.shape(),
|
|
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: other / self == self.reciprocal() * other
|
|
VLOG(6) << "Calling reciprocal_ad_func and multiply_ad_func in "
|
|
"tensor__rdiv__method";
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
if (_supported_int_dtype_.find(self_tensor.dtype()) !=
|
|
_supported_int_dtype_.end()) {
|
|
// torch's reciprocal promotes integral/bool tensors to float32.
|
|
self_tensor = cast_ad_func(self_tensor, DataType::FLOAT32);
|
|
}
|
|
Tensor recip = reciprocal_ad_func(self_tensor);
|
|
if (_supported_int_dtype_.find(other_tensor.dtype()) !=
|
|
_supported_int_dtype_.end()) {
|
|
other_tensor = cast_ad_func(other_tensor, recip.dtype());
|
|
}
|
|
ret = multiply_ad_func(recip, other_tensor);
|
|
}
|
|
return ToPyObject(ret);
|
|
} else {
|
|
// ======================= original implementation =======================
|
|
// 1. scalar exists cases
|
|
// there is no scalar_div function for __rdiv__ and __rtruediv__
|
|
if (PyFloat_Check(other_obj) || PyCheckInteger(other_obj) ||
|
|
IsNumpyType(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 (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
|
|
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::object>(py::handle(other_obj));
|
|
other_tensor = paddle::empty({}, DataType::FLOAT32, place);
|
|
InitTensorWithNumpyValue(numpy_value, place, &other_tensor);
|
|
} else {
|
|
paddle::experimental::Scalar value =
|
|
CastPyArg2Scalar(other_obj, "__rdiv__", 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(self_tensor.shape(),
|
|
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 divide_ad_func in tensor__rdiv__method";
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = divide_ad_func(other_tensor, self_tensor);
|
|
}
|
|
return ToPyObject(ret);
|
|
}
|
|
EAGER_CATCH_AND_THROW_RETURN_NULL
|
|
}
|
|
|
|
static PyObject* tensor__gt__method(TensorObject* self,
|
|
PyObject* args,
|
|
PyObject* kwargs) {
|
|
phi::RecordEvent pythonc_record_event(
|
|
"__gt__ pybind_patch_func", phi::TracerEventType::UserDefined, 1);
|
|
|
|
EAGER_TRY
|
|
VLOG(4) << "Running Eager tensor__gt__method";
|
|
|
|
SetPythonStack();
|
|
|
|
// Set Device ID
|
|
auto place = egr::Controller::Instance().GetExpectedPlace();
|
|
SetDevice(place);
|
|
|
|
Tensor ret;
|
|
Tensor self_tensor = self->tensor;
|
|
PyObject* other_obj = PyTuple_GET_ITEM(args, 0);
|
|
|
|
// 1. scalar exists cases
|
|
// there is no scalar function for __gt__ now
|
|
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
|
|
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::object>(py::handle(other_obj));
|
|
other_tensor = paddle::empty({}, DataType::FLOAT32, place);
|
|
InitTensorWithNumpyValue(numpy_value, place, &other_tensor);
|
|
} else {
|
|
paddle::experimental::Scalar value =
|
|
CastPyArg2Scalar(other_obj, "__gt__", 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(self_tensor.shape(),
|
|
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 greater_than_ad_func in tensor__gt__method";
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = greater_than_ad_func(self_tensor, other_tensor);
|
|
}
|
|
|
|
return ToPyObject(ret);
|
|
EAGER_CATCH_AND_THROW_RETURN_NULL
|
|
}
|
|
|
|
static PyObject* tensor__ge__method(TensorObject* self,
|
|
PyObject* args,
|
|
PyObject* kwargs) {
|
|
phi::RecordEvent pythonc_record_event(
|
|
"__ge__ pybind_patch_func", phi::TracerEventType::UserDefined, 1);
|
|
|
|
EAGER_TRY
|
|
VLOG(4) << "Running Eager tensor__ge__method";
|
|
|
|
SetPythonStack();
|
|
|
|
// Set Device ID
|
|
auto place = egr::Controller::Instance().GetExpectedPlace();
|
|
SetDevice(place);
|
|
|
|
Tensor ret;
|
|
Tensor self_tensor = self->tensor;
|
|
PyObject* other_obj = PyTuple_GET_ITEM(args, 0);
|
|
|
|
// 1. scalar exists cases
|
|
// there is no scalar function for __ge__ now
|
|
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
|
|
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::object>(py::handle(other_obj));
|
|
other_tensor = paddle::empty({}, DataType::FLOAT32, place);
|
|
InitTensorWithNumpyValue(numpy_value, place, &other_tensor);
|
|
} else {
|
|
paddle::experimental::Scalar value =
|
|
CastPyArg2Scalar(other_obj, "__ge__", 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(self_tensor.shape(),
|
|
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 greater_equal_ad_func in tensor__ge__method";
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = greater_equal_ad_func(self_tensor, other_tensor);
|
|
}
|
|
|
|
return ToPyObject(ret);
|
|
EAGER_CATCH_AND_THROW_RETURN_NULL
|
|
}
|
|
|
|
static PyObject* tensor__mod__method(TensorObject* self,
|
|
PyObject* args,
|
|
PyObject* kwargs) {
|
|
phi::RecordEvent pythonc_record_event(
|
|
"__mod__ pybind_patch_func", phi::TracerEventType::UserDefined, 1);
|
|
EAGER_TRY
|
|
|
|
VLOG(6) << "Running Eager tensor__mod__method";
|
|
|
|
SetPythonStack();
|
|
|
|
// Set Device ID
|
|
auto place = egr::Controller::Instance().GetExpectedPlace();
|
|
SetDevice(place);
|
|
|
|
Tensor ret;
|
|
|
|
Tensor self_tensor = self->tensor;
|
|
PyObject* other_obj = PyTuple_GET_ITEM(args, 0);
|
|
|
|
// 1. scalar exists cases
|
|
// there is no scalar_mod function for __mod__ now
|
|
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
|
|
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::object>(py::handle(other_obj));
|
|
other_tensor = paddle::empty({}, DataType::FLOAT32, place);
|
|
InitTensorWithNumpyValue(numpy_value, place, &other_tensor);
|
|
} else {
|
|
paddle::experimental::Scalar value;
|
|
|
|
// NOTE: call reflected method of other_obj if cast failed
|
|
try {
|
|
value = CastPyArg2Scalar(other_obj, "__mod__", 0);
|
|
} catch (...) {
|
|
PyObject* rmod = PyObject_GetAttrString(other_obj, "__rmod__");
|
|
if (rmod) {
|
|
bool has_callable_rmod = PyCallable_Check(rmod);
|
|
Py_DECREF(rmod);
|
|
if (has_callable_rmod) {
|
|
Py_INCREF(Py_NotImplemented);
|
|
return Py_NotImplemented;
|
|
}
|
|
}
|
|
throw;
|
|
}
|
|
|
|
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(self_tensor.shape(),
|
|
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 remainder_ad_func in tensor__mod__method";
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = remainder_ad_func(self_tensor, other_tensor);
|
|
}
|
|
return ToPyObject(ret);
|
|
EAGER_CATCH_AND_THROW_RETURN_NULL
|
|
}
|
|
|
|
static PyObject* tensor__rmod__method(TensorObject* self,
|
|
PyObject* args,
|
|
PyObject* kwargs) {
|
|
phi::RecordEvent pythonc_record_event(
|
|
"__rmod__ pybind_patch_func", phi::TracerEventType::UserDefined, 1);
|
|
EAGER_TRY
|
|
|
|
VLOG(6) << "Running Eager tensor__rmod__method";
|
|
|
|
SetPythonStack();
|
|
|
|
// Set Device ID
|
|
auto place = egr::Controller::Instance().GetExpectedPlace();
|
|
SetDevice(place);
|
|
|
|
Tensor ret;
|
|
|
|
Tensor self_tensor = self->tensor;
|
|
PyObject* other_obj = PyTuple_GET_ITEM(args, 0);
|
|
|
|
// 1. scalar exists cases
|
|
// there is no scalar_mod function for __rmod__ now
|
|
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
|
|
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::object>(py::handle(other_obj));
|
|
other_tensor = paddle::empty({}, DataType::FLOAT32, place);
|
|
InitTensorWithNumpyValue(numpy_value, place, &other_tensor);
|
|
} else {
|
|
paddle::experimental::Scalar value =
|
|
CastPyArg2Scalar(other_obj, "__rmod__", 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(self_tensor.shape(),
|
|
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 remainder_ad_func in tensor__rmod__method";
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = remainder_ad_func(other_tensor, self_tensor);
|
|
}
|
|
return ToPyObject(ret);
|
|
EAGER_CATCH_AND_THROW_RETURN_NULL
|
|
}
|
|
|
|
static PyObject* tensor__matmul__method(TensorObject* self,
|
|
PyObject* args,
|
|
PyObject* kwargs) {
|
|
phi::RecordEvent pythonc_record_event(
|
|
"__matmul__ pybind_patch_func", phi::TracerEventType::UserDefined, 1);
|
|
EAGER_TRY
|
|
|
|
VLOG(6) << "Running Eager tensor__matmul__method";
|
|
|
|
SetPythonStack();
|
|
|
|
// Set Device ID
|
|
auto place = egr::Controller::Instance().GetExpectedPlace();
|
|
SetDevice(place);
|
|
|
|
Tensor ret;
|
|
Tensor self_tensor = self->tensor;
|
|
|
|
PyObject* other_obj = PyTuple_GET_ITEM(args, 0);
|
|
|
|
// 1. scalar exists cases
|
|
// there is no scalar_matmul function for __matmul__ now
|
|
float other_double = 0.0f;
|
|
bool has_other_double = false;
|
|
if (PyFloat_Check(other_obj) || PyCheckInteger(other_obj) ||
|
|
IsNumpyType(other_obj)) {
|
|
if (PyFloat_Check(other_obj)) {
|
|
other_double = CastPyArg2Double(other_obj, "__matmul__", 0); // NOLINT
|
|
has_other_double = true;
|
|
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) || IsNumpyType(other_obj)) {
|
|
other_double = CastPyArg2Double(other_obj, "__matmul__", 0); // NOLINT
|
|
has_other_double = true;
|
|
}
|
|
}
|
|
|
|
// 2. create or get tensor for other_obj
|
|
Tensor other_tensor;
|
|
if (has_other_double) {
|
|
eager_gil_scoped_release guard;
|
|
other_tensor = full_ad_func({1},
|
|
phi::Scalar(other_double),
|
|
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);
|
|
}
|
|
} else if (PyCheckTensor(other_obj)) {
|
|
auto& self_tensor_ref = self->tensor;
|
|
auto& other_tensor_ref = CastPyArg2Tensor(other_obj, 0);
|
|
const phi::distributed::ProcessMesh* mesh = nullptr;
|
|
if (InputsContainDistTensor(&mesh, self_tensor_ref, other_tensor_ref)) {
|
|
ConvertAllInputsToDistTensor(mesh, self_tensor_ref, other_tensor_ref);
|
|
}
|
|
self_tensor = self_tensor_ref;
|
|
other_tensor = other_tensor_ref;
|
|
} else {
|
|
if (IsNumpyArray(other_obj)) {
|
|
py::object numpy_value =
|
|
py::reinterpret_borrow<py::object>(py::handle(other_obj));
|
|
other_tensor = paddle::empty({}, DataType::FLOAT32, place);
|
|
InitTensorWithNumpyValue(numpy_value, place, &other_tensor);
|
|
} else {
|
|
paddle::experimental::Scalar value;
|
|
|
|
// NOTE: call reflected method of other_obj if cast failed
|
|
try {
|
|
value = CastPyArg2Scalar(other_obj, "__matmul__", 0);
|
|
} catch (...) {
|
|
PyObject* rmatmul = PyObject_GetAttrString(other_obj, "__rmatmul__");
|
|
if (rmatmul) {
|
|
bool has_callable_rmatmul = PyCallable_Check(rmatmul);
|
|
Py_DECREF(rmatmul);
|
|
if (has_callable_rmatmul) {
|
|
Py_INCREF(Py_NotImplemented);
|
|
return Py_NotImplemented;
|
|
}
|
|
}
|
|
throw;
|
|
}
|
|
|
|
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. promote types or unify right var type to left var
|
|
DataType lhs_dtype = self_tensor.dtype();
|
|
DataType rhs_dtype = other_tensor.dtype();
|
|
if (lhs_dtype != rhs_dtype) {
|
|
// note: only op_type in _supported_promote_complex_types_ should promote
|
|
// dtype
|
|
if (_complex_dtypes.find(lhs_dtype) != _complex_dtypes.end() ||
|
|
_complex_dtypes.find(rhs_dtype) != _complex_dtypes.end()) {
|
|
DataType promote_dtype =
|
|
phi::TransToPhiDataType(framework::PromoteTypesIfComplexExists(
|
|
framework::TransToProtoVarType(lhs_dtype),
|
|
framework::TransToProtoVarType(rhs_dtype)));
|
|
if (lhs_dtype != promote_dtype) {
|
|
// cast
|
|
eager_gil_scoped_release guard;
|
|
self_tensor = cast_ad_func(self_tensor, promote_dtype);
|
|
}
|
|
if (rhs_dtype != promote_dtype) {
|
|
eager_gil_scoped_release guard;
|
|
other_tensor = cast_ad_func(other_tensor, promote_dtype);
|
|
}
|
|
} else {
|
|
VLOG(6) << "The dtype of left and right Tensor are not the same, left "
|
|
"dtype is "
|
|
<< lhs_dtype << ", but right dtype is " << rhs_dtype
|
|
<< ", the right dtype will convert to " << lhs_dtype;
|
|
eager_gil_scoped_release guard;
|
|
other_tensor = cast_ad_func(other_tensor, lhs_dtype);
|
|
}
|
|
}
|
|
|
|
// 4. calculation
|
|
VLOG(6) << "Calling matmul_ad_func in tensor__matmul__method";
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = matmul_ad_func(self_tensor, other_tensor, false, false);
|
|
}
|
|
return ToPyObject(ret);
|
|
EAGER_CATCH_AND_THROW_RETURN_NULL
|
|
}
|
|
|
|
static PyObject* tensor__rmatmul__method(TensorObject* self,
|
|
PyObject* args,
|
|
PyObject* kwargs) {
|
|
phi::RecordEvent pythonc_record_event(
|
|
"__rmatmul__ pybind_patch_func", phi::TracerEventType::UserDefined, 1);
|
|
EAGER_TRY
|
|
|
|
VLOG(6) << "Running Eager tensor__rmatmul__method";
|
|
|
|
SetPythonStack();
|
|
|
|
// Set Device ID
|
|
auto place = egr::Controller::Instance().GetExpectedPlace();
|
|
SetDevice(place);
|
|
|
|
Tensor ret;
|
|
Tensor self_tensor = self->tensor;
|
|
|
|
PyObject* other_obj = PyTuple_GET_ITEM(args, 0);
|
|
|
|
// 1. scalar exists cases
|
|
// there is no scalar_matmul function for __rmatmul__ now
|
|
float other_double = 0.0f;
|
|
bool has_other_double = false;
|
|
if (PyFloat_Check(other_obj) || PyCheckInteger(other_obj) ||
|
|
IsNumpyType(other_obj)) {
|
|
if (PyFloat_Check(other_obj)) {
|
|
other_double = CastPyArg2Double(other_obj, "__rmatmul__", 0); // NOLINT
|
|
has_other_double = true;
|
|
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) || IsNumpyType(other_obj)) {
|
|
other_double = CastPyArg2Double(other_obj, "__rmatmul__", 0); // NOLINT
|
|
has_other_double = true;
|
|
}
|
|
}
|
|
|
|
// 2. create or get tensor for other_obj
|
|
Tensor other_tensor;
|
|
if (has_other_double) {
|
|
eager_gil_scoped_release guard;
|
|
other_tensor = full_ad_func({1},
|
|
phi::Scalar(other_double),
|
|
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);
|
|
}
|
|
} else if (PyCheckTensor(other_obj)) {
|
|
auto& self_tensor_ref = self->tensor;
|
|
auto& other_tensor_ref = CastPyArg2Tensor(other_obj, 0);
|
|
const phi::distributed::ProcessMesh* mesh = nullptr;
|
|
if (InputsContainDistTensor(&mesh, self_tensor_ref, other_tensor_ref)) {
|
|
ConvertAllInputsToDistTensor(mesh, self_tensor_ref, other_tensor_ref);
|
|
}
|
|
self_tensor = self_tensor_ref;
|
|
other_tensor = other_tensor_ref;
|
|
} else {
|
|
if (IsNumpyArray(other_obj)) {
|
|
py::object numpy_value =
|
|
py::reinterpret_borrow<py::object>(py::handle(other_obj));
|
|
other_tensor = paddle::empty({}, DataType::FLOAT32, place);
|
|
InitTensorWithNumpyValue(numpy_value, place, &other_tensor);
|
|
} else {
|
|
paddle::experimental::Scalar value =
|
|
CastPyArg2Scalar(other_obj, "__matmul__", 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. promote types or unify right var type to left var
|
|
DataType lhs_dtype = self_tensor.dtype();
|
|
DataType rhs_dtype = other_tensor.dtype();
|
|
if (lhs_dtype != rhs_dtype) {
|
|
// note: only op_type in _supported_promote_complex_types_ should promote
|
|
// dtype
|
|
if (_complex_dtypes.find(lhs_dtype) != _complex_dtypes.end() ||
|
|
_complex_dtypes.find(rhs_dtype) != _complex_dtypes.end()) {
|
|
DataType promote_dtype =
|
|
phi::TransToPhiDataType(framework::PromoteTypesIfComplexExists(
|
|
framework::TransToProtoVarType(lhs_dtype),
|
|
framework::TransToProtoVarType(rhs_dtype)));
|
|
if (lhs_dtype != promote_dtype) {
|
|
// cast
|
|
eager_gil_scoped_release guard;
|
|
self_tensor = cast_ad_func(self_tensor, promote_dtype);
|
|
}
|
|
if (rhs_dtype != promote_dtype) {
|
|
eager_gil_scoped_release guard;
|
|
other_tensor = cast_ad_func(other_tensor, promote_dtype);
|
|
}
|
|
} else {
|
|
VLOG(6) << "The dtype of left and right Tensor are not the same, left "
|
|
"dtype is "
|
|
<< lhs_dtype << ", but right dtype is " << rhs_dtype
|
|
<< ", the right dtype will convert to " << lhs_dtype;
|
|
eager_gil_scoped_release guard;
|
|
other_tensor = cast_ad_func(other_tensor, lhs_dtype);
|
|
}
|
|
}
|
|
|
|
// 4. calculation
|
|
VLOG(6) << "Calling matmul_ad_func in tensor__rmatmul__method";
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = matmul_ad_func(other_tensor, self_tensor, false, false);
|
|
}
|
|
return ToPyObject(ret);
|
|
EAGER_CATCH_AND_THROW_RETURN_NULL
|
|
}
|
|
|
|
static PyObject* tensor__lt__method(TensorObject* self,
|
|
PyObject* args,
|
|
PyObject* kwargs) {
|
|
phi::RecordEvent pythonc_record_event(
|
|
"__lt__ pybind_patch_func", phi::TracerEventType::UserDefined, 1);
|
|
|
|
EAGER_TRY
|
|
VLOG(4) << "Running Eager tensor__lt__method";
|
|
|
|
SetPythonStack();
|
|
|
|
// Set Device ID
|
|
auto place = egr::Controller::Instance().GetExpectedPlace();
|
|
SetDevice(place);
|
|
|
|
Tensor ret;
|
|
Tensor self_tensor = self->tensor;
|
|
PyObject* other_obj = PyTuple_GET_ITEM(args, 0);
|
|
|
|
// 1. scalar exists cases
|
|
// there is no scalar function for __lt__ now
|
|
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
|
|
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::object>(py::handle(other_obj));
|
|
other_tensor = paddle::empty({}, DataType::FLOAT32, place);
|
|
InitTensorWithNumpyValue(numpy_value, place, &other_tensor);
|
|
} else {
|
|
paddle::experimental::Scalar value =
|
|
CastPyArg2Scalar(other_obj, "__lt__", 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(self_tensor.shape(),
|
|
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 less_than_ad_func in tensor__lt__method";
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = less_than_ad_func(self_tensor, other_tensor);
|
|
}
|
|
|
|
return ToPyObject(ret);
|
|
EAGER_CATCH_AND_THROW_RETURN_NULL
|
|
}
|
|
|
|
static PyObject* tensor__le__method(TensorObject* self,
|
|
PyObject* args,
|
|
PyObject* kwargs) {
|
|
phi::RecordEvent pythonc_record_event(
|
|
"__le__ pybind_patch_func", phi::TracerEventType::UserDefined, 1);
|
|
|
|
EAGER_TRY
|
|
VLOG(4) << "Running Eager tensor__le__method";
|
|
|
|
SetPythonStack();
|
|
|
|
// Set Device ID
|
|
auto place = egr::Controller::Instance().GetExpectedPlace();
|
|
SetDevice(place);
|
|
|
|
Tensor ret;
|
|
Tensor self_tensor = self->tensor;
|
|
PyObject* other_obj = PyTuple_GET_ITEM(args, 0);
|
|
|
|
// 1. scalar exists cases
|
|
// there is no scalar function for __le__ now
|
|
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
|
|
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::object>(py::handle(other_obj));
|
|
other_tensor = paddle::empty({}, DataType::FLOAT32, place);
|
|
InitTensorWithNumpyValue(numpy_value, place, &other_tensor);
|
|
} else {
|
|
paddle::experimental::Scalar value =
|
|
CastPyArg2Scalar(other_obj, "__le__", 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(self_tensor.shape(),
|
|
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 less_equal_ad_func in tensor__le__method";
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = less_equal_ad_func(self_tensor, other_tensor);
|
|
}
|
|
|
|
return ToPyObject(ret);
|
|
EAGER_CATCH_AND_THROW_RETURN_NULL
|
|
}
|
|
|
|
static PyObject* tensor__floordiv__method(TensorObject* self,
|
|
PyObject* args,
|
|
PyObject* kwargs) {
|
|
phi::RecordEvent pythonc_record_event(
|
|
"floordiv pybind_patch_func", phi::TracerEventType::UserDefined, 1);
|
|
EAGER_TRY
|
|
VLOG(6) << "Running Eager tensor__floordiv__method";
|
|
|
|
SetPythonStack();
|
|
|
|
// Set Device ID
|
|
auto place = egr::Controller::Instance().GetExpectedPlace();
|
|
SetDevice(place);
|
|
|
|
Tensor ret;
|
|
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 floordiv, but also 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
|
|
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::object>(py::handle(other_obj));
|
|
other_tensor = paddle::empty({}, DataType::FLOAT32, place);
|
|
InitTensorWithNumpyValue(numpy_value, place, &other_tensor);
|
|
} else {
|
|
paddle::experimental::Scalar value;
|
|
|
|
// NOTE: call reflected method of other_obj if cast failed
|
|
try {
|
|
value = CastPyArg2Scalar(other_obj, "__floordiv__", 0);
|
|
} catch (...) {
|
|
PyObject* rfloordiv =
|
|
PyObject_GetAttrString(other_obj, "__rfloordiv__");
|
|
if (rfloordiv) {
|
|
bool has_callable_rfloordiv = PyCallable_Check(rfloordiv);
|
|
Py_DECREF(rfloordiv);
|
|
if (has_callable_rfloordiv) {
|
|
Py_INCREF(Py_NotImplemented);
|
|
return Py_NotImplemented;
|
|
}
|
|
}
|
|
throw;
|
|
}
|
|
|
|
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__floordiv__method";
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = floor_divide_ad_func(self_tensor, other_tensor);
|
|
}
|
|
|
|
return ToPyObject(ret);
|
|
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";
|
|
|
|
SetPythonStack();
|
|
|
|
// Set Device ID
|
|
auto place = egr::Controller::Instance().GetExpectedPlace();
|
|
SetDevice(place);
|
|
|
|
Tensor ret;
|
|
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 also 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
|
|
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::object>(py::handle(other_obj));
|
|
other_tensor = paddle::empty({}, 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) {
|
|
phi::RecordEvent pythonc_record_event(
|
|
"pow pybind_patch_func", phi::TracerEventType::UserDefined, 1);
|
|
|
|
EAGER_TRY
|
|
VLOG(6) << "Running Eager tensor__pow__method";
|
|
|
|
SetPythonStack();
|
|
|
|
// Set Device ID
|
|
auto place = egr::Controller::Instance().GetExpectedPlace();
|
|
SetDevice(place);
|
|
|
|
Tensor ret;
|
|
Tensor self_tensor = self->tensor;
|
|
|
|
PyObject* other_obj = PyTuple_GET_ITEM(args, 0);
|
|
|
|
// 1. scalar exists cases
|
|
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);
|
|
}
|
|
double other = CastPyArg2Double(other_obj, "__pow__", 0);
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = CallScalarFunction(self_tensor, other, "pow");
|
|
}
|
|
return ToPyObject(ret);
|
|
} 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
|
|
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::object>(py::handle(other_obj));
|
|
other_tensor = paddle::empty({}, DataType::FLOAT32, place);
|
|
InitTensorWithNumpyValue(numpy_value, place, &other_tensor);
|
|
} else {
|
|
paddle::experimental::Scalar value;
|
|
|
|
// NOTE: call reflected method of other_obj if cast failed
|
|
try {
|
|
value = CastPyArg2Scalar(other_obj, "__pow__", 0);
|
|
} catch (...) {
|
|
PyObject* rpow = PyObject_GetAttrString(other_obj, "__rpow__");
|
|
if (rpow) {
|
|
bool has_callable_rpow = PyCallable_Check(rpow);
|
|
Py_DECREF(rpow);
|
|
if (has_callable_rpow) {
|
|
Py_INCREF(Py_NotImplemented);
|
|
return Py_NotImplemented;
|
|
}
|
|
}
|
|
throw;
|
|
}
|
|
|
|
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 elementwise_pow_ad_func in tensor__pow__method";
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = elementwise_pow_ad_func(self_tensor, other_tensor);
|
|
}
|
|
|
|
return ToPyObject(ret);
|
|
EAGER_CATCH_AND_THROW_RETURN_NULL
|
|
}
|
|
|
|
static PyObject* tensor__rpow__method(TensorObject* self,
|
|
PyObject* args,
|
|
PyObject* kwargs) {
|
|
phi::RecordEvent pythonc_record_event(
|
|
"__rpow__ pybind_patch_func", phi::TracerEventType::UserDefined, 1);
|
|
|
|
EAGER_TRY
|
|
VLOG(6) << "Running Eager tensor__rpow__method";
|
|
|
|
SetPythonStack();
|
|
|
|
// Set Device ID
|
|
auto place = egr::Controller::Instance().GetExpectedPlace();
|
|
SetDevice(place);
|
|
|
|
Tensor ret;
|
|
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 rpow, but also 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
|
|
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::object>(py::handle(other_obj));
|
|
other_tensor = paddle::empty({}, DataType::FLOAT32, place);
|
|
InitTensorWithNumpyValue(numpy_value, place, &other_tensor);
|
|
} else {
|
|
paddle::experimental::Scalar value =
|
|
CastPyArg2Scalar(other_obj, "__rpow__", 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(self_tensor.shape(),
|
|
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 elementwise_pow_ad_func in tensor__rpow__method";
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = elementwise_pow_ad_func(other_tensor, self_tensor);
|
|
}
|
|
|
|
return ToPyObject(ret);
|
|
EAGER_CATCH_AND_THROW_RETURN_NULL
|
|
}
|
|
|
|
static PyObject* tensor__ne__method(TensorObject* self,
|
|
PyObject* args,
|
|
PyObject* kwargs) {
|
|
phi::RecordEvent pythonc_record_event(
|
|
"__ne__ pybind_patch_func", phi::TracerEventType::UserDefined, 1);
|
|
|
|
EAGER_TRY
|
|
VLOG(6) << "Running Eager tensor__ne__method";
|
|
|
|
SetPythonStack();
|
|
|
|
// Set Device ID
|
|
auto place = egr::Controller::Instance().GetExpectedPlace();
|
|
SetDevice(place);
|
|
|
|
Tensor ret;
|
|
Tensor self_tensor = self->tensor;
|
|
PyObject* other_obj = PyTuple_GET_ITEM(args, 0);
|
|
|
|
// 1. scalar exists cases
|
|
// there is no scalar function for __ne__ now
|
|
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
|
|
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::object>(py::handle(other_obj));
|
|
other_tensor = paddle::empty({}, DataType::FLOAT32, place);
|
|
InitTensorWithNumpyValue(numpy_value, place, &other_tensor);
|
|
} else {
|
|
paddle::experimental::Scalar value;
|
|
|
|
// return True if other_obj is unsupported type
|
|
try {
|
|
value = CastPyArg2Scalar(other_obj, "__ne__", 0);
|
|
} catch (const ::common::enforce::EnforceNotMet& e) {
|
|
Py_INCREF(Py_True);
|
|
return Py_True;
|
|
}
|
|
|
|
if (PyComplex_Check(other_obj)) {
|
|
eager_gil_scoped_release guard;
|
|
other_tensor =
|
|
full_ad_func({}, value, DataType::COMPLEX64, self_tensor.place());
|
|
} else {
|
|
eager_gil_scoped_release guard;
|
|
other_tensor = full_ad_func(self_tensor.shape(),
|
|
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 not_equal_ad_func in tensor__ne__method";
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = not_equal_ad_func(self_tensor, other_tensor);
|
|
}
|
|
|
|
return ToPyObject(ret);
|
|
EAGER_CATCH_AND_THROW_RETURN_NULL
|
|
}
|
|
|
|
static PyObject* tensor__eq__method(TensorObject* self,
|
|
PyObject* args,
|
|
PyObject* kwargs) {
|
|
phi::RecordEvent pythonc_record_event(
|
|
"__eq__ pybind_patch_func", phi::TracerEventType::UserDefined, 1);
|
|
|
|
EAGER_TRY
|
|
VLOG(6) << "Running Eager tensor__eq__method";
|
|
|
|
SetPythonStack();
|
|
|
|
// Set Device ID
|
|
auto place = egr::Controller::Instance().GetExpectedPlace();
|
|
SetDevice(place);
|
|
|
|
Tensor ret;
|
|
Tensor self_tensor = self->tensor;
|
|
PyObject* other_obj = PyTuple_GET_ITEM(args, 0);
|
|
|
|
// 1. scalar exists cases
|
|
// there is no scalar function for __eq__ now
|
|
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
|
|
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::object>(py::handle(other_obj));
|
|
other_tensor = paddle::empty({}, DataType::FLOAT32, place);
|
|
InitTensorWithNumpyValue(numpy_value, place, &other_tensor);
|
|
} else {
|
|
paddle::experimental::Scalar value;
|
|
|
|
// return False if other_obj is unsupported type
|
|
try {
|
|
value = CastPyArg2Scalar(other_obj, "__eq__", 0);
|
|
} catch (const ::common::enforce::EnforceNotMet& e) {
|
|
Py_INCREF(Py_False);
|
|
return Py_False;
|
|
}
|
|
|
|
if (PyComplex_Check(other_obj)) {
|
|
eager_gil_scoped_release guard;
|
|
other_tensor =
|
|
full_ad_func({}, value, DataType::COMPLEX64, self_tensor.place());
|
|
} else {
|
|
eager_gil_scoped_release guard;
|
|
other_tensor = full_ad_func(self_tensor.shape(),
|
|
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 equal_ad_func in tensor__eq__method";
|
|
{
|
|
eager_gil_scoped_release guard;
|
|
ret = equal_ad_func(self_tensor, other_tensor);
|
|
}
|
|
|
|
return ToPyObject(ret);
|
|
EAGER_CATCH_AND_THROW_RETURN_NULL
|
|
}
|
|
|
|
PyMethodDef math_op_patch_methods[] = { // NOLINT
|
|
{"__add__",
|
|
(PyCFunction)(void (*)())tensor__add__method,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
nullptr},
|
|
{"__radd__",
|
|
(PyCFunction)(void (*)())tensor__add__method,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
nullptr},
|
|
{"__sub__",
|
|
(PyCFunction)(void (*)())tensor__sub__method,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
nullptr},
|
|
{"__rsub__",
|
|
(PyCFunction)(void (*)())tensor__rsub__method,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
nullptr},
|
|
{"__mul__",
|
|
(PyCFunction)(void (*)())tensor__mul__method,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
nullptr},
|
|
{"__rmul__",
|
|
(PyCFunction)(void (*)())tensor__mul__method,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
nullptr},
|
|
{"__div__",
|
|
(PyCFunction)(void (*)())tensor__div__method,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
nullptr},
|
|
{"__truediv__",
|
|
(PyCFunction)(void (*)())tensor__div__method,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
nullptr},
|
|
{"__rdiv__",
|
|
(PyCFunction)(void (*)())tensor__rdiv__method,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
nullptr},
|
|
{"__rtruediv__",
|
|
(PyCFunction)(void (*)())tensor__rdiv__method,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
nullptr},
|
|
{"__floordiv__",
|
|
(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,
|
|
nullptr},
|
|
{"__rpow__",
|
|
(PyCFunction)(void (*)())tensor__rpow__method,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
nullptr},
|
|
{"__mod__",
|
|
(PyCFunction)(void (*)())tensor__mod__method,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
nullptr},
|
|
{"__rmod__",
|
|
(PyCFunction)(void (*)())tensor__rmod__method,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
nullptr},
|
|
{"__matmul__",
|
|
(PyCFunction)(void (*)())tensor__matmul__method,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
nullptr},
|
|
{"__rmatmul__",
|
|
(PyCFunction)(void (*)())tensor__rmatmul__method,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
nullptr},
|
|
{"__gt__",
|
|
(PyCFunction)(void (*)())tensor__gt__method,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
nullptr},
|
|
{"__ge__",
|
|
(PyCFunction)(void (*)())tensor__ge__method,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
nullptr},
|
|
{"__lt__",
|
|
(PyCFunction)(void (*)())tensor__lt__method,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
nullptr},
|
|
{"__le__",
|
|
(PyCFunction)(void (*)())tensor__le__method,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
nullptr},
|
|
{"__eq__",
|
|
(PyCFunction)(void (*)())tensor__eq__method,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
nullptr},
|
|
{"__ne__",
|
|
(PyCFunction)(void (*)())tensor__ne__method,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
nullptr},
|
|
{nullptr, nullptr, 0, nullptr}};
|
|
|
|
} // namespace paddle::pybind
|