Files
2026-07-13 12:40:42 +08:00

1602 lines
55 KiB
C++

// Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "paddle/fluid/pybind/op_function_common.h"
#include <pybind11/chrono.h>
#include <pybind11/complex.h>
#include <pybind11/functional.h>
#include <pybind11/stl.h>
#include <memory>
#include <string>
#include <vector>
#include "paddle/fluid/framework/attribute.h"
#include "paddle/fluid/framework/op_info.h"
#include "paddle/fluid/framework/op_registry.h"
#include "paddle/fluid/framework/variable.h"
#include "paddle/fluid/imperative/tracer.h"
#include "paddle/fluid/imperative/type_defs.h"
#include "paddle/fluid/operators/ops_extra_info.h"
#include "paddle/fluid/pybind/eager.h"
#include "paddle/fluid/pybind/eager_utils.h"
#include "paddle/fluid/pybind/imperative.h"
#include "paddle/phi/common/complex.h"
#include "paddle/pir/include/core/block.h"
#include "paddle/pir/include/core/op_result.h"
#include "paddle/pir/include/core/value.h"
namespace paddle::pybind {
class OpAttrTypeMap {
public:
static OpAttrTypeMap& Instance() {
static OpAttrTypeMap g_op_attr_type_map;
return g_op_attr_type_map;
}
std::unordered_map<
std::string,
std::unordered_map<std::string, paddle::framework::proto::AttrType>>&
Map() {
return ops_attrtype_map_;
}
private:
OpAttrTypeMap() : ops_attrtype_map_() {}
std::unordered_map<
std::string,
std::unordered_map<std::string, paddle::framework::proto::AttrType>>
ops_attrtype_map_;
};
extern PyTypeObject* g_vartype_pytype;
extern PyTypeObject* g_data_type_pytype;
extern PyTypeObject* g_blockdesc_pytype;
extern PyTypeObject* p_tensor_type;
bool PyObject_CheckBool(PyObject** obj) { return PyBool_Check(*obj); }
bool PyObject_CheckVarType(PyObject* obj) {
return PyObject_TypeCheck(obj, g_vartype_pytype);
}
bool PyObject_CheckDataType(PyObject* obj) {
return PyObject_TypeCheck(obj, g_data_type_pytype);
}
bool PyObject_CheckTensor(PyObject* obj) {
return PyObject_TypeCheck(obj, p_tensor_type);
}
bool PyObject_CheckLong(PyObject* obj) {
if ((PyLong_Check(obj) && !PyBool_Check(obj)) || // NOLINT
PyObject_CheckVarType(obj) || // NOLINT
PyObject_CheckDataType(obj) || // NOLINT
(PyObject_CheckTensor(obj) &&
reinterpret_cast<TensorObject*>(obj)->tensor.numel() == 1)) {
return true;
}
std::string type_name =
std::string(reinterpret_cast<PyTypeObject*>(obj->ob_type)->tp_name);
if (type_name.find("numpy.int") != std::string::npos) {
return true;
}
return false;
}
int32_t PyObject_ToInt32(PyObject* obj) {
int64_t res = 0;
if ((PyLong_Check(obj) && !PyBool_Check(obj)) || // NOLINT
PyObject_CheckVarType(obj) || // NOLINT
PyObject_CheckDataType(obj) || // NOLINT
(PyObject_CheckTensor(obj) &&
reinterpret_cast<TensorObject*>(obj)->tensor.numel() == 1)) {
res = PyLong_AsLongLong(obj);
} else {
std::string type_name =
std::string(reinterpret_cast<PyTypeObject*>(obj->ob_type)->tp_name);
if (type_name.find("numpy.int") != std::string::npos) {
auto num_obj = PyNumber_Long(obj);
res = PyLong_AsLongLong(num_obj);
Py_DECREF(num_obj);
} else {
PADDLE_THROW(
common::errors::InvalidType("Cannot convert %s to int32", type_name));
}
}
if (res > std::numeric_limits<int32_t>::max() ||
res < std::numeric_limits<int32_t>::min()) {
PADDLE_THROW(common::errors::OutOfRange(
"Integer value %ld exceeds int32 range [%d, %d]",
res,
std::numeric_limits<int32_t>::min(),
std::numeric_limits<int32_t>::max()));
}
return static_cast<int32_t>(res);
}
uint32_t PyObject_ToUInt32(PyObject* obj) {
uint32_t res = 0;
if ((PyLong_Check(obj) && !PyBool_Check(obj)) || // NOLINT
PyObject_CheckVarType(obj) || // NOLINT
PyObject_CheckDataType(obj) || // NOLINT
(PyObject_CheckTensor(obj) &&
reinterpret_cast<TensorObject*>(obj)->tensor.numel() == 1)) {
res = static_cast<uint32_t>(PyLong_AsUnsignedLong(obj));
return res;
}
std::string type_name =
std::string(reinterpret_cast<PyTypeObject*>(obj->ob_type)->tp_name);
if (type_name.find("numpy.int") != std::string::npos) {
auto num_obj = PyNumber_Long(obj);
res = static_cast<uint32_t>(PyLong_AsUnsignedLong(obj));
Py_DECREF(num_obj);
} else {
PADDLE_THROW(
common::errors::InvalidType("Cannot convert %s to long", type_name));
}
return res;
}
int64_t PyObject_ToInt64(PyObject* obj) {
int64_t res = 0;
if ((PyLong_Check(obj) && !PyBool_Check(obj)) || // NOLINT
PyObject_CheckVarType(obj) || // NOLINT
PyObject_CheckDataType(obj) || // NOLINT
(PyObject_CheckTensor(obj) &&
reinterpret_cast<TensorObject*>(obj)->tensor.numel() == 1)) {
res = PyLong_AsLongLong(obj);
return res;
}
std::string type_name =
std::string(reinterpret_cast<PyTypeObject*>(obj->ob_type)->tp_name);
if (type_name.find("numpy.int") != std::string::npos) {
auto num_obj = PyNumber_Long(obj);
res = PyLong_AsLongLong(num_obj);
Py_DECREF(num_obj);
} else {
PADDLE_THROW(common::errors::InvalidType("Cannot convert %s to long long",
type_name));
}
return res;
}
uint64_t PyObject_ToUInt64(PyObject* obj) {
uint64_t res = 0;
if ((PyLong_Check(obj) && !PyBool_Check(obj)) || // NOLINT
PyObject_CheckVarType(obj) || // NOLINT
PyObject_CheckDataType(obj) || // NOLINT
(PyObject_CheckTensor(obj) &&
reinterpret_cast<TensorObject*>(obj)->tensor.numel() == 1)) {
res = PyLong_AsUnsignedLongLong(obj);
return res;
}
std::string type_name =
std::string(reinterpret_cast<PyTypeObject*>(obj->ob_type)->tp_name);
if (type_name.find("numpy.int") != std::string::npos) {
auto num_obj = PyNumber_Long(obj);
res = PyLong_AsUnsignedLongLong(obj);
Py_DECREF(num_obj);
} else {
PADDLE_THROW(
common::errors::InvalidType("Cannot convert %s to long", type_name));
}
return res;
}
size_t PyObject_ToSize_t(PyObject* obj) {
size_t res = 0;
if ((PyLong_Check(obj) && !PyBool_Check(obj)) || // NOLINT
PyObject_CheckVarType(obj) || // NOLINT
PyObject_CheckDataType(obj) || // NOLINT
(PyObject_CheckTensor(obj) &&
reinterpret_cast<TensorObject*>(obj)->tensor.numel() == 1)) {
res = PyLong_AsSize_t(obj);
return res;
}
std::string type_name =
std::string(reinterpret_cast<PyTypeObject*>(obj->ob_type)->tp_name);
if (type_name.find("numpy.int") != std::string::npos) {
auto num_obj = PyNumber_Long(obj);
res = PyLong_AsSize_t(num_obj);
Py_DECREF(num_obj);
} else {
PADDLE_THROW(common::errors::InvalidType("Cannot convert %s to long long",
type_name));
}
return res;
}
bool PyObject_CheckFloat(PyObject* obj) {
if (PyFloat_Check(obj) || PyLong_Check(obj) ||
(PyObject_CheckTensor(obj) &&
reinterpret_cast<TensorObject*>(obj)->tensor.numel() == 1)) {
return true;
}
auto type_name =
std::string(reinterpret_cast<PyTypeObject*>(obj->ob_type)->tp_name);
VLOG(4) << "type_name: " << type_name;
if (type_name.find("numpy") != std::string::npos &&
type_name.find("numpy.complex") == std::string::npos) {
return true;
}
return false;
}
double PyObject_ToDouble(PyObject* obj) {
double res = 0.0;
if (PyFloat_Check(obj) || PyLong_Check(obj) ||
(PyObject_CheckTensor(obj) &&
reinterpret_cast<TensorObject*>(obj)->tensor.numel() == 1)) {
res = PyFloat_AsDouble(obj);
return res;
}
auto type_name =
std::string(reinterpret_cast<PyTypeObject*>(obj->ob_type)->tp_name);
if (type_name.find("numpy") != std::string::npos &&
type_name.find("numpy.complex") == std::string::npos) {
auto num_obj = PyNumber_Float(obj);
res = PyFloat_AsDouble(num_obj);
Py_DECREF(num_obj);
} else {
PADDLE_THROW(
common::errors::InvalidType("Cannot convert %s to double", type_name));
}
return res;
}
bool PyObject_CheckComplexOrToComplex(PyObject** obj) {
if (PyComplex_Check(*obj) ||
PyObject_TypeCheck(*obj, g_vartype_pytype) || // NOLINT
PyObject_TypeCheck(*obj, p_tensor_type)) { // NOLINT
return true;
}
if (std::string(((PyTypeObject*)(*obj)->ob_type)->tp_name) // NOLINT
.find("numpy.complex") != std::string::npos) {
return true;
}
// consider numpy cfloat & numpy cdouble?
return false;
}
bool PyObject_CheckString(PyObject* obj) { return PyUnicode_Check(obj); }
bool CastPyArg2Boolean(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos) {
if (obj == Py_None || obj == Py_False) {
return false; // To be compatible with QA integration testing. Some
// test case pass in None.
} else if (obj == Py_True) {
return true;
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"bool, but got %s",
op_type,
arg_pos + 1,
((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT
}
return false;
}
bool CastPyArg2Boolean(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos,
bool default_value) {
if (obj) {
return CastPyArg2Boolean(obj, op_type, arg_pos);
} else {
return default_value;
}
}
void CastPyArg2AttrBoolean(PyObject* obj,
paddle::framework::AttributeMap& attrs, // NOLINT
const std::string& key,
const std::string& op_type,
ssize_t arg_pos) {
attrs[key] = CastPyArg2Boolean(obj, op_type, arg_pos);
}
int CastPyArg2Int(PyObject* obj, const std::string& op_type, ssize_t arg_pos) {
if (PyObject_CheckLong(obj)) {
return PyObject_ToInt32(obj);
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"int, but got %s",
op_type,
arg_pos + 1,
((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT
}
return 0;
}
int CastPyArg2Int(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos,
int default_value) {
if (obj != nullptr) {
return CastPyArg2Int(obj, op_type, arg_pos);
} else {
return default_value;
}
}
void CastPyArg2AttrInt(PyObject* obj,
paddle::framework::AttributeMap& attrs, // NOLINT
const std::string& key,
const std::string& op_type,
ssize_t arg_pos) {
attrs[key] = CastPyArg2Int(obj, op_type, arg_pos);
}
int64_t CastPyArg2Long(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos) {
if (PyObject_CheckLong(obj)) {
return PyObject_ToInt64(obj);
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"long, but got %s",
op_type,
arg_pos + 1,
((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT
}
return 0;
}
int64_t CastPyArg2Long(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos,
int64_t default_value) {
if (obj != nullptr) {
return CastPyArg2Long(obj, op_type, arg_pos);
} else {
return default_value;
}
}
void CastPyArg2AttrLong(PyObject* obj,
paddle::framework::AttributeMap& attrs, // NOLINT
const std::string& key,
const std::string& op_type,
ssize_t arg_pos) {
attrs[key] = CastPyArg2Long(obj, op_type, arg_pos);
}
void CastPyArg2AttrScalar(PyObject* obj,
paddle::framework::AttributeMap& attrs, // NOLINT
const std::string& key,
const std::string& op_type,
ssize_t arg_pos) {
attrs[key] = CastPyArg2Scalar(obj, op_type, arg_pos);
}
float16 CastPyArg2Float16(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos) {
return static_cast<float16>(CastPyArg2Double(obj, op_type, arg_pos));
}
float CastPyArg2Float(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos) {
return static_cast<float>(CastPyArg2Double(obj, op_type, arg_pos));
}
float CastPyArg2Float(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos,
float default_value) {
if (obj != nullptr) {
return CastPyArg2Float(obj, op_type, arg_pos);
} else {
return default_value;
}
}
void CastPyArg2AttrFloat(PyObject* obj,
paddle::framework::AttributeMap& attrs, // NOLINT
const std::string& key,
const std::string& op_type,
ssize_t arg_pos) {
attrs[key] = CastPyArg2Float(obj, op_type, arg_pos);
}
double CastPyArg2Double(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos) {
if (PyObject_CheckFloat(obj)) {
return PyObject_ToDouble(obj); // NOLINT
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"double, but got %s",
op_type,
arg_pos + 1,
((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT
}
return 0.0;
}
double CastPyArg2Double(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos,
double default_value) {
if (obj != nullptr) {
return CastPyArg2Double(obj, op_type, arg_pos);
} else {
return default_value;
}
}
phi::dtype::complex<float> CastPyArg2Complex(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos) {
PyTypeObject* type = obj->ob_type;
auto type_name = std::string(type->tp_name);
if (PyComplex_Check(obj)) {
double real = PyComplex_RealAsDouble(obj);
double imag = PyComplex_ImagAsDouble(obj);
return phi::dtype::complex<float>(real, imag); // NOLINT
} else if (type_name == "numpy.complex64") {
Py_complex v = PyComplex_AsCComplex(obj);
return phi::dtype::complex<float>(v.real, v.imag);
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"complex, but got %s",
op_type,
arg_pos + 1,
((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT
}
return phi::dtype::complex<float>(0, 0);
}
phi::dtype::complex<double> CastPyArg2Complex128(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos) {
if (PyComplex_Check(obj)) {
double real = PyComplex_RealAsDouble(obj);
double imag = PyComplex_ImagAsDouble(obj);
return phi::dtype::complex<double>(real, imag);
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"complex, but got %s",
op_type,
arg_pos + 1,
((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT
}
return phi::dtype::complex<double>(0, 0);
}
void CastPyArg2AttrDouble(PyObject* obj,
paddle::framework::AttributeMap& attrs, // NOLINT
const std::string& key,
const std::string& op_type,
ssize_t arg_pos) {
attrs[key] = CastPyArg2Double(obj, op_type, arg_pos);
}
std::string CastPyArg2String(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos) {
if (PyObject_CheckString(obj)) {
Py_ssize_t size = 0;
const char* data = nullptr;
data = PyUnicode_AsUTF8AndSize(obj, &size);
return std::string(data, (size_t)size); // NOLINT
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"str, but got %s",
op_type,
arg_pos + 1,
((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT
}
return "";
}
std::string CastPyArg2String(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos,
std::string default_value) {
if (obj != nullptr) {
return CastPyArg2String(obj, op_type, arg_pos);
} else {
return default_value;
}
}
void CastPyArg2AttrString(PyObject* obj,
paddle::framework::AttributeMap& attrs, // NOLINT
const std::string& key,
const std::string& op_type,
ssize_t arg_pos) {
attrs[key] = CastPyArg2String(obj, op_type, arg_pos);
}
std::vector<bool> CastPyArg2Booleans(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos) {
std::vector<bool> value;
if (PyList_Check(obj)) {
Py_ssize_t len = PyList_Size(obj);
PyObject* item = nullptr;
for (Py_ssize_t i = 0; i < len; i++) {
item = PyList_GetItem(obj, i);
if (PyObject_CheckBool(&item)) {
value.emplace_back(PyLong_AsLong(item));
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"list of bool, but got %s at pos %d",
op_type,
arg_pos + 1,
((PyTypeObject*)item->ob_type)->tp_name, // NOLINT
i));
}
}
} else if (PyTuple_Check(obj)) {
Py_ssize_t len = PyTuple_Size(obj);
PyObject* item = nullptr;
for (Py_ssize_t i = 0; i < len; i++) {
item = PyTuple_GetItem(obj, i);
if (PyObject_CheckBool(&item)) {
value.emplace_back(PyLong_AsLong(item));
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"list of bool, but got %s at pos %d",
op_type,
arg_pos + 1,
((PyTypeObject*)item->ob_type)->tp_name, // NOLINT
i));
}
}
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"list or tuple, but got %s",
op_type,
arg_pos + 1,
((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT
}
return value;
}
std::vector<bool> CastPyArg2Booleans(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos,
std::vector<bool> default_value) {
if (obj != nullptr) {
return CastPyArg2Booleans(obj, op_type, arg_pos);
} else {
return default_value;
}
}
void CastPyArg2AttrBooleans(PyObject* obj,
paddle::framework::AttributeMap& attrs, // NOLINT
const std::string& key,
const std::string& op_type,
ssize_t arg_pos) {
attrs[key] = CastPyArg2Booleans(obj, op_type, arg_pos);
}
std::vector<int> CastPyArg2Ints(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos) {
std::vector<int> value;
if (PyList_Check(obj)) {
Py_ssize_t len = PyList_Size(obj);
value.reserve(len);
PyObject* item = nullptr;
for (Py_ssize_t i = 0; i < len; i++) {
item = PyList_GetItem(obj, i);
if (PyObject_CheckLong(item)) {
value.emplace_back(PyObject_ToInt32(item));
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"list of int, but got %s at pos %d",
op_type,
arg_pos + 1,
((PyTypeObject*)item->ob_type)->tp_name, // NOLINT
i));
}
}
} else if (PyTuple_Check(obj)) {
Py_ssize_t len = PyTuple_Size(obj);
value.reserve(len);
PyObject* item = nullptr;
for (Py_ssize_t i = 0; i < len; i++) {
item = PyTuple_GetItem(obj, i);
if (PyObject_CheckLong(item)) {
value.emplace_back(PyObject_ToInt32(item));
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"list of int, but got %s at pos %d",
op_type,
arg_pos + 1,
((PyTypeObject*)item->ob_type)->tp_name, // NOLINT
i));
}
}
} else if (PySequence_Check(obj) && !PyObject_TypeCheck(obj, p_tensor_type)) {
Py_ssize_t len = PySequence_Size(obj);
value.reserve(len);
PyObject* item = nullptr;
for (Py_ssize_t i = 0; i < len; i++) {
item = PySequence_GetItem(obj, i);
if (PyObject_CheckLong(item)) {
value.emplace_back(PyObject_ToInt32(item));
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"list of int, but got %s at pos %d",
op_type,
arg_pos + 1,
((PyTypeObject*)item->ob_type)->tp_name, // NOLINT
i));
}
Py_DECREF(item);
}
} else if (PyObject_CheckLong(obj)) {
value.emplace_back(PyObject_ToInt32(obj));
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"list or tuple, but got %s",
op_type,
arg_pos + 1,
((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT
}
return value;
}
std::vector<int> CastPyArg2Ints(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos,
std::vector<int> default_value) {
if (obj != nullptr && obj != Py_None) {
return CastPyArg2Ints(obj, op_type, arg_pos);
} else {
return default_value;
}
}
void CastPyArg2AttrInts(PyObject* obj,
paddle::framework::AttributeMap& attrs, // NOLINT
const std::string& key,
const std::string& op_type,
ssize_t arg_pos) {
attrs[key] = CastPyArg2Ints(obj, op_type, arg_pos);
}
std::vector<int64_t> CastPyArg2Longs(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos) {
std::vector<int64_t> value;
if (PyList_Check(obj)) {
Py_ssize_t len = PyList_Size(obj);
PyObject* item = nullptr;
for (Py_ssize_t i = 0; i < len; i++) {
item = PyList_GetItem(obj, i);
if (PyObject_CheckLong(item)) {
value.emplace_back(PyObject_ToInt64(item));
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"list of int, but got %s at pos %d",
op_type,
arg_pos + 1,
((PyTypeObject*)item->ob_type)->tp_name, // NOLINT
i));
}
}
} else if (PyTuple_Check(obj)) {
Py_ssize_t len = PyTuple_Size(obj);
PyObject* item = nullptr;
for (Py_ssize_t i = 0; i < len; i++) {
item = PyTuple_GetItem(obj, i);
if (PyObject_CheckLong(item)) {
value.emplace_back(PyObject_ToInt64(item));
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"list of int, but got %s at pos %d",
op_type,
arg_pos + 1,
((PyTypeObject*)item->ob_type)->tp_name, // NOLINT
i));
}
}
} else if (PySequence_Check(obj) && !PyObject_TypeCheck(obj, p_tensor_type)) {
Py_ssize_t len = PySequence_Size(obj);
PyObject* item = nullptr;
for (Py_ssize_t i = 0; i < len; i++) {
item = PySequence_GetItem(obj, i);
if (PyObject_CheckLong(item)) {
value.emplace_back(PyObject_ToInt64(item));
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"list of int, but got %s at pos %d",
op_type,
arg_pos + 1,
((PyTypeObject*)item->ob_type)->tp_name, // NOLINT
i));
}
Py_DECREF(item);
}
} else if (obj == Py_None) {
return {};
} else if (PyObject_CheckLong(obj)) {
return {PyObject_ToInt64(obj)}; // NOLINT
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"list or tuple, but got %s",
op_type,
arg_pos + 1,
((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT
}
return value;
}
std::vector<int64_t> CastPyArg2Longs(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos,
std::vector<int64_t> default_value) {
if (obj) {
return CastPyArg2Longs(obj, op_type, arg_pos);
} else {
return default_value;
}
}
void CastPyArg2AttrLongs(PyObject* obj,
paddle::framework::AttributeMap& attrs, // NOLINT
const std::string& key,
const std::string& op_type,
ssize_t arg_pos) {
attrs[key] = CastPyArg2Longs(obj, op_type, arg_pos);
}
std::vector<float> CastPyArg2Floats(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos) {
std::vector<float> value;
if (PyList_Check(obj)) {
Py_ssize_t len = PyList_Size(obj);
PyObject* item = nullptr;
for (Py_ssize_t i = 0; i < len; i++) {
item = PyList_GetItem(obj, i);
if (PyObject_CheckFloat(item)) {
value.emplace_back(PyObject_ToDouble(item));
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"list of float, but got %s at pos %d",
op_type,
arg_pos + 1,
((PyTypeObject*)item->ob_type)->tp_name, // NOLINT
i));
}
}
} else if (PyTuple_Check(obj)) {
Py_ssize_t len = PyTuple_Size(obj);
PyObject* item = nullptr;
for (Py_ssize_t i = 0; i < len; i++) {
item = PyTuple_GetItem(obj, i);
if (PyObject_CheckFloat(item)) {
value.emplace_back(PyObject_ToDouble(item));
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"list of float, but got %s at pos %d",
op_type,
arg_pos + 1,
((PyTypeObject*)item->ob_type)->tp_name, // NOLINT
i));
}
}
} else if (PySequence_Check(obj) && !PyObject_TypeCheck(obj, p_tensor_type)) {
Py_ssize_t len = PySequence_Size(obj);
PyObject* item = nullptr;
for (Py_ssize_t i = 0; i < len; i++) {
item = PySequence_GetItem(obj, i);
if (PyObject_CheckFloat(item)) {
value.emplace_back(PyObject_ToDouble(item));
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"list of float, but got %s at pos %d",
op_type,
arg_pos + 1,
((PyTypeObject*)item->ob_type)->tp_name, // NOLINT
i));
}
Py_DECREF(item);
}
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"list or tuple, but got %s",
op_type,
arg_pos + 1,
((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT
}
return value;
}
std::vector<float> CastPyArg2Floats(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos,
std::vector<float> default_value) {
if (obj != nullptr) {
return CastPyArg2Floats(obj, op_type, arg_pos);
} else {
return default_value;
}
}
void CastPyArg2AttrFloats(PyObject* obj,
paddle::framework::AttributeMap& attrs, // NOLINT
const std::string& key,
const std::string& op_type,
ssize_t arg_pos) {
attrs[key] = CastPyArg2Floats(obj, op_type, arg_pos);
}
std::vector<double> CastPyArg2Float64s(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos) {
std::vector<double> value;
if (PyList_Check(obj)) {
Py_ssize_t len = PyList_Size(obj);
PyObject* item = nullptr;
for (Py_ssize_t i = 0; i < len; i++) {
item = PyList_GetItem(obj, i);
if (PyObject_CheckFloat(item)) {
value.emplace_back(PyObject_ToDouble(item));
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"list of float, but got %s at pos %d",
op_type,
arg_pos + 1,
((PyTypeObject*)item->ob_type)->tp_name, // NOLINT
i));
}
}
} else if (PyTuple_Check(obj)) {
Py_ssize_t len = PyTuple_Size(obj);
PyObject* item = nullptr;
for (Py_ssize_t i = 0; i < len; i++) {
item = PyTuple_GetItem(obj, i);
if (PyObject_CheckFloat(item)) {
value.emplace_back(PyObject_ToDouble(item));
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"list of float, but got %s at pos %d",
op_type,
arg_pos + 1,
((PyTypeObject*)item->ob_type)->tp_name, // NOLINT
i));
}
}
} else if (PySequence_Check(obj) && !PyObject_TypeCheck(obj, p_tensor_type)) {
Py_ssize_t len = PySequence_Size(obj);
PyObject* item = nullptr;
for (Py_ssize_t i = 0; i < len; i++) {
item = PySequence_GetItem(obj, i);
if (PyObject_CheckFloat(item)) {
value.emplace_back(PyObject_ToDouble(item));
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"list of float, but got %s at pos %d",
op_type,
arg_pos + 1,
((PyTypeObject*)item->ob_type)->tp_name, // NOLINT
i));
}
Py_DECREF(item);
}
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"list or tuple, but got %s",
op_type,
arg_pos + 1,
((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT
}
return value;
}
std::vector<double> CastPyArg2Float64s(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos,
std::vector<double> default_value) {
if (obj != nullptr) {
return CastPyArg2Float64s(obj, op_type, arg_pos);
} else {
return default_value;
}
}
void CastPyArg2AttrFloat64s(PyObject* obj,
paddle::framework::AttributeMap& attrs, // NOLINT
const std::string& key,
const std::string& op_type,
ssize_t arg_pos) {
attrs[key] = CastPyArg2Float64s(obj, op_type, arg_pos);
}
void CastPyArg2AttrScalars(PyObject* obj,
paddle::framework::AttributeMap& attrs, // NOLINT
const std::string& key,
const std::string& op_type,
ssize_t arg_pos) {
attrs[key] = CastPyArg2Scalars(obj, op_type, arg_pos);
}
std::vector<std::string> CastPyArg2Strings(PyObject* obj,
const std::string& op_type,
ssize_t arg_pos) {
std::vector<std::string_view> views;
if (PyList_Check(obj)) {
Py_ssize_t len = PyList_Size(obj);
views.reserve(len);
PyObject* item = nullptr;
for (Py_ssize_t i = 0; i < len; i++) {
item = PyList_GetItem(obj, i);
if (PyObject_CheckString(item)) {
Py_ssize_t size = 0;
const char* data = nullptr;
data = PyUnicode_AsUTF8AndSize(item, &size);
views.emplace_back(std::string_view(data, (size_t)size)); // NOLINT
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"list of str, but got %s at pos %d",
op_type,
arg_pos + 1,
((PyTypeObject*)item->ob_type)->tp_name, // NOLINT
i));
}
}
} else if (PyTuple_Check(obj)) {
Py_ssize_t len = PyTuple_Size(obj);
views.reserve(len);
PyObject* item = nullptr;
for (Py_ssize_t i = 0; i < len; i++) {
item = PyTuple_GetItem(obj, i);
if (PyObject_CheckString(item)) {
Py_ssize_t size = 0;
const char* data = nullptr;
data = PyUnicode_AsUTF8AndSize(item, &size);
views.emplace_back(std::string_view(data, (size_t)size)); // NOLINT
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"list of str, but got %s at pos %d",
op_type,
arg_pos + 1,
((PyTypeObject*)item->ob_type)->tp_name, // NOLINT
i));
}
}
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"list or tuple, but got %s",
op_type,
arg_pos + 1,
((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT
}
std::vector<std::string> value;
value.reserve(views.size());
for (const auto& view : views) {
value.emplace_back(view);
}
return value;
}
std::vector<std::string> CastPyArg2Strings(
PyObject* obj,
const std::string& op_type,
ssize_t arg_pos,
std::vector<std::string> default_value) {
if (obj != nullptr) {
return CastPyArg2Strings(obj, op_type, arg_pos);
} else {
return default_value;
}
}
void CastPyArg2AttrStrings(PyObject* obj,
paddle::framework::AttributeMap& attrs, // NOLINT
const std::string& key,
const std::string& op_type,
ssize_t arg_pos) {
attrs[key] = CastPyArg2Strings(obj, op_type, arg_pos);
}
std::vector<paddle::experimental::Scalar> CastPyArg2Scalars(
PyObject* obj, const std::string& op_type, ssize_t arg_pos) {
if (obj == Py_None) {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"a list of int, float, or bool, but got %s",
op_type,
arg_pos + 1,
((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT
}
PyTypeObject* type = obj->ob_type;
auto type_name = std::string(type->tp_name);
VLOG(4) << "type_name: " << type_name;
if (PyList_Check(obj)) {
Py_ssize_t len = PyList_Size(obj);
PyObject* item = nullptr;
item = PyList_GetItem(obj, 0);
if (PyObject_CheckFloat(item)) {
std::vector<paddle::experimental::Scalar> value;
for (Py_ssize_t i = 0; i < len; i++) {
item = PyList_GetItem(obj, i);
value.emplace_back(
paddle::experimental::Scalar{PyObject_ToDouble(item)});
}
return value;
} else if (PyObject_CheckLong(item)) {
std::vector<paddle::experimental::Scalar> value;
for (Py_ssize_t i = 0; i < len; i++) {
item = PyList_GetItem(obj, i);
value.emplace_back(
paddle::experimental::Scalar{PyObject_ToInt64(item)});
}
return value;
} else if (PyObject_CheckComplexOrToComplex(&item)) {
std::vector<paddle::experimental::Scalar> value;
for (Py_ssize_t i = 0; i < len; i++) {
item = PyList_GetItem(obj, i);
Py_complex v = PyComplex_AsCComplex(item);
value.emplace_back(
paddle::experimental::Scalar{std::complex<double>(v.real, v.imag)});
}
return value;
}
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"a list of int, float, complex, or bool, but got %s",
op_type,
arg_pos + 1,
((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT
}
// Fake a ScalarArray
return std::vector<paddle::experimental::Scalar>(
{paddle::experimental::Scalar(1.0)});
}
void CastPyArg2AttrBlock(PyObject* obj,
paddle::framework::AttributeMap& attrs, // NOLINT
const std::string& key,
const std::string& op_type,
ssize_t arg_pos) {
::pybind11::detail::instance* inst =
(::pybind11::detail::instance*)obj; // NOLINT
if (!PyObject_TypeCheck((PyObject*)inst, g_blockdesc_pytype)) { // NOLINT
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"BlockDesc, but got %s",
op_type,
arg_pos + 1,
((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT
}
void** vh = inst->simple_layout ? inst->simple_value_holder
: &inst->nonsimple.values_and_holders[0];
attrs[key] = reinterpret_cast<paddle::framework::BlockDesc*&>(vh[0]);
}
void CastPyArg2AttrIRBlock(PyObject* obj,
paddle::framework::AttributeMap& attrs, // NOLINT
const std::string& key,
const std::string& op_type,
ssize_t arg_pos) {
VLOG(3) << "After Process pir::Block*";
::pybind11::detail::instance* inst =
(::pybind11::detail::instance*)obj; // NOLINT
void** vh = inst->simple_layout ? inst->simple_value_holder
: &inst->nonsimple.values_and_holders[0];
attrs[key] = reinterpret_cast<pir::Block*&>(vh[0]);
}
void CastPyArg2AttrIRProgram(PyObject* obj,
paddle::framework::AttributeMap& attrs, // NOLINT
const std::string& key,
const std::string& op_type,
ssize_t arg_pos) {
VLOG(3) << "After Process pir::Program*";
const std::shared_ptr<pir::Program> program =
::py::handle(obj).cast<std::shared_ptr<pir::Program>>();
attrs[key] = program;
}
void CastPyArg2AttrValues(PyObject* obj,
paddle::framework::AttributeMap& attrs, // NOLINT
const std::string& key,
const std::string& op_type,
ssize_t arg_pos) {
std::vector<pir::Value> results;
if (PyList_Check(obj)) {
Py_ssize_t len = PyList_Size(obj);
PyObject* item = nullptr;
for (Py_ssize_t i = 0; i < len; i++) {
// TODO(xiongkun): judge Value;
item = PyList_GetItem(obj, i);
::pybind11::detail::instance* inst =
(::pybind11::detail::instance*)item; // NOLINT
void** vh = inst->simple_layout ? inst->simple_value_holder
: &inst->nonsimple.values_and_holders[0];
pir::Value* value = reinterpret_cast<pir::Value*>(vh[0]);
results.emplace_back(pir::Value(value->impl()));
}
} else {
PADDLE_THROW(common::errors::InvalidType(
"%s(): argument (position %d) must be "
"a list of int, float, complex, or bool, but got %s",
op_type,
arg_pos + 1,
((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT
}
attrs[key] = results;
VLOG(4) << "Pybind: Cast " << results.size() << " Value Finished.";
}
void ConstructAttrMapFromPyArgs(
const std::string& op_type,
PyObject* args,
ssize_t attr_start,
ssize_t attr_end,
paddle::framework::AttributeMap& attrs) { // NOLINT
PADDLE_ENFORCE_EQ((attr_end - attr_start) % 2,
0,
common::errors::InvalidArgument(
"The number of arguments for attributes should be even "
"but attr_start = %d, attr_end = %d.",
attr_start,
attr_end));
auto attr_type_map = &(OpAttrTypeMap::Instance().Map()[op_type]);
PyObject* obj = nullptr;
for (ssize_t arg_pos = attr_start; arg_pos < attr_end; arg_pos += 2) {
VLOG(5) << "Start Process " << arg_pos;
Py_ssize_t key_len = 0;
const char* key_ptr = nullptr;
obj = PyTuple_GET_ITEM(args, arg_pos);
if (PyObject_CheckString(obj)) {
key_ptr = PyUnicode_AsUTF8AndSize(obj, &key_len);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"%s(): argument (position %d) must be str, but got "
"%s",
op_type,
arg_pos,
((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT
}
std::string key(key_ptr, (size_t)key_len); // NOLINT
VLOG(5) << "Start Process " << key;
auto iter = attr_type_map->find(key);
if (iter == attr_type_map->end()) {
continue;
}
obj = PyTuple_GET_ITEM(args, arg_pos + 1);
switch (iter->second) {
case paddle::framework::proto::AttrType::INT:
CastPyArg2AttrInt(obj, attrs, key, op_type, arg_pos);
break;
case paddle::framework::proto::AttrType::FLOAT:
CastPyArg2AttrFloat(obj, attrs, key, op_type, arg_pos);
break;
case paddle::framework::proto::AttrType::FLOAT64:
CastPyArg2AttrDouble(obj, attrs, key, op_type, arg_pos);
break;
case paddle::framework::proto::AttrType::STRING:
CastPyArg2AttrString(obj, attrs, key, op_type, arg_pos);
break;
case paddle::framework::proto::AttrType::INTS:
CastPyArg2AttrInts(obj, attrs, key, op_type, arg_pos);
break;
case paddle::framework::proto::AttrType::FLOATS:
CastPyArg2AttrFloats(obj, attrs, key, op_type, arg_pos);
break;
case paddle::framework::proto::AttrType::STRINGS:
CastPyArg2AttrStrings(obj, attrs, key, op_type, arg_pos);
break;
case paddle::framework::proto::AttrType::BOOLEAN:
CastPyArg2AttrBoolean(obj, attrs, key, op_type, arg_pos);
break;
case paddle::framework::proto::AttrType::BOOLEANS:
CastPyArg2AttrBooleans(obj, attrs, key, op_type, arg_pos);
break;
case paddle::framework::proto::AttrType::LONG:
CastPyArg2AttrLong(obj, attrs, key, op_type, arg_pos);
break;
case paddle::framework::proto::AttrType::LONGS:
CastPyArg2AttrLongs(obj, attrs, key, op_type, arg_pos);
break;
case paddle::framework::proto::AttrType::FLOAT64S:
CastPyArg2AttrFloat64s(obj, attrs, key, op_type, arg_pos);
break;
case paddle::framework::proto::AttrType::BLOCK:
CastPyArg2AttrBlock(obj, attrs, key, op_type, arg_pos);
break;
case paddle::framework::proto::AttrType::SCALAR:
CastPyArg2AttrScalar(obj, attrs, key, op_type, arg_pos);
break;
case paddle::framework::proto::AttrType::SCALARS:
CastPyArg2AttrScalars(obj, attrs, key, op_type, arg_pos);
break;
default:
break;
}
}
}
void ConstructAttrMapForLegacyRunProgram(
const std::string& op_type,
PyObject* args,
ssize_t attr_start,
ssize_t attr_end,
paddle::framework::AttributeMap& attrs) { // NOLINT
PADDLE_ENFORCE_EQ((attr_end - attr_start) % 2,
0,
common::errors::InvalidArgument(
"The number of arguments for attributes should be even "
"but attr_start = %d, attr_end = %d.",
attr_start,
attr_end));
using CastFuncType = void (*)(PyObject*,
paddle::framework::AttributeMap&,
const std::string&,
const std::string&,
ssize_t);
// Static map from keys to casting function pointers
static const std::unordered_map<std::string, CastFuncType> kAttrFuncMap = {
{"forward_global_block", CastPyArg2AttrBlock},
{"backward_global_block", CastPyArg2AttrBlock},
{"is_test", CastPyArg2AttrBoolean},
{"program_id", CastPyArg2AttrLong},
{"param_grad_names", CastPyArg2AttrStrings},
{"x_names", CastPyArg2AttrStrings},
{"out_grad_names", CastPyArg2AttrStrings},
{"x_grad_names", CastPyArg2AttrStrings},
{"in_pir_pt_mode", CastPyArg2AttrBoolean},
{"use_interpretorcore", CastPyArg2AttrBoolean},
{"global_block", CastPyArg2AttrBlock},
{"start_op_index", CastPyArg2AttrLong},
{"end_op_index", CastPyArg2AttrLong},
};
PyObject* obj = nullptr;
for (ssize_t arg_pos = attr_start; arg_pos < attr_end; arg_pos += 2) {
VLOG(3) << "Start Process " << arg_pos;
Py_ssize_t key_len = 0;
const char* key_ptr = nullptr;
obj = PyTuple_GET_ITEM(args, arg_pos);
if (PyObject_CheckString(obj)) {
key_ptr = PyUnicode_AsUTF8AndSize(obj, &key_len);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"%s(): argument (position %d) must be str, but got %s",
op_type,
arg_pos,
((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT
}
std::string_view key_view(key_ptr, static_cast<size_t>(key_len));
VLOG(3) << "Start Process " << key_view;
obj = PyTuple_GET_ITEM(args, arg_pos + 1);
auto it = kAttrFuncMap.find(std::string(key_view));
if (it != kAttrFuncMap.end()) {
// Call Cast function
it->second(obj, attrs, std::string(key_view), op_type, arg_pos);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Attribute key %.*s is not recognized for operator %s.",
static_cast<int>(key_view.size()),
key_view.data(),
op_type.c_str())); // NOLINT
}
}
}
PyObject* ConstructProgramAttrMapForRunProgram(PyObject* self, PyObject* args) {
const std::string op_type = "run_program";
PyObject* attrs_dict = nullptr;
if (!PyArg_ParseTuple(args, "O", &attrs_dict)) {
return nullptr;
}
paddle::framework::AttributeMap* attrs_ptr =
new (std::nothrow) paddle::framework::AttributeMap();
if (!attrs_ptr) {
PADDLE_THROW(common::errors::InvalidArgument(
"%s(): failed to allocate memory for AttributeMap.", op_type));
}
ConstructAttrMapForRunProgram(op_type, attrs_dict, *attrs_ptr);
PyObject* py_attrs_capsule = PyCapsule_New(
attrs_ptr, "paddle.framework.AttributeMap", [](PyObject* capsule) {
paddle::framework::AttributeMap* data =
reinterpret_cast<paddle::framework::AttributeMap*>(
PyCapsule_GetPointer(capsule, "paddle.framework.AttributeMap"));
if (data) {
delete data;
}
});
if (!py_attrs_capsule) {
delete attrs_ptr;
PyErr_SetString(PyExc_RuntimeError,
"Failed to create PyCapsule for AttributeMap.");
return nullptr;
}
return py_attrs_capsule;
}
void ConstructCudaGraphAttrMapForRunProgram(
const std::string& op_type,
PyObject* args,
ssize_t arg_pos,
paddle::framework::AttributeMap& attrs) { // NOLINT
PyObject* attrs_dict = PyTuple_GET_ITEM(args, arg_pos);
ConstructAttrMapForRunProgram(op_type, attrs_dict, attrs);
}
void ConstructAttrMapForRunProgram(
const std::string& op_type,
PyObject* attrs_dict,
paddle::framework::AttributeMap& attrs) { // NOLINT
if (!PyDict_Check(attrs_dict)) {
PADDLE_THROW(common::errors::InvalidArgument(
"%s(): argument must be dict, but got %s",
op_type,
reinterpret_cast<PyTypeObject*>(attrs_dict->ob_type)->tp_name));
}
using CastFuncType = void (*)(PyObject*,
paddle::framework::AttributeMap&,
const std::string&,
const std::string&,
ssize_t);
// Static map from keys to casting function pointers
static const std::unordered_map<std::string, CastFuncType> kAttrFuncMap = {
{"forward_program", CastPyArg2AttrIRProgram},
{"backward_program", CastPyArg2AttrIRProgram},
{"is_test", CastPyArg2AttrBoolean},
{"in_sot_mode", CastPyArg2AttrBoolean},
{"program_id", CastPyArg2AttrLong},
{"fo_values", CastPyArg2AttrValues},
{"fx_names", CastPyArg2AttrStrings},
{"fp_names", CastPyArg2AttrStrings},
{"fm_names", CastPyArg2AttrStrings},
{"fo_names", CastPyArg2AttrStrings},
{"bx_names", CastPyArg2AttrStrings},
{"bp_names", CastPyArg2AttrStrings},
{"bm_names", CastPyArg2AttrStrings},
{"bo_names", CastPyArg2AttrStrings},
{"bx_g_names", CastPyArg2AttrStrings},
{"bp_g_names", CastPyArg2AttrStrings},
{"bo_g_names", CastPyArg2AttrStrings},
{"no_need_buffers_names", CastPyArg2AttrStrings},
{"cuda_graph_state", CastPyArg2AttrLong},
{"cuda_graph_dispatch_key", CastPyArg2AttrLong},
};
PyObject *key, *value;
Py_ssize_t pos = 0;
while (PyDict_Next(attrs_dict, &pos, &key, &value)) {
Py_ssize_t key_len = 0;
const char* key_ptr = nullptr;
if (PyObject_CheckString(key)) {
key_ptr = PyUnicode_AsUTF8AndSize(key, &key_len);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"%s(): dict key must be str, but got %s",
op_type,
reinterpret_cast<PyTypeObject*>(key->ob_type)->tp_name));
}
std::string_view key_view(key_ptr, static_cast<size_t>(key_len));
auto it = kAttrFuncMap.find(std::string(key_view));
if (it != kAttrFuncMap.end()) {
it->second(value, attrs, std::string(key_view), op_type, 0);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Attribute key %.*s is not recognized for operator %s.",
static_cast<int>(key_view.size()),
key_view.data(),
op_type.c_str()));
}
}
}
unsigned long GetUnsignedLongFromArgs( // NOLINT
const std::string& op_type,
const std::string& arg_name,
PyObject* args,
ssize_t arg_idx,
bool dispensable) {
PyObject* item = PyTuple_GET_ITEM(args, arg_idx);
if (item == nullptr) {
if (!dispensable) {
PADDLE_THROW(common::errors::InvalidArgument(
"%s(): argument '%s' (position %d) must be long, but got None",
op_type,
arg_name,
arg_idx));
}
return 0;
}
if (PyObject_CheckLong(item)) {
return PyObject_ToUInt64(item);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"%s(): argument '%s' (position %d) must be "
"long, but got %s",
op_type,
arg_name,
arg_idx,
((PyTypeObject*)item->ob_type)->tp_name)); // NOLINT
}
}
void InitOpsAttrTypeMap() {
auto op_info_map = paddle::framework::OpInfoMap::Instance().map();
for (auto& item : op_info_map) {
auto op_proto = item.second.proto_;
if (op_proto == nullptr) {
continue;
}
auto attrs_proto = op_proto->attrs();
for (auto& attr : attrs_proto) {
OpAttrTypeMap::Instance().Map()[item.first][attr.name()] = attr.type();
}
}
const auto& extra_attr_maps =
operators::ExtraInfoUtils::Instance().GetAllExtraAttrsMap();
for (const auto& extra_attrs : extra_attr_maps) {
for (auto& attr : extra_attrs.second) {
OpAttrTypeMap::Instance().Map()[extra_attrs.first][attr.first] =
static_cast<paddle::framework::proto::AttrType>(attr.second.index() -
1);
}
}
}
ssize_t GetIdxFromCoreOpsInfoMap(
const std::unordered_map<std::string, std::vector<std::string>>&
core_ops_info_map,
const std::string& op_type,
const std::string& name) {
// `core_ops_info_map` can be `core_ops_args_info` or
// `core_ops_returns_info`. `core_ops_args_info`: get index from
// core_ops_args_info[op_type] according to input name.
// `core_ops_returns_info`: get index from core_ops_returns_info[op_type]
// according to return name.
if (!core_ops_info_map.count(op_type)) {
PADDLE_THROW(common::errors::Fatal(
"Op %s is not found in core_ops_*_info map.", op_type));
} else {
auto args_list = core_ops_info_map.at(op_type);
auto it = std::find(args_list.begin(), args_list.end(), name);
if (it == args_list.end()) {
PADDLE_THROW(common::errors::Fatal(
"%s is not found in op %s's args.", name, op_type));
} else {
return std::distance(args_list.begin(), it);
}
}
return -1;
}
static PyMethodDef OpFunctionCommonMethods[] = {
// NOLINT
{"construct_program_attribute_map",
(PyCFunction)ConstructProgramAttrMapForRunProgram,
METH_VARARGS,
"create attribute map for run program"},
{nullptr, nullptr, 0, nullptr}};
void BindOpFunctionCommon(PyObject* module) {
if (PyModule_AddFunctions(module, OpFunctionCommonMethods) < 0) {
PADDLE_THROW(common::errors::Fatal(
"Init Paddle error in BindOpFunctionCommon(PyModule_AddFunctions)."));
return;
}
}
// For parse argruments from args and kwargs
// Get item from PyObject* args or PyObject* kwargs
PyObject* GetItemFromArgsOrKWArgs(PyObject* args,
int pos,
PyObject* kwargs,
const std::vector<std::string>& keywords,
int nargs,
int* remaining_kwargs,
bool dispensable) {
// get item from args first if pos < nargs
if (pos < nargs) {
PyObject* arg = PyTuple_GetItem(args, pos);
if (arg) {
return arg;
}
} else {
// get item from kwargs
if (kwargs) {
PyObject* arg = nullptr;
for (const std::string& keyword : keywords) {
arg = PyDict_GetItemString(kwargs, keyword.c_str());
if (arg) {
*remaining_kwargs = *remaining_kwargs - 1;
return arg;
}
}
}
}
if (!dispensable) {
PADDLE_THROW(common::errors::InvalidArgument(
"Argument '%s' (position %d) must be provided", keywords[0], pos));
}
return nullptr;
}
void CheckRemainingParamsValidity(PyObject* args,
PyObject* kwargs,
int remaining_kwargs,
int nargs,
bool inplace) {
const std::string ignored_arg_name = "name";
const std::string ignored_arg_out = "out";
if (remaining_kwargs == 0) return;
PyObject* name = PyDict_GetItemString(kwargs, ignored_arg_name.c_str());
PyObject* out = PyDict_GetItemString(kwargs, ignored_arg_out.c_str());
if (inplace) {
if (remaining_kwargs == 1 && name) return;
} else {
if (remaining_kwargs == 1 && (name || out)) return;
if (remaining_kwargs == 2 && (name && out)) return;
}
PADDLE_THROW(common::errors::InvalidArgument("has too many arguments"));
return;
}
} // namespace paddle::pybind