/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved. Copyright (c) 2022 NVIDIA 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. */ #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include #include #include #else #include #endif #include #include #include #include #include #include #include #include #include // NOLINT // for call_once #include #include #include #include #include #include #include #include #include "paddle/common/ddim.h" #include "paddle/fluid/eager/grad_node_info.h" #include "paddle/fluid/framework/compiled_program.h" #include "paddle/fluid/framework/convert_utils.h" #include "paddle/fluid/framework/custom_operator.h" #include "paddle/fluid/framework/data_layout.h" #include "paddle/fluid/framework/data_type_transform.h" #include "paddle/fluid/framework/dense_tensor_array.h" #include "paddle/fluid/framework/details/nan_inf_utils_detail.h" #include "paddle/fluid/framework/executor.h" #include "paddle/fluid/framework/executor_cache.h" #include "paddle/fluid/framework/executor_gc_helper.h" #include "paddle/fluid/framework/feed_fetch_method.h" #include "paddle/fluid/framework/feed_fetch_type.h" #include "paddle/fluid/framework/garbage_collector.h" #include "paddle/fluid/framework/io/fs.h" #include "paddle/fluid/framework/ir/coalesce_grad_tensor_pass.h" #include "paddle/fluid/framework/ir/cost_model.h" #include "paddle/fluid/framework/ir/generate_pass.h" #include "paddle/fluid/framework/ir/pass_builder.h" #include "paddle/fluid/framework/new_executor/collect_shape_manager.h" #include "paddle/fluid/framework/new_executor/executor_statistics.h" #include "paddle/fluid/framework/new_executor/interpreter/job.h" #include "paddle/fluid/framework/new_executor/interpreter/plan.h" #include "paddle/fluid/framework/new_executor/standalone_executor.h" #include "paddle/fluid/framework/op_info.h" #include "paddle/fluid/framework/op_registry.h" #include "paddle/fluid/framework/op_version_registry.h" #include "paddle/fluid/framework/phi_utils.h" #include "paddle/fluid/framework/prune.h" #include "paddle/fluid/framework/scope_pool.h" #include "paddle/fluid/framework/selected_rows_utils.h" #include "paddle/fluid/framework/tensor_util.h" #include "paddle/fluid/framework/trainer.h" #include "paddle/fluid/framework/type_defs.h" #include "paddle/fluid/framework/version.h" #include "paddle/fluid/imperative/amp_auto_cast.h" #include "paddle/fluid/imperative/layer.h" #include "paddle/fluid/prim/utils/utils.h" #include "paddle/fluid/pybind/size.h" #include "paddle/fluid/pybind/torch_compat.h" #include "paddle/phi/common/bfloat16.h" #include "paddle/phi/common/float16.h" #include "paddle/phi/common/int_array.h" #include "paddle/phi/common/logging_utils.h" #include "paddle/phi/core/framework/reader.h" #include "paddle/phi/core/memory/allocation/allocator_strategy.h" #include "paddle/phi/core/raw_tensor.h" #include "paddle/phi/core/tensor_meta.h" #if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) #include "paddle/phi/core/memory/allocation/auto_growth_best_fit_allocator_v2.h" #include "paddle/phi/core/memory/allocation/cuda_ipc_allocator.h" #endif #include "paddle/common/macros.h" #include "paddle/fluid/operators/ops_extra_info.h" #include "paddle/fluid/operators/py_func_op.h" #include "paddle/fluid/platform/enforce.h" #include "paddle/fluid/platform/init.h" #include "paddle/fluid/platform/profiler/event_python.h" #include "paddle/fluid/platform/profiler/profiler.h" #include "paddle/fluid/platform/tensorrt/engine_params.h" #include "paddle/fluid/pybind/auto_parallel_py.h" #include "paddle/fluid/pybind/bind_cost_model.h" #include "paddle/fluid/pybind/communication.h" #include "paddle/fluid/pybind/compatible.h" #include "paddle/fluid/pybind/const_value.h" #include "paddle/fluid/pybind/cuda_streams_py.h" #include "paddle/fluid/pybind/cudart_py.h" #include "paddle/fluid/pybind/custom_device_py.h" #include "paddle/fluid/pybind/data_set_py.h" #include "paddle/fluid/pybind/distributed_py.h" #include "paddle/fluid/pybind/eager.h" #include "paddle/fluid/pybind/exception.h" #include "paddle/fluid/pybind/fleet_wrapper_py.h" #include "paddle/fluid/pybind/generator_py.h" #include "paddle/fluid/pybind/global_value_getter_setter.h" #include "paddle/fluid/pybind/gloo_context_py.h" #include "paddle/fluid/pybind/gloo_wrapper_py.h" #include "paddle/fluid/pybind/graph.h" #include "paddle/fluid/pybind/imperative.h" #include "paddle/fluid/pybind/inference_api.h" #include "paddle/fluid/pybind/io.h" #include "paddle/fluid/pybind/jit.h" #include "paddle/fluid/pybind/native_meta_tensor.h" #include "paddle/fluid/pybind/pir.h" #include "paddle/fluid/pybind/pybind_variant_caster.h" #include "paddle/fluid/pybind/python_callable_registry.h" #include "paddle/fluid/pybind/xpu_streams_py.h" #include "paddle/phi/backends/cpu/cpu_info.h" #include "paddle/phi/backends/device_manager.h" #include "paddle/phi/backends/dynload/dynamic_loader.h" #include "paddle/phi/backends/gpu/gpu_info.h" #include "paddle/phi/backends/xpu/xpu_info.h" #include "paddle/phi/common/data_type.h" #include "paddle/phi/common/place.h" #include "paddle/phi/core/compat/convert_utils.h" #include "paddle/phi/core/lod_utils.h" #include "paddle/phi/core/memory/allocation/mmap_allocator.h" #include "paddle/phi/core/memory/mem_utils.h" #include "paddle/phi/core/platform/cpu_helper.h" #include "paddle/phi/core/platform/device/device_wrapper.h" #include "paddle/phi/core/platform/device_context.h" #include "paddle/phi/core/platform/monitor.h" #include "paddle/phi/core/platform/profiler.h" #include "paddle/phi/core/platform/profiler/event_tracing.h" #include "paddle/phi/kernels/funcs/common_infer_shape_functions.h" #include "paddle/utils/none.h" #ifdef PADDLE_WITH_DISTRIBUTE #include "paddle/fluid/pybind/deep_ep_api.h" #include "paddle/fluid/pybind/dist_api.h" #endif #if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL) #include "paddle/fluid/pybind/nccl_wrapper_py.h" #endif #include "paddle/fluid/framework/data_type.h" #include "paddle/fluid/pybind/compiled_program.h" #include "paddle/fluid/pybind/place.h" #include "paddle/fluid/pybind/protobuf.h" #include "paddle/fluid/pybind/pybind.h" // NOLINT #include "paddle/fluid/pybind/reader_py.h" #include "paddle/fluid/pybind/tensor.h" #include "paddle/fluid/pybind/tensor_py.h" #include "paddle/utils/string/to_string.h" #if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) #if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL) #include "paddle/fluid/operators/nccl/nccl_gpu_common.h" #endif #ifdef PADDLE_WITH_CUDA #include "paddle/phi/backends/gpu/cuda/gpu_event_timer.h" #endif #ifndef PADDLE_WITH_HIP #include "paddle/phi/core/platform/device/gpu/cuda/cuda_profiler.h" #endif #include "paddle/phi/core/platform/device/gpu/gpu_info.h" #endif #ifdef PADDLE_WITH_XPU #include "paddle/phi/backends/xpu/cuda_graph.h" #include "paddle/phi/core/memory/allocation/xpu_ipc_allocator.h" #include "paddle/phi/core/platform/device/xpu/xpu_info.h" #include "paddle/phi/core/platform/device/xpu/xpu_op_list.h" #include "paddle/phi/core/platform/device/xpu/xpu_profiler.h" #endif #ifdef PADDLE_WITH_CUSTOM_DEVICE #include "paddle/fluid/platform/profiler/custom_device/custom_tracer.h" #include "paddle/phi/backends/device_base.h" #include "paddle/phi/capi/capi.h" #include "paddle/phi/core/platform/collective_helper.h" #include "paddle/phi/core/platform/device/custom/custom_device_resource_pool.h" #endif #include "paddle/phi/backends/c_cuda_graph_lib.h" #include "paddle/phi/core/platform/cuda_graph_with_memory_pool.h" #ifdef PADDLE_WITH_IPU #include "paddle/fluid/platform/device/ipu/ipu_backend.h" #include "paddle/fluid/platform/device/ipu/ipu_info.h" #endif #ifdef PADDLE_WITH_CRYPTO #include "paddle/fluid/pybind/crypto.h" #endif #ifdef PADDLE_WITH_CINN #include "paddle/fluid/pybind/test.h" #endif #include "paddle/common/flags.h" #include "paddle/fluid/eager/api/utils/global_utils.h" #include "paddle/fluid/eager/nan_inf_utils.h" #include "paddle/fluid/imperative/layout_autotune.h" #include "paddle/fluid/pir/dialect/distributed/ir/dist_interface.h" #include "paddle/fluid/pir/dialect/operator/interface/decomp.h" #include "paddle/fluid/pir/dialect/operator/interface/decomp_vjp.h" #include "paddle/fluid/pir/dialect/operator/interface/vjp.h" #include "paddle/fluid/pir/dialect/operator/ir/api_builder.h" #include "paddle/fluid/pir/dialect/operator/ir/manual_pylayer_op.h" #include "paddle/fluid/pir/dialect/operator/trait/custom_vjp.h" #include "paddle/fluid/pir/dialect/operator/trait/forward_only.h" #include "paddle/fluid/prim/utils/eager/eager_tensor_operants.h" #include "paddle/fluid/prim/utils/static/static_tensor_operants.h" #include "paddle/fluid/primitive/base/decomp_trans.h" #include "paddle/fluid/pybind/eager_utils.h" #include "paddle/fluid/pybind/op_function_common.h" #include "paddle/phi/api/ext/op_meta_info.h" #include "paddle/phi/api/include/operants_manager.h" #include "paddle/phi/api/include/tensor_operants.h" #include "paddle/phi/common/type_promotion.h" #include "paddle/phi/kernels/autotune/cache.h" #include "paddle/phi/kernels/autotune/switch_autotune.h" #include "paddle/pir/include/core/program.h" #include "paddle/pir/include/dialect/control_flow/ir/cf_op.h" #include "paddle/pir/include/dialect/control_flow/ir/cf_type.h" #include "pybind11/stl.h" #ifdef PADDLE_WITH_TENSORRT #include "paddle/fluid/inference/tensorrt/pir/declare_plugin.h" #include "paddle/fluid/platform/tensorrt/trt_plugin.h" #endif #include "paddle/fluid/eager/accumulation/accumulation_node.h" #ifdef PADDLE_WITH_CUDA #include "paddle/fluid/eager/activation_offloader.h" #endif #include "paddle/phi/core/memory/allocation/retry_allocator.h" COMMON_DECLARE_bool(use_mkldnn); COMMON_DECLARE_bool(use_onednn); COMMON_DECLARE_int64(offload_retry_times); COMMON_DECLARE_string(prim_backward_blacklist); // disable auto conversion to list in Python PYBIND11_MAKE_OPAQUE(phi::TensorArray); PYBIND11_MAKE_OPAQUE(paddle::framework::FetchUnmergedList); PYBIND11_MAKE_OPAQUE(paddle::framework::FetchList); PYBIND11_MAKE_OPAQUE(paddle::framework::FetchType); // Opaque type for AllBlockInfoOfAllocator — avoid full O(n) conversion // at pybind boundary; only convert on per-group access (__getitem__). using AllBlocksInfoType = std::vector>>; PYBIND11_MAKE_OPAQUE(AllBlocksInfoType); DECLARE_FILE_SYMBOLS(init_phi); DECLARE_FILE_SYMBOLS(kernel_dialect); #ifdef PADDLE_WITH_DISTRIBUTE DECLARE_FILE_SYMBOLS(dist_dialect); #endif DECLARE_FILE_SYMBOLS(buffered_allocator); DECLARE_FILE_SYMBOLS(best_fit_allocator); DECLARE_FILE_SYMBOLS(aligned_allocator); DECLARE_FILE_SYMBOLS(pass_timing); DECLARE_FILE_SYMBOLS(sub_graph_detector); DECLARE_FILE_SYMBOLS(pd_op_to_kernel_pass); namespace paddle::pybind { PyTypeObject *g_framework_scope_pytype = nullptr; PyTypeObject *g_framework_densetensorarray_pytype = nullptr; PyTypeObject *g_custom_op_kernel_ctx_pytype = nullptr; PyTypeObject *g_data_type_pytype = nullptr; PyTypeObject *g_tensorrt_engine_params_pytype = nullptr; // Custom hash function for DataType enum that extracts the underlying integer // value directly from pybind11's instance layout. This is much faster than // pybind11's default Python-level `__hash__ = lambda self: int(self)` which // involves method dispatch and temporary Python int object creation. // The hash is value-based, consistent with pybind11's value-based `__eq__`. static Py_hash_t DataTypeEnumHash(PyObject *self) { auto *inst = reinterpret_cast(self); return static_cast( *reinterpret_cast(inst->simple_value_holder[0])); } bool IsCompiledWithAVX() { #ifndef PADDLE_WITH_AVX return false; #else return true; #endif } bool IsCompiledWithCUDA() { #if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) return true; #endif return false; } bool IsCompiledWithCudnnFrontend() { #ifndef PADDLE_WITH_CUDNN_FRONTEND return false; #else return true; #endif } bool IsCompiledWithDISTRIBUTE() { #if !defined(PADDLE_WITH_DISTRIBUTE) return false; #else return true; #endif } bool IsCompiledWithNCCL() { #ifdef PADDLE_WITH_NCCL return true; #else return false; #endif } bool IsCompiledWithFlagcx() { #ifdef PADDLE_WITH_FLAGCX return true; #else return false; #endif } bool IsCompiledWithDeepEP() { #if defined(PADDLE_WITH_DISTRIBUTE) && defined(PADDLE_WITH_DEEP_EP) return true; #else return false; #endif } bool IsCompiledWithMPI() { #ifdef PADDLE_WITH_MPI return true; #else return false; #endif } // NOTE some mpi lib can support cuda aware, support it in the future. bool IsCompiledWithMPIAWARE() { #ifdef PADDLE_WITH_MPI_AWARE return true; #else return false; #endif } bool IsCompiledWithROCM() { #ifndef PADDLE_WITH_HIP return false; #else return true; #endif } bool IsCompiledWithXPU() { #ifndef PADDLE_WITH_XPU return false; #else return true; #endif } bool IsCompiledWithCustomDevice(std::string device_type) { #ifndef PADDLE_WITH_CUSTOM_DEVICE return false; #else std::vector device_types; device_types = phi::DeviceManager::GetAllCustomDeviceTypes(); if (std::count(device_types.begin(), device_types.end(), device_type)) { return true; } else { return false; } #endif } bool IsCompiledWithIPU() { #ifndef PADDLE_WITH_IPU return false; #else return true; #endif } bool IsCompiledWithONEDNN() { #ifndef PADDLE_WITH_DNNL return false; #else return true; #endif } bool IsCompiledWithCINN() { #ifndef PADDLE_WITH_CINN return false; #else return true; #endif } bool IsCompiledWithHETERPS() { return false; } bool SupportsBfloat16() { #ifndef PADDLE_WITH_DNNL return false; #else if (phi::backends::cpu::MayIUse(phi::backends::cpu::cpu_isa_t::avx512_core)) return true; else return false; #endif } bool SupportsBfloat16FastPerformance() { #ifndef PADDLE_WITH_DNNL return false; #else if (phi::backends::cpu::MayIUse(phi::backends::cpu::cpu_isa_t::avx512_bf16)) return true; else return false; #endif } bool SupportsInt8() { #ifndef PADDLE_WITH_DNNL return false; #else return (phi::backends::cpu::MayIUse(phi::backends::cpu::cpu_isa_t::avx2) || phi::backends::cpu::MayIUse(phi::backends::cpu::cpu_isa_t::avx512f)); #endif } bool SupportsAvx512F() { return phi::backends::cpu::MayIUse(phi::backends::cpu::cpu_isa_t::avx512f); } bool SupportsVNNI() { #ifndef PADDLE_WITH_DNNL return false; #else return phi::backends::cpu::MayIUse( phi::backends::cpu::cpu_isa_t::avx512_core_vnni); #endif } bool IsCompiledWithBrpc() { #ifndef PADDLE_WITH_DISTRIBUTE return false; #else return true; #endif } bool IsCompiledWithDIST() { #ifdef PADDLE_WITH_DISTRIBUTE return true; #else return false; #endif } struct iinfo { int64_t min; uint64_t max; int bits; std::string dtype; #define CASE_IINFO_BODY(type, ctype) \ do { \ min = static_cast(std::numeric_limits::min()); \ max = static_cast(std::numeric_limits::max()); \ bits = sizeof(ctype) * 8; \ dtype = #type; \ } while (0) explicit iinfo(const DataType &type) { switch (type) { case DataType::UINT8: CASE_IINFO_BODY(uint8, uint8_t); break; case DataType::UINT16: CASE_IINFO_BODY(uint16, uint16_t); break; case DataType::UINT32: CASE_IINFO_BODY(uint32, uint32_t); break; case DataType::UINT64: CASE_IINFO_BODY(uint64, uint64_t); break; case DataType::INT8: CASE_IINFO_BODY(int8, int8_t); break; case DataType::INT16: CASE_IINFO_BODY(int16, int16_t); break; case DataType::INT32: CASE_IINFO_BODY(int32, int32_t); break; case DataType::INT64: CASE_IINFO_BODY(int64, int64_t); break; default: PADDLE_THROW(common::errors::InvalidArgument( "the argument of paddle.iinfo can only be paddle.int8, " "paddle.int16, paddle.int32, paddle.int64, paddle.uint8, " "paddle.uint16, paddle.uint32, or paddle.uint64")); break; } } #undef CASE_IINFO_BODY }; struct finfo { int64_t bits; double eps; double min; // lowest() double max; double tiny; double smallest_normal; // min() double resolution; std::string dtype; #define CASE_FINFO_BODY(type, ctype) \ do { \ eps = std::numeric_limits::epsilon(); \ min = std::numeric_limits::lowest(); \ max = std::numeric_limits::max(); \ smallest_normal = std::numeric_limits::min(); \ tiny = smallest_normal; \ resolution = std::pow(10, -std::numeric_limits::digits10); \ bits = sizeof(ctype) * 8; \ dtype = #type; \ } while (0) explicit finfo(const DataType &type) { switch (type) { case DataType::FLOAT8_E4M3FN: CASE_FINFO_BODY(float8_e4m3fn, phi::float8_e4m3fn); break; case DataType::FLOAT8_E5M2: CASE_FINFO_BODY(float8_e5m2, phi::float8_e5m2); break; case DataType::FLOAT16: CASE_FINFO_BODY(float16, phi::float16); break; case DataType::BFLOAT16: CASE_FINFO_BODY(bfloat16, phi::bfloat16); break; case DataType::FLOAT32: case DataType::COMPLEX64: CASE_FINFO_BODY(float32, float); break; case DataType::FLOAT64: case DataType::COMPLEX128: CASE_FINFO_BODY(float64, double); break; default: PADDLE_THROW(common::errors::InvalidArgument( "The argument of paddle.finfo can only be paddle.float32, " "paddle.float64, paddle.float16, paddle.bfloat16, " "paddle.float8_e4m3fn, paddle.float8_e5m2, " "paddle.complex64 or paddle.complex128")); break; } } #undef CASE_FINFO_BODY }; static PyObject *GetPythonAttribute(PyObject *obj, const char *attr_name) { // NOTE(zjl): PyObject_GetAttrString would return nullptr when attr_name // is not inside obj, but it would also set the error flag of Python. // If the error flag is set in C++, C++ code would not raise Exception, // but Python would raise Exception once C++ call ends. // To avoid unexpected Exception raised in Python, we check whether // attribute exists before calling PyObject_GetAttrString. // // Caution: PyObject_GetAttrString would increase reference count of PyObject. // Developer should call Py_DECREF manually after the attribute is not used. if (PyObject_HasAttrString(obj, attr_name)) { return PyObject_GetAttrString(obj, attr_name); } else { return nullptr; } } using PyNameVarBaseMap = std::unordered_map; static std::vector> GetVarBaseList( const PyNameVarBaseMap &state_dict) { std::vector> vec_res; vec_res.reserve(state_dict.size()); for (auto ¶ : state_dict) { PyObject *py_obj = para.second.ptr(); if (!py_obj || py_obj == Py_None) { PADDLE_THROW(common::errors::InvalidArgument( "The parameter [%s] to save is None", para.first)); } vec_res.emplace_back( PyObjectCast>(py_obj)); } return vec_res; } static std::vector inline GetNameList( const py::handle &py_handle) { std::vector vec_res; PyObject *py_obj = py_handle.ptr(); // get underlying PyObject // Python None is not nullptr in C++! if (!py_obj || py_obj == Py_None) { PADDLE_THROW( common::errors::InvalidArgument("The parameter list to save is None")); } if (PyList_Check(py_obj)) { size_t len = PyList_GET_SIZE(py_obj); vec_res.reserve(len); const char *kNameField = "name"; for (size_t i = 0; i < len; ++i) { PyObject *py_name = PyObject_GetAttrString(PyList_GET_ITEM(py_obj, i), kNameField); PADDLE_ENFORCE_NOT_NULL(py_name, common::errors::InvalidArgument( "The name of parameter to save is None")); vec_res.emplace_back(PyObjectCast(py_name)); Py_DECREF(py_name); } } else { PADDLE_THROW(common::errors::InvalidArgument( "The parameters to save is not a list")); } return vec_res; } static void inline CreateVariableIfNotExist( const py::handle &py_handle, const framework::Scope &scope, const framework::Executor *exe = nullptr) { std::vector vec_res; PyObject *py_obj = py_handle.ptr(); // get underlying PyObject // Python None is not nullptr in C++! if (!py_obj || py_obj == Py_None) { PADDLE_THROW( common::errors::InvalidArgument("The parameter list to set is None")); } if (PyList_Check(py_obj)) { size_t len = PyList_GET_SIZE(py_obj); vec_res.reserve(len); const char *kNameField = "name"; const char *kVarDescField = "desc"; for (size_t i = 0; i < len; ++i) { PyObject *py_name = PyObject_GetAttrString(PyList_GET_ITEM(py_obj, i), kNameField); PADDLE_ENFORCE_NOT_NULL(py_name, common::errors::InvalidArgument( "The name of parameter to set is None")); auto para_name = PyObjectCast(py_name); Py_DECREF(py_name); auto var = scope.FindVar(para_name); if (var == nullptr) { PADDLE_ENFORCE_NOT_NULL(exe, common::errors::InvalidArgument( "Parameter not Initialized, " "Please set argument [executor] not None " "or run startup program first")); PyObject *py_var_desc = PyObject_GetAttrString(PyList_GET_ITEM(py_obj, i), kVarDescField); PADDLE_ENFORCE_NOT_NULL( py_var_desc, common::errors::InvalidArgument( "The var_desc of parameter to set is None")); auto var_desc = PyObjectCast(py_var_desc); Py_DECREF(py_var_desc); var = const_cast(&scope)->Var(para_name); auto *tensor_temp = var->GetMutable(); tensor_temp->Resize(common::make_ddim(var_desc.GetShape())); tensor_temp->mutable_data( exe->GetPlace(), phi::TransToPhiDataType(var_desc.GetDataType())); } } } else { PADDLE_THROW( common::errors::InvalidArgument("The parameters to set is not a list")); } return; } static void AssertStaticGraphAndDygraphGradMakerNoDiff() { std::set ops; for (auto &pair : framework::OpInfoMap::Instance().map()) { bool has_static_grad_maker = (pair.second.grad_op_maker_ != nullptr); bool has_dygraph_grad_maker = (pair.second.dygraph_grad_op_maker_ != nullptr); if (has_static_grad_maker ^ has_dygraph_grad_maker) { bool has_kernel = (framework::OperatorWithKernel::AllOpKernels().count(pair.first) > 0); if (has_kernel) { ops.insert(pair.first); } else { VLOG(5) << pair.first << " has no kernels, skip"; } } } PADDLE_ENFORCE_EQ(ops.empty(), true, common::errors::Unimplemented( "OperatorWithKernel [%s] have only static graph grad " "maker or have only dygraph grad maker, which is not " "allowed", string::join_strings(ops, ','))); } #if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL) static int GetNCCLVersion() { #if NCCL_VERSION_CODE >= 2304 int ver; PADDLE_ENFORCE_GPU_SUCCESS(phi::dynload::ncclGetVersion(&ver)); return ver; #else PADDLE_THROW(common::errors::External( "Cannot get NCCL version successfully when nccl version < 2.3.4")); #endif } #endif // NOTE: Use to manage the context of pylayer op constructing block class PyLayerBlockContextManager { public: explicit PyLayerBlockContextManager(pir::Block *block) { dialect::ApiBuilder::Instance().PushInsertionPoint(); dialect::ApiBuilder::Instance().SetInsertionPointToBlockEnd(block); } ~PyLayerBlockContextManager() { dialect::ApiBuilder::Instance().LoadInsertionPoint(); } PyLayerBlockContextManager(const PyLayerBlockContextManager &) = delete; PyLayerBlockContextManager &operator=(const PyLayerBlockContextManager &) = delete; private: // disable default constructor PyLayerBlockContextManager() = default; }; int DLPackDLTensorFromPyObjectNoSync(void *py_obj, DLTensor *out) { try { // Use handle (non-owning) to avoid unnecessary refcount operations py::handle handle(static_cast(py_obj)); Tensor tensor = handle.cast(); std::shared_ptr dense_tensor = std::static_pointer_cast(tensor.impl()); paddle::framework::ToDLPackNonOwningImpl(*dense_tensor, out); return 0; } catch (const std::exception &e) { PyErr_SetString(PyExc_RuntimeError, e.what()); return -1; } } int DLPackManagedTensorFromPyObjectNoSync(void *py_obj, DLManagedTensorVersioned **out) { try { py::handle handle(static_cast(py_obj)); Tensor tensor = handle.cast(); std::shared_ptr dense_tensor = std::static_pointer_cast(tensor.impl()); *out = paddle::framework::ToDLPackVersioned(*dense_tensor); return 0; } catch (const std::exception &e) { PyErr_SetString(PyExc_RuntimeError, e.what()); return -1; } } int DLPackManagedTensorToPyObjectNoSync(DLManagedTensorVersioned *src, void **py_obj_out) { try { DenseTensor dense_tensor = paddle::framework::FromDLPackVersioned(src); Tensor tensor(std::make_shared(dense_tensor)); egr::EagerUtils::autograd_meta(&tensor)->SetPersistable(false); *py_obj_out = ToPyObject(tensor); return 0; } catch (const std::exception &e) { PyErr_SetString(PyExc_RuntimeError, e.what()); return -1; } } int DLPackManagedTensorAllocator(::DLTensor *prototype, ::DLManagedTensorVersioned **out, void *error_ctx, void (*SetError)(void *error_ctx, const char *kind, const char *message)) { try { phi::IntArray shape(prototype->shape, prototype->ndim); Place place(paddle::framework::DLDeviceToPlace(prototype->device)); DataType dtype = paddle::framework::DLDataTypeToPhiDataType(prototype->dtype); Tensor tensor = paddle::empty(shape, dtype, place); std::shared_ptr dense_tensor = std::static_pointer_cast(tensor.impl()); *out = paddle::framework::ToDLPackVersioned(*dense_tensor); return 0; } catch (const std::exception &e) { SetError(error_ctx, "DLPackManagedTensorAllocator", e.what()); return -1; } } int DLPackCurrentWorkStream(DLDeviceType device_type, int32_t device_id, void **out_stream) { try { #if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) || \ defined(PADDLE_WITH_CUSTOM_DEVICE) if (device_type == kDLCUDA || device_type == kDLROCM) { *out_stream = platform::get_current_stream(device_id)->raw_stream(); } #endif return 0; } catch (const std::exception &e) { PyErr_SetString(PyExc_RuntimeError, e.what()); return -1; } } struct PaddleDLPackExchangeAPI : public ::DLPackExchangeAPI { PaddleDLPackExchangeAPI() { header.version.major = DLPACK_MAJOR_VERSION; header.version.minor = DLPACK_MINOR_VERSION; header.prev_api = nullptr; managed_tensor_allocator = DLPackManagedTensorAllocator; managed_tensor_from_py_object_no_sync = DLPackManagedTensorFromPyObjectNoSync; managed_tensor_to_py_object_no_sync = DLPackManagedTensorToPyObjectNoSync; dltensor_from_py_object_no_sync = DLPackDLTensorFromPyObjectNoSync; current_work_stream = DLPackCurrentWorkStream; } static const DLPackExchangeAPI *Instance() { static PaddleDLPackExchangeAPI inst; return &inst; } }; // NOTE: use to load file by Mmap enum MMapLoadModes { ALLOCATOR_MAPPED_SHARED = 1, ALLOCATOR_MAPPED_SHAREDMEM = 2, ALLOCATOR_MAPPED_EXCLUSIVE = 4, ALLOCATOR_MAPPED_NOCREATE = 8, ALLOCATOR_MAPPED_KEEPFD = 16, ALLOCATOR_MAPPED_FROMFD = 32, ALLOCATOR_MAPPED_UNLINK = 64 }; struct MmapStorage { MmapStorage(const std::string &filename_, int64_t nbytes) : base_ptr_(nullptr), size(nbytes) { // https://github.com/pytorch/pytorch/blob/d58ed04d89c34c6930d0f28be351c53db407078f/aten/src/ATen/MapAllocator.cpp#L65-L370 int flags_{0}; if ((flags_ ^ ALLOCATOR_MAPPED_EXCLUSIVE) == 0) { PADDLE_THROW(common::errors::Unavailable( "ALLOCATOR_MAPPED_EXCLUSIVE flag requires opening the file in shared " "mode")); } if (!(flags_ & ALLOCATOR_MAPPED_SHARED) && !(flags_ & ALLOCATOR_MAPPED_SHAREDMEM)) { flags_ &= ~ALLOCATOR_MAPPED_NOCREATE; } #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) constexpr const char *unknown_eventname = "eventname not specified"; void *handle_ = INVALID_HANDLE_VALUE; void *event_ = INVALID_HANDLE_VALUE; std::string eventname_ = filename_.empty() ? unknown_eventname : (std::string(filename_) + "_event"); if (flags_ & ALLOCATOR_MAPPED_SHAREDMEM) { // Shadowing const wchar_t *filename; const wchar_t *eventname; std::wstring_convert> converter; const std::wstring wFilename = converter.from_bytes(filename_); const std::wstring wEventname = converter.from_bytes(eventname_); LARGE_INTEGER hfilesz; if (filename_[0] == '/') { filename = wFilename.c_str() + 1; eventname = wEventname.c_str() + 1; } else { filename = wFilename.c_str(); eventname = wEventname.c_str(); } hfilesz.QuadPart = size; if (flags_ & ALLOCATOR_MAPPED_EXCLUSIVE) { event_ = CreateEventW(nullptr, FALSE, FALSE, eventname); } else if (flags_ & ALLOCATOR_MAPPED_NOCREATE) { event_ = OpenEventW(EVENT_ALL_ACCESS, FALSE, eventname); } else { PADDLE_THROW(common::errors::Unavailable( "Expected either ALLOCATOR_MAPPED_EXCLUSIVE or " "ALLOCATOR_MAPPED_NOCREATE")); } if (event_ == nullptr) { PADDLE_THROW(common::errors::Unavailable( "Couldn't open shared event: <%s>.", eventname)); } if (flags_ & ALLOCATOR_MAPPED_EXCLUSIVE) { handle_ = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, hfilesz.HighPart, hfilesz.LowPart, filename); } else if (flags_ & ALLOCATOR_MAPPED_NOCREATE) { handle_ = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, filename); } else { PADDLE_THROW(common::errors::Unavailable( "Expected either ALLOCATOR_MAPPED_EXCLUSIVE or " "ALLOCATOR_MAPPED_NOCREATE")); } if (handle_ == nullptr) { PADDLE_THROW(common::errors::Unavailable( "Couldn't open shared file mapping: <%s>.", eventname)); } base_ptr_ = MapViewOfFile(handle_, FILE_MAP_ALL_ACCESS, 0, 0, size); if (!base_ptr_) { PADDLE_THROW(common::errors::Unavailable( "Couldn't map view of shared file <%s>.", eventname)); } } else { HANDLE hfile; HANDLE hmfile; LARGE_INTEGER hfilesz; if (flags_ & ALLOCATOR_MAPPED_EXCLUSIVE) { PADDLE_THROW(common::errors::Unavailable( "exclusive file mapping is not supported on Windows")); } if (flags_ & ALLOCATOR_MAPPED_NOCREATE) { PADDLE_THROW(common::errors::Unavailable( "file mapping without creation is not supported on Windows")); } if (flags_ & ALLOCATOR_MAPPED_KEEPFD) { PADDLE_THROW(common::errors::Unavailable( "ALLOCATOR_MAPPED_KEEPFD not supported on Windows")); } if (flags_ & ALLOCATOR_MAPPED_FROMFD) { PADDLE_THROW(common::errors::Unavailable( "ALLOCATOR_MAPPED_FROMFD not supported on Windows")); } // Shadowing const wchar_t *filename; std::wstring_convert> converter; const std::wstring wFilename = converter.from_bytes(filename_); filename = wFilename.c_str(); /* open file */ /* FILE_FLAG_RANDOM_ACCESS ? */ if (flags_) { hfile = CreateFileW(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if (hfile == INVALID_HANDLE_VALUE) { PADDLE_THROW(common::errors::Unavailable( "could not open file <%s> in read-write mode;", filename_)); } } else { hfile = CreateFileW(filename, GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (hfile == INVALID_HANDLE_VALUE) { PADDLE_THROW(common::errors::Unavailable( "could not open file <%s> in read-only mode;", filename_)); } } if (GetFileSizeEx(hfile, &hfilesz) == 0) { PADDLE_THROW(common::errors::Unavailable( "could not get file size: <%s>;", filename_)); } if (size > 0) { if (size > hfilesz.QuadPart) { if (flags_) { hfilesz.QuadPart = size; if (SetFilePointerEx(hfile, hfilesz, NULL, FILE_BEGIN) == 0) { CloseHandle(hfile); PADDLE_THROW(common::errors::Unavailable( "unable to stretch file : <%s> to the right size;", filename_)); } if (SetEndOfFile(hfile) == 0) { CloseHandle(hfile); PADDLE_THROW(common::errors::Unavailable( "unable to write to file : <%s>", filename_)); } } else { CloseHandle(hfile); PADDLE_THROW(common::errors::Unavailable( "file: <%s> size <%d> is smaller than the required mapping " "size <%d>", filename_, hfilesz.QuadPart, size)); } } } else { size = hfilesz.QuadPart; } /* if we are here, it must be the right size */ hfilesz.QuadPart = size; /* get map handle */ if (flags_) { if ((hmfile = CreateFileMappingW(hfile, NULL, PAGE_READWRITE, hfilesz.HighPart, hfilesz.LowPart, NULL)) == NULL) { CloseHandle(hfile); PADDLE_THROW(common::errors::Unavailable( "could not create a map on file <%s>", filename_)); } } else { if ((hmfile = CreateFileMappingW(hfile, NULL, PAGE_WRITECOPY, hfilesz.HighPart, hfilesz.LowPart, NULL)) == NULL) { PADDLE_THROW(common::errors::Unavailable( "could not create a map on file <%s>", filename_)); } } /* map the stuff */ if (flags_) { base_ptr_ = MapViewOfFile(hmfile, FILE_MAP_ALL_ACCESS, 0, 0, 0); } else { base_ptr_ = MapViewOfFile(hmfile, FILE_MAP_COPY, 0, 0, 0); } CloseHandle(hfile); CloseHandle(hmfile); } #else // open file // OK, now do the allocation int fd{-1}; int flags{0}; // shadow if (flags_ & (ALLOCATOR_MAPPED_SHARED | ALLOCATOR_MAPPED_SHAREDMEM)) { flags = O_RDWR | O_CREAT; } else { flags = O_RDONLY; } if (flags_ & ALLOCATOR_MAPPED_EXCLUSIVE) { flags |= O_EXCL; } if (flags_ & ALLOCATOR_MAPPED_NOCREATE) { flags &= ~O_CREAT; } if (!(flags_ & ALLOCATOR_MAPPED_FROMFD)) { if (flags_ & ALLOCATOR_MAPPED_SHARED) { if ((fd = open(filename_.c_str(), flags, (mode_t)0600)) == -1) { PADDLE_THROW(common::errors::Unavailable( "unable to open file <%s> in read-write mode.", filename_)); } } else if (flags_ & ALLOCATOR_MAPPED_SHAREDMEM) { #ifdef HAVE_SHM_OPEN if ((fd = shm_open(filename_.c_str(), flags, (mode_t)0600)) == -1) { PADDLE_THROW(common::errors::Unavailable( "unable to open shared memory file <%s> in read-write mode.", filename_)); } #else PADDLE_THROW(common::errors::Unavailable( "unable to open file <%s> in sharedmem mode, shm_open unavailable " "on this platform.", filename_)); #endif } else { if ((fd = open(filename_.c_str(), O_RDONLY)) == -1) { PADDLE_THROW(common::errors::Unavailable( "unable to open file <%s> in read-only mode.", filename_)); } } } PADDLE_ENFORCE_GE(fd, 0, common::errors::Unavailable("open file filed.")); struct stat file_stat {}; if (fstat(fd, &file_stat) == -1) { if (!(flags_ & ALLOCATOR_MAPPED_FROMFD)) { ::close(fd); } PADDLE_THROW(common::errors::Unavailable("unable to stat the file <%s>", filename_)); } if (size > 0) { if (static_cast(size) > file_stat.st_size) { if (flags_) { if (ftruncate(fd, static_cast(size)) == -1) { PADDLE_THROW(common::errors::Unavailable( "unable to resize file <%s> to the right size", filename_)); } if (fstat(fd, &file_stat) == -1 || file_stat.st_size < static_cast(size)) { ::close(fd); PADDLE_THROW(common::errors::Unavailable( "unable to stretch file <%s> to the right size", filename_)); } } else { ::close(fd); PADDLE_THROW(common::errors::Unavailable( "file <%s> size <%d> is smaller than the required mapping size " "<%d>", filename_, file_stat.st_size, size)); } } } else { size = file_stat.st_size; } ptrdiff_t size_ = static_cast( size); // if we are here, it must be the right size // map it if (flags_ & (ALLOCATOR_MAPPED_SHARED | ALLOCATOR_MAPPED_SHAREDMEM)) { base_ptr_ = mmap(nullptr, size_, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); } else { base_ptr_ = mmap(nullptr, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); } if (base_ptr_ == MAP_FAILED) { base_ptr_ = nullptr; // let's be sure it is NULL PADDLE_THROW(common::errors::Unavailable( "unable to mmap %d bytes from file <%s>", size, filename_)); } if (::close(fd) == -1) { PADDLE_THROW( common::errors::Unavailable("Error closing file <%s>", filename_)); } if (flags_ & ALLOCATOR_MAPPED_UNLINK) { if (flags_ & ALLOCATOR_MAPPED_SHAREDMEM) { #ifdef HAVE_SHM_UNLINK if (shm_unlink(filename_.c_str()) == -1) { PADDLE_THROW(common::errors::Unavailable( "could not unlink the shared memory file <%s>", filename_)); } #else PADDLE_THROW(common::errors::Unavailable( "could not unlink the shared memory file <%s>, shm_unlink not " "available on platform", filename_)); #endif } else { if (unlink(filename_.c_str()) == -1) PADDLE_THROW(common::errors::Unavailable( "could not unlink file <%s>", filename_)); } } if (base_ptr_ == MAP_FAILED) { PADDLE_THROW(common::errors::Unavailable( "unable to mmap memory: you tried to mmap %d bytes", size_ / 1073741824)); } #endif } ~MmapStorage() { if (base_ptr_) { #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN6) UnmapViewOfFile(base_ptr_); #else munmap(base_ptr_, size); #endif base_ptr_ = nullptr; } } void *base_ptr_; int64_t size; }; static std::vector> GenerateBackwardBlockForPyLayerOp( pir::Operation *op, const std::vector> &inputs_, const std::vector> &outputs, const std::vector> &out_grads, const std::vector> &stop_gradients) { PADDLE_ENFORCE( op->isa(), common::errors::InvalidArgument( "GenerateBackwardBlockForPyLayerOp only support PyLayerOp")); // 1. construct pylayer grad op VLOG(6) << "Prepare Outputs for pylayer_grad"; std::vector output_types; // NOTE: the last input of pylayer op is create_stack when called // save_for_backward, whose stop_gradient is always True for (size_t i = 0; i < inputs_.size(); ++i) { if (inputs_[i][0].type().isa()) break; output_types.push_back(inputs_[i][0].type()); } VLOG(6) << "Prepare Inputs for pylayer_grad"; std::vector output_grads; for (size_t i = 0; i < out_grads.size(); ++i) { output_grads.push_back(out_grads[i][0]); } std::vector pylayer_grad_inputs(output_types.size()); auto pylayer_grad = dialect::ApiBuilder::Instance() .GetBuilder() ->Build( output_grads, std::move(output_types), -1); VLOG(6) << "Construct pylayer_grad finished"; // 2.1 Get registered backward function from // `PythonCallableRegistrar::python_callable_registry_`. int backward_function_id = op->attributes() .at(paddle::dialect::PyLayerOp::kBackwardFunctionIdAttrName) .dyn_cast() .data(); PADDLE_ENFORCE_GE( backward_function_id, 0, common::errors::InvalidArgument("The backward function id of pylayer op " "should be non-negative, but got %d", backward_function_id)); VLOG(6) << "pylayer op unique_id is " << op->id(); VLOG(6) << "pylayer op backward_function_id is " << backward_function_id; auto py_callable = paddle::pybind::PythonCallableRegistrar::GetInstance().Get( static_cast(backward_function_id)); // 2.2 Get TuplePushOp from forward block if exists auto pylayer_op = op->dyn_cast(); std::vector tuple_push_op_list; for (auto &op : pylayer_op.forward_block()) { if (op.isa()) { tuple_push_op_list.push_back(&op); } } PADDLE_ENFORCE_LE(tuple_push_op_list.size(), 1, common::errors::InvalidArgument( "The number of tuple_push op in pylayer forward block " "is either unique or does not exist.")); { // enter block of pylayer_grad PyLayerBlockContextManager pylayer_block_context_manager( &(pylayer_grad.forward_block())); // create tuple_pop op if needed if (tuple_push_op_list.size() > 0) { VLOG(6) << "Start creating tuple_pop op in the front of backward block " "of pylayer."; auto tuple_push_op = tuple_push_op_list[0]->dyn_cast(); dialect::ApiBuilder::Instance().GetBuilder()->Build( tuple_push_op.outlet()); VLOG(6) << "Finish creating tuple_pop op."; } VLOG(6) << "call pylayer op backward function"; PirCallPythonFunc(py_callable, output_grads, &pylayer_grad_inputs); // append yield op for outputs value dialect::ApiBuilder::Instance().GetBuilder()->Build( pylayer_grad_inputs); // exit block of pylayer_grad } VLOG(6) << "Construct pylayer backward block finished"; // 3. Update pylayer_grad op's attributes of outputs pylayer_grad.UpdateOutput(); VLOG(6) << "Update pylayer_grad op finished"; std::vector> res{inputs_.size()}; for (size_t i = 0; i < res.size(); ++i) { res[i].resize(1); res[i][0] = !stop_gradients[i][0] ? pylayer_grad->result(i) : pir::Value(); } return res; } void BindVjp(pybind11::module *m) { m->def( "call_vjp", [](pir::Operation &fwd_op, const std::vector> &inputs, const std::vector> &outputs, const std::vector> &out_grads, const std::vector> &stop_gradients) { // NOTE(dev): Prim decomposed rules will call paddle::dialect::xx // api, which has amp strategy. But Prim already process cast operation // and we need to disable amp strategy here. paddle::imperative::AutoCastGuard guard( egr::Controller::Instance().GetCurrentAmpAttrs(), paddle::imperative::AmpLevel::O0); py::list res; std::vector> vjp_res; if (fwd_op.isa()) { // NOTE(MarioLulab): In PIR mode, even though the `PyLayer` op does // not have a vjp interface, we still need to generate the backward // block based on its registered backward function. vjp_res = GenerateBackwardBlockForPyLayerOp( &fwd_op, inputs, outputs, out_grads, stop_gradients); } else { paddle::dialect::VjpInterface vjp_interface = fwd_op.dyn_cast(); PADDLE_ENFORCE(vjp_interface, common::errors::InvalidArgument( "The vjp function is not registered in %s op ", fwd_op.name())); vjp_res = vjp_interface.Vjp( &fwd_op, inputs, outputs, out_grads, stop_gradients); } PADDLE_ENFORCE_EQ( stop_gradients.size(), vjp_res.size(), common::errors::InvalidArgument( "The size of %s stop_gradients should be the same as vjp_res " "size." "But the size of stop_gradients: %d, vjp_res size: %d", fwd_op.name(), stop_gradients.size(), vjp_res.size())); for (size_t i = 0; i < vjp_res.size(); ++i) { PADDLE_ENFORCE_EQ(stop_gradients[i].size(), vjp_res[i].size(), common::errors::InvalidArgument( "The size of stop_gradients[%d] should be the " "same as vjp_res[%d] " "size." "But the size of stop_gradients[%d]: %d, " "vjp_res[%d] size: %d", i, i, i, stop_gradients[i].size(), i, vjp_res[i].size())); py::list sub_res; for (size_t j = 0; j < vjp_res[i].size(); ++j) { if (!vjp_res[i][j]) { sub_res.append(nullptr); } else { // The grad_type must equal to forward type. sub_res.append(vjp_res[i][j]); } } res.append(sub_res); } paddle::dialect::OpYamlInfoInterface yaml_interface = fwd_op.dyn_cast(); if (yaml_interface) { auto inputs_grad_info = std::get<0>(yaml_interface.GetOpInfo()); PADDLE_ENFORCE_EQ(inputs.size(), inputs_grad_info.size(), common::errors::InvalidArgument( "The size of %s inputs should be the " "same as inputs_grad_info size.", fwd_op.name())); size_t grad_index = 0; for (size_t idx = 0; idx < inputs.size(); ++idx) { if (!inputs_grad_info[idx].with_grad_semantic) continue; PADDLE_ENFORCE_EQ(inputs[idx].size(), vjp_res[grad_index].size(), common::errors::InvalidArgument( "The size of inputs[%d] should be the " "same as vjp_res[%d] size.", idx, grad_index)); for (size_t j = 0; j < inputs[idx].size(); ++j) { if (vjp_res[grad_index][j]) { // The grad_type must equal to forward type. if (auto fwd_type = inputs[idx][j] .type() .dyn_cast()) { if (auto bwd_type = vjp_res[grad_index][j] .type() .dyn_cast()) { auto fwd_attr = fwd_type.tensor_dist_attr(); auto bwd_attr = bwd_type.tensor_dist_attr(); if (fwd_attr.process_mesh_attr() == bwd_attr.process_mesh_attr() && fwd_attr.dims_mapping() == bwd_attr.dims_mapping()) { continue; } } } vjp_res[grad_index][j].set_type(inputs[idx][j].type()); } } ++grad_index; } } return res; }); m->def("has_vjp", [](pir::Operation &fwd_op) { pir::IrContext *ctx = pir::IrContext::Instance(); pir::OpInfo fwd_op_info = ctx->GetRegisteredOpInfo(fwd_op.name()); auto vjp_interface_impl = fwd_op_info.GetInterfaceImpl(); if (vjp_interface_impl == nullptr) return false; return true; }); m->def( "has_custom_vjp", [](pir::Operation &op) -> py::bool_ { return op.info().HasTrait(); }, R"DOC( Return whether an op has custom vjp rules. Args: op (pir::Operation): op to be checked Returns: out (bool): True means that the op has custom vjp rules, False means it does not. )DOC"); m->def( "is_forward_only", [](pir::Operation &op) -> py::bool_ { return op.info().HasTrait(); }, R"DOC( Return whether an op is forward only op. Args: op (pir::Operation): op to be checked Returns: out (bool): True means that the op is forward only op, False means it does not. )DOC"); } void BindDecompRule(pybind11::module *m) { m->def( "sinking_decomp", [](pir::Program *program, std::vector &src_vars, std::set &blacklist, std::set &whitelist, int start_index, int end_index) { VLOG(4) << "[Prim] Bind Decomp sinking_decomp begin."; auto original_insertion_point = paddle::dialect::ApiBuilder::Instance().GetCurrentInsertionPoint(); DecompProgram decomp_object( program, src_vars, blacklist, whitelist, start_index, end_index); decomp_object.decomp_program(); std::vector tar_vars = decomp_object.get_dst_vars(); paddle::dialect::ApiBuilder::Instance().SetInsertionPoint( original_insertion_point); VLOG(4) << "[Prim] Bind Decomp sinking_decomp end."; return tar_vars; }); m->def("call_decomp_rule", [](pir::Operation &fwd_op) { py::list res; std::vector> decomp_res = call_decomp_rule(&fwd_op); for (size_t i = 0; i < decomp_res.size(); ++i) { py::list sub_res; for (size_t j = 0; j < decomp_res[i].size(); ++j) { if (!decomp_res[i][j]) { sub_res.append(nullptr); } else { sub_res.append(decomp_res[i][j]); } } res.append(sub_res); } return res; }); m->def("has_decomp_rule", [](pir::Operation &fwd_op) { return paddle::has_decomp_rule(fwd_op); }); } void BindDecompVjp(pybind11::module *m) { m->def("call_decomp_vjp", [](pir::Operation &vjp_op) { py::list res; std::vector> decomp_res = call_decomp_vjp(&vjp_op); for (size_t i = 0; i < decomp_res.size(); ++i) { py::list sub_res; for (size_t j = 0; j < decomp_res[i].size(); ++j) { sub_res.append(decomp_res[i][j]); } res.append(sub_res); } return res; }); m->def("has_decomp_vjp", [](pir::Operation &vjp_op) { return paddle::has_decomp_vjp(vjp_op); }); } PYBIND11_MODULE(libpaddle, m) { BindImperative(&m); BindEager(&m); BindEagerStringTensor(&m); BindCudaStream(&m); BindXpuStream(&m); BindJit(&m); BindSot(&m); BindCustomDevicePy(&m); BindNativeMetaTensor(&m); BindEagerUtils(m.ptr()); BindOpFunctionCommon(m.ptr()); // Not used, just make sure cpu_info.cc is linked. phi::backends::cpu::CpuTotalPhysicalMemory(); paddle::memory::allocation::UseAllocatorStrategyGFlag(); AssertStaticGraphAndDygraphGradMakerNoDiff(); m.doc() = "C++ core of PaddlePaddle"; // using framework in this function. Since it is inside a function, it will // not cause namespace pollution. using namespace paddle::framework; // NOLINT BindException(&m); #define SET_STR_DEFINE(name) m.attr("_" #name) = std::string(name); #ifdef PYBIND11_COMPILER_TYPE SET_STR_DEFINE(PYBIND11_COMPILER_TYPE); #endif #ifdef PYBIND11_STDLIB SET_STR_DEFINE(PYBIND11_STDLIB); #endif #ifdef PYBIND11_BUILD_ABI SET_STR_DEFINE(PYBIND11_BUILD_ABI); #endif #ifdef _GLIBCXX_USE_CXX11_ABI m.attr("_GLIBCXX_USE_CXX11_ABI") = true; #else m.attr("_GLIBCXX_USE_CXX11_ABI") = false; #endif py::class_(m, "iinfo") .def(py::init()) .def_property_readonly("min", [](const iinfo &a) { return py::int_(a.min); }) .def_property_readonly( "max", [](const iinfo &a) { return py::cast(static_cast(a.max)); }) .def_readonly("bits", &iinfo::bits) .def_readonly("dtype", &iinfo::dtype) .def("__repr__", [](const iinfo &a) { std::ostringstream oss; oss << "paddle.iinfo(min=" << a.min; oss << ", max=" << a.max; oss << ", bits=" << a.bits; oss << ", dtype=" << a.dtype << ")"; return oss.str(); }); py::class_(m, "finfo") .def(py::init()) .def_readonly("min", &finfo::min) .def_readonly("max", &finfo::max) .def_readonly("bits", &finfo::bits) .def_readonly("eps", &finfo::eps) .def_readonly("resolution", &finfo::resolution) .def_readonly("smallest_normal", &finfo::smallest_normal) .def_readonly("tiny", &finfo::tiny) .def_readonly("dtype", &finfo::dtype) .def("__repr__", [](const finfo &a) { std::ostringstream oss; oss << "paddle.finfo(min=" << a.min; oss << ", max=" << a.max; oss << ", eps=" << a.eps; oss << ", resolution=" << a.resolution; oss << ", smallest_normal=" << a.smallest_normal; oss << ", tiny=" << a.tiny; oss << ", bits=" << a.bits; oss << ", dtype=" << a.dtype << ")"; return oss.str(); }); m.def("__set_bwd_prim_enabled", &paddle::prim::PrimCommonUtils::SetBwdPrimEnabled); m.def("_is_bwd_prim_enabled", &paddle::prim::PrimCommonUtils::IsBwdPrimEnabled); m.def("__set_fwd_prim_enabled", &paddle::prim::PrimCommonUtils::SetFwdPrimEnabled); m.def("_is_fwd_prim_enabled", &paddle::prim::PrimCommonUtils::IsFwdPrimEnabled); m.def("_is_all_prim_enabled", &paddle::prim::PrimCommonUtils::IsAllPrimEnabled); m.def("__set_all_prim_enabled", &paddle::prim::PrimCommonUtils::SetAllPrimEnabled); m.def("_is_eager_prim_enabled", &paddle::prim::PrimCommonUtils::IsEagerPrimEnabled); m.def("__set_eager_prim_enabled", &paddle::prim::PrimCommonUtils::SetEagerPrimEnabled); m.def("_set_prim_target_grad_name", &paddle::prim::PrimCommonUtils::SetTargetGradName); m.def("set_num_threads", &platform::SetNumThreads); m.def("need_type_promotion_old_ir", [](const std::string &op_name, framework::proto::VarType::Type type_x, framework::proto::VarType::Type type_y) { return phi::NeedTypePromotionOldIr(op_name, phi::TransToPhiDataType(type_x), phi::TransToPhiDataType(type_y)); }); m.def("get_promote_dtype_old_ir", [](const std::string &op_name, framework::proto::VarType::Type type_x, framework::proto::VarType::Type type_y) { return framework::TransToProtoVarType( phi::GetPromoteDtypeOldIr(op_name, phi::TransToPhiDataType(type_x), phi::TransToPhiDataType(type_y))); }); m.def("is_common_dtype_for_scalar", [](framework::proto::VarType::Type type_x, framework::proto::VarType::Type type_y) { return phi::is_common_dtype_for_scalar( phi::TransToPhiDataType(type_x), phi::TransToPhiDataType(type_y)); }); m.def("disable_signal_handler", &DisableSignalHandler); m.def("clear_gradients", [](std::vector> param_list, bool set_to_zero) { for (auto const ¶m : param_list) { param->ClearGradient(set_to_zero); } }); m.def("_ipc_collect", []() { #if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_XPU) #if defined(_WIN32) PADDLE_THROW(common::errors::Unavailable( "ipc_collect is not supported on Windows (CUDA/XPU IPC).")); #else paddle::memory::allocation::IpcCollect(); #endif #else PADDLE_THROW(common::errors::Unavailable( "Paddle is not compiled with CUDA/XPU, " "so `ipc_collect` cannot be used.")); #endif }); class NodePostHookRemoveHelper { public: NodePostHookRemoveHelper(std::shared_ptr node, int64_t hook_id) : node_(node), hook_id_(hook_id) {} ~NodePostHookRemoveHelper() = default; bool remove() { return node_->RemoveNodePostHook(hook_id_); } private: std::shared_ptr node_; int64_t hook_id_; }; py::class_>( m, "NodePostHookRemoveHelper") .def("remove", &NodePostHookRemoveHelper::remove); py::class_>( m, "GradNodeBase") .def("name", [](const std::shared_ptr &self) { return self->name(); }) .def_property_readonly( "next_functions", [](const std::shared_ptr &self) { return self->NextFunctions(); }) .def("node_ptr", &egr::GradNodeBase::GetPtr) .def("input_meta", [](const std::shared_ptr &self) { return self->InputMeta(); }) .def("output_meta", [](const std::shared_ptr &self) { return self->OutputMeta(); }) .def("_register_post_hook", [](const std::shared_ptr &self, py::object hook) { if (std::dynamic_pointer_cast(self)) { PADDLE_THROW(common::errors::InvalidArgument( "Could not register hook for GradNodeAccumulation.")); } int64_t hook_id = self->RegisterNodePostHook( std::make_shared(hook)); return std::make_shared(self, hook_id); }); #if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) m.def("cudnn_version", &platform::DnnVersion); m.def("gpu_memory_available", []() { size_t available = 0; size_t total = 0; paddle::platform::GpuMemoryUsage(&available, &total); return available; }); #endif #if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL) m.def("nccl_version", &GetNCCLVersion); #endif m.def("is_cuda_graph_capturing", &platform::IsCUDAGraphCapturing); #if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) || \ defined(PADDLE_WITH_CUSTOM_DEVICE) auto cuda_graph_class = py::class_(m, "CUDAGraph"); cuda_graph_class .def_static("begin_capture", #if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) [](GPUPlace place, int mode) { platform::BeginCUDAGraphCapture( place, static_cast(mode)); } #else [](phi::CustomPlace place, int mode) { platform::BeginCUDAGraphCapture( place, static_cast(mode)); } #endif ) .def_static("begin_capture_with_pool_id", #if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) [](GPUPlace place, int mode, std::optional pool_id, bool enable_replace) { if (pool_id.has_value()) { platform::BeginCUDAGraphCapture( place, static_cast(mode), pool_id.value(), enable_replace); } else { platform::BeginCUDAGraphCapture( place, static_cast(mode), phi::backends::gpu::CUDAGraph::kInvalidPoolID, enable_replace); } } #else [](phi::CustomPlace place, int mode, std::optional pool_id, bool enable_replace) { if (pool_id.has_value()) { platform::BeginCUDAGraphCapture( place, static_cast(mode), pool_id.value()); } else { platform::BeginCUDAGraphCapture( place, static_cast(mode)); } } #endif ) .def_static("end_capture", &platform::EndCUDAGraphCapture) .def_static("gen_new_memory_pool_id", &phi::backends::gpu::CUDAGraph::UniqueMemoryPoolID) .def("replay", &phi::backends::gpu::CUDAGraph::Replay) .def("reset", &phi::backends::gpu::CUDAGraph::Reset) .def("print_to_dot_files", &phi::backends::gpu::CUDAGraph::PrintToDotFiles); #if defined(PADDLE_WITH_CUDA) cuda_graph_class.def( "replace_input_ptrs", [](phi::backends::gpu::CUDAGraph &self, const std::vector &old_ptrs_int, const std::vector &new_ptrs_int) { std::vector old_ptrs(old_ptrs_int.size()); std::vector new_ptrs(new_ptrs_int.size()); for (size_t i = 0; i < old_ptrs_int.size(); ++i) { old_ptrs[i] = reinterpret_cast(old_ptrs_int[i]); } for (size_t i = 0; i < new_ptrs_int.size(); ++i) { new_ptrs[i] = reinterpret_cast(new_ptrs_int[i]); } self.ReplaceInputPtrs(old_ptrs, new_ptrs); }); #endif #endif #ifdef PADDLE_WITH_XPU py::class_(m, "CUDAGraph") .def_static( "begin_capture", [](phi::XPUPlace place, int mode) { platform::BeginCUDAGraphCapture( place, static_cast(mode)); }) .def_static( "begin_capture_with_pool_id", [](phi::XPUPlace place, int mode, std::optional pool_id, bool enable_replace) { if (pool_id.has_value()) { platform::BeginCUDAGraphCapture( place, static_cast(mode), pool_id.value()); } else { platform::BeginCUDAGraphCapture( place, static_cast(mode)); } }) .def_static("end_capture", &platform::EndCUDAGraphCapture) .def_static("gen_new_memory_pool_id", &phi::backends::xpu::CUDAGraph::UniqueMemoryPoolID) .def("replay", &phi::backends::xpu::CUDAGraph::Replay) .def("reset", &phi::backends::xpu::CUDAGraph::Reset) .def("print_to_dot_files", &phi::backends::xpu::CUDAGraph::PrintToDotFiles); #endif m.def("wait_device", [](const Place &place) { phi::DeviceContextPool::Instance().Get(place)->Wait(); }); py::class_>( m, "MmapStorage") // class attr: base_ptr_, size_ .def(py::init()) // filename_, nbytes .def("get_slice", [](py::object self_obj, proto::VarType::Type dtype, int64_t start, int64_t stop, int64_t step) { auto self_sp = py::cast>(self_obj); MmapStorage &self = *self_sp; if (stop < 0) { stop = start + 1; // default: get the start element. } Py_ssize_t size_py = static_cast(self.size); Py_ssize_t start_py = static_cast(start); Py_ssize_t stop_py = static_cast(stop); Py_ssize_t step_py = static_cast(step); Py_ssize_t slicelength = PySlice_AdjustIndices(size_py, &start_py, &stop_py, step_py); auto data = static_cast(self.base_ptr_) + start; auto dtype_phi = phi::TransToPhiDataType(dtype); return from_blob( reinterpret_cast(data), phi::IntArray({slicelength}), dtype_phi, phi::DataLayout::NCHW, CPUPlace(), [self_sp = std::move(self_sp)]( void *) mutable { // NOLINT(readability/casting) pybind11::gil_scoped_acquire gil; self_sp.reset(); }); }); m.def( "frombuffer", [](py::object buffer, DataType dtype, int64_t count, int64_t offset) { int64_t actual_count = 0; auto elsize = phi::SizeOf(dtype); Py_buffer view; if (PyObject_GetBuffer(buffer.ptr(), &view, PyBUF_WRITABLE) < 0) { PADDLE_ENFORCE_EQ( PyObject_GetBuffer(buffer.ptr(), &view, PyBUF_SIMPLE) >= 0, true, common::errors::InvalidArgument( "could not retrieve buffer from object")); PyErr_Clear(); } Py_INCREF(view.obj); std::unique_ptr obj(view.obj); auto len = view.len; auto buf = view.buf; PyBuffer_Release(&view); PADDLE_ENFORCE_EQ( len > 0 && count != 0, true, common::errors::InvalidArgument( "both buffer length and count must be greater than 0")); PADDLE_ENFORCE_EQ( offset >= 0 && offset < len, true, common::errors::InvalidArgument("offset must be non-negative and " "no greater than buffer length")); PADDLE_ENFORCE_EQ( count > 0 || (len - offset) % elsize == 0, true, common::errors::InvalidArgument("buffer length after offset must " "be a multiple of element size")); if (count < 0) { actual_count = static_cast(len - offset) / elsize; } else { actual_count = static_cast(count); } PADDLE_ENFORCE_LE(static_cast(offset) + actual_count * elsize, static_cast(len), common::errors::InvalidArgument( "requested buffer length after offset must not " "be greater than actual buffer length")); auto offset_buf = static_cast(buf) + offset; return from_blob(offset_buf, phi::IntArray({actual_count}), dtype, phi::DataLayout::NCHW, CPUPlace(), [obj = obj.release()](void *) { pybind11::gil_scoped_acquire gil; Py_DECREF(obj); }); }, py::arg("buffer"), py::arg("dtype"), py::arg("count") = -1, py::arg("offset") = 0); m.def("place_to_dl_device", [](const Place &place) { ::DLDevice dl_device = PlaceToDLDevice(place); return py::make_tuple(static_cast(dl_device.device_type), dl_device.device_id); }); m.def("dlpack_exchange_api_ptr", []() -> int64_t { return reinterpret_cast(PaddleDLPackExchangeAPI::Instance()); }); m.def("dlpack_exchange_api_pycapsule", []() -> py::capsule { return py::capsule(PaddleDLPackExchangeAPI::Instance(), "dlpack_exchange_api"); }); m.def("from_dlpack", [](py::object data) { if (PyCapsule_IsValid(data.ptr(), DLPackTraits::capsule)) { DLManagedTensorVersioned *dlMTensor = reinterpret_cast(PyCapsule_GetPointer( data.ptr(), DLPackTraits::capsule)); PADDLE_ENFORCE_NOT_NULL( dlMTensor, common::errors::InvalidArgument( "from_dlpack received an invalid capsule. " "Note that DLTensor capsules can be consumed only once, " "so you might have already constructed a tensor from it once.")); PADDLE_ENFORCE_LE( dlMTensor->version.major, DLPACK_MAJOR_VERSION, common::errors::InvalidArgument( "The major version of DLManagedTensorVersioned (%d) is " "greater than the supported version (%d).", dlMTensor->version.major, DLPACK_MAJOR_VERSION)); // NOTE: Might meet bugged numpy version, see: // https://github.com/pytorch/pytorch/blob/main/torch/csrc/utils/tensor_new.cpp#L1636-L1638 auto ptensor = DLPackTraits::FromDLPack(dlMTensor); PyCapsule_SetName(data.ptr(), DLPackTraits::used); return ptensor; } else { DLManagedTensor *dlMTensor = reinterpret_cast(PyCapsule_GetPointer( data.ptr(), DLPackTraits::capsule)); PADDLE_ENFORCE_NOT_NULL( dlMTensor, common::errors::InvalidArgument( "from_dlpack received an invalid capsule. " "Note that DLTensor capsules can be consumed only once, " "so you might have already constructed a tensor from it once.")); auto ptensor = DLPackTraits::FromDLPack(dlMTensor); PyCapsule_SetName(data.ptr(), DLPackTraits::used); return ptensor; } }); m.def("tensor_from_cuda_array_interface", [](py::object obj) { // We use CUDA Array Interface (Version 2) protocol: // https://numba.pydata.org/numba-doc/dev/cuda/cuda_array_interface.html py::object cuda_array_interface = obj.attr("__cuda_array_interface__"); PADDLE_ENFORCE_EQ(py::isinstance(cuda_array_interface), true, common::errors::InvalidArgument( "`__cuda_array_interface` must be a dict")); py::dict cuda_dict = cuda_array_interface.cast(); // Extract the `obj.__cuda_array_interface__['shape']` attribute PADDLE_ENFORCE_EQ( cuda_dict.contains("shape"), true, common::errors::InvalidArgument( "The 'shape' key is missing in the __cuda_array_interface__ " "dict.")); py::object shape_obj = cuda_dict["shape"]; PADDLE_ENFORCE_EQ( py::isinstance(shape_obj) || py::isinstance(shape_obj), true, common::errors::InvalidArgument("Shape must be a tuple or list")); std::vector shapes; shapes = shape_obj.cast>(); phi::IntArray shapeIntArray = phi::IntArray(shapes); // Extract the `obj.__cuda_array_interface__['typestr'] attribute PADDLE_ENFORCE_EQ( cuda_dict.contains("typestr"), true, common::errors::InvalidArgument( "The 'typestr' key is missing in the __cuda_array_interface__ " "dict.")); py::object typestr_obj = cuda_dict["typestr"]; std::string typestr = typestr_obj.cast(); DataType dtype = paddle::framework::ConvertToPDDataType(typestr); // Extract the `obj.__cuda_array_interface__['data']` attribute PADDLE_ENFORCE_EQ( cuda_dict.contains("data"), true, common::errors::InvalidArgument( "The 'data' key is missing in the __cuda_array_interface__ " "dict.")); py::object data_obj = cuda_dict["data"]; py::tuple data_tuple = data_obj.cast(); // Data tuple(ptr_as_int, read_only_flag). // The ptr_as_int stands for data pointer but in Python it is a integer. // It need to be converted to a large enough integral type first // and then convert to void* void *data_ptr = reinterpret_cast(data_tuple[0].cast()); PADDLE_ENFORCE_NE( data_tuple[1].cast(), true, common::errors::InvalidArgument("Read-only array is not supported")); // Extract the `obj.__cuda_array_interface__['strides']` attribute phi::IntArray stridesIntArray; if (cuda_dict.contains("strides") && !cuda_dict["strides"].is_none()) { std::vector strides_vec = cuda_dict["strides"].cast>(); // __cuda_array_interface__ strides uses bytes size_t element_size = phi::SizeOf(dtype); for (auto &stride : strides_vec) { PADDLE_ENFORCE_NE( stride % element_size, 0, common::errors::InvalidArgument( "strides must be a multiple of the element size.")); stride /= element_size; } stridesIntArray = phi::IntArray(strides_vec); } else { DDim ddim_strides = phi::DenseTensorMeta::calc_strides(common::make_ddim(shapes)); int rank = ddim_strides.size(); const int64_t *ddim_data = ddim_strides.Get(); std::vector strides_vec(ddim_data, ddim_data + rank); stridesIntArray = phi::IntArray(strides_vec); } return paddle::from_blob(data_ptr, shapeIntArray, stridesIntArray, dtype, phi::DataLayout::NCHW, Place(), [obj](void *data) { py::gil_scoped_acquire gil; obj.dec_ref(); }); }); m.def("_create_loaded_parameter", [](const py::handle &vec_var_list, const Scope &scope, const Executor *executor) { CreateVariableIfNotExist(vec_var_list, scope, executor); }); m.def("save_op_version_info", [](framework::ProgramDesc &desc) { framework::compatible::pb::OpVersionMap pb_vmap{desc.OpVersionMap()}; framework::compatible::SaveOpVersions( framework::compatible::OpVersionRegistrar::GetInstance() .GetVersionMap(), &pb_vmap); }); m.def("set_printoptions", [](const py::kwargs &kwargs) { auto &print_opt = framework::PrintOptions::Instance(); if (kwargs.contains("precision")) { print_opt.precision = kwargs["precision"].cast(); } if (kwargs.contains("threshold")) { print_opt.threshold = kwargs["threshold"].cast(); } if (kwargs.contains("edgeitems")) { print_opt.edgeitems = kwargs["edgeitems"].cast(); } if (kwargs.contains("linewidth")) { print_opt.linewidth = kwargs["linewidth"].cast(); } if (kwargs.contains("sci_mode")) { print_opt.sci_mode = kwargs["sci_mode"].cast(); } VLOG(4) << "Set printoptions: precision=" << print_opt.precision << ", threshold=" << print_opt.threshold << ", edgeitems=" << print_opt.edgeitems << ", linewidth=" << print_opt.linewidth << ", sci_mode=" << print_opt.sci_mode; }); m.def( "broadcast_shape", [](const std::vector &x_dim, const std::vector &y_dim) { return common::vectorize(phi::funcs::BroadcastTwoDims( common::make_ddim(x_dim), common::make_ddim(y_dim), -1)); }); m.def( "_append_python_callable_object_and_return_id", [](py::object py_obj) -> size_t { return paddle::operators::AppendPythonCallableObjectAndReturnId(py_obj); }); m.def("_get_use_default_grad_op_desc_maker_ops", [] { return OpInfoMap::Instance().GetUseDefaultGradOpDescMakerOps(); }); m.def( "_get_all_register_op_kernels", [](const std::string &lib) { std::unordered_map> all_kernels_info; if (lib == "fluid" || lib == "all") { auto &all_kernels = paddle::framework::OperatorWithKernel::AllOpKernels(); for (auto &kernel_pair : all_kernels) { auto op_type = kernel_pair.first; std::vector kernel_types; for (auto &info_pair : kernel_pair.second) { paddle::framework::OpKernelType kernel_type = info_pair.first; kernel_types.emplace_back( paddle::framework::KernelTypeToString(kernel_type)); } all_kernels_info.emplace(op_type, kernel_types); } } if (lib == "phi" || lib == "all") { auto phi_kernels = phi::KernelFactory::Instance().kernels(); for (auto &kernel_pair : phi_kernels) { auto op_type = phi::TransToFluidOpName(kernel_pair.first); std::vector kernel_types; for (auto &info_pair : kernel_pair.second) { framework::OpKernelType kernel_type = framework::TransPhiKernelKeyToOpKernelType(info_pair.first); auto kernel_type_str = framework::KernelTypeToString(kernel_type); if (all_kernels_info.count(op_type)) { if (std::find(all_kernels_info[op_type].begin(), all_kernels_info[op_type].end(), kernel_type_str) == all_kernels_info[op_type].end()) { all_kernels_info[op_type].emplace_back(kernel_type_str); } } else { kernel_types.emplace_back(kernel_type_str); } } if (!kernel_types.empty()) { all_kernels_info.emplace(op_type, kernel_types); } } } return all_kernels_info; }, py::arg("lib") = "all", R"DOC( Return the registered kernels in paddle. Args: lib[string]: the library, could be 'phi', 'fluid' and 'all'. )DOC"); m.def( "_get_registered_phi_kernels", [](const std::string &kernel_registered_type) { std::unordered_map> all_kernels_info; auto phi_kernels = phi::KernelFactory::Instance().kernels(); for (auto &kernel_pair : phi_kernels) { auto kernel_name = kernel_pair.first; std::vector kernel_keys; for (auto &info_pair : kernel_pair.second) { bool get_function_kernel = kernel_registered_type == "function" && info_pair.second.GetKernelRegisteredType() == phi::KernelRegisteredType::FUNCTION; bool get_structure_kernel = kernel_registered_type == "structure" && info_pair.second.GetKernelRegisteredType() == phi::KernelRegisteredType::STRUCTURE; if (kernel_registered_type == "all" || get_function_kernel || get_structure_kernel) { std::ostringstream stream; stream << info_pair.first; std::string kernel_key_str = stream.str(); if (all_kernels_info.count(kernel_name)) { bool kernel_exist = std::find(all_kernels_info[kernel_name].begin(), all_kernels_info[kernel_name].end(), kernel_key_str) != all_kernels_info[kernel_name].end(); if (!kernel_exist) { all_kernels_info[kernel_name].emplace_back(kernel_key_str); } } else { kernel_keys.emplace_back(kernel_key_str); } } } if (!kernel_keys.empty()) { all_kernels_info.emplace(kernel_name, kernel_keys); } } return all_kernels_info; }, py::arg("kernel_registered_type") = "function", R"DOC( Return the registered kernels in phi. Args: kernel_registered_type[string]: the library, could be 'function', 'structure', and 'all'. )DOC"); // NOTE(Aganlengzi): KernelFactory static instance is initialized BEFORE // plugins are loaded for custom kernels, but de-initialized AFTER they are // unloaded. We need manually clear symbols(may contain plugins' symbols) // stored in this static instance to avoid illegal memory access. m.def("clear_kernel_factory", []() { phi::KernelFactory::Instance().kernels().clear(); }); m.def("clear_device_manager", []() { #ifdef PADDLE_WITH_CUSTOM_DEVICE platform::XCCLCommContext::Release(); platform::CustomTracer::Release(); platform::CustomDeviceEventResourcePool::Release(); platform::CustomDeviceStreamResourcePool::Release(); phi::DeviceManager::Release(); #endif }); // NOTE(zjl): ctest would load environment variables at the beginning even // though we have not `import paddle.base as base`. So we add this API // to enable eager deletion mode in unittest. m.def("_set_eager_deletion_mode", &paddle::framework::SetEagerDeletionMode); m.def("_set_fuse_parameter_group_size", &paddle::framework::ir::SetFuseParameterGroupsSize); m.def("_set_fuse_parameter_memory_size", &paddle::framework::ir::SetFuseParameterMemorySize); m.add_object("_cleanup", py::capsule([]() { ScopePool::Instance().Clear(); })); m.def("_set_paddle_lib_path", &phi::dynload::SetPaddleLibPath); m.def("set_current_thread_name", &phi::SetCurrentThreadName); m.def("_promote_types_if_complex_exists", &paddle::framework::PromoteTypesIfComplexExists); py::class_(m, "Variable", R"DOC(Variable Class. All parameter, weight, gradient are variables in Paddle. )DOC") .def(py::init<>()) .def("is_int", [](const Variable &var) { return var.IsType(); }) .def("set_int", [](Variable &var, int val) -> void { *var.GetMutable() = val; }) .def("get_int", [](const Variable &var) -> int { return var.Get(); }) .def("is_float", [](const Variable &var) { return var.IsType(); }) .def("set_float", [](Variable &var, float val) -> void { *var.GetMutable() = val; }) .def("get_float", [](const Variable &var) -> float { return var.Get(); }) .def( "get_tensor", [](Variable &self) -> DenseTensor * { return self.GetMutable(); }, py::return_value_policy::reference) .def("get_bytes", [](Variable &self) { if (self.IsType()) { // NOLINT return py::bytes(*(self.GetMutable())); } else { return py::bytes( *(self.GetMutable()->GetMutable())); } }) .def("set_string_list", [](Variable &self, std::vector str_list) { *self.GetMutable() = str_list; }) .def("set_vocab", [](Variable &self, const std::unordered_map &vocab) { *self.GetMutable() = vocab; }) .def( "get_string_tensor", [](Variable &self) { return self.GetMutable(); }, py::return_value_policy::reference) .def( "get_map_tensor", [](Variable &self) { return self.GetMutable(); }, py::return_value_policy::reference) .def( "get_selected_rows", [](Variable &self) -> phi::SelectedRows * { return self.GetMutable(); }, py::return_value_policy::reference) .def( "get_dense_tensor_array", [](Variable &self) { return self.GetMutable(); }, py::return_value_policy::reference) .def( "get_fetch_list", [](Variable &self) { return self.GetMutable(); }, py::return_value_policy::reference) #if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL) .def( "get_communicator", [](Variable &self) -> platform::Communicator * { return self.GetMutable(); }, py::return_value_policy::reference) #endif .def( "get_reader", [](Variable &self) -> framework::ReaderHolder * { PADDLE_ENFORCE_EQ(self.IsType(), true, common::errors::InvalidArgument( "The variable is not type of ReaderHolder.")); return self.GetMutable(); }, py::return_value_policy::reference) .def( "get_scope", [](Variable &self) -> Scope * { auto scope_vec = self.GetMutable>(); PADDLE_ENFORCE_GT( scope_vec->size(), 0, common::errors::InvalidArgument( "The size of scope_vec should be greater than 0")); return scope_vec->front(); }, py::return_value_policy::reference) .def("set_scope", [](Variable &self, Scope &scope) { auto scope_vec = self.GetMutable>(); scope_vec->emplace_back(&scope); }); BindReader(&m); py::class_ _Scope(m, "_Scope", R"DOC( Scope is an association of a name to Variable. All variables belong to Scope. Variables in a parent scope can be retrieved from local scope. You need to specify a scope to run a Net, i.e., `exe.Run(&scope)`. One net can run in different scopes and update different variable in the scope. You can create var in a scope and get it from the scope. Examples: .. code-block:: pycon >>> import paddle >>> import numpy as np >>> scope = paddle.static.global_scope() >>> place = paddle.CPUPlace() >>> # create tensor from a scope and set value to it. >>> param = scope.var('Param').get_tensor() >>> param_array = np.full((10, 12), 5.0).astype("float32") >>> param.set(param_array, place) )DOC"); g_framework_scope_pytype = reinterpret_cast(_Scope.ptr()); _Scope .def("_remove_from_pool", [](Scope &self) { ScopePool::Instance().Remove(&self); }) .def("raw_address", [](Scope &self) { return reinterpret_cast(&self); }) .def( "var", [](Scope &self, const std::string &name) -> Variable * { return self.Var(name); }, py::arg("name"), R"DOC( Find or create variable named :code:`name` in the current scope. If the variable named :code:`name` does not exist in the current scope, the variable would be created. Otherwise, return the existing variable. Args: name (str): the variable name. Returns: out (core.Variable): the found or created variable. )DOC", py::return_value_policy::reference) .def("find_var", &Scope::FindVar, py::arg("name"), R"DOC( Find variable named :code:`name` in the current scope or its parent scope. Return None if not found. Args: name (str): the variable name. Returns: out (core.Variable|None): the found variable or None. )DOC", py::return_value_policy::reference) .def("size", &Scope::Size) .def("local_var_names", &Scope::LocalVarNames, R"DOC( Get all variable names in the current scope. Returns: List[str]: The list of variable names. )DOC", py::return_value_policy::reference) .def("erase", &Scope::EraseVars, py::arg("names"), R"DOC( Find variable named :code:`name` in the current scope or its parent scope. Return None if not found. Args: name (str): the variable names to be erase. Returns: None )DOC", py::return_value_policy::reference) .def( "new_scope", [](Scope &self) -> Scope * { return &self.NewScope(); }, R"DOC( Create a new sub-scope of the current scope. Returns: out (core._Scope): the created sub-scope. )DOC", py::return_value_policy::reference) .def("drop_kids", &Scope::DropKids, R"DOC( Delete all sub-scopes of the current scope. )DOC") .def("_kids", &Scope::kids) .def_property("_can_reused", &Scope::CanReused, &Scope::SetCanReused); m.def( "Scope", []() -> Scope * { auto *s = new Scope(); ScopePool::Instance().Insert(std::unique_ptr(s)); return s; }, R"DOC( Create a new scope. Returns: out (core._Scope): the created scope. )DOC", py::return_value_policy::reference); //! @note: Be careful! PyBind will return std::string as an unicode, not //! Python str. If you want a str object, you should cast them in Python. m.def("get_all_op_protos", []() -> std::vector { std::vector ret_values; for (auto &iter : OpInfoMap::Instance().map()) { auto &info = iter.second; if (info.HasOpProtoAndChecker()) { std::string str; PADDLE_ENFORCE_EQ( info.Proto().SerializeToString(&str), true, common::errors::Fatal( "Serialize OpProto Error. This could be a bug of Paddle.")); ret_values.emplace_back(str); } } return ret_values; }); m.def( "get_all_op_names", [](const std::string &lib) { std::vector op_names; for (auto &iter : OpInfoMap::Instance().map()) { op_names.emplace_back(iter.first); } if (lib == "phi") { std::vector ops_with_phi_kernel; for (const auto &op_name : op_names) { if (phi::KernelFactory::Instance().HasCompatiblePhiKernel( op_name)) { ops_with_phi_kernel.emplace_back(op_name); } } return ops_with_phi_kernel; } else if (lib == "fluid") { std::vector ops_with_fluid_kernel; auto all_fluid_op_kernels = paddle::framework::OperatorWithKernel::AllOpKernels(); for (const auto &op_name : op_names) { if (all_fluid_op_kernels.find(op_name) != all_fluid_op_kernels.end()) { ops_with_fluid_kernel.emplace_back(op_name); } } return ops_with_fluid_kernel; } else { return op_names; } }, py::arg("lib") = "all", R"DOC( Return the operator names in paddle. Args: lib[string]: the library contains corresponding OpKernel, could be 'phi', 'fluid' and 'all'. Default value is 'all'. )DOC"); m.def("get_op_attrs_default_value", [](py::bytes byte_name) -> paddle::framework::AttributeMap { std::string op_type = byte_name; paddle::framework::AttributeMap res; auto info = OpInfoMap::Instance().GetNullable(op_type); if (info != nullptr) { if (info->HasOpProtoAndChecker()) { auto op_checker = info->Checker(); res = op_checker->GetDefaultAttrsMap(); } } return res; }); m.def( "get_op_extra_attrs", [](const std::string &op_type) -> const paddle::framework::AttributeMap & { return operators::ExtraInfoUtils::Instance().GetExtraAttrsMap(op_type); }); m.def( "get_attribute_type", [](const std::string &op_type, const std::string &attr_name) -> paddle::framework::proto::AttrType { const auto &default_val = operators::ExtraInfoUtils::Instance().GetExtraAttrsMap(op_type).at( attr_name); return static_cast( default_val.index() - 1); }); m.def("_add_skip_comp_ops", &paddle::prim::PrimCommonUtils::AddSkipCompOps); m.def("_set_bwd_prim_blacklist", &paddle::prim::PrimCommonUtils::SetPrimBackwardBlacklist); m.def("_remove_skip_comp_ops", &paddle::prim::PrimCommonUtils::RemoveSkipCompOps); m.def("get_grad_op_desc", [](const OpDesc &op_desc, const std::unordered_set &no_grad_set, const std::vector &grad_sub_block) { std::unordered_map grad_to_var; auto op_info = framework::OpInfoMap::Instance().Get(op_desc.Type()); auto grad_op_maker = op_info.GradOpMaker(); auto grad_comp_op_maker = op_info.CompGradOpMaker(); if ((grad_op_maker == nullptr) && (grad_comp_op_maker == nullptr)) { // Normally, proto_ should not be null, except some special // operators, such as LeaklyReluDoubleGrad op. std::string type = op_desc.Type(); PADDLE_THROW(common::errors::NotFound( "Neither operator %s's GradOpMaker nor CompGradOpMaker has " "been registered.\nPlease check whether (%s) operator has " "gradient operator.\nIf not, please set stop_gradient to be " "True for its input and output variables using " "var.stop_gradient=True.", type.c_str(), type.c_str())); } // In PrimEnabled mode, the priority of CompGradOpMaker is greater // than GradCompMaker as we need split first-order grad operator into // primitive operators for compiler. In PrimDisabled mode, the // priority of CompGradOpMaker is less than GradCompMaker for better // performance. std::vector> grad_op_descs; auto need_skip = paddle::prim::PrimCommonUtils::CheckSkipCompOps(op_desc.Type()); VLOG(3) << "need skip: " << need_skip << std::endl; if (paddle::prim::PrimCommonUtils::IsBwdPrimEnabled()) { if ((grad_comp_op_maker != nullptr) && (!need_skip)) { VLOG(3) << "Prim Flag Open: Running composite grad fun for " << op_desc.Type(); grad_op_descs = grad_comp_op_maker(op_desc, no_grad_set, &grad_to_var, op_desc.Block(), grad_sub_block); } else { grad_op_descs = grad_op_maker( op_desc, no_grad_set, &grad_to_var, grad_sub_block); } } else { if (grad_op_maker != nullptr) { VLOG(6) << "Prim Flag Close: Running origin grad fun for " << op_desc.Type(); grad_op_descs = grad_op_maker( op_desc, no_grad_set, &grad_to_var, grad_sub_block); } else { VLOG(6) << "Prim Flag Close: Running composite grad fun for " << op_desc.Type(); grad_op_descs = grad_comp_op_maker(op_desc, no_grad_set, &grad_to_var, op_desc.Block(), grad_sub_block); } } std::vector grad_op_desc_ptrs(grad_op_descs.size()); std::transform( grad_op_descs.begin(), grad_op_descs.end(), grad_op_desc_ptrs.begin(), [](std::unique_ptr &p) { return p.release(); }); return std::make_pair(grad_op_desc_ptrs, grad_to_var); }); m.def("has_comp_grad_op_maker", [](const std::string op_type) { return framework::OpInfoMap::Instance().Get(op_type).HasCompGradOpMaker(); }); m.def("has_grad_op_maker", [](const std::string op_type) { return framework::OpInfoMap::Instance().Get(op_type).HasGradOpMaker(); }); m.def("has_non_empty_grad_op_maker", [](const std::string op_type) { return framework::OpInfoMap::Instance() .Get(op_type) .HasNonEmptyGradOpMaker(); }); m.def("has_empty_grad_op_maker", [](const std::string op_type) { return framework::OpInfoMap::Instance().Get(op_type).HasEmptyGradOpMaker(); }); m.def("has_infer_inplace", [](const std::string op_type) { return framework::OpInfoMap::Instance().Get(op_type).HasInferInplace(); }); m.def("infer_no_need_buffer_slots", [](const std::string op_type, const framework::VariableNameMap &inputs, const framework::VariableNameMap &outputs, const framework::AttributeMap &attrs) { auto infer_func = framework::OpInfoMap::Instance() .Get(op_type) .NoNeedBufferVarsInferer(); if (infer_func) { return infer_func(inputs, outputs, attrs); } else { std::unordered_set empty = {}; return empty; } }); m.def("prune", [](const ProgramDesc &origin, const std::set &feeded_var_names, const std::vector> &targets) { ProgramDesc prog_with_targets(origin); for (const auto &t : targets) { prog_with_targets.MutableBlock(t[0]) ->Op(static_cast(t[1])) ->SetIsTarget(true); } proto::ProgramDesc pruned_desc; auto pruned_origin_block_id_map = Prune(*prog_with_targets.Proto(), feeded_var_names, &pruned_desc); return std::make_tuple(ProgramDesc(pruned_desc), pruned_origin_block_id_map); }); m.def( "prune_backward", [](const framework::ProgramDesc &program) { return PruneBackward(program); }, R"DOC( Prune the backward part of a program, mostly called in program.clone(for_test=True). Args: program (ProgramDesc): The original program. Returns: tuple(ProgramDesc, map): The first part is the pruned program desc, and the second part is a map which contains the id pair of pruned block and corresponding origin block. )DOC"); m.def("empty_var_name", []() { return std::string(framework::kEmptyVarName); }); m.def("grad_var_suffix", []() { return std::string(framework::kGradVarSuffix); }); m.def_submodule( "var_names", "The module will return special predefined variable name in Paddle") .def("empty", []() { return kEmptyVarName; }) .def("temp", []() { return kTempVarName; }); py::class_(m, "DeviceContext") .def_static("create", [](CPUPlace &place) -> phi::DeviceContext * { auto *context = new phi::CPUContext(); context->SetAllocator( paddle::memory::allocation::AllocatorFacade::Instance() .GetAllocator(place) .get()); context->SetHostAllocator( paddle::memory::allocation::AllocatorFacade::Instance() .GetAllocator(CPUPlace()) .get()); context->SetZeroAllocator( paddle::memory::allocation::AllocatorFacade::Instance() .GetZeroAllocator(place) .get()); context->SetHostZeroAllocator( paddle::memory::allocation::AllocatorFacade::Instance() .GetZeroAllocator(CPUPlace()) .get()); return context; }) .def_static( "create", [](phi::XPUPlace &place) -> phi::DeviceContext * { #ifndef PADDLE_WITH_XPU PADDLE_THROW(common::errors::PermissionDenied( "Cannot use XPUPlace in CPU/GPU version, " "Please recompile or reinstall Paddle with XPU support.")); #else auto *context = new phi::XPUContext(place); context->SetAllocator( paddle::memory::allocation::AllocatorFacade::Instance() .GetAllocator(place) .get()); context->SetHostAllocator( paddle::memory::allocation::AllocatorFacade::Instance() .GetAllocator(CPUPlace()) .get()); context->SetZeroAllocator( paddle::memory::allocation::AllocatorFacade::Instance() .GetZeroAllocator(place) .get()); context->SetHostZeroAllocator( paddle::memory::allocation::AllocatorFacade::Instance() .GetZeroAllocator(CPUPlace()) .get()); context->SetPinnedAllocator( paddle::memory::allocation::AllocatorFacade::Instance() .GetAllocator(phi::XPUPinnedPlace()) .get()); return context; #endif }) .def_static( "create", [](phi::XPUPinnedPlace &place) -> phi::DeviceContext * { #if !defined(PADDLE_WITH_XPU) PADDLE_THROW(common::errors::PermissionDenied( "Cannot use XPUPinnedPlace in CPU only version, " "Please recompile or reinstall Paddle with XPU support.")); #else return new phi::XPUPinnedContext(place); #endif }) .def_static("create", [](phi::CustomPlace &place) -> phi::DeviceContext * { #ifndef PADDLE_WITH_CUSTOM_DEVICE PADDLE_THROW(common::errors::PermissionDenied( "Cannot use CustomPlace in CPU/GPU/XPU version, " "Please recompile or reinstall Paddle with " "CustomDevice support.")); #else return new phi::CustomContext(place); #endif }) .def_static( "create", [](GPUPlace &place) -> phi::DeviceContext * { #if !defined(PADDLE_WITH_CUDA) && !defined(PADDLE_WITH_HIP) PADDLE_THROW(common::errors::PermissionDenied( "Cannot use CUDAPlace in CPU only version, " "Please recompile or reinstall Paddle with CUDA support.")); #else auto *context = new phi::GPUContext(place); context->SetAllocator( paddle::memory::allocation::AllocatorFacade::Instance() .GetAllocator(place, context->stream()) .get()); context->SetHostAllocator( paddle::memory::allocation::AllocatorFacade::Instance() .GetAllocator(CPUPlace()) .get()); context->SetZeroAllocator( paddle::memory::allocation::AllocatorFacade::Instance() .GetZeroAllocator(place) .get()); context->SetHostZeroAllocator( paddle::memory::allocation::AllocatorFacade::Instance() .GetZeroAllocator(CPUPlace()) .get()); context->SetPinnedAllocator( paddle::memory::allocation::AllocatorFacade::Instance() .GetAllocator(phi::GPUPinnedPlace()) .get()); context->PartialInitWithAllocator(); return context; #endif }) .def_static( "create", [](phi::GPUPinnedPlace &place) -> phi::DeviceContext * { #if !defined(PADDLE_WITH_CUDA) && !defined(PADDLE_WITH_HIP) PADDLE_THROW(common::errors::PermissionDenied( "Cannot use CUDAPinnedPlace in CPU only version, " "Please recompile or reinstall Paddle with CUDA support.")); #else return new phi::GPUPinnedContext(place); #endif }); #if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL) py::class_(m, "Communicator").def(py::init<>()); #endif m.def("get_all_device_type", []() { std::vector device_types; #ifdef PADDLE_WITH_CUSTOM_DEVICE device_types = phi::DeviceManager::GetAllDeviceTypes(); #elif defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) device_types.push_back("gpu"); #elif defined(PADDLE_WITH_XPU) device_types.push_back("xpu"); #else VLOG(1) << string::Sprintf( "Cannot use get_all_device_type because you have installed " "CPU version PaddlePaddle.\n" "If you want to use get_all_device_type, please try to install " "CUDA/XPU/CustomDevice version " "PaddlePaddle by: pip install paddlepaddle\n"); #endif return device_types; }); m.def("get_all_custom_device_type", []() { std::vector device_types; #ifdef PADDLE_WITH_CUSTOM_DEVICE device_types = phi::DeviceManager::GetAllCustomDeviceTypes(); #else VLOG(1) << string::Sprintf( "Cannot use get_all_custom_device_type because you have " "installed CPU/GPU version PaddlePaddle.\n" "If you want to use get_all_custom_device_type, please try to " "install CustomDevice version " "PaddlePaddle by: pip install paddlepaddle\n"); #endif return device_types; }); m.def("get_available_device", [] { std::vector devices; #ifdef PADDLE_WITH_CUSTOM_DEVICE devices = phi::DeviceManager::GetAllDeviceList(); #elif defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) int gpu_count = phi::backends::gpu::GetGPUDeviceCount(); for (int i = 0; i < gpu_count; ++i) { devices.push_back("gpu:" + std::to_string(i)); } #elif defined(PADDLE_WITH_XPU) int xpu_count = phi::backends::xpu::GetXPUDeviceCount(); for (int i = 0; i < xpu_count; ++i) { devices.push_back("xpu:" + std::to_string(i)); } #else VLOG(1) << string::Sprintf( "Cannot use get_available_device because you have installed " "CPU version PaddlePaddle.\n" "If you want to use get_available_device, please try to install " "CUDA/XPU/CustomDevice version " "PaddlePaddle by: pip install paddlepaddle\n"); #endif return devices; }); m.def("get_available_custom_device", [] { std::vector devices; #ifdef PADDLE_WITH_CUSTOM_DEVICE devices = phi::DeviceManager::GetAllCustomDeviceList(); #else VLOG(1) << string::Sprintf( "Cannot use get_available_custom_device because you have " "installed CPU/GPU version PaddlePaddle.\n" "If you want to use get_available_custom_device, please try to " "install " "CustomDevice version " "PaddlePaddle by: pip install paddlepaddle\n"); #endif return devices; }); m.def("get_custom_device_count", [](const std::string &device_type) { size_t device_count = 0; #ifdef PADDLE_WITH_CUSTOM_DEVICE // TODO(duanyanhui): Optimize DeviceManager::GetDeviceCount to support // returning default device when only one device is registered in // DeviceManager. device_count = phi::DeviceManager::GetDeviceCount(device_type); #else VLOG(1) << string::Sprintf( "Cannot use get_custom_device_count because you have " "installed CPU/GPU version PaddlePaddle.\n" "If you want to use get_custom_device_count, please try to " "install " "CustomDevice version " "PaddlePaddle by: pip install paddlepaddle\n"); #endif return device_count; }); py::class_(m, "Operator") .def_static("create", [](py::bytes protobin) { proto::OpDesc desc; PADDLE_ENFORCE_EQ(desc.ParsePartialFromString(protobin), true, common::errors::InvalidArgument( "Cannot parse user input to OpDesc")); PADDLE_ENFORCE_EQ(desc.IsInitialized(), true, common::errors::InvalidArgument( "The provided OpDesc is not " "initialized, the reason is: %s", desc.InitializationErrorString())); return OpRegistry::CreateOp(desc); }) .def("run", [](OperatorBase &self, const Scope &scope, const CPUPlace &place) { pybind11::gil_scoped_release release; self.Run(scope, place); }) .def("run", [](OperatorBase &self, const Scope &scope, const phi::XPUPlace &place) { pybind11::gil_scoped_release release; self.Run(scope, place); }) .def("run", [](OperatorBase &self, const Scope &scope, const GPUPlace &place) { pybind11::gil_scoped_release release; self.Run(scope, place); }) .def("run", [](OperatorBase &self, const Scope &scope, const phi::GPUPinnedPlace &place) { pybind11::gil_scoped_release release; self.Run(scope, place); }) .def("run", [](OperatorBase &self, const Scope &scope, const phi::XPUPinnedPlace &place) { pybind11::gil_scoped_release release; self.Run(scope, place); }) .def("run", [](OperatorBase &self, const Scope &scope, const phi::CustomPlace &place) { pybind11::gil_scoped_release release; self.Run(scope, place); }) .def("type", [](const OperatorBase &op) -> std::string { return op.Type(); }) .def("outputs", [](const OperatorBase &op) -> std::map> { return op.Outputs(); }) .def("output_vars", [](const OperatorBase &op) { return op.OutputVars(true); }) .def("inputs", [](const OperatorBase &op) { return op.Inputs(); }) .def("input_vars", [](const OperatorBase &op) { return op.InputVars(); }) .def("__str__", &OperatorBase::DebugString) .def("no_intermediate_outputs", [](const OperatorBase &op) { return op.OutputVars(false); }) .def("support_gpu", &OperatorBase::SupportGPU); py::class_(m, "ExecutorPrepareContext") .def(py::init()); py::class_>( m, "TrainerBase") .def( "get_worker_scope", [](TrainerBase &self, int thread_id) -> Scope * { return self.GetWorkerScope(thread_id); }, py::return_value_policy::reference) .def("finalize", &TrainerBase::Finalize) .def("ResetDataset", &TrainerBase::ResetDataset); m.def("_get_eager_deletion_vars", &framework::GetEagerDeletionCleanVars); py::class_(m, "Executor") .def(py::init()) .def("close", &Executor::Close) .def("get_place", &Executor::GetPlace) .def("run_from_dataset", &Executor::RunFromDataset, py::call_guard()) .def("release_trainer", &Executor::ReleaseTrainer, py::call_guard()) .def("init_for_dataset", [](Executor &self, const ProgramDesc &prog, const std::string &trainer_desc, Scope *scope, Dataset *dataset) -> std::shared_ptr { pybind11::gil_scoped_release release; return self.InitForDataset(prog, trainer_desc, scope, dataset); }) .def("run_from_dataset", [](Executor &self, std::shared_ptr trainer) { pybind11::gil_scoped_release release; self.RunFromDataset(trainer); }) .def("run_prepared_ctx", [](Executor &self, ExecutorPrepareContext *ctx, Scope *scope, std::map *feed_targets, std::map *fetch_targets, bool create_local_scope = true, bool create_vars = true, const std::string &feed_holder_name = "feed", const std::string &fetch_holder_name = "fetch") { pybind11::gil_scoped_release release; self.RunPreparedContext(ctx, scope, feed_targets, fetch_targets, create_local_scope, create_vars, feed_holder_name, fetch_holder_name); }) .def("run_prepared_ctx", [](Executor &self, ExecutorPrepareContext *ctx, Scope *scope, bool create_local_scope = true, bool create_vars = true, bool keep_kids = false) { pybind11::gil_scoped_release release; self.RunPreparedContext( ctx, scope, create_local_scope, create_vars, keep_kids); }) .def("prepare", [](Executor &self, const ProgramDesc &program, int block_id, const std::vector &skip_ref_cnt_vars = std::vector(), bool force_disable_gc = false) { pybind11::gil_scoped_release release; return self.Prepare( program, block_id, skip_ref_cnt_vars, force_disable_gc); }) .def("create_variables", &Executor::CreateVariables) .def("run", [](Executor &self, const ProgramDesc &prog, Scope *scope, int block_id, bool create_local_scope, bool create_vars, const std::vector &fetch_vars) { pybind11::gil_scoped_release release; self.Run(prog, scope, block_id, create_local_scope, create_vars, fetch_vars); }); py::class_(m, "CostInfo") .def(py::init<>()) .def("total_time", [](interpreter::CostInfo &self) { return self.total_time; }) .def("device_memory_bytes", [](interpreter::CostInfo &self) { return self.device_memory_bytes; }); py::class_(m, "StandaloneExecutor") .def(py::init()) .def("run", [](StandaloneExecutor &self, std::vector feed_names, bool enable_job_schedule_profiler = false) { paddle::framework::FetchList ret; { pybind11::gil_scoped_release release; ret = self.Run(feed_names, enable_job_schedule_profiler); } return py::cast(std::move(ret)); }) .def("run_profile", [](StandaloneExecutor &self, std::vector feed_names) { std::shared_ptr program_desc; { pybind11::gil_scoped_release release; program_desc = self.RunProfile(feed_names); } return py::cast(std::move(program_desc)); }); py::class_>(m, "Job") .def(py::init(), py::arg("type")) .def("micro_batch_id", &framework::interpreter::Job::MicroBatchId) .def("type", &framework::interpreter::Job::Type) .def("set_micro_batch_id", &framework::interpreter::Job::SetMicroBatchId) .def("set_skip_gc_vars", &framework::interpreter::Job::SetSkipGcVars); py::class_(m, "Plan") .def( py::init< const std::vector> &, const std::unordered_map> &>(), py::arg("job_list"), py::arg("type_to_program")) .def( py::init< const std::vector> &, const std::unordered_map> &>(), py::arg("job_list"), py::arg("type_to_ir_program")) .def("job_list", &framework::interpreter::Plan::JobList) .def("job_types", &framework::interpreter::Plan::JobTypes) .def("micro_batch_num", &framework::interpreter::Plan::MicroBatchNum) .def("set_ir_program", &framework::interpreter::Plan::SetIrProgram) .def("ir_program", &framework::interpreter::Plan::IrProgram) .def("program", &framework::interpreter::Plan::Program); m.def("get_no_need_buffer_values", framework::interpreter::GetNoNeedBufferValues); #ifdef PADDLE_WITH_CUDA py::class_(m, "GPUEventTimer") .def(py::init(), py::arg("place")) .def( "start", [](phi::GPUEventTimer &timer, phi::CUDAStream *stream) { if (stream == nullptr) { timer.Start(); } else { timer.Start(stream->raw_stream()); } }, py::arg("stream") = nullptr, py::call_guard()) .def( "stop", [](phi::GPUEventTimer &timer, phi::CUDAStream *stream) { if (stream == nullptr) { timer.Stop(); } else { timer.Stop(stream->raw_stream()); } }, py::arg("stream") = nullptr, py::call_guard()) .def("reset", &phi::GPUEventTimer::Reset, py::call_guard()) .def("elapsed", &phi::GPUEventTimer::Elapsed, py::arg("reset") = true, py::call_guard()) .def( "elapsed_list", [](phi::GPUEventTimer &timer, bool reset) { std::vector values; { py::gil_scoped_release release; values = timer.ElapsedList(reset); } size_t n = values.size(); py::array_t array(n); auto buffer = array.request(); std::memcpy(buffer.ptr, values.data(), sizeof(values[0]) * n); return array; }, py::arg("reset") = true) .def("pre_alloc", &phi::GPUEventTimer::PreAlloc, py::arg("n"), py::call_guard()) .def("shrink_to_fit", &phi::GPUEventTimer::ShrinkToFit, py::call_guard()) .def("size", &phi::GPUEventTimer::Size, py::call_guard()) .def("capacity", &phi::GPUEventTimer::Capacity, py::call_guard()); #endif m.def("init_gflags", framework::InitGflags); m.def("init_gflags_from_env", framework::InitGflagsFromEnv); m.def("init_glog", framework::InitGLOG); m.def("init_memory_method", framework::InitMemoryMethod); m.def("load_op_meta_info_and_register_op", [](const std::string dso_name) { const auto &new_op_meta_info_map = framework::LoadOpMetaInfoAndRegisterOp(dso_name); // Merging failed? egr::Controller::Instance().MergeOpMetaInfoMap(new_op_meta_info_map); py::list key_list; for (const auto &pair : new_op_meta_info_map) { key_list.append(pair.first); } return key_list; }); m.def("init_devices", []() { framework::InitDevices(); }); m.def("init_default_kernel_signatures", []() { framework::InitDefaultKernelSignatureMap(); }); m.def("init_tensor_operants", []() { paddle::OperantsManager::Instance().eager_operants = std::make_unique(); paddle::OperantsManager::Instance().static_operants = std::make_unique(); paddle::OperantsManager::Instance().phi_operants = std::make_unique(); VLOG(7) << "Initialize tensor operants successfully"; }); m.def("is_compiled_with_flagcx", IsCompiledWithFlagcx); m.def("is_compiled_with_deepep", IsCompiledWithDeepEP); m.def("is_compiled_with_avx", IsCompiledWithAVX); m.def("is_compiled_with_cuda", IsCompiledWithCUDA); m.def("is_compiled_with_cudnn_frontend", IsCompiledWithCudnnFrontend); m.def("is_compiled_with_rocm", IsCompiledWithROCM); m.def("is_compiled_with_custom_device", IsCompiledWithCustomDevice); m.def("is_compiled_with_ipu", IsCompiledWithIPU); m.def("is_compiled_with_xpu", IsCompiledWithXPU); m.def("is_compiled_with_mkldnn", IsCompiledWithONEDNN); // deprecated m.def("is_compiled_with_onednn", IsCompiledWithONEDNN); m.def("is_compiled_with_nccl", IsCompiledWithNCCL); m.def("is_compiled_with_mpi", IsCompiledWithMPI); m.def("is_compiled_with_mpi_aware", IsCompiledWithMPIAWARE); m.def("is_compiled_with_cinn", IsCompiledWithCINN); m.def("is_compiled_with_distribute", IsCompiledWithDISTRIBUTE); m.def("_is_compiled_with_heterps", IsCompiledWithHETERPS); m.def("supports_bfloat16", SupportsBfloat16); m.def("supports_bfloat16_fast_performance", SupportsBfloat16FastPerformance); m.def("supports_int8", SupportsInt8); m.def("supports_avx512f", SupportsAvx512F); m.def("supports_vnni", SupportsVNNI); m.def("op_supported_infos", imperative::OpSupportedInfos); m.def("is_compiled_with_brpc", IsCompiledWithBrpc); m.def("is_compiled_with_dist", IsCompiledWithDIST); m.def("_cuda_synchronize", [](const GPUPlace &place) { phi::DeviceContextPool::Instance().Get(place)->Wait(); }); m.def("_check_last_cuda_error", []() { #if defined(PADDLE_WITH_CUDA) PADDLE_ENFORCE_GPU_SUCCESS(cudaGetLastError()); #endif }); m.def("_set_warmup", [](bool warmup) { #if defined(PADDLE_WITH_CUDA) paddle::memory::allocation::AutoGrowthBestFitAllocatorV2State::GetInstance() .SetWarmup(warmup); #endif }); m.def("_test_enforce_gpu_success", []() { #if defined(PADDLE_WITH_CUDA) PADDLE_ENFORCE_GPU_SUCCESS(cudaErrorInsufficientDriver); #endif }); m.def("get_float_stats", []() { std::vector> float_stats; paddle::platform::StatRegistry::Instance().publish(float_stats); std::unordered_map stats_map; for (const auto &stat : float_stats) { stats_map[stat.key] = stat.value; } return stats_map; }); m.def("get_int_stats", []() { std::vector> int_stats; paddle::platform::StatRegistry::Instance().publish(int_stats); std::unordered_map stats_map; for (const auto &stat : int_stats) { stats_map[stat.key] = stat.value; } return stats_map; }); m.def("device_memory_stat_current_value", memory::DeviceMemoryStatCurrentValue); m.def("device_memory_stat_peak_value", memory::DeviceMemoryStatPeakValue); m.def("device_memory_stat_reset_peak_value", memory::DeviceMemoryStatResetPeakValue); m.def("host_memory_stat_current_value", memory::HostMemoryStatCurrentValue); m.def("host_memory_stat_peak_value", memory::HostMemoryStatPeakValue); m.def("host_memory_stat_reset_peak_value", memory::HostMemoryStatResetPeakValue); m.def( "run_cmd", [](const std::string &cmd, int time_out = -1, int sleep_inter = -1) -> const std::string { return paddle::framework::shell_get_command_output( cmd, time_out, sleep_inter); }, py::arg("cmd"), py::arg("time_out") = -1, py::arg("sleep_inter") = -1); m.def( "shell_execute_cmd", [](const std::string &cmd, int time_out = 0, int sleep_inter = 0, bool redirect_stderr = false) -> std::vector { return paddle::framework::shell_execute_cmd( cmd, time_out, sleep_inter, redirect_stderr); }, py::arg("cmd"), py::arg("time_out") = 0, py::arg("sleep_inter") = 0, py::arg("redirect_stderr") = false); m.def("set_variable", static_cast(&framework::SetVariable)); m.def( "set_vlog_level", [](py::object module_levels) { if (py::isinstance(module_levels)) { auto level = module_levels.cast(); // Do not using google::SetVLOGLevel("*", level); // It may cause configuration effects for a single module VLOG(3) << "Set the VLOG level of all modules to " << level; FLAGS_v = level; phi::set_phi_vlog_level(level); } else if (py::isinstance(module_levels)) { auto module_levels_dict = module_levels.cast(); for (auto &item : module_levels_dict) { auto module_name = item.first.cast(); auto level = item.second.cast(); if (module_name == "*") { VLOG(3) << "Set the VLOG level of all modules to " << level; FLAGS_v = level; phi::set_phi_vlog_level(level); } else { google::SetVLOGLevel(module_name.c_str(), level); phi::set_phi_vlog_level(module_name.c_str(), level); } } } else { PADDLE_THROW(common::errors::InvalidArgument( "The parameters of set_vlog_level must be int or dict! ")); } }, py::arg("module_levels"), R"DOC( Set the verbosity logging level for specified modules. This function allows setting the VLOG level for specific modules or for all modules. The VLOG level controls the verbosity of logging output, with higher levels producing more detailed logs. Parameters: module_levels (dict|int): A dictionary where the keys are module names (str) and the values are the corresponding verbosity levels (int), or an int variable that represents the verbosity level set globally for all modules. Example: .. code-block:: pycon >>> import paddle >>> # case1: Set GLOG_v=1 >>> paddle.base.core.set_vlog_level(1) >>> # case2: Another way to set GLOG_v=1 >>> paddle.base.core.set_vlog_level({"*": 1}) >>> # case3: Set GLOG_vmodule=dygraph_functions=4,nodes=5 >>> paddle.base.core.set_vlog_level({"dygraph_functions": 4, "nodes": 5}) )DOC"); m.def("set_feed_variable", static_cast(&framework::SetFeedVariable)); m.def("get_fetch_variable", [](const Scope &scope, const std::string &var_name, size_t index) -> py::object { auto &var = framework::GetFetchVariable(scope, var_name, index); if (data_is_dense_tensor(var)) { // NOLINT return py::cast(PADDLE_GET(phi::DenseTensor, var)); } else { return py::cast(PADDLE_GET(phi::TensorArray, var)); } }); m.def("get_variable_tensor", framework::GetVariableTensor); m.def("_is_program_version_supported", IsProgramVersionSupported); #if defined(PADDLE_WITH_CUDA) m.def("allocator_dump", [](const GPUPlace &place) { auto allocator = std::dynamic_pointer_cast< paddle::memory::allocation::AutoGrowthBestFitAllocator>( paddle::memory::allocation::AllocatorFacade::Instance() .GetAutoGrowthAllocator(place)); allocator->DumpInfo(); }); m.def("set_skip_offload_callback_tensors", [](const std::vector &tensors) { egr::ActivationOffloader::Instance()->SetSkipTensors(tensors); }); m.def("register_offload_callback", [] { paddle::memory::allocation::RegisterOOMCallback( [](Place place, size_t size) -> size_t { return egr::ActivationOffloader::Instance()->Offload(place, size); }); }); m.def("clear_offload_callback", [] { paddle::memory::allocation::RegisterOOMCallback(nullptr); }); m.def("offload_cached_size", [] { return egr::ActivationOffloader::Instance()->CachedSize(); }); #endif BindProgramDesc(&m); BindBlockDesc(&m); BindVarDesc(&m); BindOpDesc(&m); BindCostModel(&m); BindConstValue(&m); BindGlobalValueGetterSetter(&m); BindTCPStore(&m); BindCommContextManager(&m); #if defined(PADDLE_WITH_RCCL) || defined(PADDLE_WITH_NCCL) BindNCCLConfig(&m); #endif BindAutoParallel(&m); BindJitProperty(&m); py::class_ pydensetensorarray(m, "DenseTensorArray", R"DOC( DenseTensorArray is array of DenseTensor, it supports operator[], len() and for-loop iteration. Examples: .. code-block:: pycon >>> import paddle >>> arr = paddle.framework.core.DenseTensorArray() )DOC"); g_framework_densetensorarray_pytype = reinterpret_cast(pydensetensorarray.ptr()); pydensetensorarray .def(py::init([]() { return std::make_unique(); })) .def( "__getitem__", [](phi::TensorArray &self, size_t i) { return &self.at(i); }, py::return_value_policy::reference) .def("__len__", [](phi::TensorArray &self) { return self.size(); }) .def("__setitem__", [](phi::TensorArray &self, size_t i, const DenseTensor &t) { PADDLE_ENFORCE_LT(i, self.size(), common::errors::InvalidArgument( "The index to set is larger than the size " "of DenseTensorArray.")); self[i].ShareDataWith(t); }) .def( "append", [](phi::TensorArray &self, const DenseTensor &t) { self.emplace_back(); self.back().ShareDataWith(t); self.back().set_lod(t.lod()); }, py::arg("tensor"), R"DOC( Append a DenseTensor to DenseTensorArray. Args: tensor (DenseTensor): The DenseTensor to be appended. Returns: None. Examples: .. code-block:: pycon >>> import paddle >>> import numpy as np >>> arr = paddle.framework.core.DenseTensorArray() >>> t = paddle.framework.core.DenseTensor() >>> t.set(np.ndarray([5, 30]), paddle.CPUPlace()) >>> arr.append(t) )DOC") .def( "_move_to_list", [](phi::TensorArray &self) -> py::list { py::list res(self.size()); for (size_t i = 0; i < self.size(); ++i) { res[i] = py::cast(std::move(self[i])); } self.clear(); return res; }, py::return_value_policy::take_ownership); py::class_(m, "FetchList", R"DOC( FetchList is a vector of paddle::variant. )DOC") .def( "_move_to_list", [](FetchList &self) -> py::list { py::list res(self.size()); for (size_t i = 0; i < self.size(); ++i) { if (data_is_dense_tensor(self[i])) { auto &data = PADDLE_GET(phi::DenseTensor, self[i]); res[i] = py::cast(std::move(data)); } else if (data_is_sparse_coo_tensor(self[i])) { auto &data = PADDLE_GET(phi::SparseCooTensor, self[i]); res[i] = py::cast(std::move(data)); } else { auto &data = PADDLE_GET(phi::TensorArray, self[i]); py::list tmp(data.size()); for (size_t j = 0; j < data.size(); ++j) { tmp[j] = py::cast(std::move(data[j])); } res[i] = std::move(tmp); } } self.clear(); return res; }, py::return_value_policy::take_ownership) .def( "append", [](FetchList &self, const DenseTensor &t) { self.emplace_back(); auto &dense_tensor = PADDLE_GET(phi::DenseTensor, self.back()); dense_tensor.ShareDataWith(t); }, py::arg("var")) .def( "append", [](FetchList &self, const phi::TensorArray &t) { self.emplace_back(); auto &dense_tensor_array = PADDLE_GET(phi::TensorArray, self.back()); for (size_t i = 0; i < t.size(); ++i) { dense_tensor_array[i].ShareDataWith(t[i]); } }, py::arg("var")); py::class_(m, "FetchUnmergedList", R"DOC( FetchUnmergedList is 2-D array of FetchType(paddle::variant(DenseTensor, DenseTensorArray)). )DOC") .def( "_move_to_list", [](FetchUnmergedList &self) -> py::list { py::list res(self.size()); for (size_t i = 0; i < self.size(); ++i) { py::list tmp(self[i].size()); for (size_t j = 0; j < self[i].size(); ++j) { if (data_is_dense_tensor(self[i][j])) { auto &var = PADDLE_GET(phi::DenseTensor, self[i][j]); tmp[j] = py::cast(std::move(var)); } else { auto &var = PADDLE_GET(phi::TensorArray, self[i][j]); py::list tmp_array(var.size()); for (size_t k = 0; k < var.size(); ++k) { tmp_array[k] = std::move(var[k]); } tmp[j] = std::move(tmp_array); } } res[i] = std::move(tmp); self[i].clear(); } self.clear(); return res; }, py::return_value_policy::take_ownership); m.def("op_support_gpu", OpSupportGPU); m.def("eager_set_device_id", &EagerSetDeviceId); #if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) m.def("get_cuda_device_count", platform::GetGPUDeviceCount); m.def("get_cuda_current_device_id", &platform::GetCurrentDeviceId); m.def("set_cuda_current_device_id", &platform::SetDeviceId, py::arg("i")); m.def("cuda_empty_cache", [] { for (int dev_id : platform::GetSelectedDevices()) { auto *dev_ctx = phi::DeviceContextPool::Instance().GetByPlace(GPUPlace(dev_id)); dev_ctx->cudnn_workspace_handle().ResetWorkspace(); } platform::EmptyCache(); }); m.def( "get_device_properties", [](int id) -> const gpuDeviceProp & { return platform::GetDeviceProperties(id); }, py::return_value_policy::reference); py::class_(m, "_gpuDeviceProperties", py::module_local()) .def_property_readonly( "name", [](const gpuDeviceProp &prop) { return prop.name; }) .def_property_readonly( "major", [](const gpuDeviceProp &prop) { return prop.major; }) .def_property_readonly( "minor", [](const gpuDeviceProp &prop) { return prop.minor; }) .def_property_readonly( "total_memory", [](const gpuDeviceProp &prop) { return prop.totalGlobalMem; }) .def_property_readonly( "multi_processor_count", [](const gpuDeviceProp &prop) { return prop.multiProcessorCount; }) .def_property_readonly( "is_multi_gpu_board", [](const gpuDeviceProp &prop) { return prop.isMultiGpuBoard; }) .def_property_readonly( "is_integrated", [](const gpuDeviceProp &prop) { return prop.integrated; }) .def("__repr__", [](const gpuDeviceProp &prop) { std::stringstream ostr; ostr << "_gpuDeviceProperties(name='" << prop.name << "', major=" << prop.major << ", minor=" << prop.minor << ", total_memory=" << prop.totalGlobalMem / (1024 * 1024) << "MB, multi_processor_count=" << prop.multiProcessorCount << ")"; return ostr.str(); }); #if !defined(PADDLE_WITH_HIP) && !defined(_WIN32) m.def("nvprof_init", platform::CudaProfilerInit); m.def("nvprof_start", platform::CudaProfilerStart); m.def("nvprof_stop", platform::CudaProfilerStop); m.def("nvprof_nvtx_push", [](const std::string &name) { platform::CudaNvtxRangePush(name, platform::NvtxRangeColor::Green); }); m.def("nvprof_nvtx_pop", platform::CudaNvtxRangePop); m.def("nvprof_enable_record_event", platform::NvprofEnableRecordEvent); m.def("nvprof_disable_record_event", platform::NvprofDisableRecordEvent); #endif #endif #if defined(PADDLE_WITH_CUDA) // Register opaque AllBlocksInfo type — lazy per-group conversion py::class_(m, "AllBlocksInfo") .def("__len__", &AllBlocksInfoType::size) .def("__getitem__", [](const AllBlocksInfoType &self, int64_t i) -> std::vector> { if (i < 0) i += static_cast(self.size()); if (i < 0 || static_cast(i) >= self.size()) throw py::index_error(); return self[i]; }) .def( "__iter__", [](const AllBlocksInfoType &self) { return py::make_iterator(self.begin(), self.end()); }, py::keep_alive<0, 1>()); m.def("vmm_max_free_size", [](int device_id) { return memory::VmmMaxFreeSize(GPUPlace(device_id), 1); }); m.def("vmm_compact", [](int device_id) { return paddle::memory::VmmCompact(GPUPlace(device_id)); }); m.def("vmm_free_block_info", [](int device_id) { return paddle::memory::FreeBlockInfoOfVmmAllocator(GPUPlace(device_id)); }); m.def( "all_block_info", [](int device_id) -> AllBlocksInfoType { return paddle::memory::AllBlockInfoOfAllocator(GPUPlace(device_id)); }, py::return_value_policy::move); m.def( "vmm_all_block_info", [](int device_id) -> AllBlocksInfoType { return paddle::memory::AllBlockInfoOfAllocator(GPUPlace(device_id)); }, py::return_value_policy::move); m.def( "large_pool_block_info", [](int device_id) -> AllBlocksInfoType { return paddle::memory::LargePoolBlockInfo(GPUPlace(device_id)); }, py::return_value_policy::move); m.def( "small_pool_block_info", [](int device_id) -> AllBlocksInfoType { return paddle::memory::SmallPoolBlockInfo(GPUPlace(device_id)); }, py::return_value_policy::move); m.def("get_allocate_record", [](int device_id) { return paddle::memory::GetAllocateEvent(GPUPlace(device_id)); }); m.def("get_compact_size", [](int device_id) { return paddle::memory::GetCompactSize(GPUPlace(device_id)); }); #endif #ifdef PADDLE_WITH_CUSTOM_DEVICE m.def( "get_device_properties", [](std::string dev_type, int id) -> const phi::DeviceProp & { return phi::DeviceManager::GetDeviceProperties(dev_type, id); }, py::return_value_policy::copy); m.def("device_empty_cache", [] { std::vector dev_types = phi::DeviceManager::GetAllCustomDeviceTypes(); std::string dev_type = dev_types[0]; std::vector devices = phi::DeviceManager::GetSelectedDeviceList(dev_type); for (auto device : devices) { memory::Release(phi::CustomPlace(dev_type, device)); } }); py::class_(m, "_customDeviceProperties", py::module_local()) .def_property_readonly( "name", [](const phi::DeviceProp &prop) { return prop.name; }) .def_property_readonly( "major", [](const phi::DeviceProp &prop) { return prop.deviceMajor; }) .def_property_readonly( "minor", [](const phi::DeviceProp &prop) { return prop.deviceMinor; }) .def_property_readonly( "total_memory", [](const phi::DeviceProp &prop) { return prop.totalGlobalMem; }) .def_property_readonly( "multi_processor_count", [](const phi::DeviceProp &prop) { return prop.multiProcessorCount; }) .def_property_readonly( "is_multi_gpu_board", [](const phi::DeviceProp &prop) { return prop.isMultiGpuBoard; }) .def_property_readonly( "is_integrated", [](const phi::DeviceProp &prop) { return prop.integrated; }) .def("__repr__", [](const phi::DeviceProp &prop) { std::stringstream ostr; ostr << "_customDeviceProperties(name='" << prop.name << "', major=" << prop.deviceMajor << ", minor=" << prop.deviceMinor << ", total_memory=" << prop.totalGlobalMem / (1024 * 1024) << "MB, multi_processor_count=" << prop.multiProcessorCount << ")"; return ostr.str(); }); #endif #ifdef PADDLE_WITH_IPU m.def("get_ipu_device_count", platform::GetIPUDeviceCount); #endif #ifdef PADDLE_WITH_XPU m.def("get_xpu_device_count", platform::GetXPUDeviceCount); m.def("get_xpu_current_device_id", &platform::GetXPUCurrentDeviceId); m.def("set_xpu_current_device_id", &platform::SetXPUDeviceId, py::arg("i")); m.def("xpu_empty_cache", platform::EmptyCache); m.def( "get_device_properties", [](int id) -> const gpuDeviceProp & { return platform::GetDeviceProperties(id); }, py::return_value_policy::reference); py::class_(m, "_gpuDeviceProperties", py::module_local()) .def_property_readonly( "name", [](const gpuDeviceProp &prop) { return prop.name; }) .def_property_readonly( "major", [](const gpuDeviceProp &prop) { return prop.major; }) .def_property_readonly( "minor", [](const gpuDeviceProp &prop) { return prop.minor; }) .def_property_readonly( "total_memory", [](const gpuDeviceProp &prop) { return prop.totalGlobalMem; }) .def_property_readonly( "multi_processor_count", [](const gpuDeviceProp &prop) { return prop.multiProcessorCount; }) .def_property_readonly( "is_multi_gpu_board", [](const gpuDeviceProp &prop) { return prop.isMultiGpuBoard; }) .def_property_readonly( "is_integrated", [](const gpuDeviceProp &prop) { return prop.integrated; }) .def("__repr__", [](const gpuDeviceProp &prop) { std::stringstream ostr; ostr << "_gpuDeviceProperties(name='" << prop.name << "', major=" << prop.major << ", minor=" << prop.minor << ", total_memory=" << prop.totalGlobalMem / (1024 * 1024) << "MB, multi_processor_count=" << prop.multiProcessorCount << ")"; return ostr.str(); }); m.def("get_xpu_device_utilization_rate", platform::GetXPUDeviceUtilizationRate); m.def("get_xpu_device_total_memory", platform::GetXPUDeviceTotalMemory); m.def("get_xpu_device_used_memory", platform::GetXPUDeviceUsedMemory); m.def("nvprof_start", platform::CudaProfilerStart); m.def("nvprof_stop", platform::CudaProfilerStop); m.def("nvprof_nvtx_push", [](const std::string &name) { platform::CudaNvtxRangePush(name, platform::NvtxRangeColor::Green); }); m.def("nvprof_nvtx_pop", platform::CudaNvtxRangePop); m.def("nvprof_enable_record_event", platform::NvprofEnableRecordEvent); m.def("nvprof_disable_record_event", platform::NvprofDisableRecordEvent); #endif py::enum_(m, "TracerOption", py::arithmetic()) .value("kDefault", platform::TracerOption::kDefault) .value("kOpDetail", platform::TracerOption::kOpDetail) .value("kAllOpDetail", platform::TracerOption::kAllOpDetail) .export_values(); py::enum_(m, "ProfilerState", py::arithmetic()) .value("kDisabled", platform::ProfilerState::kDisabled) .value("kCPU", platform::ProfilerState::kCPU) .value("kCUDA", platform::ProfilerState::kCUDA) .value("kAll", platform::ProfilerState::kAll) .export_values(); py::enum_(m, "EventSortingKey", py::arithmetic()) .value("kDefault", platform::EventSortingKey::kDefault) .value("kCalls", platform::EventSortingKey::kCalls) .value("kTotal", platform::EventSortingKey::kTotal) .value("kMin", platform::EventSortingKey::kMin) .value("kMax", platform::EventSortingKey::kMax) .value("kAve", platform::EventSortingKey::kAve) .export_values(); m.def("set_tracer_option", platform::SetTracerOption); m.def("enable_profiler", platform::EnableProfiler); m.def("disable_profiler", platform::DisableProfiler); m.def("is_profiler_enabled", platform::IsProfileEnabled); m.def("reset_profiler", platform::ResetProfiler); m.def("register_pass", [](const std::string &pass_type, py::object callable) { PADDLE_ENFORCE_EQ( framework::ir::PassRegistry::Instance().Has(pass_type), false, common::errors::AlreadyExists("Pass '%s' is registered more than " "once. Please use another name.", pass_type)); callable.inc_ref(); framework::ir::PassRegistry::Instance().Insert( pass_type, [pass_type, callable]() { py::gil_scoped_acquire guard; std::unique_ptr pass( new framework::ir::GeneratePass(py::cast(callable()), pass_type)); return pass; }); }); m.def("get_pass", [](const std::string &pass_type) { auto pass = framework::ir::PassRegistry::Instance().Get(pass_type); return std::shared_ptr(std::move(pass)); }); m.def("register_subgraph_pass", [](const std::string &pass_type) { framework::ir::Pass::AddSupportSubgraphPass(pass_type); }); m.def("size_of_dtype", framework::SizeOfType); m.def("size_of_dtype", phi::SizeOf); py::class_(m, "_ProfilerResult") .def(py::init<>()) .def("get_data", &paddle::platform::ProfilerResult::GetData, py::return_value_policy::automatic_reference) .def("save", &paddle::platform::ProfilerResult::Save) .def("get_extra_info", &paddle::platform::ProfilerResult::GetExtraInfo) .def("get_version", &paddle::platform::ProfilerResult::GetVersion) #if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) || PADDLE_WITH_XPU .def("get_span_index", &paddle::platform::ProfilerResult::GetSpanIndex) .def("get_device_property", &paddle::platform::ProfilerResult::GetDeviceProperty); #else .def("get_span_index", &paddle::platform::ProfilerResult::GetSpanIndex); #endif py::class_(m, "MemPythonNode") .def(py::init<>()) .def_readwrite("timestamp_ns", &paddle::platform::MemPythonNode::timestamp_ns) .def_readwrite("addr", &paddle::platform::MemPythonNode::addr) .def_readwrite("type", &paddle::platform::MemPythonNode::type) .def_readwrite("process_id", &paddle::platform::MemPythonNode::process_id) .def_readwrite("thread_id", &paddle::platform::MemPythonNode::thread_id) .def_readwrite("increase_bytes", &paddle::platform::MemPythonNode::increase_bytes) .def_readwrite("place", &paddle::platform::MemPythonNode::place) .def_readwrite("current_allocated", &paddle::platform::MemPythonNode::current_allocated) .def_readwrite("current_reserved", &paddle::platform::MemPythonNode::current_reserved) .def_readwrite("peak_allocated", &paddle::platform::MemPythonNode::peak_allocated) .def_readwrite("peak_reserved", &paddle::platform::MemPythonNode::peak_reserved) .def("__repr__", [](paddle::platform::MemPythonNode &event_node) { std::stringstream ostr; ostr << "MemPythonNode(timestamp_ns=" << event_node.timestamp_ns << ", addr=" << event_node.addr << ", type='" << paddle::platform::StringTracerMemEventType(event_node.type) << "', process_id=" << event_node.process_id << ", thread_id=" << event_node.thread_id << ")"; return ostr.str(); }); py::class_(m, "DevicePythonNode") .def(py::init<>()) .def_readwrite("name", &paddle::platform::DevicePythonNode::name) .def_readwrite("type", &paddle::platform::DevicePythonNode::type) .def_readwrite("start_ns", &paddle::platform::DevicePythonNode::start_ns) .def_readwrite("end_ns", &paddle::platform::DevicePythonNode::end_ns) .def_readwrite("device_id", &paddle::platform::DevicePythonNode::device_id) .def_readwrite("context_id", &paddle::platform::DevicePythonNode::context_id) .def_readwrite("stream_id", &paddle::platform::DevicePythonNode::stream_id) .def_readwrite("correlation_id", &paddle::platform::DevicePythonNode::correlation_id) .def_readwrite("block_x", &paddle::platform::DevicePythonNode::block_x) .def_readwrite("block_y", &paddle::platform::DevicePythonNode::block_y) .def_readwrite("block_z", &paddle::platform::DevicePythonNode::block_z) .def_readwrite("grid_x", &paddle::platform::DevicePythonNode::grid_x) .def_readwrite("grid_y", &paddle::platform::DevicePythonNode::grid_y) .def_readwrite("grid_z", &paddle::platform::DevicePythonNode::grid_z) .def_readwrite("shared_memory", &paddle::platform::DevicePythonNode::shared_memory) .def_readwrite("registers_per_thread", &paddle::platform::DevicePythonNode::registers_per_thread) .def_readwrite("blocks_per_sm", &paddle::platform::DevicePythonNode::blocks_per_sm) .def_readwrite("warps_per_sm", &paddle::platform::DevicePythonNode::warps_per_sm) .def_readwrite("occupancy", &paddle::platform::DevicePythonNode::occupancy) .def_readwrite("num_bytes", &paddle::platform::DevicePythonNode::num_bytes) .def_readwrite("value", &paddle::platform::DevicePythonNode::value) .def("__repr__", [](paddle::platform::DevicePythonNode &event_node) { std::stringstream ostr; ostr << "DevicePythonNode(name='" << event_node.name << "', type='" << paddle::platform::StringTracerEventType(event_node.type) << "', start_ns=" << event_node.start_ns << ", end_ns=" << event_node.end_ns << ", device_id=" << event_node.device_id << ", context_id=" << event_node.context_id << ", stream_id=" << event_node.stream_id << ")"; return ostr.str(); }); py::class_(m, "HostPythonNode") .def(py::init<>()) .def_readwrite("name", &paddle::platform::HostPythonNode::name) .def_readwrite("type", &paddle::platform::HostPythonNode::type) .def_readwrite("start_ns", &paddle::platform::HostPythonNode::start_ns) .def_readwrite("end_ns", &paddle::platform::HostPythonNode::end_ns) .def_readwrite("process_id", &paddle::platform::HostPythonNode::process_id) .def_readwrite("thread_id", &paddle::platform::HostPythonNode::thread_id) .def_readwrite("correlation_id", &paddle::platform::HostPythonNode::correlation_id) .def_readwrite("input_shapes", &paddle::platform::HostPythonNode::input_shapes) .def_readwrite("dtypes", &paddle::platform::HostPythonNode::dtypes) .def_readwrite("callstack", &paddle::platform::HostPythonNode::callstack) .def_readwrite("attributes", &paddle::platform::HostPythonNode::attributes) .def_readwrite("op_id", &paddle::platform::HostPythonNode::op_id) .def_readwrite("children_node", &paddle::platform::HostPythonNode::children_node_ptrs) .def_readwrite("runtime_node", &paddle::platform::HostPythonNode::runtime_node_ptrs) .def_readwrite("device_node", &paddle::platform::HostPythonNode::device_node_ptrs) .def_readwrite("mem_node", &paddle::platform::HostPythonNode::mem_node_ptrs) .def("__repr__", [](paddle::platform::HostPythonNode &event_node) { std::stringstream ostr; ostr << "HostPythonNode(name='" << event_node.name << "', type='" << paddle::platform::StringTracerEventType(event_node.type) << "', start_ns=" << event_node.start_ns << ", end_ns=" << event_node.end_ns << ", process_id=" << event_node.process_id << ", thread_id=" << event_node.thread_id << ")"; return ostr.str(); }); py::class_(m, "_Profiler") .def("create", &paddle::platform::Profiler::Create, py::return_value_policy::take_ownership) .def("is_cupti_supported", &paddle::platform::Profiler::IsCuptiSupported) .def("is_cnpapi_supported", &paddle::platform::Profiler::IsCnpapiSupported) .def("is_xpti_supported", &paddle::platform::Profiler::IsXPTISupported) .def("prepare", [](paddle::platform::Profiler *profiler) { platform::EnableHostEventRecorder(); profiler->Prepare(); }) .def("start", &paddle::platform::Profiler::Start) .def( "stop", [](paddle::platform::Profiler *profiler) { platform::DisableHostEventRecorder(); auto result = profiler->Stop(); framework::StaticGraphExecutorPerfStatistics( result->GetNodeTrees()); return result; }, py::return_value_policy::automatic_reference); py::class_(m, "ProfilerOptions") .def(py::init<>()) .def_readwrite("trace_switch", &paddle::platform::ProfilerOptions::trace_switch); py::class_(m, "_RecordEvent") .def(py::init([](std::string name, phi::TracerEventType type) { return std::make_unique( name, type, 1, phi::EventRole::kOrdinary); })) .def("end", [](phi::RecordEvent *event) { event->End(); }); py::enum_(m, "TracerMemEventType") #define BIND_ENUM_ITEM(name) .value(#name, phi::TracerMemEventType::name) FOR_EACH_TRACER_MEM_EVENT_TYPES(BIND_ENUM_ITEM) #undef BIND_ENUM_ITEM ; // NOLINT py::enum_(m, "TracerEventType") #define BIND_ENUM_ITEM(name) .value(#name, phi::TracerEventType::name) FOR_EACH_TRACER_EVENT_TYPES(BIND_ENUM_ITEM) #undef BIND_ENUM_ITEM ; // NOLINT m.def("tracer_event_type_to_string", &paddle::platform::StringTracerEventType); m.def("tracer_mem_event_type_to_string", &paddle::platform::StringTracerMemEventType); m.def("load_profiler_result", &paddle::platform::LoadProfilerResult); m.def("enable_memory_recorder", &paddle::platform::EnableMemoryRecorder); m.def("disable_memory_recorder", &paddle::platform::DisableMemoryRecorder); m.def("enable_op_info_recorder", &phi::EnableOpInfoRecorder); m.def("disable_op_info_recorder", &phi::DisableOpInfoRecorder); #if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) || \ defined(PADDLE_WITH_CUSTOM_DEVICE) m.def("set_cublas_switch", phi::SetAllowTF32Cublas); m.def("get_cublas_switch", phi::AllowTF32Cublas); m.def("set_cudnn_switch", phi::SetAllowTF32Cudnn); m.def("get_cudnn_switch", phi::AllowTF32Cudnn); #endif // PADDLE_WITH_CUDA m.def("clear_executor_cache", []() { pybind11::gil_scoped_release release; framework::InterpreterCoreInfoCache::Instance().Finalize(); }); m.def("parse_safe_eager_deletion_skip_vars", paddle::framework::details::ParseSafeEagerDeletionSkipVarsSet); #ifdef PADDLE_WITH_IPU py::class_>( m, "IpuBackend") // manage IpuBackend in C++ .def( "get_instance", []() { return std::unique_ptr( platform::ipu::IpuBackend::GetInstance()); }, py::return_value_policy::reference) .def("weights_to_host", &platform::ipu::IpuBackend::WeightsToHost) .def("detach", &platform::ipu::IpuBackend::Detach) .def("reset", &platform::ipu::IpuBackend::Reset) .def("set_scope", &platform::ipu::IpuBackend::SetScope) .def("set_ipu_strategy", &platform::ipu::IpuBackend::SetIpuStrategy) .def("save_model_proto", &platform::ipu::IpuBackend::SaveModelProto); py::class_(m, "IpuStrategy") .def(py::init()) .def("set_options", [](platform::ipu::IpuStrategy &self, const py::dict &opt) { for (auto element : opt) { auto option_name = element.first.cast(); VLOG(10) << "Set option: " << option_name; if (option_name == "compilation_progress_logger") { self.SetCompilationProgressLogger( element.second.cast()); } else if (py::isinstance(element.second)) { self.AddBoolOption(option_name, element.second.cast()); } else if (py::isinstance(element.second)) { self.AddDoubleOption(option_name, element.second.cast()); } else if (py::isinstance(element.second)) { self.AddUint64Option(option_name, element.second.cast()); } else if (py::isinstance(element.second)) { self.AddStringOption(option_name, element.second.cast()); } else if (py::isinstance(element.second) || py::isinstance(element.second)) { for (auto option : element.second.cast()) { std::string option_val; if (py::isinstance(option)) { option_val = option.cast(); } else if (py::isinstance(option)) { option_val = std::to_string(option.cast()); } else { PADDLE_THROW(common::errors::Unimplemented( "Failed to convert type: %s when set IpuStrategy " "option: %s", option.get_type(), option_name)); } self.InsertStringOption(option_name, option_val); } } else if (py::isinstance(element.second)) { if (option_name.rfind("location_", 0) == 0) { for (auto option : element.second.cast()) { self.SetTensorLocation( option_name, option.first.cast(), option.second.cast()); } } else if (option_name == "replicated_collectives_settings") { for (auto option : element.second.cast()) { self.SetReplicatedCollectivesSettings( option.first.cast(), option.second.cast()); } } else if (option_name == "accumulate_outer_fragment") { for (auto option : element.second.cast()) { std::vector values; for (auto value : option.second.cast()) { values.push_back(value.cast()); } self.SetAccumulateOuterFragmentSettings( option.first.cast(), values); } } else if (option_name == "custom_op") { std::string paddle_op; std::string popart_op; std::string domain; int version = -1; for (auto option : element.second.cast()) { std::string option_key = option.first.cast(); if (option_key == "paddle_op") { paddle_op = option.second.cast(); } else if (option_key == "popart_op") { popart_op = option.second.cast(); } else if (option_key == "domain") { domain = option.second.cast(); } else if (option_key == "version") { version = option.second.cast(); } else { PADDLE_THROW(common::errors::InvalidArgument( "Invalid argument, key must be one of paddle_op, " "popart_op, domain or version, but received %s", option_key)); } } self.AddCustomOp(paddle_op, popart_op, domain, version); } else { for (auto option : element.second.cast()) { std::string option_key = option.first.cast(); std::string option_val; if (py::isinstance(option.second)) { option_val = option.second.cast(); } else if (py::isinstance(option.second)) { option_val = std::to_string(option.second.cast()); } else { PADDLE_THROW(common::errors::Unimplemented( "Failed to convert value type: %s when set " "IpuStrategy option: %s", option.second.get_type(), option_key)); } self.InsertStringPairOption( option_name, option_key, option_val); } } } else { PADDLE_THROW(common::errors::InvalidArgument( "Invalid IpuStrategy option value type: %s, please check " "input value for option: %s", element.second.get_type(), option_name)); } } }) .def("get_option", [](platform::ipu::IpuStrategy &self, const std::string &name) { py::dict res; auto option_type = self.GetOptionType(name); res["name"] = name; res["type"] = option_type; if (option_type == "vector") { auto value = self.GetVectorOption(name); res["value"] = value; } else if (option_type == "map") { auto value = self.GetMapOption(name); res["value"] = value; } else { auto value_s = self.GetOption(name); res["value_s"] = value_s; if (option_type == "bool") { res["value"] = static_cast(std::stoi(value_s)); } else if (option_type == "uint64") { res["value"] = std::stoul(value_s); } else if (option_type == "double") { res["value"] = std::stod(value_s); } else if (option_type == "string") { res["value"] = value_s; } } return res; }) .def("get_all_option_names", &platform::ipu::IpuStrategy::GetAllOptionNames) .def("enable_pattern", &platform::ipu::IpuStrategy::EnablePattern) .def("disable_pattern", &platform::ipu::IpuStrategy::DisablePattern) .def("is_pattern_enabled", &platform::ipu::IpuStrategy::IsPatternEnabled); #endif m.def("get_low_precision_op_list", [] { py::dict op_list; auto list_op = phi::KernelFactory::Instance().GetLowPrecisionKernelList(); for (auto &op_item : list_op) { auto op_name = (op_item.first).c_str(); auto counts = op_item.second; op_list[op_name] = std::to_string(counts.fp16_called_) + "," + std::to_string(counts.bf16_called_) + "," + std::to_string(counts.fp32_called_) + "," + std::to_string(counts.other_called_); } return op_list; }); m.def("clear_low_precision_op_list", [] { phi::KernelFactory::Instance().ClearLowPrecisionKernelList(); }); m.def("enable_autotune", [] { return phi::autotune::AutoTuneStatus::Instance().EnableAutoTune(); }); m.def("disable_autotune", [] { return phi::autotune::AutoTuneStatus::Instance().DisableAutoTune(); }); m.def("set_autotune_range", [](int64_t start, int64_t stop) { return phi::autotune::AutoTuneStatus::Instance().SetAutoTuneRange(start, stop); }); m.def("update_autotune_status", [] { return phi::autotune::AutoTuneStatus::Instance().Update(); }); m.def("autotune_status", [] { py::dict res; phi::autotune::AutoTuneCache::Instance().UpdateStatus(); res["step_id"] = phi::autotune::AutoTuneStatus::Instance().StepID(); res["cache_size"] = phi::autotune::AutoTuneCache::Instance().Size(); res["cache_hit_rate"] = phi::autotune::AutoTuneCache::Instance().CacheHitRate(); return res; }); m.def("enable_layout_autotune", [] { return egr::Controller::Instance().EnableLayoutAutoTune(); }); m.def("disable_layout_autotune", [] { return egr::Controller::Instance().DisableLayoutAutoTune(); }); m.def("use_layout_autotune", [] { return egr::Controller::Instance().UseLayoutAutoTune(); }); // Add the api for nan op debug m.def("set_nan_inf_stack_limit", &paddle::framework::details::SetNanInfStackLimit); // Add the api for nan op debug m.def("set_nan_inf_debug_path", &paddle::framework::details::SetNanInfDebugPath); // Add check op lost m.def("set_checked_op_list", [](const std::string &op_list) { egr::SetCheckOpList(op_list); }); // Add skipped op list m.def("set_skipped_op_list", [](const std::string &op_list) { egr::SetSkipOpList(op_list); }); BindFleetWrapper(&m); BindIO(&m); BindCompiledProgram(m); BindPlace(m); BindTensor(m); BindSize(&m); py::enum_ data_type(m, "DataType"); g_data_type_pytype = (PyTypeObject *)data_type.ptr(); // NOLINT data_type.value("UNDEFINED", DataType::UNDEFINED) .value("BOOL", DataType::BOOL) .value("UINT8", DataType::UINT8) .value("INT8", DataType::INT8) .value("UINT16", DataType::UINT16) .value("INT16", DataType::INT16) .value("UINT32", DataType::UINT32) .value("INT32", DataType::INT32) .value("UINT64", DataType::UINT64) .value("INT64", DataType::INT64) .value("FLOAT32", DataType::FLOAT32) .value("FLOAT64", DataType::FLOAT64) .value("COMPLEX64", DataType::COMPLEX64) .value("COMPLEX128", DataType::COMPLEX128) .value("FLOAT16", DataType::FLOAT16) .value("BFLOAT16", DataType::BFLOAT16) .value("FLOAT8_E4M3FN", DataType::FLOAT8_E4M3FN) .value("FLOAT8_E5M2", DataType::FLOAT8_E5M2) .value("PSTRING", DataType::PSTRING) .value("ALL_DTYPE", DataType::ALL_DTYPE) .export_values() .def("__dlpack_data_type__", [](const DataType &self) { ::DLDataType dl_dtype = paddle::framework::PhiDataTypeToDLDataType(self); return py::make_tuple(dl_dtype.code, dl_dtype.bits, dl_dtype.lanes); }); // Initialize the DataType singleton cache from the registered enum // attributes. After this, all C++ → Python conversions of DataType (via // pybind11 auto-cast or ToPyObject) will return cached singletons, // guaranteeing `paddle.float32 is value.dtype` for all code paths. DataTypeSingletonCache::Instance().Init(g_data_type_pytype); // Override the hash function with a fast C-level implementation that hashes // based on the underlying enum integer value. This is faster than pybind11's // default hash (which goes through Python method dispatch). // With singleton caching, identity-based hash would also work, but we keep // value-based hash as a safety net for any edge cases. g_data_type_pytype->tp_hash = DataTypeEnumHash; PyType_Modified(g_data_type_pytype); py::class_ engine_params(m, "TRTEngineParams"); g_tensorrt_engine_params_pytype = reinterpret_cast(engine_params.ptr()); engine_params.def(py::init<>()) .def_readwrite("max_workspace_size", &paddle::platform::EngineParams::max_workspace_size) .def_readwrite("min_input_shape", &paddle::platform::EngineParams::min_input_shape) .def_readwrite("max_input_shape", &paddle::platform::EngineParams::max_input_shape) .def_readwrite("optim_input_shape", &paddle::platform::EngineParams::optim_input_shape) .def_readwrite("min_shape_tensor", &paddle::platform::EngineParams::min_shape_tensor) .def_readwrite("max_shape_tensor", &paddle::platform::EngineParams::max_shape_tensor) .def_readwrite("optim_shape_tensor", &paddle::platform::EngineParams::optim_shape_tensor) .def_readwrite("engine_serialized_data", &paddle::platform::EngineParams::engine_serialized_data) .def_readwrite("use_cuda_graph", &paddle::platform::EngineParams::use_cuda_graph) .def_readwrite("refit_params_path", &paddle::platform::EngineParams::refit_params_path) .def_readwrite("refit_param_name", &paddle::platform::EngineParams::refit_param_names) .def_readwrite( "refit_param_names2trt_names", &paddle::platform::EngineParams::refit_param_names2trt_names); py::enum_(m, "ShapeMode") .value("kMIN", paddle::framework::ShapeMode::kMIN) .value("kMAX", paddle::framework::ShapeMode::kMAX) .value("kOPT", paddle::framework::ShapeMode::kOPT) .export_values(); m.def("get_value_shape_range_info", [](const pir::Value value, bool is_shape_tensor, paddle::framework::ShapeMode shape_mode) -> py::list { py::list res; paddle::framework::CollectShapeManager::Instance() .StatisticShapeRangeInfo(); auto shape_result = paddle::framework::CollectShapeManager::Instance() .GetValueShapeRangeInfo(value, is_shape_tensor, shape_mode); for (auto i : shape_result) { res.append(i); } return res; }); m.def("clear_shape_info", []() { paddle::framework::CollectShapeManager::Instance().ClearShapeInfo(); }); #ifdef PADDLE_WITH_TENSORRT m.def("register_paddle_plugin", []() { paddle::platform::TrtPluginRegistry::Global()->RegisterToTrt(); }); #endif BindGlooWrapper(&m); #if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL) BindNCCLWrapper(&m); #endif #ifdef PADDLE_WITH_GLOO BindGlooContext(&m); #endif BindGraph(&m); BindNode(&m); BindPass(&m); BindInferenceApi(&m); BindCompatible(&m); BindDataset(&m); BindGenerator(&m); #ifndef PADDLE_NO_PYTHON BindDistributed(&m); #endif #ifdef PADDLE_WITH_CRYPTO BindCrypto(&m); #endif BindPir(&m); BindVjp(&m); BindDecompRule(&m); BindDecompVjp(&m); py::module torch_compat = m.def_submodule( "torch_compat", "Compatibility layer for PyTorch-like APIs"); BindTorchCompat(&torch_compat); #ifdef PADDLE_WITH_DISTRIBUTE BindDistApi(&m); #endif #if defined(PADDLE_WITH_DISTRIBUTE) && defined(PADDLE_WITH_DEEP_EP) BindDeepEPApi(&m); #endif #if defined(PADDLE_WITH_CUDA) BindCudaRt(&m); #endif } } // namespace paddle::pybind