Files
paddlepaddle--paddle/paddle/fluid/pybind/eager.cc
T
2026-07-13 12:40:42 +08:00

1573 lines
62 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. */
// disable numpy compile error
#include "paddle/fluid/pybind/eager.h"
#include <Python.h>
#include <string>
#include <vector>
#include "paddle/fluid/eager/accumulation/accumulation_node.h"
#include "paddle/fluid/eager/api/all.h"
#include "paddle/fluid/eager/autograd_meta.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_utils.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/fluid/framework/phi_utils.h"
#include "paddle/fluid/framework/python_headers.h"
#include "paddle/fluid/pybind/exception.h"
#include "paddle/fluid/pybind/tensor_py.h"
#include "paddle/phi/api/lib/data_transform.h"
#include "paddle/phi/core/distributed/auto_parallel/dist_tensor.h"
#include "paddle/phi/core/distributed/auto_parallel/placement_types.h"
#include "paddle/phi/core/distributed/auto_parallel/process_mesh.h"
#include "paddle/phi/core/string_tensor.h"
using phi::distributed::DistTensor;
using phi::distributed::DistTensorMeta;
using phi::distributed::Placement;
using phi::distributed::Placements;
using phi::distributed::ProcessMesh;
using phi::distributed::TensorDistAttr;
using phi::distributed::auto_parallel::str_join;
namespace paddle::pybind {
namespace py = ::pybind11;
extern PyTypeObject* p_tensor_type;
extern PyTypeObject* p_string_tensor_type; // For StringTensor
extern PyTypeObject* g_vartype_pytype;
extern PyTypeObject* g_data_type_pytype;
extern PyTypeObject* g_framework_tensor_pytype;
PyObject* TensorNew(PyTypeObject* type, PyObject* args, PyObject* kwargs) {
PyObject* obj = type->tp_alloc(type, 0);
if (obj) {
auto v = reinterpret_cast<TensorObject*>(obj);
new (&(v->tensor)) Tensor();
}
return obj;
}
// TODO(jiabin): Overload this once we need more constructor in Python
void EmptyTensorInitializer(TensorObject* self,
const std::string& name,
const Place& place,
bool persistable = false,
int stop_gradient = -1,
DataType dtype = DataType::FLOAT32,
const std::vector<int>& dims = {0},
framework::proto::VarType::Type var_type =
framework::proto::VarType::DENSE_TENSOR,
ProcessMesh* process_mesh = nullptr,
Placements* placements = nullptr) {
auto ddims = common::make_ddim(dims);
self->tensor.set_name(name);
auto autograd_meta = egr::EagerUtils::autograd_meta(&(self->tensor));
autograd_meta->SetPersistable(persistable);
if (stop_gradient != -1) {
autograd_meta->SetStopGradient(static_cast<bool>(stop_gradient));
}
if (process_mesh != nullptr) {
#ifdef PADDLE_WITH_DISTRIBUTE
VLOG(6) << "in EmptyTensorInitializer, create DistTensor";
self->tensor.set_impl(std::make_shared<DistTensor>());
#else
PADDLE_THROW(common::errors::Unavailable(
"The tensor-based initialization of (Dist)Tensor is not supported "
"in the current PaddlePaddle, please recompile and install "
"PaddlePaddle "
"with the option of `WITH_DISTRIBUTE=ON`."));
#endif
} else {
VLOG(6) << "in EmptyTensorInitializer, create DenseTensor";
if (var_type == framework::proto::VarType::DENSE_TENSOR) {
// TODO(jiabin): Maybe support LegacyLoD later
std::shared_ptr<DenseTensor> dense_tensor = nullptr;
if (dims.size() == 1 && dims[0] == 0) {
std::shared_ptr<phi::Allocation> allocation_ptr = nullptr;
dense_tensor = std::make_shared<DenseTensor>(
allocation_ptr, phi::DenseTensorMeta(dtype, ddims));
} else {
// TODO(dev): we need enhance check for ddims.
dense_tensor =
std::make_shared<DenseTensor>(std::make_shared<phi::Allocation>(),
phi::DenseTensorMeta(dtype, ddims));
}
self->tensor.set_impl(dense_tensor);
} else if (var_type == framework::proto::VarType::SELECTED_ROWS) {
std::shared_ptr<phi::SelectedRows> tensor =
std::make_shared<phi::SelectedRows>();
self->tensor.set_impl(tensor);
}
}
if (!autograd_meta->GetMutableGradNode()) {
autograd_meta->SetGradNode(
std::make_shared<egr::GradNodeAccumulation>(self->tensor));
VLOG(3) << "Tensor(" << name
<< ") have not GradNode, add GradNodeAccumulation("
<< autograd_meta->GradNode() << ") for it.";
}
}
void EmptyStringTensorInitializer(TensorObject* self,
const std::string& name,
const Place& place,
const std::vector<int>& dims = {}) {
auto ddims = common::make_ddim(dims);
self->tensor.set_name(name);
// Note(zhoushunjie): Only support CPUPlace when create StringTensor
auto actual_place = CPUPlace();
// Allocate memory
paddle::experimental::DefaultAllocator string_allocator(actual_place);
std::shared_ptr<phi::StringTensor> string_tensor =
std::make_shared<phi::StringTensor>(&string_allocator,
phi::StringTensorMeta{ddims});
if (common::product(ddims) > 0) {
string_tensor->mutable_data(actual_place);
}
self->tensor.set_impl(string_tensor);
}
void InitTensorWithNumpyValue(TensorObject* self,
const py::object& array,
const Place& place,
bool zero_copy = false) {
PADDLE_ENFORCE_EQ(
self->tensor.defined(),
true,
common::errors::Unavailable(
"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."));
DenseTensor* impl_ptr = static_cast<DenseTensor*>(self->tensor.impl().get());
if (phi::is_cpu_place(place)) {
SetTensorFromPyArray<CPUPlace>(impl_ptr, array, place, zero_copy);
} else if (phi::is_xpu_place(place)) {
#if defined(PADDLE_WITH_XPU)
phi::backends::xpu::SetXPUDeviceId(place.device);
VLOG(4) << "CurrentDeviceId: "
<< phi::backends::xpu::GetXPUCurrentDeviceId() << " from "
<< static_cast<int>(place.device);
#else
PADDLE_THROW(common::errors::PreconditionNotMet(
"PaddlePaddle should compile with XPU if use XPUPlace."));
#endif
SetTensorFromPyArray<phi::XPUPlace>(impl_ptr, array, place, zero_copy);
} else if (phi::is_gpu_place(place)) {
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
phi::backends::gpu::SetDeviceId(place.device);
VLOG(4) << "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
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_xpu_pinned_place(place)) {
SetTensorFromPyArray<phi::XPUPinnedPlace>(
impl_ptr, array, place, zero_copy);
} else if (phi::is_custom_place(place)) {
#if defined(PADDLE_WITH_CUSTOM_DEVICE)
phi::DeviceManager::SetDevice(place);
VLOG(4) << "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
SetTensorFromPyArray<phi::CustomPlace>(impl_ptr, array, place, zero_copy);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Place should be one of "
"CPUPlace/XPUPlace/CUDAPlace/"
"CUDAPinnedPlace/XPUPinnedPlace/CustomPlace"));
}
}
void InitStringTensorWithNumpyValue(TensorObject* self, const py::object& obj) {
PADDLE_ENFORCE_EQ(
self->tensor.defined(),
true,
common::errors::Fatal(
"Calling InitStringTensorWithNumpyValue of Eager StringTensor "
"without "
"EmptyStringTensorInitializer is "
"forbidden. Please check your code and make sure you new a "
"eager tensor before init it with NumPy."));
phi::StringTensor* impl_ptr =
static_cast<phi::StringTensor*>(self->tensor.impl().get());
Place place = impl_ptr->place();
auto array = obj.cast<py::array>();
if (phi::is_cpu_place(place)) {
SetStringTensorFromPyArray<CPUPlace>(impl_ptr, array, place);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"StringTensor only support CPUPlace now, but receive %s",
place.DebugString()));
}
}
void InitDistTensorWithTensor(TensorObject* self,
const Tensor& src,
const Place& place,
const std::string& name,
const ProcessMesh& process_mesh,
const Placements& placements) {
#ifdef PADDLE_WITH_DISTRIBUTE
PADDLE_ENFORCE_EQ(src.is_dense_tensor(),
true,
common::errors::InvalidArgument(
"DistTensor can only initialize by DenseTensor"));
self->tensor.set_name(name);
VLOG(4) << "Do TensorCopy from DenseTensor to DistTensor.";
if (place == src.place()) {
std::shared_ptr<DenseTensor> tensor =
std::static_pointer_cast<DenseTensor>(src.impl());
self->tensor.set_impl(
std::make_shared<DistTensor>(tensor, process_mesh, placements));
VLOG(4) << "Same place, do ShareDataWith for DistTensor.";
} else {
std::shared_ptr<DenseTensor> tensor;
if (src.initialized()) {
tensor = std::static_pointer_cast<DenseTensor>(
src.copy_to(place, true).impl());
} else {
// lazy init branch. The src tensor is on undefined place.
PADDLE_ENFORCE(
src.place().GetType() == phi::AllocationType::UNDEFINED,
common::errors::InvalidArgument("Only undefined place is support for "
"uninitialized input tensor."));
tensor = std::static_pointer_cast<DenseTensor>(src.impl());
}
self->tensor.set_impl(
std::make_shared<DistTensor>(tensor, process_mesh, placements));
VLOG(4) << "Different place, do TensorCopy for DistTensor.";
}
if (src.get_autograd_meta()) {
egr::EagerUtils::autograd_meta(&(self->tensor))
->SetPersistable(
egr::EagerUtils::unsafe_autograd_meta(src)->Persistable());
} else {
egr::EagerUtils::autograd_meta(&(self->tensor))->SetPersistable(false);
}
#else
PADDLE_THROW(common::errors::Unavailable(
"The tensor-based initialization of (Dist)Tensor is not supported "
"in the current PaddlePaddle, please recompile and install PaddlePaddle "
"with the option of `WITH_DISTRIBUTE=ON`."));
#endif
}
void InitDistTensorWithTensor(TensorObject* self,
const Tensor& local_tensor,
const std::vector<int>& global_dims,
const Place& place,
const std::string& name,
const ProcessMesh& process_mesh,
const Placements& placements) {
#ifdef PADDLE_WITH_DISTRIBUTE
PADDLE_ENFORCE_EQ(local_tensor.is_dense_tensor(),
true,
common::errors::InvalidArgument(
"DistTensor can only initialize by DenseTensor"));
self->tensor.set_name(name);
auto global_ddims = common::make_ddim(global_dims);
VLOG(4) << "Do TensorCopy from DenseTensor to DistTensor.";
if (place == local_tensor.place()) {
std::shared_ptr<DenseTensor> tensor =
std::static_pointer_cast<DenseTensor>(local_tensor.impl());
self->tensor.set_impl(std::make_shared<DistTensor>(
tensor, global_ddims, process_mesh, placements));
VLOG(4) << "Same place, do ShareDataWith for DistTensor.";
} else {
std::shared_ptr<DenseTensor> tensor = std::static_pointer_cast<DenseTensor>(
local_tensor.copy_to(place, true).impl());
self->tensor.set_impl(std::make_shared<DistTensor>(
tensor, global_ddims, process_mesh, placements));
VLOG(4) << "Different place, do TensorCopy for DistTensor.";
}
if (local_tensor.get_autograd_meta()) {
egr::EagerUtils::autograd_meta(&(self->tensor))
->SetPersistable(
egr::EagerUtils::unsafe_autograd_meta(local_tensor)->Persistable());
} else {
egr::EagerUtils::autograd_meta(&(self->tensor))->SetPersistable(false);
}
#else
PADDLE_THROW(common::errors::Unavailable(
"The tensor-based initialization of (Dist)Tensor is not supported "
"in the current PaddlePaddle, please recompile and install PaddlePaddle "
"with the option of `WITH_DISTRIBUTE=ON`."));
#endif
}
void InitTensorWithTensor(TensorObject* self,
const Tensor& src,
const Place& place,
const std::string& name) {
self->tensor.set_name(name);
if (place == src.place()) {
self->tensor.set_impl(src.impl());
VLOG(4) << "Same place, do ShareDataWith";
} else {
self->tensor.set_impl(src.copy_to(place, true).impl());
VLOG(4) << "Different place, do TensorCopy";
}
if (src.get_autograd_meta()) {
egr::EagerUtils::autograd_meta(&(self->tensor))
->SetPersistable(
egr::EagerUtils::unsafe_autograd_meta(src)->Persistable());
} else {
egr::EagerUtils::autograd_meta(&(self->tensor))->SetPersistable(false);
}
}
void InitTensorWithFrameworkTensor(TensorObject* self,
const DenseTensor& src,
const Place& place,
const std::string& name) {
self->tensor.set_name(name);
if (place == src.place()) {
self->tensor.set_impl(std::make_shared<DenseTensor>(src));
VLOG(4) << "Same place, do ShareDataWith";
} else {
auto temp = Tensor(std::make_shared<DenseTensor>(src));
self->tensor.set_impl(temp.copy_to(place, true).impl());
VLOG(4) << "Different place, do TensorCopy";
}
egr::EagerUtils::autograd_meta(&(self->tensor))->SetPersistable(false);
}
void InitStringTensorWithStringTensor(TensorObject* self,
const Tensor& src,
const Place& place,
const std::string& name) {
self->tensor.set_name(name);
auto impl = std::static_pointer_cast<phi::StringTensor>(src.impl());
self->tensor.set_impl(impl);
VLOG(4)
<< "Do ShareDataWith when using StringTensor to initialize StringTensor";
}
py::object ParsePyArray(
std::unordered_map<std::string, PyObject*> kws_map,
std::unordered_map<std::string, Py_ssize_t> kw_order_map,
PyObject* args,
bool flag_kwargs,
Py_ssize_t args_num) {
py::object numpy_value = py::object();
if (kw_order_map["value"] <= args_num) {
numpy_value = py::reinterpret_borrow<py::object>(
py::handle(PyTuple_GET_ITEM(args, kw_order_map["value"] - 1)));
} else {
if (flag_kwargs && kws_map["value"] != nullptr) {
numpy_value =
py::reinterpret_borrow<py::object>(py::handle(kws_map["value"]));
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"The first expected arguments is {value: PyArray}, "
"but could not parse the first argument {value: PyArray} "
"successfully. "
"Please check your input first and make sure you are on the right "
"way."));
}
}
return numpy_value;
}
Place ParsePlace(std::unordered_map<std::string, PyObject*> kws_map,
std::unordered_map<std::string, Py_ssize_t> kw_order_map,
PyObject* args,
bool flag_kwargs,
Py_ssize_t args_num) {
Place place = egr::Controller::Instance().GetExpectedPlace();
if (kw_order_map["place"] <= args_num) {
place = CastPyArg2Place(PyTuple_GET_ITEM(args, kw_order_map["place"] - 1),
kw_order_map["place"] - 1);
} else {
if (flag_kwargs && kws_map["place"] != nullptr) {
place = CastPyArg2Place(kws_map["place"], 0);
} else {
// default
return place;
}
}
return place;
}
ProcessMesh ParseProcessMeshArgs(
std::unordered_map<std::string, PyObject*> kws_map,
std::unordered_map<std::string, Py_ssize_t> kw_order_map,
PyObject* args,
bool flag_kwargs,
Py_ssize_t args_num) {
ProcessMesh process_mesh;
if (kw_order_map["process_mesh"] <= args_num) {
process_mesh = CastPyArg2ProcessMesh(
PyTuple_GET_ITEM(args, kw_order_map["process_mesh"] - 1),
kw_order_map["process_mesh"] - 1);
} else if (flag_kwargs && kws_map["process_mesh"] != nullptr) {
process_mesh = CastPyArg2ProcessMesh(kws_map["process_mesh"], 0);
}
return process_mesh;
}
Placements ParsePlacementsArgs(
std::unordered_map<std::string, PyObject*> kws_map,
std::unordered_map<std::string, Py_ssize_t> kw_order_map,
PyObject* args,
bool flag_kwargs,
Py_ssize_t args_num) {
Placements placements;
const std::string& placements_key = "placements";
if (kw_order_map[placements_key] <= args_num) { // NOLINT
placements = CastPyArg2VectorOfPlacement(
PyTuple_GET_ITEM(args, kw_order_map[placements_key] - 1),
kw_order_map[placements_key] - 1);
} else if (flag_kwargs && kws_map[placements_key] != nullptr) {
placements = CastPyArg2VectorOfPlacement(kws_map[placements_key], 0);
}
return placements;
}
std::vector<int> ParseDimsArgs(
std::unordered_map<std::string, PyObject*> kws_map,
std::unordered_map<std::string, Py_ssize_t> kw_order_map,
PyObject* args,
bool flag_kwargs,
Py_ssize_t args_num) {
std::vector<int> dims;
const std::string& dims_key = "dims";
if (kw_order_map[dims_key] <= args_num) {
dims = CastPyArg2VectorOfInt(
PyTuple_GET_ITEM(args, kw_order_map[dims_key] - 1),
kw_order_map[dims_key] - 1);
} else if (flag_kwargs && kws_map[dims_key] != nullptr) {
dims = CastPyArg2VectorOfInt(kws_map[dims_key], 0);
}
return dims;
}
// boolean arguments: zero_copy, stop_gradient, persistable
int ParseBooleanArgs(std::string key,
std::unordered_map<std::string, PyObject*> kws_map,
std::unordered_map<std::string, Py_ssize_t> kw_order_map,
PyObject* args,
bool flag_kwargs,
Py_ssize_t args_num) {
int res = -1;
if (kw_order_map[key] <= args_num) {
res = static_cast<int>(CastPyArg2AttrBoolean(
PyTuple_GET_ITEM(args, kw_order_map[key] - 1), kw_order_map[key] - 1));
} else {
if (flag_kwargs && kws_map[key] != nullptr) {
res = static_cast<int>(CastPyArg2AttrBoolean(kws_map[key], 0));
}
}
return res;
}
std::string ParseName(std::unordered_map<std::string, PyObject*> kws_map,
std::unordered_map<std::string, Py_ssize_t> kw_order_map,
PyObject* args,
bool flag_kwargs,
Py_ssize_t args_num,
std::string unique_name_prefix = "generated_tensor") {
std::string act_name = "";
if (kw_order_map["name"] <= args_num) {
PyObject* name_obj = PyTuple_GET_ITEM(args, kw_order_map["name"] - 1);
if (name_obj == Py_None) {
act_name =
egr::Controller::Instance().GenerateUniqueName(unique_name_prefix);
} else {
act_name = CastPyArg2AttrString(name_obj, kw_order_map["name"] - 1);
}
} else {
if (flag_kwargs) {
if ((kws_map["name"] == NULL) || (kws_map["name"] == Py_None)) {
act_name =
egr::Controller::Instance().GenerateUniqueName(unique_name_prefix);
} else {
act_name = CastPyArg2AttrString(kws_map["name"], 0);
}
} else {
act_name =
egr::Controller::Instance().GenerateUniqueName(unique_name_prefix);
}
}
return act_name;
}
// initialize Tensor by PyArray(first argument is PyArray,
// mix args and kwargs) automatically.
void AutoInitTensorByPyArray(TensorObject* py_tensor_ptr,
std::unordered_map<std::string, PyObject*> kws_map,
PyObject* args,
bool flag_kwargs,
Py_ssize_t args_num) {
// The first argument of the Tensor constructor is PyArray,
// there are 6 arguments to construct the new Tensor,
// kw_order_map's key is every arguments of the constructor,
// kw_order_map's value is the position of the arguments respectively.
// If u want to update this constructor with new arguments,
// need to update this map and to add or change related code.
std::unordered_map<std::string, Py_ssize_t> kw_order_map{
{"value", 1},
{"place", 2},
{"persistable", 3},
{"zero_copy", 4},
{"name", 5},
{"stop_gradient", 6}};
py::object numpy_value = py::object();
Place place = egr::Controller::Instance().GetExpectedPlace();
bool persistable = false;
bool zero_copy = false;
std::string act_name = "";
int stop_gradient = -1;
numpy_value =
ParsePyArray(kws_map, kw_order_map, args, flag_kwargs, args_num);
place = ParsePlace(kws_map, kw_order_map, args, flag_kwargs, args_num);
persistable =
(1 ==
ParseBooleanArgs(
"persistable", kws_map, kw_order_map, args, flag_kwargs, args_num));
zero_copy =
(1 ==
ParseBooleanArgs(
"zero_copy", kws_map, kw_order_map, args, flag_kwargs, args_num));
act_name = ParseName(kws_map, kw_order_map, args, flag_kwargs, args_num);
stop_gradient = ParseBooleanArgs(
"stop_gradient", kws_map, kw_order_map, args, flag_kwargs, args_num);
EmptyTensorInitializer(
py_tensor_ptr, act_name, place, persistable, stop_gradient);
InitTensorWithNumpyValue(py_tensor_ptr, numpy_value, place, zero_copy);
}
// initialize Tensor by Tensor or DenseTensor (mix args and
// kwargs) automatically.
void AutoInitTensorByTensor(TensorObject* py_tensor_ptr,
std::unordered_map<std::string, PyObject*> kws_map,
PyObject* args,
bool flag_kwargs,
Py_ssize_t args_num,
bool init_by_egr_tensor = true) {
// The first argument of the Tensor constructor is Tensor or
// framework Tensor,
// there are 6 arguments to construct the new Tensor,
// kw_order_map's key is every arguments of the constructor,
// kw_order_map's value is the position of the arguments respectively.
// If u want to update this constructor with new arguments,
// need to update this map and to add or change related code.
std::unordered_map<std::string, Py_ssize_t> kw_order_map{{"value", 1},
{"place", 2},
{"name", 3},
{"dims", 4},
{"process_mesh", 5},
{"placements", 6}};
Place place = egr::Controller::Instance().GetExpectedPlace();
std::string act_name = "";
place = ParsePlace(kws_map, kw_order_map, args, flag_kwargs, args_num);
act_name = ParseName(kws_map, kw_order_map, args, flag_kwargs, args_num);
if (init_by_egr_tensor) {
Tensor src_tensor;
if (kw_order_map["value"] <= args_num) {
src_tensor =
CastPyArg2Tensor(PyTuple_GET_ITEM(args, kw_order_map["value"] - 1),
kw_order_map["value"] - 1);
} else {
if (flag_kwargs && kws_map["value"] != nullptr) {
src_tensor = CastPyArg2Tensor(kws_map["value"], 0);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"The first expected kwargs is {value: Tensor}, "
"but could not parse the first argument {value: Tensor} "
"successfully. "
"Please check your input first and make sure you are on the right "
"way."));
}
}
ProcessMesh process_mesh = ParseProcessMeshArgs(
kws_map, kw_order_map, args, flag_kwargs, args_num);
if (!process_mesh.empty()) {
auto placements = ParsePlacementsArgs(
kws_map, kw_order_map, args, flag_kwargs, args_num);
auto global_dims =
ParseDimsArgs(kws_map, kw_order_map, args, flag_kwargs, args_num);
if (!global_dims.empty()) {
InitDistTensorWithTensor(py_tensor_ptr,
src_tensor,
global_dims,
place,
act_name,
process_mesh,
placements);
} else {
InitDistTensorWithTensor(py_tensor_ptr,
src_tensor,
place,
act_name,
process_mesh,
placements);
}
} else {
InitTensorWithTensor(py_tensor_ptr, src_tensor, place, act_name);
}
} else {
// init by framework tensor
DenseTensor src_tensor;
if (kw_order_map["value"] <= args_num) {
src_tensor = CastPyArg2FrameworkTensor(
PyTuple_GET_ITEM(args, kw_order_map["value"] - 1),
kw_order_map["value"] - 1);
} else {
if (flag_kwargs && kws_map["value"] != nullptr) {
src_tensor = CastPyArg2FrameworkTensor(kws_map["value"], 0);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"The first expected arguments is {value: DenseTensor}, "
"but could not parse the first argument {value: DenseTensor} "
"successfully. "
"Please check your input first and make sure you are on the right "
"way."));
}
}
InitTensorWithFrameworkTensor(py_tensor_ptr, src_tensor, place, act_name);
}
}
void AutoInitStringTensorByPyArray(
TensorObject* py_tensor_ptr,
std::unordered_map<std::string, PyObject*> kws_map,
PyObject* args,
bool flag_kwargs,
Py_ssize_t args_num) {
// The first argument of the StringTensor constructor is PyArray,
// there are 4 arguments to construct the new StringTensor,
// kw_order_map's key is every arguments of the constructor,
// kw_order_map's value is the position of the arguments respectively.
// If u want to update this constructor with new arguments,
// need to update this map and to add or change related code.
std::unordered_map<std::string, Py_ssize_t> kw_order_map{{"value", 1},
{"name", 2}};
py::object numpy_value = py::object();
Place place = egr::Controller::Instance().GetExpectedPlace();
std::string act_name = "";
numpy_value =
ParsePyArray(kws_map, kw_order_map, args, flag_kwargs, args_num);
act_name = ParseName(kws_map,
kw_order_map,
args,
flag_kwargs,
args_num,
"generated_string_tensor");
EmptyStringTensorInitializer(py_tensor_ptr, act_name, place);
InitStringTensorWithNumpyValue(py_tensor_ptr, numpy_value);
}
void AutoInitStringTensorByStringTensor(
TensorObject* py_tensor_ptr,
std::unordered_map<std::string, PyObject*> kws_map,
PyObject* args,
bool flag_kwargs,
Py_ssize_t args_num) {
// The first argument of the Tensor constructor is StringTensor,
// there are 3 arguments to construct the new StringTensor,
// kw_order_map's key is every arguments of the constructor,
// kw_order_map's value is the position of the arguments respectively.
// If u want to update this constructor with new arguments,
// need to update this map and to add or change related code.
std::unordered_map<std::string, Py_ssize_t> kw_order_map{{"value", 1},
{"name", 2}};
Place place = egr::Controller::Instance().GetExpectedPlace();
std::string act_name = "";
act_name = ParseName(kws_map,
kw_order_map,
args,
flag_kwargs,
args_num,
"generated_string_tensor");
Tensor src_tensor;
if (kw_order_map["value"] <= args_num) {
src_tensor =
CastPyArg2Tensor(PyTuple_GET_ITEM(args, kw_order_map["value"] - 1),
kw_order_map["value"] - 1);
} else {
if (flag_kwargs && kws_map["value"] != nullptr) {
src_tensor = CastPyArg2Tensor(kws_map["value"], 0);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"The first expected kwargs is {value: Tensor}, "
"but could not parse the first argument {value: Tensor} "
"successfully. "
"Please check your input first and make sure you are on the right "
"way."));
}
}
InitStringTensorWithStringTensor(py_tensor_ptr, src_tensor, place, act_name);
}
PyDoc_STRVAR( // NOLINT
TensorDoc,
R"DOC(Tensor($self, /, value, place, persistable, zero_copy, name, stop_gradient, dims, dtype, type)
--
Tensor is the basic data structure in PaddlePaddle. There are some ways to create a Tensor:
- Use the existing ``data`` to create a Tensor, please refer to :ref:`api_paddle_to_tensor`.
- Create a Tensor with a specified ``shape``, please refer to :ref:`api_paddle_ones`,
:ref:`api_paddle_zeros`, :ref:`api_paddle_full`.
- Create a Tensor with the same ``shape`` and ``dtype`` as other Tensor, please refer to
:ref:`api_paddle_ones_like`, :ref:`api_paddle_zeros_like`, :ref:`api_paddle_full_like`.
)DOC");
/** We should have init function with signature:
* 1.
* def __init__ ()
* 2.
* (should have at least five parameter, five parameters create DenseTensor,
* seven parameters create DistTensor)
* def __init__ (
* ** dtype: DataType,
* ** dims: vector<int>,
* ** name: std::string,
* ** type: paddle::framework::proto::VarType::DENSE_TENSOR,
* ** persistable: bool,
* ** process_mesh: phi::distributed::ProcessMesh,
* ** placements: std::vector<Placement>)
* 3. (multi-place)
* (should have at least one parameter, one parameter equals to case 4, zero
* parameter equals to case 1)
* def __init__ (
* ** value: ndarray,
* ** place: Place,
* ** persistable: bool,
* ** zero_copy: bool,
* ** name: std::string,
* ** stop_gradient: bool)
* 4.
* def __init__ (
* ** value: ndarray)
* 5.
* def __init__ (
* ** tensor: Tensor)
* 6. (multi-place)
* (should have at least one parameter, one parameter equals to case 5, zero
* parameter equals to case 1.)
* def __init__ (
* ** global_tensor: Tensor,
* ** place: Place,
* ** name: std::string,
* ** process_mesh: phi::distributed::ProcessMesh,
* ** placements: std::vector<Placement>)
* 7. (multi-place)
* (should have at least one parameter, one parameter equals to case 5, zero
* parameter equals to case 1.)
* def __init__ (
* ** local_tensor: Tensor,
* ** global_dims: vector<int>,
* ** name: std::string,
* ** process_mesh: phi::distributed::ProcessMesh,
* ** placements: std::vector<Placement>)
* 8. (multi-place) (should have at least one parameter, one parameter similar
* to case 5, zero parameter equals to case 1.)
* def __init__ (
* ** tensor: FrameworkTensor,
* ** place: Place,
* ** name: std::string)
* **/
int TensorInit(PyObject* self, PyObject* args, PyObject* kwargs) {
EAGER_TRY
SetPythonStack();
// set a flag to record use kwargs or not
bool flag_kwargs = false;
if (kwargs && PyDict_Size(kwargs) > 0) flag_kwargs = true;
// all kwargs
PyObject* kw_zero_copy = nullptr;
PyObject* kw_persistable = nullptr;
PyObject* kw_stop_gradient = nullptr;
PyObject* kw_value = nullptr; // receive PyArray or Tensor
PyObject* kw_place = nullptr;
PyObject* kw_name = nullptr;
PyObject* kw_dims = nullptr;
PyObject* kw_dtype = nullptr;
PyObject* kw_type = nullptr;
PyObject* kw_process_mesh = nullptr;
PyObject* kw_placements = nullptr;
// the keywords argument
static char* kwlist[] = {const_cast<char*>("value"), // NOLINT
const_cast<char*>("place"),
const_cast<char*>("persistable"),
const_cast<char*>("zero_copy"),
const_cast<char*>("name"),
const_cast<char*>("stop_gradient"),
const_cast<char*>("dims"),
const_cast<char*>("dtype"),
const_cast<char*>("type"),
const_cast<char*>("process_mesh"),
const_cast<char*>("placements"),
nullptr};
// 'O' Store a Python object (without any conversion) in a C object pointer,
// '|' Indicates that the remaining arguments in the Python argument list are
// optional.
// PyArg_ParseTupleAndKeywords can Parse the parameters of a function that
// takes both positional and keyword parameters into local variables,
// which enhance case2, case3, case4, case5, case6, case7.
bool flag_ = PyArg_ParseTupleAndKeywords(args,
kwargs,
"|OOOOOOOOOOO",
kwlist,
&kw_value,
&kw_place,
&kw_persistable,
&kw_zero_copy,
&kw_name,
&kw_stop_gradient,
&kw_dims,
&kw_dtype,
&kw_type,
&kw_process_mesh,
&kw_placements);
// helper map
std::unordered_map<std::string, PyObject*> kws_map{
{"value", kw_value},
{"place", kw_place},
{"persistable", kw_persistable},
{"zero_copy", kw_zero_copy},
{"name", kw_name},
{"stop_gradient", kw_stop_gradient},
{"dims", kw_dims},
{"dtype", kw_dtype},
{"type", kw_type},
{"process_mesh", kw_process_mesh},
{"placements", kw_placements}};
PADDLE_ENFORCE_EQ(
flag_,
true,
common::errors::PreconditionNotMet(
"Could not parse args and kwargs successfully, "
"please check your input first and make "
"sure you are on the right way. "
"The expected arguments as follow: ("
"value, place, persistable, zero_copy, "
"name, stop_gradient, dims, dtype, type, process_mesh, placements)"));
PADDLE_ENFORCE_NOT_NULL(
self,
common::errors::Fatal(
"Calling __init__ of Eager Tensor without __new__ is "
"forbidden. Please check your code and make sure you new a "
"eager tensor before init it."));
auto py_tensor_ptr = reinterpret_cast<TensorObject*>(self);
Py_ssize_t args_num = PyTuple_Size(args);
VLOG(6) << " args_num: " << args_num;
// args_num = 0, means that there is no position arguments.
if (args_num == (Py_ssize_t)0) {
if (!flag_kwargs) {
// case 1
VLOG(6) << "Calling case1's initializer.";
EmptyTensorInitializer(
py_tensor_ptr,
egr::Controller::Instance().GenerateUniqueName("generated_tensor"),
egr::Controller::Instance().GetExpectedPlace());
return 0;
} else { // no position args, all arguments are kwargs
if (kw_value != nullptr) {
if (pybind11::detail::npy_api::get().PyArray_Check_(kw_value)) {
VLOG(6) << "Calling case3's or case4's initializer";
AutoInitTensorByPyArray(
py_tensor_ptr, kws_map, args, flag_kwargs, args_num);
return 0;
} else if (PyObject_TypeCheck(kw_value, p_tensor_type)) {
VLOG(6) << "Calling case5's or case6's or case7's initializer";
AutoInitTensorByTensor(
py_tensor_ptr, kws_map, args, flag_kwargs, args_num);
return 0;
} else if (PyObject_TypeCheck(kw_value, g_framework_tensor_pytype)) {
VLOG(6) << "Calling case8's initializer.";
AutoInitTensorByTensor(py_tensor_ptr,
kws_map,
args,
flag_kwargs,
args_num,
/* false means not init by egr tensor*/ false);
return 0;
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Could not parse the first keyword argument successfully, "
"the first keyword argument is value, but it should be PyArray "
"or Tensor or DenseTensor. "
"Please check your input first and make sure you are on the "
"right way."));
}
} else if (kw_dtype != nullptr &&
(PyObject_TypeCheck(kw_dtype, g_data_type_pytype) ||
PyObject_TypeCheck(kw_dtype, g_vartype_pytype))) {
// TODO(jeff41404): until the default value of FLAGS_deable_ir_appi is
// True, can delete `PyObject_TypeCheck(kw_dtype, g_vartype_pytype)`
// Retain it during the transitional period.
VLOG(6) << "Calling case2's initializer";
PADDLE_ENFORCE_NOT_NULL(
kw_dims,
common::errors::InvalidArgument(
"Calling __init__ of Eager Tensor with NULL dims is "
"forbidden. Please check your code and make sure you new a "
"dims before calling this constructor."));
PADDLE_ENFORCE_NOT_NULL(
kw_name,
common::errors::InvalidArgument(
"Calling __init__ of Eager Tensor with NULL name is "
"forbidden. Please check your code and make sure you new a "
"name before calling this constructor."));
PADDLE_ENFORCE_NOT_NULL(
kw_dtype,
common::errors::InvalidArgument(
"Calling __init__ of Eager Tensor with NULL dtype is "
"forbidden. Please check your code and make sure you new a "
"dtype before calling this constructor."));
PADDLE_ENFORCE_NOT_NULL(
kw_persistable,
common::errors::InvalidArgument(
"Calling __init__ of Eager Tensor with NULL persistable is "
"forbidden. Please check your code and make sure you new a "
"persistable before calling this constructor."));
DataType dtype = CastPyArg2DataType(kw_dtype, "TensorInit", 0);
std::vector<int> dims = CastPyArg2VectorOfInt(kw_dims, 0);
std::string act_name = "";
if (kw_name == Py_None) {
act_name = egr::Controller::Instance().GenerateUniqueName(
"generated_tensor");
} else {
act_name = CastPyArg2AttrString(kw_name, 0);
}
framework::proto::VarType::Type var_type =
CastPyArg2ProtoType(kw_type, 0);
bool persistable = CastPyArg2AttrBoolean(kw_persistable, 0);
ProcessMesh* process_mesh_ptr = nullptr;
if (kw_process_mesh != nullptr) {
ProcessMesh process_mesh = CastPyArg2ProcessMesh(kw_process_mesh, 0);
process_mesh_ptr = &process_mesh;
}
Placements* placements_ptr = nullptr;
if (kw_placements != nullptr) {
Placements placements = CastPyArg2VectorOfPlacement(kw_placements, 0);
placements_ptr = &placements;
}
EmptyTensorInitializer(py_tensor_ptr,
act_name,
egr::Controller::Instance().GetExpectedPlace(),
persistable,
/* stop_gradient */ -1,
dtype,
dims,
var_type,
process_mesh_ptr,
placements_ptr);
return 0;
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"We not only support construct Tensor from numpy value "
"or tensor(Tensor or DenseTensor) "
"with python kwargs by this initializer, "
"but also even support dtype to init a empty Tensor. "
"Please check your input first and make sure you call the existed "
"constructor."));
}
}
} else if (args_num == (Py_ssize_t)1 || args_num == (Py_ssize_t)2 ||
args_num == (Py_ssize_t)3) {
// 1 to 3 position args, remaining arguments are kwargs
PyObject* arg0_ptr = PyTuple_GET_ITEM(args, 0);
if (pybind11::detail::npy_api::get().PyArray_Check_(arg0_ptr)) {
VLOG(6) << "Calling case3's or case4's initializer.";
AutoInitTensorByPyArray(
py_tensor_ptr, kws_map, args, flag_kwargs, args_num);
return 0;
} else if (PyObject_TypeCheck(arg0_ptr, p_tensor_type)) {
VLOG(6) << "Calling case5's or case6's or case7's initializer.";
AutoInitTensorByTensor(
py_tensor_ptr, kws_map, args, flag_kwargs, args_num);
return 0;
} else if (PyObject_TypeCheck(arg0_ptr, g_framework_tensor_pytype)) {
VLOG(6) << "Calling case8's initializer.";
AutoInitTensorByTensor(py_tensor_ptr,
kws_map,
args,
flag_kwargs,
args_num,
/* false means not init by egr tensor*/ false);
return 0;
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"We support construct Tensor from numpy value "
"or tensor(Tensor or DenseTensor) "
"with python args and kwargs by this initializer, "
"but the first argument should be PyArray or Tensor or "
"DenseTensor. "
"Please check your input first and make sure you call the existed "
"constructor."));
}
} else if (args_num == (Py_ssize_t)4) {
// 4 position args, remaining arguments are kwargs
PyObject* arg0_ptr = PyTuple_GET_ITEM(args, 0);
if (pybind11::detail::npy_api::get().PyArray_Check_(arg0_ptr)) {
VLOG(6) << "Calling case3's or case4's initializer.";
AutoInitTensorByPyArray(
py_tensor_ptr, kws_map, args, flag_kwargs, args_num);
return 0;
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Incompatible constructor arguments, "
"there are 4 position args and remaining arguments arg kwargs,"
"but the first position args should be PyArray. "
"Please check your code and make sure the first position args is "
"PyArray."));
}
} else if (args_num == (Py_ssize_t)5) {
if (!flag_kwargs) {
PyObject* arg0_ptr = PyTuple_GET_ITEM(args, 0);
// TODO(jeff41404): until the default value of FLAGS_deable_ir_appi is
// True, can delete `PyObject_TypeCheck(arg0_ptr, g_vartype_pytype)`
// Retain it during the transitional period.
if (PyObject_TypeCheck(arg0_ptr, g_data_type_pytype) ||
PyObject_TypeCheck(arg0_ptr, g_vartype_pytype)) {
VLOG(6) << "Calling case2's initializer.";
DataType dtype = CastPyArg2DataType(arg0_ptr, "TensorInit", 0);
std::vector<int> dims =
CastPyArg2VectorOfInt(PyTuple_GET_ITEM(args, 1), 1);
std::string act_name = "";
PyObject* name_obj = PyTuple_GET_ITEM(args, 2);
if (name_obj == Py_None) {
act_name = egr::Controller::Instance().GenerateUniqueName(
"generated_tensor");
} else {
act_name = CastPyArg2AttrString(PyTuple_GET_ITEM(args, 2), 2);
}
framework::proto::VarType::Type var_type =
CastPyArg2ProtoType(PyTuple_GET_ITEM(args, 3), 3);
bool persistable = CastPyArg2AttrBoolean(PyTuple_GET_ITEM(args, 4), 4);
EmptyTensorInitializer(py_tensor_ptr,
act_name,
egr::Controller::Instance().GetExpectedPlace(),
persistable,
-1,
dtype,
dims,
var_type);
return 0;
} else if (pybind11::detail::npy_api::get().PyArray_Check_(arg0_ptr)) {
VLOG(6) << "Calling case3's initializer.";
AutoInitTensorByPyArray(
py_tensor_ptr, kws_map, args, flag_kwargs, args_num);
return 0;
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Incompatible constructor arguments, "
"there are only 5 position args,"
"but the first position args should be PyArray or dtype. "
"Please check your code and make sure you call the existed "
"constructor."));
}
} else { // five position args, remaining arguments are kwargs
PyObject* arg0_ptr = PyTuple_GET_ITEM(args, 0);
if (pybind11::detail::npy_api::get().PyArray_Check_(arg0_ptr)) {
VLOG(6) << "Calling case3's or case4's initializer";
AutoInitTensorByPyArray(
py_tensor_ptr, kws_map, args, flag_kwargs, args_num);
return 0;
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Incompatible constructor arguments, "
"there are 5 position args and remaining arguments are kwargs,"
"but the first position args should be PyArray. "
"Please check your code and make sure the first position args is "
"PyArray."));
}
}
} else if (args_num == (Py_ssize_t)6) {
if (!flag_kwargs) {
// case 3
VLOG(6) << "Calling case3's initializer.";
AutoInitTensorByPyArray(
py_tensor_ptr, kws_map, args, flag_kwargs, args_num);
return 0;
} else { // six position args, remaining arguments are kwargs, but this
// is not a right way
PADDLE_THROW(common::errors::InvalidArgument(
"Incompatible constructor arguments, "
"there are 6 position args and the remaining arguments are kwargs. "
"Please check your code and make sure the first position args is "
"PyArray."));
}
} else if (args_num == (Py_ssize_t)7) {
if (!flag_kwargs) {
PyObject* arg0_ptr = PyTuple_GET_ITEM(args, 0);
// TODO(jeff41404): until the default value of FLAGS_deable_ir_appi is
// True, can delete `PyObject_TypeCheck(arg0_ptr, g_vartype_pytype)`
// Retain it during the transitional period.
if (PyObject_TypeCheck(arg0_ptr, g_data_type_pytype) ||
PyObject_TypeCheck(arg0_ptr, g_vartype_pytype)) {
VLOG(6) << "Calling case2's initializer.";
DataType dtype = CastPyArg2DataType(arg0_ptr, "TensorInit", 0);
std::vector<int> dims =
CastPyArg2VectorOfInt(PyTuple_GET_ITEM(args, 1), 1);
std::string act_name = "";
PyObject* name_obj = PyTuple_GET_ITEM(args, 2);
if (name_obj == Py_None) {
act_name = egr::Controller::Instance().GenerateUniqueName(
"generated_tensor");
} else {
act_name = CastPyArg2AttrString(PyTuple_GET_ITEM(args, 2), 2);
}
framework::proto::VarType::Type var_type =
CastPyArg2ProtoType(PyTuple_GET_ITEM(args, 3), 3);
bool persistable = CastPyArg2AttrBoolean(PyTuple_GET_ITEM(args, 4), 4);
ProcessMesh process_mesh =
CastPyArg2ProcessMesh(PyTuple_GET_ITEM(args, 5), 5);
Placements placements =
CastPyArg2VectorOfPlacement(PyTuple_GET_ITEM(args, 6), 6);
EmptyTensorInitializer(py_tensor_ptr,
act_name,
egr::Controller::Instance().GetExpectedPlace(),
persistable,
-1,
dtype,
dims,
var_type,
&process_mesh,
&placements);
return 0;
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Incompatible constructor arguments, "
"there are only 7 position args,"
"but the first position args should be dtype. "
"Please check your code and make sure you call the existed "
"constructor."));
}
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Incompatible constructor arguments, "
"there are 7 position args and remaining arguments are kwargs,"
"Please check your code and make sure you call the existed "
"constructor."));
}
} else {
PADDLE_THROW(common::errors::Fatal(
"Can't not find expected num of args, please check your call, and "
"make sure u call the existed constructor."));
}
return -1;
EAGER_CATCH_AND_THROW_RETURN_NEG
}
/** We should have init function with signature:
* 1.
* def __init__ ()
*
* 2.
* def __init__ (
* ** dims: vector<int>,
* ** name: std::string)
*
* 3.
* (should have at least one parameter, one parameter equals to case 4, zero
* parameter equals to case 1)
* def __init__ (
* ** value: ndarray,
* ** zero_copy: bool,
* ** name: std::string)
*
* 4.
* def __init__ (
* ** value: ndarray)
*
* 5.
* def __init__ (
* ** tensor: Tensor)
*
* 6.
* (should have at least one parameter, one parameter equals to case 5, zero
* parameter equals to case 1.)
* def __init__ (
* ** tensor: Tensor,
* ** name: std::string)
* **/
int StringTensorInit(PyObject* self, PyObject* args, PyObject* kwargs) {
// set a flag to record use kwargs or not
bool flag_kwargs = false;
if (kwargs) flag_kwargs = true;
// all kwargs
PyObject* kw_zero_copy = nullptr;
PyObject* kw_value = nullptr; // receive PyArray or Tensor
PyObject* kw_name = nullptr;
PyObject* kw_dims = nullptr;
// the keywords argument
static char* kwlist[] = {const_cast<char*>("value"), // NOLINT
const_cast<char*>("zero_copy"),
const_cast<char*>("name"),
const_cast<char*>("dims"),
nullptr};
// 'O' Store a Python object (without any conversion) in a C object pointer,
// '|' Indicates that the remaining arguments in the Python argument list are
// optional.
// PyArg_ParseTupleAndKeywords can Parse the parameters of a function that
// takes both positional and keyword parameters into local variables,
// which enhance case1, case2, case3, case4, case 5, case 6.
bool flag_ = PyArg_ParseTupleAndKeywords(args,
kwargs,
"|OOOO",
kwlist,
&kw_value,
&kw_zero_copy,
&kw_name,
&kw_dims);
// helper map
std::unordered_map<std::string, PyObject*> kws_map{
{"value", kw_value},
{"zero_copy", kw_zero_copy},
{"name", kw_name},
{"dims", kw_dims}};
PADDLE_ENFORCE_EQ(flag_,
true,
common::errors::PreconditionNotMet(
"Could not parse args and kwargs successfully, "
"please check your input first and make "
"sure you are on the right way. "
"The expected arguments as follow: ("
"value, zero_copy, name, dims)"));
PADDLE_ENFORCE_NOT_NULL(
self,
common::errors::Fatal(
"Calling __init__ of Eager Tensor without __new__ is "
"forbidden. Please check your code and make sure you new a "
"eager tensor before init it."));
auto py_tensor_ptr = reinterpret_cast<TensorObject*>(self);
Py_ssize_t args_num = PyTuple_Size(args);
VLOG(6) << " args_num: " << args_num;
// args_num = 0, means that there is no position arguments.
if (args_num == (Py_ssize_t)0) {
if (!flag_kwargs) {
// case 1
VLOG(6) << "Calling case1's string initializer.";
EmptyStringTensorInitializer(
py_tensor_ptr,
egr::Controller::Instance().GenerateUniqueName(
"generated_string_tensor"),
egr::Controller::Instance().GetExpectedPlace());
return 0;
} else {
if (kw_value != nullptr) {
if (pybind11::detail::npy_api::get().PyArray_Check_(kw_value)) {
VLOG(6) << "Calling case3's or case4's string initializer";
AutoInitStringTensorByPyArray(
py_tensor_ptr, kws_map, args, flag_kwargs, args_num);
return 0;
} else if (PyObject_TypeCheck(kw_value, p_string_tensor_type)) {
VLOG(6) << "Calling case5's or case6's string initializer";
AutoInitStringTensorByStringTensor(
py_tensor_ptr, kws_map, args, flag_kwargs, args_num);
return 0;
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Could not parse the first keyword argument successfully, "
"the first keyword argument is value, but it should be PyArray "
"or StringTensor."
"Please check your input first and make sure you are on the "
"right way."));
}
} else if (kw_dims != nullptr) {
VLOG(6) << "Calling case2's string initializer.";
std::unordered_map<std::string, Py_ssize_t> kw_order_map{{"dims", 1},
{"name", 2}};
std::vector<int> dims = CastPyArg2VectorOfInt(kw_dims, 0);
std::string act_name = ParseName(kws_map,
kw_order_map,
args,
flag_kwargs,
args_num,
"generated_string_tensor");
EmptyStringTensorInitializer(
py_tensor_ptr,
act_name,
egr::Controller::Instance().GetExpectedPlace(),
dims);
return 0;
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"We not only support construct Tensor from numpy value "
"or StringTensor with python kwargs by this initializer, "
"but also even support dtype to init a empty StringTensor. "
"Please check your input first and make sure you call the existed "
"constructor."));
}
}
} else if (args_num == (Py_ssize_t)1) { // case 3 ~ 6
// 1 position args, remaining arguments are kwargs
PyObject* arg0_ptr = PyTuple_GET_ITEM(args, 0);
if (pybind11::detail::npy_api::get().PyArray_Check_(arg0_ptr)) {
VLOG(6) << "Calling case3's or case4's string initializer.";
AutoInitStringTensorByPyArray(
py_tensor_ptr, kws_map, args, flag_kwargs, args_num);
return 0;
} else if (PyObject_TypeCheck(arg0_ptr, p_string_tensor_type)) {
VLOG(6) << "Calling case5's or case6's string initializer.";
AutoInitStringTensorByStringTensor(
py_tensor_ptr, kws_map, args, flag_kwargs, args_num);
return 0;
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Could not parse the first keyword argument successfully, "
"the first keyword argument is value, but it should be PyArray "
"or StringTensor."
"Please check your input first and make sure you are on the "
"right way."));
}
} else if (args_num == (Py_ssize_t)2) { // case 2
// 2 position args
if (!flag_kwargs) {
PyObject* arg0_ptr = PyTuple_GET_ITEM(args, 0);
if (PyObject_TypeCheck(arg0_ptr, p_string_tensor_type)) {
VLOG(6) << "Calling case6's string initializer.";
AutoInitStringTensorByStringTensor(
py_tensor_ptr, kws_map, args, flag_kwargs, args_num);
return 0;
} else if (pybind11::detail::npy_api::get().PyArray_Check_(arg0_ptr)) {
VLOG(6) << "Calling case3's string initializer.";
AutoInitStringTensorByPyArray(
py_tensor_ptr, kws_map, args, flag_kwargs, args_num);
return 0;
} else {
VLOG(6) << "Calling case2's string initializer.";
std::vector<int> dims = CastPyArg2VectorOfInt(arg0_ptr, 0);
std::string act_name = "";
PyObject* name_obj = PyTuple_GET_ITEM(args, 1);
if (name_obj == Py_None) {
act_name = egr::Controller::Instance().GenerateUniqueName(
"generated_string_tensor");
} else {
act_name = CastPyArg2AttrString(PyTuple_GET_ITEM(args, 1), 1);
}
EmptyStringTensorInitializer(
py_tensor_ptr,
act_name,
egr::Controller::Instance().GetExpectedPlace(),
dims);
return 0;
}
} else {
PADDLE_THROW(common::errors::Fatal(
"Can't not find expected num of args, please check your call, and "
"make sure u call the existed constructor."));
}
}
return 1;
}
void AddPyMethodDefs(std::vector<PyMethodDef>* vector, PyMethodDef* methods) {
if (!vector->empty()) {
// remove nullptr terminator
vector->pop_back();
}
while (true) {
vector->push_back(*methods);
if (!methods->ml_name) {
break;
}
methods++;
}
}
static void TensorDealloc(TensorObject* self) {
if (self->weakrefs != nullptr)
PyObject_ClearWeakRefs(reinterpret_cast<PyObject*>(self));
self->tensor.~Tensor();
Py_XDECREF(self->dict);
Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
}
extern struct PyGetSetDef variable_properties[]; // NOLINT
extern struct PyGetSetDef string_tensor_variable_properties[]; // NOLINT
extern PyMethodDef variable_methods[]; // NOLINT
extern PyMethodDef math_op_patch_methods[]; // NOLINT
extern PyMethodDef string_tensor_variable_methods[]; // NOLINT
PyNumberMethods number_methods;
PySequenceMethods sequence_methods;
PyMappingMethods mapping_methods;
void BindEager(pybind11::module* module) {
auto m = module->def_submodule("eager");
static std::vector<PyMethodDef> methods;
AddPyMethodDefs(&methods, variable_methods);
AddPyMethodDefs(&methods, math_op_patch_methods);
auto heap_type = reinterpret_cast<PyHeapTypeObject*>(
PyType_Type.tp_alloc(&PyType_Type, 0));
heap_type->ht_name = ToPyObject("Tensor");
heap_type->ht_qualname = ToPyObject("Tensor");
auto type = &heap_type->ht_type;
type->tp_name = "Tensor";
type->tp_basicsize = sizeof(TensorObject);
type->tp_dealloc = (destructor)TensorDealloc;
type->tp_as_number = &number_methods;
type->tp_as_sequence = &sequence_methods;
type->tp_as_mapping = &mapping_methods;
type->tp_methods = methods.data();
type->tp_getset = variable_properties;
type->tp_init = TensorInit;
type->tp_new = TensorNew;
type->tp_doc = TensorDoc;
type->tp_weaklistoffset = offsetof(TensorObject, weakrefs);
Py_INCREF(&PyBaseObject_Type);
type->tp_base = reinterpret_cast<PyTypeObject*>(&PyBaseObject_Type);
type->tp_flags |=
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; // NOLINT
type->tp_dictoffset = offsetof(TensorObject, dict);
type->tp_as_async = &heap_type->as_async;
p_tensor_type = type;
if (PyType_Ready(type) < 0) {
PADDLE_THROW(
common::errors::Fatal("Init Paddle error in BindEager(PyType_Ready)."));
return;
}
Py_INCREF(type);
if (PyModule_AddObject(m.ptr(), "Tensor", reinterpret_cast<PyObject*>(type)) <
0) {
Py_DECREF(type);
Py_DECREF(m.ptr());
PADDLE_THROW(common::errors::Fatal(
"Init Paddle error in BindEager(PyModule_AddObject)."));
return;
}
BindFunctions(m.ptr());
BindEagerPyLayer(m.ptr());
BindEagerOpFunctions(&m);
}
void BindEagerStringTensor(pybind11::module* module) {
auto m = module->def_submodule("eager");
auto heap_type = reinterpret_cast<PyHeapTypeObject*>(
PyType_Type.tp_alloc(&PyType_Type, 0));
heap_type->ht_name = ToPyObject("StringTensor");
heap_type->ht_qualname = ToPyObject("StringTensor");
auto type = &heap_type->ht_type;
type->tp_name = "StringTensor";
type->tp_basicsize = sizeof(TensorObject);
type->tp_dealloc = (destructor)TensorDealloc;
type->tp_as_number = &number_methods;
type->tp_as_sequence = &sequence_methods;
type->tp_as_mapping = &mapping_methods;
type->tp_methods = string_tensor_variable_methods;
type->tp_getset = string_tensor_variable_properties;
type->tp_init = StringTensorInit;
type->tp_new = TensorNew;
Py_INCREF(&PyBaseObject_Type);
type->tp_base = reinterpret_cast<PyTypeObject*>(&PyBaseObject_Type);
type->tp_flags |=
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; // NOLINT
type->tp_dictoffset = offsetof(TensorObject, dict);
type->tp_as_async = &heap_type->as_async;
p_string_tensor_type = type;
if (PyType_Ready(type) < 0) {
PADDLE_THROW(
common::errors::Fatal("Init Paddle error in BindEager(PyType_Ready)."));
return;
}
Py_INCREF(type);
if (PyModule_AddObject(
m.ptr(), "StringTensor", reinterpret_cast<PyObject*>(type)) < 0) {
Py_DECREF(type);
Py_DECREF(m.ptr());
PADDLE_THROW(common::errors::Fatal(
"Init Paddle error in BindEagerStringTensor(PyModule_AddObject)."));
return;
}
}
} // namespace paddle::pybind