Remove numpy dependency from its Python binary build (#657)
This commit is contained in:
Родитель
972cb17a82
Коммит
69a08ffb1d
|
@ -3,11 +3,11 @@ block(PROPAGATE Python3_FOUND)
|
|||
# if we don't set this to NEVER (or possibly LAST) the builds of the wheel for different python versions will fail
|
||||
# as it will find the system python version first and not the correct python version for the wheel.
|
||||
set(Python3_FIND_FRAMEWORK NEVER)
|
||||
find_package(Python3 COMPONENTS Interpreter Development.Module NumPy)
|
||||
find_package(Python3 COMPONENTS Interpreter Development.Module)
|
||||
endblock()
|
||||
|
||||
if (NOT Python3_FOUND)
|
||||
message(FATAL_ERROR "Python3 or NumPy not found!")
|
||||
message(FATAL_ERROR "Python3 not found!")
|
||||
endif()
|
||||
|
||||
file(GLOB TARGET_SRC_PYOPS "pyop/*.cc" "pyop/*.h" "shared/*.cc")
|
||||
|
@ -25,7 +25,6 @@ include(pybind11)
|
|||
target_include_directories(extensions_pydll PRIVATE
|
||||
${pybind11_INCLUDE_DIRS}
|
||||
$<TARGET_PROPERTY:Python3::Module,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
$<TARGET_PROPERTY:Python3::NumPy,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
$<TARGET_PROPERTY:ocos_operators,INTERFACE_INCLUDE_DIRECTORIES>)
|
||||
|
||||
target_compile_definitions(extensions_pydll PRIVATE
|
||||
|
|
144
pyop/pyfunc.cc
144
pyop/pyfunc.cc
|
@ -8,7 +8,6 @@
|
|||
|
||||
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
|
||||
#define PY_ARRAY_UNIQUE_SYMBOL ocos_python_ARRAY_API
|
||||
#include <numpy/arrayobject.h>
|
||||
|
||||
#include <pybind11/iostream.h>
|
||||
#include <pybind11/pybind11.h>
|
||||
|
@ -43,42 +42,6 @@ const int PyCustomOpDef::dt_complex128 = ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX12
|
|||
// Non-IEEE floating-point format based on IEEE754 single-precision
|
||||
const int PyCustomOpDef::dt_bfloat16 = ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16;
|
||||
|
||||
static int to_numpy(ONNXTensorElementDataType dt) {
|
||||
switch (dt) {
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT:
|
||||
return NPY_FLOAT;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8:
|
||||
return NPY_UINT8;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8:
|
||||
return NPY_INT8;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16:
|
||||
return NPY_UINT16;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16:
|
||||
return NPY_INT16;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32:
|
||||
return NPY_INT32;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64:
|
||||
return NPY_INT64;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL:
|
||||
return NPY_BOOL;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16:
|
||||
return NPY_FLOAT16;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE:
|
||||
return NPY_DOUBLE;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32:
|
||||
return NPY_UINT32;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64:
|
||||
return NPY_UINT64;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX64:
|
||||
return NPY_COMPLEX64;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX128:
|
||||
return NPY_COMPLEX128;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING:
|
||||
return NPY_OBJECT;
|
||||
default:
|
||||
throw std::runtime_error("No corresponding Numpy data type/Tensor data Type.");
|
||||
}
|
||||
}
|
||||
|
||||
static size_t element_size(ONNXTensorElementDataType dt) {
|
||||
switch (dt) {
|
||||
|
@ -117,44 +80,6 @@ static size_t element_size(ONNXTensorElementDataType dt) {
|
|||
}
|
||||
}
|
||||
|
||||
static ONNXTensorElementDataType from_numpy(int dt) {
|
||||
switch (dt) {
|
||||
case NPY_FLOAT:
|
||||
return ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT;
|
||||
case NPY_UINT8:
|
||||
return ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8;
|
||||
case NPY_INT8:
|
||||
return ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8;
|
||||
case NPY_UINT16:
|
||||
return ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16;
|
||||
case NPY_INT16:
|
||||
return ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16;
|
||||
case NPY_INT32:
|
||||
return ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32;
|
||||
case NPY_INT64:
|
||||
return ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64;
|
||||
case NPY_BOOL:
|
||||
return ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL;
|
||||
case NPY_FLOAT16:
|
||||
return ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16;
|
||||
case NPY_DOUBLE:
|
||||
return ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE;
|
||||
case NPY_UINT32:
|
||||
return ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32;
|
||||
case NPY_UINT64:
|
||||
return ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64;
|
||||
case NPY_COMPLEX64:
|
||||
return ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX64;
|
||||
case NPY_COMPLEX128:
|
||||
return ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX128;
|
||||
case NPY_OBJECT:
|
||||
case NPY_STRING:
|
||||
return ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING;
|
||||
default:
|
||||
throw std::runtime_error("No corresponding ONNX data type/Tensor data Type.");
|
||||
}
|
||||
}
|
||||
|
||||
struct PyCustomOpDefImpl : public PyCustomOpDef {
|
||||
typedef std::vector<int64_t> shape_t;
|
||||
static int64_t calc_size_from_shape(const shape_t& sp) {
|
||||
|
@ -165,19 +90,66 @@ struct PyCustomOpDefImpl : public PyCustomOpDef {
|
|||
return c;
|
||||
}
|
||||
|
||||
static py::object BuildPyObjFromTensor(
|
||||
static py::object BuildPyArrayFromTensor(
|
||||
const OrtApi& api, OrtW::CustomOpApi& ort, OrtKernelContext* context, const OrtValue* value,
|
||||
const shape_t& shape, ONNXTensorElementDataType dtype) {
|
||||
std::vector<npy_intp> npy_dims;
|
||||
std::vector<std::size_t> npy_dims;
|
||||
for (auto n : shape) {
|
||||
npy_dims.push_back(n);
|
||||
}
|
||||
const int numpy_type = to_numpy(dtype);
|
||||
py::object obj = py::reinterpret_steal<py::object>(PyArray_SimpleNew(
|
||||
static_cast<int>(shape.size()), npy_dims.data(), numpy_type));
|
||||
void* out_ptr = static_cast<void*>(
|
||||
PyArray_DATA(reinterpret_cast<PyArrayObject*>(obj.ptr())));
|
||||
py::array obj;
|
||||
|
||||
switch (dtype) {
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING:
|
||||
obj = py::array(py::dtype("O"), npy_dims);
|
||||
break;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT:
|
||||
obj = py::array_t<float>(npy_dims);
|
||||
break;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8:
|
||||
obj = py::array_t<uint8_t>(npy_dims);
|
||||
break;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8:
|
||||
obj = py::array_t<int8_t>(npy_dims);
|
||||
break;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16:
|
||||
obj = py::array_t<uint16_t>(npy_dims);
|
||||
break;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16:
|
||||
obj = py::array_t<int16_t>(npy_dims);
|
||||
break;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32:
|
||||
obj = py::array_t<int32_t>(npy_dims);
|
||||
break;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64:
|
||||
obj = py::array_t<int64_t>(npy_dims);
|
||||
break;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL:
|
||||
obj = py::array_t<bool>(npy_dims);
|
||||
break;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16:
|
||||
throw std::runtime_error(MakeString(
|
||||
"Type float16 not supported by python customops api"));
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE:
|
||||
obj = py::array_t<double>(npy_dims);
|
||||
break;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32:
|
||||
obj = py::array_t<uint32_t>(npy_dims);
|
||||
break;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64:
|
||||
obj = py::array_t<uint64_t>(npy_dims);
|
||||
break;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX64:
|
||||
obj = py::array_t<std::complex<float>>(npy_dims);
|
||||
break;
|
||||
case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX128:
|
||||
obj = py::array_t<std::complex<double>>(npy_dims);
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error(MakeString("Unsupported ONNX Tensor type: ", dtype));
|
||||
}
|
||||
|
||||
void* out_ptr = obj.mutable_data();
|
||||
if (dtype == ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING) {
|
||||
py::object* outObj = static_cast<py::object*>(out_ptr);
|
||||
auto size = calc_size_from_shape(shape);
|
||||
|
@ -292,7 +264,7 @@ void PyCustomOpKernel::Compute(OrtKernelContext* context) {
|
|||
{
|
||||
py::list pyinputs;
|
||||
for (auto it = inputs.begin(); it != inputs.end(); ++it) {
|
||||
py::object input0 = PyCustomOpDefImpl::BuildPyObjFromTensor(
|
||||
py::object input0 = PyCustomOpDefImpl::BuildPyArrayFromTensor(
|
||||
api_, ort_, context, it->input_X, it->dimensions, it->dtype);
|
||||
pyinputs.append(input0);
|
||||
}
|
||||
|
@ -462,11 +434,6 @@ OrtStatusPtr RegisterPythonDomainAndOps(OrtSessionOptions* options, const OrtApi
|
|||
return status;
|
||||
}
|
||||
|
||||
static int init_numpy() {
|
||||
import_array1(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t hash_64(const std::string& str, uint64_t num_buckets, bool fast) {
|
||||
if (fast) {
|
||||
return Hash64Fast(str.c_str(), str.size()) % static_cast<uint64_t>(num_buckets);
|
||||
|
@ -514,7 +481,6 @@ void AddObjectMethods(pybind11::module& m) {
|
|||
PYBIND11_MODULE(_extensions_pydll, m) {
|
||||
m.doc() = "pybind11 stateful interface to ONNXRuntime-Extensions";
|
||||
|
||||
init_numpy();
|
||||
AddGlobalMethods(m);
|
||||
AddObjectMethods(m);
|
||||
auto atexit = py::module_::import("atexit");
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[build-system]
|
||||
# Minimum requirements for the build system to execute.
|
||||
requires = ["setuptools", "wheel", "numpy>=1.18.5", "ninja", "cmake"] # PEP 508 specifications.
|
||||
requires = ["setuptools", "wheel", "ninja", "cmake"] # PEP 508 specifications.
|
||||
build-backend = "backend"
|
||||
backend-path = [".pyproject"]
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import os
|
|||
import onnx
|
||||
import unittest
|
||||
import numpy as np
|
||||
from numpy.testing import assert_almost_equal
|
||||
from numpy.testing import assert_almost_equal, assert_array_equal
|
||||
from onnx import helper, onnx_pb as onnx_proto
|
||||
import onnxruntime as _ort
|
||||
from onnxruntime_extensions import (
|
||||
|
@ -72,11 +72,11 @@ def _create_test_model_2outputs(prefix, domain='ai.onnx.contrib'):
|
|||
]
|
||||
|
||||
input0 = helper.make_tensor_value_info(
|
||||
'x', onnx_proto.TensorProto.FLOAT, [])
|
||||
'x', onnx_proto.TensorProto.FLOAT, None)
|
||||
output1 = helper.make_tensor_value_info(
|
||||
'neg', onnx_proto.TensorProto.FLOAT, [])
|
||||
'neg', onnx_proto.TensorProto.FLOAT, None)
|
||||
output2 = helper.make_tensor_value_info(
|
||||
'pos', onnx_proto.TensorProto.FLOAT, [])
|
||||
'pos', onnx_proto.TensorProto.FLOAT, None)
|
||||
|
||||
graph = helper.make_graph(nodes, 'test0', [input0], [output1, output2])
|
||||
model = make_onnx_model(graph)
|
||||
|
@ -225,7 +225,7 @@ class TestPythonOp(unittest.TestCase):
|
|||
arr = np.array([["a", "b"]], dtype=object)
|
||||
txout = sess.run(None, {'input_1': arr})
|
||||
exp = np.array(["a;b"], dtype=object)
|
||||
assert txout[0][0] == exp[0]
|
||||
assert_array_equal(txout[0][0], exp[0])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
Загрузка…
Ссылка в новой задаче