mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-07-28 20:11:22 +00:00
Delete pyop (#21094)
### Description
Remove the "--enable_language_interop_ops" build flag, because the code
is incompatible with the latest numpy, and the build flag is not used
anywhere except a macOS CI pipeline. It does not seem to have a ship
plan.
### Motivation and Context
The build error was:
```
onnxruntime/core/language_interop_ops/pyop/pyop.cc:122:85: error: no member named 'elsize' in '_PyArray_Descr'
static_cast<int64_t>(PyArray_DescrFromType(type)->elsize),
~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^
```
This commit is contained in:
parent
8ab8e649a7
commit
be423747b1
13 changed files with 2 additions and 655 deletions
|
|
@ -123,7 +123,6 @@ option(onnxruntime_GCOV_COVERAGE "Compile with options necessary to run code cov
|
|||
option(onnxruntime_DONT_VECTORIZE "Do not vectorize operations in Eigen" OFF)
|
||||
|
||||
option(onnxruntime_USE_FULL_PROTOBUF "Link to libprotobuf instead of libprotobuf-lite when this option is ON" OFF)
|
||||
option(onnxruntime_ENABLE_LANGUAGE_INTEROP_OPS "Enable operator implemented in language other than cpp" OFF)
|
||||
option(onnxruntime_DEBUG_NODE_INPUTS_OUTPUTS "Dump debug information about node inputs and outputs when executing the model." OFF)
|
||||
cmake_dependent_option(onnxruntime_DEBUG_NODE_INPUTS_OUTPUTS_ENABLE_DUMP_TO_SQLDB "Build dump debug information about node inputs and outputs with support for sql database." OFF "onnxruntime_DEBUG_NODE_INPUTS_OUTPUTS" OFF)
|
||||
option(onnxruntime_USE_DML "Build with DirectML support" OFF)
|
||||
|
|
@ -439,13 +438,6 @@ if (onnxruntime_ENABLE_MEMORY_PROFILE)
|
|||
endif()
|
||||
|
||||
set(ONNX_ML 1)
|
||||
if (NOT onnxruntime_ENABLE_PYTHON)
|
||||
set(onnxruntime_ENABLE_LANGUAGE_INTEROP_OPS OFF)
|
||||
endif()
|
||||
|
||||
if (onnxruntime_ENABLE_LANGUAGE_INTEROP_OPS)
|
||||
add_compile_definitions(ENABLE_LANGUAGE_INTEROP_OPS)
|
||||
endif()
|
||||
|
||||
if (NOT (UNIX AND onnxruntime_ENABLE_PYTHON AND onnxruntime_ENABLE_TRAINING AND (NOT onnxruntime_BUILD_SHARED_LIB)))
|
||||
if (onnxruntime_ENABLE_TRAINING_TORCH_INTEROP)
|
||||
|
|
@ -578,7 +570,7 @@ endif()
|
|||
#Need python to generate def file
|
||||
if (onnxruntime_BUILD_SHARED_LIB OR onnxruntime_ENABLE_PYTHON)
|
||||
if (onnxruntime_ENABLE_PYTHON)
|
||||
if (onnxruntime_ENABLE_LANGUAGE_INTEROP_OPS OR onnxruntime_REQUIRE_PYTHON_EMBED_LIB)
|
||||
if (onnxruntime_REQUIRE_PYTHON_EMBED_LIB)
|
||||
find_package(Python 3.8 COMPONENTS Interpreter Development NumPy)
|
||||
else()
|
||||
find_package(Python 3.8 COMPONENTS Interpreter Development.Module NumPy)
|
||||
|
|
|
|||
|
|
@ -205,13 +205,6 @@ set(onnxruntime_INTERNAL_LIBRARIES
|
|||
onnxruntime_flatbuffers
|
||||
)
|
||||
|
||||
if (onnxruntime_ENABLE_LANGUAGE_INTEROP_OPS)
|
||||
list(APPEND onnxruntime_INTERNAL_LIBRARIES
|
||||
onnxruntime_language_interop
|
||||
onnxruntime_pyop
|
||||
)
|
||||
endif()
|
||||
|
||||
if (onnxruntime_USE_EXTENSIONS)
|
||||
list(APPEND onnxruntime_INTERNAL_LIBRARIES
|
||||
onnxruntime_extensions
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT License.
|
||||
include(onnxruntime_pyop.cmake)
|
||||
file (GLOB onnxruntime_language_interop_ops_src "${ONNXRUNTIME_ROOT}/core/language_interop_ops/language_interop_ops.cc")
|
||||
onnxruntime_add_static_library(onnxruntime_language_interop ${onnxruntime_language_interop_ops_src})
|
||||
add_dependencies(onnxruntime_language_interop onnxruntime_pyop)
|
||||
onnxruntime_add_include_to_target(onnxruntime_language_interop onnxruntime_common onnxruntime_graph onnxruntime_framework onnxruntime_pyop onnx onnx_proto ${PROTOBUF_LIB} flatbuffers::flatbuffers safeint_interface Boost::mp11)
|
||||
target_include_directories(onnxruntime_language_interop PRIVATE ${ONNXRUNTIME_ROOT} ${eigen_INCLUDE_DIRS})
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT License.
|
||||
onnxruntime_add_static_library(onnxruntime_pyop "${ONNXRUNTIME_ROOT}/core/language_interop_ops/pyop/pyop.cc")
|
||||
add_dependencies(onnxruntime_pyop ${onnxruntime_EXTERNAL_DEPENDENCIES})
|
||||
onnxruntime_add_include_to_target(onnxruntime_pyop onnxruntime_common onnxruntime_graph onnxruntime_framework onnx onnx_proto ${PROTOBUF_LIB} flatbuffers::flatbuffers ${GSL_TARGET} Boost::mp11)
|
||||
target_include_directories(onnxruntime_pyop PRIVATE ${ONNXRUNTIME_ROOT} ${eigen_INCLUDE_DIRS})
|
||||
onnxruntime_add_include_to_target(onnxruntime_pyop Python::Module Python::NumPy)
|
||||
if (TARGET Python::Python)
|
||||
target_link_libraries(onnxruntime_pyop PRIVATE Python::Python)
|
||||
else()
|
||||
target_link_libraries(onnxruntime_pyop PRIVATE Python::Module)
|
||||
endif()
|
||||
|
|
@ -193,10 +193,6 @@ target_link_libraries(onnxruntime_pybind11_state PRIVATE
|
|||
${pybind11_lib}
|
||||
)
|
||||
|
||||
if (onnxruntime_ENABLE_LANGUAGE_INTEROP_OPS)
|
||||
target_link_libraries(onnxruntime_pybind11_state PRIVATE onnxruntime_language_interop onnxruntime_pyop)
|
||||
endif()
|
||||
|
||||
set(onnxruntime_pybind11_state_dependencies
|
||||
${onnxruntime_EXTERNAL_DEPENDENCIES}
|
||||
${pybind11_dep}
|
||||
|
|
@ -1027,6 +1023,3 @@ if (onnxruntime_USE_QNN)
|
|||
endif()
|
||||
|
||||
endif()
|
||||
if (onnxruntime_ENABLE_LANGUAGE_INTEROP_OPS)
|
||||
include(onnxruntime_language_interop_ops.cmake)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -141,10 +141,6 @@ if (onnxruntime_BUILD_UNIT_TESTS)
|
|||
Boost::mp11 safeint_interface
|
||||
)
|
||||
|
||||
if (onnxruntime_ENABLE_LANGUAGE_INTEROP_OPS)
|
||||
list(APPEND ONNXRUNTIME_LIBS onnxruntime_language_interop onnxruntime_pyop)
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
if (HAS_NO_MAYBE_UNINITIALIZED)
|
||||
target_compile_options(onnxruntime_training_mnist PUBLIC "-Wno-maybe-uninitialized")
|
||||
|
|
|
|||
|
|
@ -583,10 +583,6 @@ if(onnxruntime_USE_ARMNN)
|
|||
list(APPEND onnxruntime_test_providers_dependencies onnxruntime_providers_armnn)
|
||||
endif()
|
||||
|
||||
if (onnxruntime_ENABLE_LANGUAGE_INTEROP_OPS)
|
||||
set(ONNXRUNTIME_INTEROP_TEST_LIBS PRIVATE onnxruntime_language_interop onnxruntime_pyop)
|
||||
endif()
|
||||
|
||||
set(ONNXRUNTIME_TEST_LIBS
|
||||
onnxruntime_session
|
||||
${ONNXRUNTIME_INTEROP_TEST_LIBS}
|
||||
|
|
@ -916,10 +912,6 @@ endif()
|
|||
if (onnxruntime_DEBUG_NODE_INPUTS_OUTPUTS)
|
||||
target_compile_definitions(onnxruntime_test_all PRIVATE DEBUG_NODE_INPUTS_OUTPUTS)
|
||||
endif()
|
||||
|
||||
if (onnxruntime_ENABLE_LANGUAGE_INTEROP_OPS)
|
||||
target_link_libraries(onnxruntime_test_all PRIVATE onnxruntime_language_interop onnxruntime_pyop)
|
||||
endif()
|
||||
if (onnxruntime_USE_ROCM)
|
||||
if (onnxruntime_USE_COMPOSABLE_KERNEL)
|
||||
target_compile_definitions(onnxruntime_test_all PRIVATE USE_COMPOSABLE_KERNEL)
|
||||
|
|
@ -1057,10 +1049,6 @@ set(onnx_test_libs
|
|||
onnx_test_data_proto
|
||||
${onnxruntime_EXTERNAL_LIBRARIES})
|
||||
|
||||
if (onnxruntime_ENABLE_LANGUAGE_INTEROP_OPS)
|
||||
list(APPEND onnx_test_libs onnxruntime_language_interop onnxruntime_pyop)
|
||||
endif()
|
||||
|
||||
if (NOT IOS)
|
||||
onnxruntime_add_executable(onnx_test_runner ${onnx_test_runner_src_dir}/main.cc)
|
||||
if(MSVC)
|
||||
|
|
@ -1241,10 +1229,6 @@ if (NOT onnxruntime_ENABLE_TRAINING_TORCH_INTEROP)
|
|||
endif()
|
||||
set_target_properties(onnxruntime_perf_test PROPERTIES FOLDER "ONNXRuntimeTest")
|
||||
|
||||
if (onnxruntime_ENABLE_LANGUAGE_INTEROP_OPS AND NOT onnxruntime_BUILD_SHARED_LIB)
|
||||
target_link_libraries(onnxruntime_perf_test PRIVATE onnxruntime_language_interop onnxruntime_pyop)
|
||||
endif()
|
||||
|
||||
if (onnxruntime_USE_TVM)
|
||||
if (WIN32)
|
||||
target_link_options(onnxruntime_perf_test PRIVATE "/STACK:4000000")
|
||||
|
|
@ -1474,10 +1458,6 @@ endif()
|
|||
onnxruntime_flatbuffers
|
||||
)
|
||||
|
||||
if (onnxruntime_ENABLE_LANGUAGE_INTEROP_OPS)
|
||||
list(APPEND ONNXRUNTIME_TEST_LIBS onnxruntime_language_interop onnxruntime_pyop)
|
||||
endif()
|
||||
|
||||
target_link_libraries(onnxruntime_test_trainer PRIVATE
|
||||
${ONNXRUNTIME_TEST_LIBS}
|
||||
${onnxruntime_EXTERNAL_LIBRARIES}
|
||||
|
|
|
|||
|
|
@ -1,65 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "language_interop_ops.h"
|
||||
#include "core/framework/tensorprotoutils.h"
|
||||
#include "core/platform/env.h"
|
||||
#include "core/session/inference_session.h"
|
||||
#include "pyop/pyop.h"
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
|
||||
namespace onnxruntime {
|
||||
|
||||
void LoadInterOp(const std::basic_string<ORTCHAR_T>& model_uri, InterOpDomains& domains, const InterOpLogFunc& log_func) {
|
||||
int fd;
|
||||
|
||||
// match the error message from model.cc to keep the nodejs tests happy.
|
||||
// as this is deprecated just cut-and-paste equivalent code for now.
|
||||
auto status = Env::Default().FileOpenRd(model_uri, fd);
|
||||
if (!status.IsOK()) {
|
||||
if (status.Category() == common::SYSTEM) {
|
||||
switch (status.Code()) {
|
||||
case ENOENT:
|
||||
status = ORT_MAKE_STATUS(ONNXRUNTIME, NO_SUCHFILE, "Load model ", ToUTF8String(model_uri),
|
||||
" failed. File doesn't exist");
|
||||
break;
|
||||
case EINVAL:
|
||||
status = ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Load model ", ToUTF8String(model_uri), " failed");
|
||||
break;
|
||||
default:
|
||||
status = ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "system error number ", status.Code());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ORT_ENFORCE(status.IsOK(), status.ErrorMessage());
|
||||
|
||||
google::protobuf::io::FileInputStream f(fd);
|
||||
f.SetCloseOnDelete(true);
|
||||
ONNX_NAMESPACE::ModelProto model_proto;
|
||||
ORT_ENFORCE(model_proto.ParseFromZeroCopyStream(&f), "Failed to parse model proto");
|
||||
LoadInterOp(model_proto, domains, log_func);
|
||||
}
|
||||
|
||||
void LoadInterOp(const ONNX_NAMESPACE::ModelProto& model_proto, InterOpDomains& domains, const InterOpLogFunc& log_func) {
|
||||
LoadInterOp(model_proto.graph(), domains, log_func);
|
||||
}
|
||||
|
||||
void LoadInterOp(const ONNX_NAMESPACE::GraphProto& graph_proto, InterOpDomains& domains, const InterOpLogFunc& log_func) {
|
||||
for (int i = 0; i < graph_proto.node_size(); ++i) {
|
||||
const auto& node_proto = graph_proto.node(i);
|
||||
if (node_proto.op_type() == "PyOp") {
|
||||
auto pyop_domain = Ort::CustomOpDomain(node_proto.domain().c_str());
|
||||
pyop_domain.Add(LoadPyOp(node_proto, log_func));
|
||||
domains.push_back(std::move(pyop_domain));
|
||||
} else {
|
||||
for (int j = 0, limit = node_proto.attribute_size(); j < limit; ++j) {
|
||||
const auto& attr = node_proto.attribute(j);
|
||||
if (utils::HasGraph(attr)) {
|
||||
LoadInterOp(attr.g(), domains, log_func); // load pyop in subgraph
|
||||
}
|
||||
} // for
|
||||
} // else
|
||||
} // for
|
||||
}
|
||||
} // namespace onnxruntime
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "core/graph/graph.h"
|
||||
#include "core/session/onnxruntime_cxx_api.h"
|
||||
|
||||
namespace onnxruntime {
|
||||
using InterOpLogFunc = std::function<void(const char*)>;
|
||||
using InterOpDomains = std::vector<Ort::CustomOpDomain>;
|
||||
void LoadInterOp(const std::basic_string<ORTCHAR_T>& model_uri, InterOpDomains& domains, const InterOpLogFunc& log_func);
|
||||
void LoadInterOp(const ONNX_NAMESPACE::ModelProto& model_proto, InterOpDomains& domains, const InterOpLogFunc& log_func);
|
||||
void LoadInterOp(const ONNX_NAMESPACE::GraphProto& graph_proto, InterOpDomains& domains, const InterOpLogFunc& log_func);
|
||||
} // namespace onnxruntime
|
||||
|
|
@ -1,399 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "pyop.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define LIB_PYOP "onnxruntime_pywrapper.dll"
|
||||
#define LOAD_PYOP_LIB(n, v, m) ORT_ENFORCE((v = LoadLibraryA(n)) != nullptr, m)
|
||||
#else
|
||||
#ifdef __APPLE__
|
||||
#define LIB_PYOP "./libonnxruntime_pywrapper.dylib"
|
||||
#else
|
||||
#define LIB_PYOP "./libonnxruntime_pywrapper.so"
|
||||
#endif
|
||||
#define LOAD_PYOP_LIB(n, v, m) ORT_ENFORCE((v = dlopen(n, RTLD_NOW | RTLD_GLOBAL)) != nullptr, m)
|
||||
#include "dlfcn.h"
|
||||
#endif
|
||||
|
||||
#include "core/framework/tensorprotoutils.h"
|
||||
#include "core/platform/env.h"
|
||||
#ifdef _DEBUG
|
||||
#undef _DEBUG
|
||||
#include <Python.h>
|
||||
#define _DEBUG
|
||||
#else
|
||||
#include <Python.h>
|
||||
#endif
|
||||
|
||||
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
|
||||
#include "numpy/arrayobject.h"
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace onnxruntime {
|
||||
|
||||
PyOpLibProxy& PyOpLibProxy::GetInstance() {
|
||||
static PyOpLibProxy proxy;
|
||||
return proxy;
|
||||
}
|
||||
|
||||
class Scope {
|
||||
public:
|
||||
Scope(const std::vector<PyObject*>& objs = {}) : objs_(objs) {
|
||||
mtx_.lock();
|
||||
}
|
||||
~Scope() {
|
||||
for (auto obj : objs_) {
|
||||
Py_XDECREF(obj);
|
||||
}
|
||||
mtx_.unlock();
|
||||
}
|
||||
void Add(PyObject* obj) {
|
||||
objs_.push_back(obj);
|
||||
}
|
||||
|
||||
private:
|
||||
static std::mutex mtx_;
|
||||
std::vector<PyObject*> objs_;
|
||||
};
|
||||
|
||||
PyOpLibProxy::PyOpLibProxy() {
|
||||
Scope scope;
|
||||
Py_Initialize();
|
||||
if (_import_array() < 0) {
|
||||
return;
|
||||
}
|
||||
auto path_list = PySys_GetObject("path"); // do not release it
|
||||
if (nullptr == path_list || !PyList_Check(path_list) ||
|
||||
PyList_Append(path_list, PyUnicode_FromString(".")) != 0) {
|
||||
return;
|
||||
}
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
PyOpLibProxy::~PyOpLibProxy() {
|
||||
if (initialized_) {
|
||||
Py_Finalize();
|
||||
}
|
||||
}
|
||||
|
||||
std::mutex Scope::mtx_;
|
||||
|
||||
const char* PyOpLibProxy::GetLastErrorMessage(std::string& err) {
|
||||
Scope scope;
|
||||
if (PyErr_Occurred()) {
|
||||
PyObject *type, *value, *trace;
|
||||
PyErr_Fetch(&type, &value, &trace);
|
||||
if (nullptr != value) {
|
||||
auto pyVal = PyObject_Repr(value);
|
||||
scope.Add(pyVal);
|
||||
auto pyStr = PyUnicode_AsEncodedString(pyVal, "utf-8", "Error ~");
|
||||
scope.Add(pyStr);
|
||||
err = PyBytes_AS_STRING(pyStr);
|
||||
}
|
||||
PyErr_Restore(type, value, trace);
|
||||
}
|
||||
return err.c_str();
|
||||
}
|
||||
|
||||
int32_t PyOpLibProxy::GetGil() const {
|
||||
return PyGILState_Ensure();
|
||||
}
|
||||
|
||||
void PyOpLibProxy::PutGil(int32_t state) const {
|
||||
PyGILState_Release((PyGILState_STATE)state);
|
||||
}
|
||||
|
||||
PyObject* MakePyObj(const void* data, int32_t type, const std::vector<int64_t>& dim) {
|
||||
std::vector<npy_intp> np_dim;
|
||||
for (auto d : dim) {
|
||||
np_dim.push_back(static_cast<npy_intp>(d));
|
||||
}
|
||||
auto pyObj = static_cast<PyObject*>(PyArray_EMPTY(static_cast<int>(np_dim.size()), np_dim.data(), type, 0));
|
||||
auto data_len = std::accumulate(begin(np_dim), end(np_dim),
|
||||
static_cast<int64_t>(PyArray_DescrFromType(type)->elsize),
|
||||
std::multiplies<int64_t>());
|
||||
auto np_array = reinterpret_cast<PyArrayObject*>(pyObj);
|
||||
memcpy(PyArray_DATA(np_array), data, data_len);
|
||||
return pyObj;
|
||||
}
|
||||
|
||||
bool ExtractOutput(PyObject* pyObj,
|
||||
std::vector<std::unique_ptr<char[]>>& outputs,
|
||||
std::vector<int32_t>& outputs_elem_size,
|
||||
std::vector<std::vector<int64_t>>& outputs_dim) {
|
||||
if (!PyArray_Check(pyObj)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outputs_dim.push_back({});
|
||||
auto np_array = reinterpret_cast<PyArrayObject*>(pyObj);
|
||||
outputs_elem_size.push_back(static_cast<int32_t>(PyArray_ITEMSIZE(np_array)));
|
||||
|
||||
for (int i = 0; i < PyArray_NDIM(np_array); ++i) {
|
||||
outputs_dim.back().push_back(PyArray_SHAPE(np_array)[i]);
|
||||
}
|
||||
|
||||
auto data_len = std::accumulate(begin(outputs_dim.back()),
|
||||
end(outputs_dim.back()),
|
||||
static_cast<int64_t>(outputs_elem_size.back()),
|
||||
std::multiplies<int64_t>());
|
||||
|
||||
outputs.push_back(std::unique_ptr<char[]>(new char[data_len]));
|
||||
memcpy(static_cast<void*>(outputs.back().get()), PyArray_DATA(np_array), data_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
void* PyOpLibProxy::NewInstance(const char* module, const char* class_name,
|
||||
const std::unordered_map<std::string, std::string>& args) {
|
||||
Scope scope;
|
||||
auto pyModule = PyImport_ImportModule(module);
|
||||
if (nullptr == pyModule) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
scope.Add(pyModule);
|
||||
auto pyClass = PyObject_GetAttrString(pyModule, class_name);
|
||||
if (nullptr == pyClass) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
scope.Add(pyClass);
|
||||
auto empty_args = PyTuple_New(0);
|
||||
scope.Add(empty_args);
|
||||
auto named_args = PyDict_New();
|
||||
scope.Add(named_args);
|
||||
for (const auto& iter : args) {
|
||||
PyDict_SetItemString(named_args, iter.first.c_str(), PyUnicode_FromString(iter.second.c_str()));
|
||||
}
|
||||
|
||||
return PyObject_Call(pyClass, empty_args, named_args);
|
||||
}
|
||||
|
||||
void PyOpLibProxy::ReleaseInstance(void* instance) {
|
||||
Scope scope({static_cast<PyObject*>(instance)});
|
||||
}
|
||||
|
||||
bool PyOpLibProxy::InvokePythonFunc(void* raw_inst,
|
||||
const char* function,
|
||||
const std::vector<const void*>& inputs,
|
||||
const std::vector<int32_t>& inputs_type,
|
||||
const std::vector<std::vector<int64_t>>& inputs_dim,
|
||||
std::vector<std::unique_ptr<char[]>>& outputs,
|
||||
std::vector<int32_t>& outputs_elem_size,
|
||||
std::vector<std::vector<int64_t>>& outputs_dim,
|
||||
std::function<void(const char*)> logging_func) {
|
||||
Scope scope;
|
||||
auto instance = static_cast<PyObject*>(raw_inst);
|
||||
if (nullptr == instance || nullptr == function) {
|
||||
logging_func("InvokePythonFunc: found invalid instance or function");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto pyFunc = PyObject_GetAttrString(instance, function);
|
||||
if (nullptr == pyFunc) {
|
||||
logging_func("InvokePythonFunc: failed to create function object");
|
||||
return false;
|
||||
}
|
||||
|
||||
scope.Add(pyFunc);
|
||||
auto pyArgs = PyTuple_New(inputs.size());
|
||||
for (size_t i = 0; i < inputs.size(); ++i) {
|
||||
PyTuple_SetItem(pyArgs, i, MakePyObj(inputs[i], inputs_type[i], inputs_dim[i]));
|
||||
}
|
||||
|
||||
scope.Add(pyArgs);
|
||||
auto pyResult = PyObject_CallObject(pyFunc, pyArgs);
|
||||
if (nullptr == pyResult) {
|
||||
logging_func("InvokePythonFunc: no result");
|
||||
return false;
|
||||
}
|
||||
|
||||
scope.Add(pyResult);
|
||||
if (PyArray_Check(pyResult)) {
|
||||
ExtractOutput(pyResult, outputs, outputs_elem_size, outputs_dim);
|
||||
} else if (PyTuple_Check(pyResult)) {
|
||||
for (int32_t i = 0; i < PyTuple_Size(pyResult); ++i) {
|
||||
if (!ExtractOutput(PyTuple_GetItem(pyResult, i), outputs, outputs_elem_size, outputs_dim)) {
|
||||
logging_func("InvokePythonFunc: failed to extract output");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logging_func("InvokePythonFunc: returned value must be numpy(s)");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} // bool InvokePythonFunc
|
||||
|
||||
PyCustomKernel::PyCustomKernel(const OnnxAttrs& attrs,
|
||||
const std::string& module,
|
||||
const std::string& class_name,
|
||||
const std::string& compute,
|
||||
PyOpLogFunc logging_func) : attrs_(attrs), module_(module), class_name_(class_name), compute_(compute), logging_func_(logging_func) {
|
||||
std::string err;
|
||||
auto state = PyOpLibProxy::GetInstance().GetGil();
|
||||
ORT_ENFORCE(PyOpLibProxy::GetInstance().Initialized(), "Py library not properly initialized.");
|
||||
instance_ = PyOpLibProxy::GetInstance().NewInstance(module.c_str(), class_name_.c_str(), attrs_);
|
||||
PyOpLibProxy::GetInstance().PutGil(state);
|
||||
ORT_ENFORCE(nullptr != instance_, PyOpLibProxy::GetInstance().GetLastErrorMessage(err));
|
||||
}
|
||||
|
||||
PyCustomKernel::~PyCustomKernel() {
|
||||
if (nullptr != instance_) {
|
||||
auto state = PyOpLibProxy::GetInstance().GetGil();
|
||||
PyOpLibProxy::GetInstance().ReleaseInstance(instance_);
|
||||
PyOpLibProxy::GetInstance().PutGil(state);
|
||||
instance_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Do nothing since Custom Op does not trigger shape inference
|
||||
void PyCustomKernel::GetOutputShape(OrtKernelContext*, size_t, OrtTensorTypeAndShapeInfo*) {}
|
||||
|
||||
void PyCustomKernel::Compute(OrtKernelContext* context) {
|
||||
ORT_ENFORCE(nullptr != context);
|
||||
|
||||
Ort::KernelContext ctx(context);
|
||||
const auto inputs_count = ctx.GetInputCount();
|
||||
|
||||
std::vector<const void*> inputs;
|
||||
std::vector<std::unique_ptr<char[]>> outputs;
|
||||
std::vector<int32_t> inputs_type, outputs_elem_size;
|
||||
std::vector<std::vector<int64_t>> inputs_dim, outputs_dim;
|
||||
|
||||
inputs.reserve(inputs_count);
|
||||
inputs_dim.reserve(inputs_count);
|
||||
for (size_t i = 0; i < inputs_count; ++i) {
|
||||
auto value = ctx.GetInput(i);
|
||||
ORT_ENFORCE(value.IsTensor(), "input must be a tensor");
|
||||
|
||||
inputs.push_back(value.GetTensorRawData());
|
||||
|
||||
auto type_and_shape = value.GetTensorTypeAndShapeInfo();
|
||||
inputs_type.push_back(GetNumpyType(type_and_shape.GetElementType()));
|
||||
auto shape = type_and_shape.GetShape();
|
||||
inputs_dim.push_back(std::move(shape));
|
||||
}
|
||||
|
||||
std::string err;
|
||||
auto state = PyOpLibProxy::GetInstance().GetGil();
|
||||
ORT_ENFORCE(PyOpLibProxy::GetInstance().InvokePythonFunc(instance_, compute_.c_str(), inputs, inputs_type,
|
||||
inputs_dim, outputs, outputs_elem_size,
|
||||
outputs_dim, logging_func_),
|
||||
PyOpLibProxy::GetInstance().GetLastErrorMessage(err)); // ORT_ENFORCE
|
||||
PyOpLibProxy::GetInstance().PutGil(state);
|
||||
|
||||
for (size_t i = 0; i < outputs.size(); ++i) {
|
||||
auto ort_output = ctx.GetOutput(i, outputs_dim[i].data(), outputs_dim[i].size());
|
||||
auto output_mem_addr = ort_output.GetTensorMutableData<char>();
|
||||
auto output_len = std::accumulate(begin(outputs_dim[i]), end(outputs_dim[i]), static_cast<int64_t>(outputs_elem_size[i]), std::multiplies<int64_t>());
|
||||
memcpy(output_mem_addr, outputs[i].get(), output_len);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t PyCustomKernel::GetNumpyType(int32_t elem_type) const {
|
||||
int32_t numpy_type;
|
||||
namespace on = ONNX_NAMESPACE;
|
||||
switch (elem_type) {
|
||||
case on::TensorProto_DataType_BOOL:
|
||||
numpy_type = 0;
|
||||
break;
|
||||
case on::TensorProto_DataType_INT8:
|
||||
numpy_type = 1;
|
||||
break;
|
||||
case on::TensorProto_DataType_UINT8:
|
||||
numpy_type = 2;
|
||||
break;
|
||||
case on::TensorProto_DataType_INT16:
|
||||
numpy_type = 3;
|
||||
break;
|
||||
case on::TensorProto_DataType_UINT16:
|
||||
numpy_type = 4;
|
||||
break;
|
||||
case on::TensorProto_DataType_INT32:
|
||||
numpy_type = 5;
|
||||
break;
|
||||
case on::TensorProto_DataType_UINT32:
|
||||
numpy_type = 6;
|
||||
break;
|
||||
case on::TensorProto_DataType_INT64:
|
||||
numpy_type = 9;
|
||||
break;
|
||||
case on::TensorProto_DataType_UINT64:
|
||||
numpy_type = 10;
|
||||
break;
|
||||
case on::TensorProto_DataType_FLOAT:
|
||||
numpy_type = 11;
|
||||
break;
|
||||
case on::TensorProto_DataType_DOUBLE:
|
||||
numpy_type = 12;
|
||||
break;
|
||||
default:
|
||||
ORT_THROW("Input primitive type not supported: ", elem_type);
|
||||
}
|
||||
return numpy_type;
|
||||
}
|
||||
|
||||
PyCustomOp::PyCustomOp(const OnnxAttrs& attrs,
|
||||
const OnnxTypes& inputs_type,
|
||||
const OnnxTypes& outputs_type,
|
||||
const std::string& module,
|
||||
const std::string& class_name,
|
||||
const std::string& compute,
|
||||
PyOpLogFunc logging_func) : attrs_(attrs), inputs_type_(inputs_type), outputs_type_(outputs_type), module_(module), class_name_(class_name), compute_(compute), logging_func_(logging_func) { OrtCustomOp::version = ORT_API_VERSION; }
|
||||
|
||||
void* PyCustomOp::CreateKernel(const OrtApi&, const OrtKernelInfo*) const {
|
||||
return new PyCustomKernel(attrs_, module_, class_name_, compute_, logging_func_);
|
||||
}
|
||||
|
||||
const char* PyCustomOp::GetName() const { return "PyOp"; }
|
||||
|
||||
size_t PyCustomOp::GetInputTypeCount() const { return inputs_type_.size(); }
|
||||
ONNXTensorElementDataType PyCustomOp::GetInputType(size_t index) const { return inputs_type_[index]; }
|
||||
|
||||
size_t PyCustomOp::GetOutputTypeCount() const { return outputs_type_.size(); }
|
||||
ONNXTensorElementDataType PyCustomOp::GetOutputType(size_t index) const { return outputs_type_[index]; }
|
||||
|
||||
PyCustomOp* LoadPyOp(const ONNX_NAMESPACE::NodeProto& node_proto, PyOpLogFunc log_func) {
|
||||
OnnxAttrs onnx_attrs;
|
||||
OnnxTypes input_types, output_types;
|
||||
std::string module, class_name, compute = "compute";
|
||||
for (int j = 0; j < node_proto.attribute_size(); ++j) {
|
||||
const auto& attr = node_proto.attribute(j);
|
||||
if (utils::HasString(attr)) {
|
||||
if (attr.name() == "module")
|
||||
module = attr.s();
|
||||
else if (attr.name() == "class_name")
|
||||
class_name = attr.s();
|
||||
else if (attr.name() == "compute")
|
||||
compute = attr.s();
|
||||
else
|
||||
onnx_attrs[attr.name()] = attr.s();
|
||||
} else if (attr.ints_size() > 0) {
|
||||
if (attr.name() == "input_types") {
|
||||
for (int k = 0; k < attr.ints_size(); ++k) {
|
||||
input_types.push_back(static_cast<ONNXTensorElementDataType>(attr.ints(k)));
|
||||
}
|
||||
} else if (attr.name() == "output_types") {
|
||||
for (int k = 0; k < attr.ints_size(); ++k) {
|
||||
output_types.push_back(static_cast<ONNXTensorElementDataType>(attr.ints(k)));
|
||||
}
|
||||
}
|
||||
}
|
||||
} // for
|
||||
ORT_ENFORCE(module != "", "PyOp module not specified");
|
||||
ORT_ENFORCE(class_name != "", "PyOp class name not specified");
|
||||
ORT_ENFORCE(!input_types.empty(), "PyOp node inputs not specified");
|
||||
ORT_ENFORCE(!output_types.empty(), "PyOp node outputs not specified");
|
||||
return new PyCustomOp(onnx_attrs, input_types, output_types, module, class_name, compute, log_func);
|
||||
}
|
||||
} // namespace onnxruntime
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/platform/env.h"
|
||||
#define LOAD_PYOP_SYM(n, v, m) ORT_ENFORCE(Env::Default().GetSymbolFromLibrary(handle_, n, reinterpret_cast<void**>(&v)) == Status::OK(), m)
|
||||
|
||||
#include "core/session/onnxruntime_cxx_api.h"
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#define HMODULE void*
|
||||
#endif
|
||||
|
||||
namespace ONNX_NAMESPACE {
|
||||
class NodeProto;
|
||||
}
|
||||
|
||||
namespace onnxruntime {
|
||||
|
||||
using OnnxTypes = std::vector<ONNXTensorElementDataType>;
|
||||
using OnnxAttrs = std::unordered_map<std::string, std::string>;
|
||||
using PyOpLogFunc = std::function<void(const char*)>;
|
||||
|
||||
class PyOpLibProxy {
|
||||
public:
|
||||
static PyOpLibProxy& GetInstance();
|
||||
void ReleaseInstance(void*);
|
||||
bool InvokePythonFunc(void*,
|
||||
const char*,
|
||||
const std::vector<const void*>&,
|
||||
const std::vector<int32_t>&,
|
||||
const std::vector<std::vector<int64_t>>&,
|
||||
std::vector<std::unique_ptr<char[]>>&,
|
||||
std::vector<int32_t>&,
|
||||
std::vector<std::vector<int64_t>>&,
|
||||
std::function<void(const char*)>);
|
||||
const char* GetLastErrorMessage(std::string&);
|
||||
void* NewInstance(const char*, const char*, const OnnxAttrs&);
|
||||
bool Initialized() const { return initialized_; }
|
||||
int32_t GetGil() const;
|
||||
void PutGil(int32_t) const;
|
||||
|
||||
private:
|
||||
PyOpLibProxy();
|
||||
~PyOpLibProxy();
|
||||
bool initialized_ = false;
|
||||
};
|
||||
|
||||
struct PyCustomKernel {
|
||||
PyCustomKernel(const OnnxAttrs& attrs,
|
||||
const std::string& module,
|
||||
const std::string& class_name,
|
||||
const std::string& compute,
|
||||
PyOpLogFunc logging_func);
|
||||
~PyCustomKernel();
|
||||
void GetOutputShape(OrtKernelContext*, size_t, OrtTensorTypeAndShapeInfo*);
|
||||
void Compute(OrtKernelContext* context);
|
||||
int32_t GetNumpyType(int32_t elem_type) const;
|
||||
|
||||
private:
|
||||
OnnxAttrs attrs_;
|
||||
std::string module_;
|
||||
std::string class_name_;
|
||||
std::string compute_;
|
||||
void* instance_ = nullptr;
|
||||
PyOpLogFunc logging_func_;
|
||||
};
|
||||
|
||||
struct PyCustomOp : Ort::CustomOpBase<PyCustomOp, PyCustomKernel> {
|
||||
PyCustomOp(
|
||||
const OnnxAttrs& attrs,
|
||||
const OnnxTypes& inputs_type,
|
||||
const OnnxTypes& outputs_type,
|
||||
const std::string& module,
|
||||
const std::string& class_name,
|
||||
const std::string& compute = "compute",
|
||||
PyOpLogFunc logging_func = [](const char*) {});
|
||||
void* CreateKernel(const OrtApi&, const OrtKernelInfo*) const;
|
||||
const char* GetName() const;
|
||||
size_t GetInputTypeCount() const;
|
||||
ONNXTensorElementDataType GetInputType(size_t index) const;
|
||||
size_t GetOutputTypeCount() const;
|
||||
ONNXTensorElementDataType GetOutputType(size_t index) const;
|
||||
|
||||
private:
|
||||
OnnxAttrs attrs_;
|
||||
OnnxTypes inputs_type_;
|
||||
OnnxTypes outputs_type_;
|
||||
std::string module_;
|
||||
std::string class_name_;
|
||||
std::string compute_;
|
||||
PyOpLogFunc logging_func_;
|
||||
}; // struct PyCustomOp
|
||||
|
||||
PyCustomOp* LoadPyOp(const ONNX_NAMESPACE::NodeProto& node_proto, PyOpLogFunc log_func);
|
||||
} // namespace onnxruntime
|
||||
|
|
@ -605,11 +605,6 @@ def parse_arguments():
|
|||
parser.add_argument(
|
||||
"--enable_msvc_static_runtime", action="store_true", help="Enable static linking of MSVC runtimes."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--enable_language_interop_ops",
|
||||
action="store_true",
|
||||
help="Enable operator implemented in language other than cpp",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cmake_generator",
|
||||
choices=[
|
||||
|
|
@ -1053,7 +1048,6 @@ def generate_build_tree(
|
|||
else "OFF"
|
||||
),
|
||||
"-Donnxruntime_REDUCED_OPS_BUILD=" + ("ON" if is_reduced_ops_build(args) else "OFF"),
|
||||
"-Donnxruntime_ENABLE_LANGUAGE_INTEROP_OPS=" + ("ON" if args.enable_language_interop_ops else "OFF"),
|
||||
"-Donnxruntime_USE_DML=" + ("ON" if args.use_dml else "OFF"),
|
||||
"-Donnxruntime_USE_WINML=" + ("ON" if args.use_winml else "OFF"),
|
||||
"-Donnxruntime_BUILD_MS_EXPERIMENTAL_OPS=" + ("ON" if args.ms_experimental else "OFF"),
|
||||
|
|
|
|||
|
|
@ -32,5 +32,5 @@ stages:
|
|||
parameters:
|
||||
AllowReleasedOpsetOnly: 0
|
||||
BuildForAllArchs: false
|
||||
AdditionalBuildFlags: --build_objc --enable_language_interop_ops --build_wheel --use_xnnpack
|
||||
AdditionalBuildFlags: --build_objc --build_wheel --use_xnnpack
|
||||
WithCache: true
|
||||
|
|
|
|||
Loading…
Reference in a new issue