From b88fb68fac3e6ce132c9cd2f9689ccb1afdf973e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Dupr=C3=A9?= Date: Tue, 22 Mar 2022 22:44:48 +0100 Subject: [PATCH] Adds missing numpy type when looking for the ort correspondance (#10943) --- .../python/onnxruntime_pybind_iobinding.cc | 4 +- .../python/onnxruntime_pybind_mlvalue.cc | 29 ++-------- .../python/onnxruntime_pybind_mlvalue.h | 4 +- .../python/onnxruntime_pybind_ortvalue.cc | 2 +- .../onnxruntime_pybind_sparse_tensor.cc | 6 +-- .../onnxruntime_test_python_iobinding.py | 54 +++++++++++++++++++ 6 files changed, 64 insertions(+), 35 deletions(-) diff --git a/onnxruntime/python/onnxruntime_pybind_iobinding.cc b/onnxruntime/python/onnxruntime_pybind_iobinding.cc index 8d25292a82..50061ff71a 100644 --- a/onnxruntime/python/onnxruntime_pybind_iobinding.cc +++ b/onnxruntime/python/onnxruntime_pybind_iobinding.cc @@ -71,7 +71,7 @@ void addIoBindingMethods(pybind11::module& m) { Py_DECREF(dtype); OrtMemoryInfo info(GetDeviceName(device), OrtDeviceAllocator, device, device.Id()); - auto ml_type = NumpyTypeToOnnxRuntimeType(type_num); + auto ml_type = NumpyTypeToOnnxRuntimeTensorType(type_num); OrtValue ml_value; Tensor::InitOrtValue(ml_type, gsl::make_span(shape), reinterpret_cast(data_ptr), info, ml_value); @@ -124,7 +124,7 @@ void addIoBindingMethods(pybind11::module& m) { Py_DECREF(dtype); OrtMemoryInfo info(GetDeviceName(device), OrtDeviceAllocator, device, device.Id()); - auto ml_type = NumpyTypeToOnnxRuntimeType(type_num); + auto ml_type = NumpyTypeToOnnxRuntimeTensorType(type_num); OrtValue ml_value; Tensor::InitOrtValue(ml_type, gsl::make_span(shape), reinterpret_cast(data_ptr), info, ml_value); diff --git a/onnxruntime/python/onnxruntime_pybind_mlvalue.cc b/onnxruntime/python/onnxruntime_pybind_mlvalue.cc index 480fdcef04..6a9b44cad0 100644 --- a/onnxruntime/python/onnxruntime_pybind_mlvalue.cc +++ b/onnxruntime/python/onnxruntime_pybind_mlvalue.cc @@ -236,30 +236,7 @@ int OnnxRuntimeTensorToNumpyType(const DataTypeImpl* tensor_type) { } } -MLDataType NumpyTypeToOnnxRuntimeType(int numpy_type) { - static std::map type_map{ - {NPY_BOOL, DataTypeImpl::GetType()}, - {NPY_FLOAT, DataTypeImpl::GetType()}, - {NPY_FLOAT16, DataTypeImpl::GetType()}, - {NPY_DOUBLE, DataTypeImpl::GetType()}, - {NPY_INT8, DataTypeImpl::GetType()}, - {NPY_UINT8, DataTypeImpl::GetType()}, - {NPY_INT16, DataTypeImpl::GetType()}, - {NPY_UINT16, DataTypeImpl::GetType()}, - {NPY_INT, DataTypeImpl::GetType()}, - {NPY_UINT, DataTypeImpl::GetType()}, - {NPY_LONGLONG, DataTypeImpl::GetType()}, - {NPY_ULONGLONG, DataTypeImpl::GetType()}, - {NPY_OBJECT, DataTypeImpl::GetType()}}; - const auto it = type_map.find(numpy_type); - if (it == type_map.end()) { - throw std::runtime_error("No corresponding Numpy type for Tensor Type."); - } else { - return it->second; - } -} - -MLDataType NumpyToOnnxRuntimeTensorType(int numpy_type) { +MLDataType NumpyTypeToOnnxRuntimeTensorType(int numpy_type) { static std::map type_map{ {NPY_BOOL, DataTypeImpl::GetType()}, {NPY_FLOAT, DataTypeImpl::GetType()}, @@ -452,7 +429,7 @@ static std::unique_ptr CreateTensor(const AllocatorPtr& alloc, const std const int npy_type = PyArray_TYPE(darray); TensorShape shape = GetArrayShape(darray); - auto element_type = NumpyToOnnxRuntimeTensorType(npy_type); + auto element_type = NumpyTypeToOnnxRuntimeTensorType(npy_type); if (IsNumericNumpyType(npy_type) && use_numpy_data_memory) { if (pyObject == darray) { // Use the memory of numpy array directly. The ownership belongs to the calling @@ -544,7 +521,7 @@ static void CreateTensorMLValue(const AllocatorPtr& alloc, const std::string& na static void CreateTensorMLValueOwned(const OrtPybindSingleUseAllocatorPtr& pybind_alloc, const AllocatorPtr& alloc, OrtValue* p_mlvalue) { auto npy_type = PyArray_TYPE(pybind_alloc->GetContiguous()); TensorShape shape = GetArrayShape(pybind_alloc->GetContiguous()); - auto element_type = NumpyToOnnxRuntimeTensorType(npy_type); + auto element_type = NumpyTypeToOnnxRuntimeTensorType(npy_type); std::unique_ptr p_tensor; diff --git a/onnxruntime/python/onnxruntime_pybind_mlvalue.h b/onnxruntime/python/onnxruntime_pybind_mlvalue.h index d253dfdcb1..4c27ee026a 100644 --- a/onnxruntime/python/onnxruntime_pybind_mlvalue.h +++ b/onnxruntime/python/onnxruntime_pybind_mlvalue.h @@ -35,9 +35,7 @@ TensorShape GetShape(const pybind11::array& arr); int OnnxRuntimeTensorToNumpyType(const DataTypeImpl* tensor_type); -MLDataType NumpyTypeToOnnxRuntimeType(int numpy_type); - -MLDataType NumpyToOnnxRuntimeTensorType(int numpy_type); +MLDataType NumpyTypeToOnnxRuntimeTensorType(int numpy_type); using MemCpyFunc = void (*)(void*, const void*, size_t); diff --git a/onnxruntime/python/onnxruntime_pybind_ortvalue.cc b/onnxruntime/python/onnxruntime_pybind_ortvalue.cc index 8d3829ddad..510a3b7598 100644 --- a/onnxruntime/python/onnxruntime_pybind_ortvalue.cc +++ b/onnxruntime/python/onnxruntime_pybind_ortvalue.cc @@ -152,7 +152,7 @@ void addOrtValueMethods(pybind11::module& m) { } auto ml_value = std::make_unique(); - auto ml_type = NumpyTypeToOnnxRuntimeType(type_num); + auto ml_type = NumpyTypeToOnnxRuntimeTensorType(type_num); Tensor::InitOrtValue(ml_type, gsl::make_span(shape), std::move(allocator), *ml_value); return ml_value; }) diff --git a/onnxruntime/python/onnxruntime_pybind_sparse_tensor.cc b/onnxruntime/python/onnxruntime_pybind_sparse_tensor.cc index 5e2839ed5f..801817444a 100644 --- a/onnxruntime/python/onnxruntime_pybind_sparse_tensor.cc +++ b/onnxruntime/python/onnxruntime_pybind_sparse_tensor.cc @@ -140,7 +140,7 @@ void addSparseTensorMethods(pybind11::module& m) { TensorShape dense_shape(py_dense_shape); auto values_type = GetNumpyArrayType(py_values); - auto ml_type = NumpyToOnnxRuntimeTensorType(values_type); + auto ml_type = NumpyTypeToOnnxRuntimeTensorType(values_type); std::unique_ptr result; if (IsNumericNumpyType(values_type)) { @@ -199,7 +199,7 @@ void addSparseTensorMethods(pybind11::module& m) { TensorShape dense_shape(py_dense_shape); auto values_type = GetNumpyArrayType(py_values); - auto ml_type = NumpyToOnnxRuntimeTensorType(values_type); + auto ml_type = NumpyTypeToOnnxRuntimeTensorType(values_type); std::unique_ptr result; if (IsNumericNumpyType(values_type)) { @@ -262,7 +262,7 @@ void addSparseTensorMethods(pybind11::module& m) { TensorShape values_shape = GetShape(py_values); TensorShape index_shape = GetShape(py_indices); auto values_type = GetNumpyArrayType(py_values); - auto ml_type = NumpyToOnnxRuntimeTensorType(values_type); + auto ml_type = NumpyTypeToOnnxRuntimeTensorType(values_type); std::unique_ptr result; if (IsNumericNumpyType(values_type)) { diff --git a/onnxruntime/test/python/onnxruntime_test_python_iobinding.py b/onnxruntime/test/python/onnxruntime_test_python_iobinding.py index 4d2660c053..03a9399ac1 100644 --- a/onnxruntime/test/python/onnxruntime_test_python_iobinding.py +++ b/onnxruntime/test/python/onnxruntime_test_python_iobinding.py @@ -1,5 +1,11 @@ import numpy as np +from numpy.testing import assert_almost_equal +from onnx.mapping import NP_TYPE_TO_TENSOR_TYPE +from onnx.defs import onnx_opset_version +from onnx import helper import onnxruntime as onnxrt +from onnxruntime.capi._pybind_state import ( # pylint: disable=E0611 + OrtDevice as C_OrtDevice, OrtValue as C_OrtValue, SessionIOBinding) import unittest from helper import get_name @@ -48,6 +54,54 @@ class TestIOBinding(unittest.TestCase): # Validate results self.assertTrue(np.array_equal(self.create_expected_output(), ort_output)) + def test_bind_input_types(self): + + opset = onnx_opset_version() + devices = [(C_OrtDevice(C_OrtDevice.cpu(), C_OrtDevice.default_memory(), 0), ['CPUExecutionProvider'])] + if "CUDAExecutionProvider" in onnxrt.get_all_providers(): + devices.append((C_OrtDevice(C_OrtDevice.cuda(), C_OrtDevice.default_memory(), 0), ['CUDAExecutionProvider'])) + + for device, provider in devices: + for dtype in [np.float32, np.float64, np.int32, np.uint32, + np.int64, np.uint64, np.int16, np.uint16, + np.int8, np.uint8, np.float16, np.bool_]: + with self.subTest(dtype=dtype, device=str(device)): + + x = np.arange(8).reshape((-1, 2)).astype(dtype) + proto_dtype = NP_TYPE_TO_TENSOR_TYPE[x.dtype] + + X = helper.make_tensor_value_info('X', proto_dtype, [None, x.shape[1]]) + Y = helper.make_tensor_value_info('Y', proto_dtype, [None, x.shape[1]]) + + # inference + node_add = helper.make_node('Identity', ['X'], ['Y']) + + # graph + graph_def = helper.make_graph([node_add], 'lr', [X], [Y], []) + model_def = helper.make_model( + graph_def, producer_name='dummy', ir_version=7, + producer_version="0", + opset_imports=[helper.make_operatorsetid('', opset)]) + + sess = onnxrt.InferenceSession(model_def.SerializeToString(), providers=provider) + + bind = SessionIOBinding(sess._sess) + ort_value = C_OrtValue.ortvalue_from_numpy(x, device) + bind.bind_ortvalue_input('X', ort_value) + bind.bind_output('Y', device) + sess._sess.run_with_iobinding(bind, None) + ortvalue = bind.get_outputs()[0] + y = ortvalue.numpy() + assert_almost_equal(x, y) + + bind = SessionIOBinding(sess._sess) + bind.bind_input('X', device, dtype, x.shape, ort_value.data_ptr()) + bind.bind_output('Y', device) + sess._sess.run_with_iobinding(bind, None) + ortvalue = bind.get_outputs()[0] + y = ortvalue.numpy() + assert_almost_equal(x, y) + def test_bind_input_only(self): input = self.create_ortvalue_input_on_gpu()