diff --git a/paddle/fluid/eager/auto_code_generator/eager_generator.cc b/paddle/fluid/eager/auto_code_generator/eager_generator.cc index cb25da21d05772b8e76fcc5cc7edf1a27fb31dac..c87cda34cee955b65660a7f83206ced63bc46ddf 100644 --- a/paddle/fluid/eager/auto_code_generator/eager_generator.cc +++ b/paddle/fluid/eager/auto_code_generator/eager_generator.cc @@ -29,6 +29,12 @@ namespace paddle { namespace framework { +// To handle append_op at python-level +std::unordered_map> + core_ops_returns_info = {}; +std::unordered_map> core_ops_args_info = + {}; + /* --- Static maps to handle corner cases --- */ static std::unordered_map operators_with_attrs = {}; @@ -1109,6 +1115,8 @@ static std::pair GenerateForwardFunctionContents( std::string generated_function_body = ""; std::string dygraph_function_args_str = ""; + core_ops_args_info[op_type] = {}; + core_ops_args_info[op_type].resize(in_vars.size()); /* ------ Dygraph forward function generation ------ */ generated_function_body += " // Dygraph Forward Pass\n"; @@ -1131,6 +1139,7 @@ static std::pair GenerateForwardFunctionContents( input_args_str_list[input_position] = paddle::string::Sprintf(FWD_INS_ARG_TEMPLATE, input_name); } + core_ops_args_info[op_type][input_position] = input_name; if (input.dispensable()) continue; @@ -1208,6 +1217,8 @@ static std::pair GenerateForwardFunctionContents( outs_contents_str += paddle::string::Sprintf( FWD_OUTS_CONTENT_TEMPLATE, output_name, output_var_name); + core_ops_args_info[op_type].push_back(output_var_name); + } else { if (output.duplicable()) { outnum = output_name + "Num"; @@ -1220,6 +1231,7 @@ static std::pair GenerateForwardFunctionContents( "{ \"%s\", egr::EagerUtils::ConstructDuplicableOutput(%s) },"; outs_contents_str += paddle::string::Sprintf(FWD_OUTS_CONTENT_TEMPLATE, output_name, outnum); + core_ops_args_info[op_type].push_back(outnum); } else { const char* FWD_OUTS_CONTENT_TEMPLATE = "{ \"%s\", " @@ -1294,6 +1306,9 @@ static std::pair GenerateForwardFunctionContents( generated_function_body += "\n"; VLOG(6) << "Converted Output VarBase to EagerTensor(s)"; + // [Generation] Handle core_ops_returns_info + core_ops_returns_info[op_type] = return_contents; + // [Generation] ComputeRequireGrad -> GradNodeCreation if (!bwd_info.GenerateForwardOnly()) { std::string grad_node_creation_body_str = @@ -1808,6 +1823,25 @@ static std::string GenerateGradNodeHeaderContents( /* --------------------------------- */ /* --------- FileGeneration --------- */ /* ---------------------------------- */ +static std::string GenerateDygraphHFileIncludes() { + std::string dygraph_forward_api_includes_str = + "#pragma once\n" + "#include \"glog/logging.h\"\n" + "#include \"paddle/fluid/eager/autograd_meta.h\"\n" + "#include \"paddle/pten/api/all.h\"\n" + "#include \"paddle/fluid/eager/utils.h\"\n" + "#include \"paddle/fluid/framework/op_registry.h\"\n\n"; + + dygraph_forward_api_includes_str += + "extern std::unordered_map> " + "core_ops_args_info;\n"; + dygraph_forward_api_includes_str += + "extern std::unordered_map> " + "core_ops_returns_info;\n\n"; + + return dygraph_forward_api_includes_str; +} + static void GenerateForwardHFile(const std::string& output_dir, const std::string& dygraph_forward_api_str) { std::string dygraph_forward_api_path = output_dir + "/dygraph_forward_api.h"; @@ -1875,16 +1909,50 @@ static void GenerateNodeCCFile(const std::string& output_dir, node_cc_stream.close(); } -static std::string GenerateDygraphHFileIncludes() { - std::string dygraph_forward_api_includes_str = - "#pragma once\n" - "#include \"glog/logging.h\"\n" - "#include \"paddle/fluid/eager/autograd_meta.h\"\n" - "#include \"paddle/pten/api/all.h\"\n" - "#include \"paddle/fluid/eager/utils.h\"\n" - "#include \"paddle/fluid/framework/op_registry.h\"\n\n"; +static std::string ConvertCoreOpsInfosToString( + const std::unordered_map>& + core_ops_info) { + std::string core_ops_returns_info_init_str = ""; + for (const auto& iter : core_ops_info) { + const char* Core_Ops_Returns_TEMPLATE = "{ \"%s\", { %s } },\n"; + const std::string& op_type = iter.first; - return dygraph_forward_api_includes_str; + std::string returns_str = ""; + for (const auto& vector_iter : iter.second) { + returns_str += "\"" + vector_iter + "\" ,"; + } + + // Remove trailing ',' + if (returns_str.size() > 0) returns_str.pop_back(); + std::string op_type_init_str = paddle::string::Sprintf( + Core_Ops_Returns_TEMPLATE, op_type, returns_str); + core_ops_returns_info_init_str += op_type_init_str; + } + + // Remove trailing ',' + if (core_ops_returns_info_init_str.size() > 0) + core_ops_returns_info_init_str.pop_back(); + + return core_ops_returns_info_init_str; +} + +static std::string GenerateCoreOpsReturnsInfo() { + const char* Core_Ops_Returns_MAP_TEMPLATE = + "std::unordered_map> " + "core_ops_args_info = { %s };\n" + "std::unordered_map> " + "core_ops_returns_info = { %s };\n"; + + std::string core_ops_args_info_init_str = + ConvertCoreOpsInfosToString(core_ops_args_info); + std::string core_ops_returns_info_init_str = + ConvertCoreOpsInfosToString(core_ops_returns_info); + + std::string core_ops_info_str = paddle::string::Sprintf( + Core_Ops_Returns_MAP_TEMPLATE, core_ops_args_info_init_str, + core_ops_returns_info_init_str); + + return core_ops_info_str; } static void DygraphCodeGeneration(const std::string& output_dir) { @@ -1953,6 +2021,8 @@ static void DygraphCodeGeneration(const std::string& output_dir) { } VLOG(6) << "-------- GenerateDygraphForwardCCFile -------"; + fwd_function_str += "\n"; + fwd_function_str += GenerateCoreOpsReturnsInfo(); GenerateForwardDygraphFile(output_dir, fwd_function_str); VLOG(6) << "-------- GenerateForwardHFile -------"; diff --git a/paddle/fluid/pybind/eager.cc b/paddle/fluid/pybind/eager.cc index 72fb71585e428eaa419b7854eb64ab495c89ee13..c500e9fbb9ee64c7c0b94b96ec51187066380a7c 100644 --- a/paddle/fluid/pybind/eager.cc +++ b/paddle/fluid/pybind/eager.cc @@ -15,7 +15,6 @@ limitations under the License. */ #include #include "paddle/fluid/eager/api/all.h" -#include "paddle/fluid/eager/api/generated/fluid_generated/dygraph_forward_api.h" #include "paddle/fluid/eager/autograd_meta.h" #include "paddle/fluid/eager/utils.h" #include "paddle/fluid/memory/allocation/allocator.h" diff --git a/paddle/fluid/pybind/eager_op_function_generator.cc b/paddle/fluid/pybind/eager_op_function_generator.cc index 8ac90ac15019de03b23bc6fa6af6c5dde58d9b4b..4e880f78c6d1928eaa85bde3b3534d6e72af8cd8 100644 --- a/paddle/fluid/pybind/eager_op_function_generator.cc +++ b/paddle/fluid/pybind/eager_op_function_generator.cc @@ -290,6 +290,41 @@ std::string GenerateOpFunctionsBody( return op_function_str; } +static std::string GenerateCoreOpsInfoMap() { + std::string result = + "static PyObject * eager_get_core_ops_args_info(PyObject *self) {\n" + " PyThreadState *tstate = nullptr;\n" + " try\n" + " {\n" + " return ToPyObject(core_ops_args_info);\n" + " }\n" + " catch(...) {\n" + " if (tstate) {\n" + " PyEval_RestoreThread(tstate);\n" + " }\n" + " ThrowExceptionToPython(std::current_exception());\n" + " return nullptr;\n" + " }\n" + "}\n" + "\n" + "static PyObject * eager_get_core_ops_returns_info(PyObject *self) {\n" + " PyThreadState *tstate = nullptr;\n" + " try\n" + " {\n" + " return ToPyObject(core_ops_returns_info);\n" + " }\n" + " catch(...) {\n" + " if (tstate) {\n" + " PyEval_RestoreThread(tstate);\n" + " }\n" + " ThrowExceptionToPython(std::current_exception());\n" + " return nullptr;\n" + " }\n" + "}\n"; + + return result; +} + static std::tuple, std::vector> GenerateOpFunctions() { auto& op_info_map = paddle::framework::OpInfoMap::Instance().map(); @@ -338,6 +373,8 @@ int main(int argc, char* argv[]) { std::vector headers{ "\"pybind11/detail/common.h\"", "\"paddle/fluid/pybind/op_function_common.h\"", + "\"paddle/fluid/eager/api/generated/fluid_generated/" + "dygraph_forward_api.h\"", "\"paddle/fluid/pybind/exception.h\"", ""}; std::ofstream out(argv[1], std::ios::out); @@ -351,15 +388,25 @@ int main(int argc, char* argv[]) { out << "\n\n"; auto op_funcs = GenerateOpFunctions(); + auto core_ops_infos = GenerateCoreOpsInfoMap(); + std::string core_ops_infos_registry = + "{\"get_core_ops_args_info\", " + "(PyCFunction)(void(*)(void))eager_get_core_ops_args_info, METH_NOARGS, " + "\"C++ interface function for eager_get_core_ops_args_info.\"},\n" + " {\"get_core_ops_returns_info\", " + "(PyCFunction)(void(*)(void))eager_get_core_ops_returns_info, " + "METH_NOARGS, \"C++ interface function for " + "eager_get_core_ops_returns_info.\"},\n"; out << "namespace paddle {\n" << "namespace pybind {\n\n"; + out << core_ops_infos; out << paddle::string::join_strings(std::get<0>(op_funcs), '\n'); out << "\n\n"; out << "static PyMethodDef ExtestMethods[] = {\n" - << paddle::string::join_strings(std::get<1>(op_funcs), '\n') - << "\n {nullptr,nullptr,0,nullptr}" + << paddle::string::join_strings(std::get<1>(op_funcs), '\n') << "\n" + << core_ops_infos_registry << "\n {nullptr,nullptr,0,nullptr}" << "};\n\n"; out << "inline void BindEagerOpFunctions(pybind11::module *module) {\n" diff --git a/paddle/fluid/pybind/eager_utils.cc b/paddle/fluid/pybind/eager_utils.cc index 98966922e49c8bca54de03863cdecb5e3a966bc3..c1cd900919252a09add4fae28455d7b8a765f12f 100644 --- a/paddle/fluid/pybind/eager_utils.cc +++ b/paddle/fluid/pybind/eager_utils.cc @@ -402,6 +402,41 @@ PyObject* ToPyObject(const void* value) { platform::errors::Fatal("ToPyObject do not support void* with value.")); } +PyObject* ToPyObject( + const std::unordered_map>& value) { + PyObject* dict = PyDict_New(); + for (const auto map_iter : value) { + // Convert Key + PyObject* key_string = PyUnicode_FromString(map_iter.first.c_str()); + if (!key_string) { + PADDLE_THROW( + platform::errors::Fatal("Unable to convert std::string to PyObject")); + } + + // Convert Val + PyObject* py_list = PyList_New(0); + for (const auto vector_iter : map_iter.second) { + PyObject* val_string = PyUnicode_FromString(vector_iter.c_str()); + if (!val_string) { + PADDLE_THROW(platform::errors::Fatal( + "Unable to convert std::string to PyObject")); + } + + if (PyList_Append(py_list, val_string) != 0) { + PADDLE_THROW( + platform::errors::Fatal("Unable to append string to py_list")); + } + } + + if (PyDict_SetItem(dict, key_string, py_list) != 0) { + PADDLE_THROW( + platform::errors::Fatal("Unable to set key:value for py_dict")); + } + } + + return dict; +} + egr::EagerTensor GetEagerTensorFromArgs(const std::string& op_type, const std::string& arg_name, PyObject* args, ssize_t arg_idx, diff --git a/paddle/fluid/pybind/eager_utils.h b/paddle/fluid/pybind/eager_utils.h index 4ddc5ae11fbff4bf01fcd7559e8ffb1f70bc8fb8..1dea81d0263233f2a580cadc59d1690c394733ae 100644 --- a/paddle/fluid/pybind/eager_utils.h +++ b/paddle/fluid/pybind/eager_utils.h @@ -54,6 +54,8 @@ PyObject* ToPyObject(const std::vector& value); PyObject* ToPyObject(const platform::Place& value); PyObject* ToPyObject(const paddle::framework::proto::VarType::Type& dtype); PyObject* ToPyObject(const void* value); +PyObject* ToPyObject( + const std::unordered_map>& value); template struct TupleEagerTensorResult {