diff --git a/onnxruntime/python/onnxruntime_pybind_ortvalue.cc b/onnxruntime/python/onnxruntime_pybind_ortvalue.cc index 8388558bd1ec..a4e7523ecf1f 100644 --- a/onnxruntime/python/onnxruntime_pybind_ortvalue.cc +++ b/onnxruntime/python/onnxruntime_pybind_ortvalue.cc @@ -51,19 +51,19 @@ void addOrtValueMethods(pybind11::module& m) { // TODO: Add check to ensure that string arrays are not passed - we currently don't support string tensors in CUDA CreateGenericMLValue(nullptr, GetCudaAllocator(device.Id()), "", array_on_cpu, ml_value.get(), true, false, CpuToCudaMemCpy); #elif USE_ROCM - if (!IsRocmDeviceIdValid(logging::LoggingManager::DefaultLogger(), device.Id())) { - throw std::runtime_error("The provided device id doesn't match any available GPUs on the machine."); - } + if (!IsRocmDeviceIdValid(logging::LoggingManager::DefaultLogger(), device.Id())) { + throw std::runtime_error("The provided device id doesn't match any available GPUs on the machine."); + } - // InputDeflist is null because OrtValue creation is not tied to a specific model - // Likewise, there is no need to specify the name (as the name was previously used to lookup the def list) - // TODO: Add check to ensure that string arrays are not passed - we currently don't support string tensors in CUDA - CreateGenericMLValue(nullptr, GetRocmAllocator(device.Id()), "", array_on_cpu, ml_value.get(), true, false, CpuToRocmMemCpy); + // InputDeflist is null because OrtValue creation is not tied to a specific model + // Likewise, there is no need to specify the name (as the name was previously used to lookup the def list) + // TODO: Add check to ensure that string arrays are not passed - we currently don't support string tensors in CUDA + CreateGenericMLValue(nullptr, GetRocmAllocator(device.Id()), "", array_on_cpu, ml_value.get(), true, false, CpuToRocmMemCpy); #else - throw std::runtime_error( - "Can't allocate memory on the CUDA device using this package of OnnxRuntime. " - "Please use the CUDA package of OnnxRuntime to use this feature."); + throw std::runtime_error( + "Can't allocate memory on the CUDA device using this package of OnnxRuntime. " + "Please use the CUDA package of OnnxRuntime to use this feature."); #endif } else { throw std::runtime_error("Unsupported device: Cannot place the OrtValue on this device"); @@ -97,9 +97,9 @@ void addOrtValueMethods(pybind11::module& m) { } allocator = GetCudaAllocator(device.Id()); #else - throw std::runtime_error( - "Can't allocate memory on the CUDA device using this package of OnnxRuntime. " - "Please use the CUDA package of OnnxRuntime to use this feature."); + throw std::runtime_error( + "Can't allocate memory on the CUDA device using this package of OnnxRuntime. " + "Please use the CUDA package of OnnxRuntime to use this feature."); #endif } else { throw std::runtime_error("Unsupported device: Cannot place the OrtValue on this device"); @@ -111,6 +111,7 @@ void addOrtValueMethods(pybind11::module& m) { return ml_value; }) +#if !defined(DISABLE_SPARSE_TENSORS) .def_static("ort_value_from_sparse_tensor", [](const PySparseTensor* py_sparse_tensor) -> std::unique_ptr { return py_sparse_tensor->AsOrtValue(); }) @@ -121,6 +122,7 @@ void addOrtValueMethods(pybind11::module& m) { } return std::make_unique(*ort_value); }) +#endif // Get a pointer to Tensor data .def("data_ptr", [](OrtValue* ml_value) -> int64_t { // TODO: Assumes that the OrtValue is a Tensor, make this generic to handle non-Tensors @@ -138,21 +140,31 @@ void addOrtValueMethods(pybind11::module& m) { .def("device_name", [](const OrtValue* ort_value) -> std::string { if (ort_value->IsTensor()) { return std::string(GetDeviceName(ort_value->Get().Location().device)); - } else if (ort_value->IsSparseTensor()) { + } +#if !defined(DISABLE_SPARSE_TENSORS) + else if (ort_value->IsSparseTensor()) { return std::string(GetDeviceName(ort_value->Get().Location().device)); - } else { - ORT_THROW("Only OrtValues that are Tensors/SparseTensors are currently supported"); } + + ORT_THROW("Only OrtValues that are Tensors/SparseTensors are currently supported"); +#else + ORT_THROW("Only OrtValues that are Tensors are supported in this build"); +#endif }) .def("shape", [](const OrtValue* ort_value) -> py::list { + py::list shape_arr; +#if !defined(DISABLE_SPARSE_TENSORS) // OrtValue can only be a Tensor/SparseTensor, make this generic to handle non-Tensors ORT_ENFORCE(ort_value->IsTensor() || ort_value->IsSparseTensor(), "Only OrtValues that are Tensors/SpareTensors are currently supported"); - py::list shape_arr; const auto& dims = (ort_value->IsTensor()) ? ort_value->Get().Shape().GetDims() : ort_value->Get().DenseShape().GetDims(); +#else + ORT_ENFORCE(ort_value->IsTensor(), "Only OrtValues that are Tensors are supported in this build"); + const auto& dims = ort_value->Get().Shape().GetDims(); +#endif for (auto dim : dims) { // For sequence tensors - we would append a list of dims to the outermost list @@ -168,9 +180,11 @@ void addOrtValueMethods(pybind11::module& m) { if (ort_value->IsTensor()) { auto elem_type = ort_value->Get().GetElementType(); type_proto = DataTypeImpl::TensorTypeFromONNXEnum(elem_type)->GetTypeProto(); +#if !defined(DISABLE_SPARSE_TENSORS) } else if (ort_value->IsSparseTensor()) { auto elem_type = ort_value->Get().GetElementType(); type_proto = DataTypeImpl::SparseTensorTypeFromONNXEnum(elem_type)->GetTypeProto(); +#endif } else if (ort_value->IsTensorSequence()) { auto elem_type = ort_value->Get().DataType()->AsPrimitiveDataType()->GetDataType(); type_proto = DataTypeImpl::SequenceTensorTypeFromONNXEnum(elem_type)->GetTypeProto(); @@ -204,9 +218,9 @@ void addOrtValueMethods(pybind11::module& m) { #ifdef USE_CUDA GetPyObjFromTensor(ml_value->Get(), obj, nullptr, GetCudaToHostMemCpyFunction()); #elif USE_ROCM - GetPyObjFromTensor(ml_value->Get(), obj, nullptr, GetRocmToHostMemCpyFunction()); + GetPyObjFromTensor(ml_value->Get(), obj, nullptr, GetRocmToHostMemCpyFunction()); #else - GetPyObjFromTensor(ml_value->Get(), obj, nullptr, nullptr); + GetPyObjFromTensor(ml_value->Get(), obj, nullptr, nullptr); #endif return obj; }) diff --git a/onnxruntime/python/onnxruntime_pybind_sparse_tensor.cc b/onnxruntime/python/onnxruntime_pybind_sparse_tensor.cc index 138e7f69df7d..f8f51d257d5b 100644 --- a/onnxruntime/python/onnxruntime_pybind_sparse_tensor.cc +++ b/onnxruntime/python/onnxruntime_pybind_sparse_tensor.cc @@ -28,6 +28,8 @@ namespace python { namespace py = pybind11; using namespace onnxruntime::logging; +#if !defined(DISABLE_SPARSE_TENSORS) + namespace { // Create a pybind11:dtype numpy instance using ONNX Tensor Element Type template @@ -79,13 +81,17 @@ class PySparseBlockSparseView : public SparseTensor::BlockSparseView { : SparseTensor::BlockSparseView(view), parent_(parent) {} }; +#endif // !defined(DISABLE_SPARSE_TENSORS) + void addSparseTensorMethods(pybind11::module& m) { + // this is exported via __init__.py so has to exist py::enum_(m, "OrtSparseFormat") .value("ORT_SPARSE_UNDEFINED", OrtSparseFormat::ORT_SPARSE_UNDEFINED) .value("ORT_SPARSE_COO", OrtSparseFormat::ORT_SPARSE_COO) .value("ORT_SPARSE_CSRC", OrtSparseFormat::ORT_SPARSE_CSRC) .value("ORT_SPARSE_BLOCK_SPARSE", OrtSparseFormat::ORT_SPARSE_BLOCK_SPARSE); +#if !defined(DISABLE_SPARSE_TENSORS) py::class_(m, "SparseCooView") // Returns a numpy array of COO indices backed by Sparse Tensor memory // be aware that indices may reside on GPU if Sparse Tensor is on GPU @@ -111,59 +117,63 @@ void addSparseTensorMethods(pybind11::module& m) { }); py::class_ sparse_bind(m, "SparseTensor"); - // Factory method to create a COO Sparse Tensor from numpy arrays acting as backing storage. - // Numeric arrays memory is used as is with reference count increment. All other supported - // types are copied and supported only on CPU. - // Use numpy.ascontiguousarray() to obtain contiguous array of values and indices if necessary - // py_dense_shape - numpy dense shape of the sparse tensor - // py_values - contiguous and homogeneous numpy array of values - // py_indices - contiguous numpy array of int64_t indices - // ort_device - where the value and indices buffers are allocated. For non-primitive types, - // only cpu device is supported. There is not a way to verify that ort_device - // accurately describes the memory that is backing values and indices. - sparse_bind - .def_static("sparse_coo_from_numpy", [](const std::vector& py_dense_shape, const py::array& py_values, const py::array_t& py_indices, const OrtDevice& ort_device) -> std::unique_ptr { - if (1 != py_values.ndim()) { - ORT_THROW("Expecting values 1-D numpy values array for COO format. Got dims: ", py_values.ndim()); - } - - TensorShape dense_shape(py_dense_shape); - auto values_type = GetNumpyArrayType(py_values); - auto ml_type = NumpyToOnnxRuntimeTensorType(values_type); - - std::unique_ptr result; - if (IsNumericNumpyType(values_type)) { - if (!PyArray_ISCONTIGUOUS(reinterpret_cast(py_values.ptr()))) { - throw std::runtime_error("Require contiguous numpy array of values"); - } - - if (!PyArray_ISCONTIGUOUS(reinterpret_cast(py_indices.ptr()))) { - throw std::runtime_error("Require contiguous numpy array of indices"); - } - - // create references to make sure storage does not disappear - std::vector reference_holders = {py_values, py_indices}; - OrtMemoryInfo mem_info = GetMemoryInfoPerDeviceType(ort_device); - TensorShape values_shape{py_values.size()}; - auto sparse_tensor = std::make_unique(ml_type, dense_shape, values_shape, - const_cast(py_values.data()), mem_info); - auto index_span = gsl::make_span(const_cast(py_indices.data()), py_indices.size()); - ORT_THROW_IF_ERROR(sparse_tensor->UseCooIndices(index_span)); - result = std::make_unique(std::move(sparse_tensor), std::move(reference_holders)); - } else if (values_type == NPY_UNICODE || values_type == NPY_STRING) { - if (ort_device.Type() != OrtDevice::CPU) { - throw std::runtime_error("Only CPU based devices are supported for non-numeric datatypes"); - } - auto sparse_tensor = std::make_unique(ml_type, dense_shape, GetAllocator()); - auto mutator = sparse_tensor->MakeCooData(py_values.size(), py_indices.size()); - CopyDataToTensor(py_values, values_type, mutator.Values()); - CopyDataToTensor(py_indices, GetNumpyArrayType(py_indices), mutator.Indices()); - result = std::make_unique(std::move(sparse_tensor)); - } else { - ORT_THROW("Unsupported values data type: ", values_type); - } - return result; - }) + // Factory method to create a COO Sparse Tensor from numpy arrays acting as backing storage. + // Numeric arrays memory is used as is with reference count increment. All other supported + // types are copied and supported only on CPU. + // Use numpy.ascontiguousarray() to obtain contiguous array of values and indices if necessary + // py_dense_shape - numpy dense shape of the sparse tensor + // py_values - contiguous and homogeneous numpy array of values + // py_indices - contiguous numpy array of int64_t indices + // ort_device - where the value and indices buffers are allocated. For non-primitive types, + // only cpu device is supported. There is not a way to verify that ort_device + // accurately describes the memory that is backing values and indices. + sparse_bind + .def_static("sparse_coo_from_numpy", + [](const std::vector& py_dense_shape, + const py::array& py_values, + const py::array_t& py_indices, + const OrtDevice& ort_device) -> std::unique_ptr { + if (1 != py_values.ndim()) { + ORT_THROW("Expecting values 1-D numpy values array for COO format. Got dims: ", py_values.ndim()); + } + + TensorShape dense_shape(py_dense_shape); + auto values_type = GetNumpyArrayType(py_values); + auto ml_type = NumpyToOnnxRuntimeTensorType(values_type); + + std::unique_ptr result; + if (IsNumericNumpyType(values_type)) { + if (!PyArray_ISCONTIGUOUS(reinterpret_cast(py_values.ptr()))) { + throw std::runtime_error("Require contiguous numpy array of values"); + } + + if (!PyArray_ISCONTIGUOUS(reinterpret_cast(py_indices.ptr()))) { + throw std::runtime_error("Require contiguous numpy array of indices"); + } + + // create references to make sure storage does not disappear + std::vector reference_holders = {py_values, py_indices}; + OrtMemoryInfo mem_info = GetMemoryInfoPerDeviceType(ort_device); + TensorShape values_shape{py_values.size()}; + auto sparse_tensor = std::make_unique(ml_type, dense_shape, values_shape, + const_cast(py_values.data()), mem_info); + auto index_span = gsl::make_span(const_cast(py_indices.data()), py_indices.size()); + ORT_THROW_IF_ERROR(sparse_tensor->UseCooIndices(index_span)); + result = std::make_unique(std::move(sparse_tensor), std::move(reference_holders)); + } else if (values_type == NPY_UNICODE || values_type == NPY_STRING) { + if (ort_device.Type() != OrtDevice::CPU) { + throw std::runtime_error("Only CPU based devices are supported for non-numeric datatypes"); + } + auto sparse_tensor = std::make_unique(ml_type, dense_shape, GetAllocator()); + auto mutator = sparse_tensor->MakeCooData(py_values.size(), py_indices.size()); + CopyDataToTensor(py_values, values_type, mutator.Values()); + CopyDataToTensor(py_indices, GetNumpyArrayType(py_indices), mutator.Indices()); + result = std::make_unique(std::move(sparse_tensor)); + } else { + ORT_THROW("Unsupported values data type: ", values_type); + } + return result; + }) // Factory method to create a CSR Sparse Tensor from numpy arrays acting as backing storage. // Numeric arrays memory is used as is with reference count increment. All other supported // types are copied and supported only on CPU. @@ -175,55 +185,61 @@ void addSparseTensorMethods(pybind11::module& m) { // ort_device - where the value and indices buffers are allocated. For non-primitive types, // only cpu device is supported. There is not a way to verify that ort_device // accurately describes the memory that is backing values and indices. - .def_static("sparse_csr_from_numpy", [](const std::vector& py_dense_shape, const py::array& py_values, const py::array_t& py_inner_indices, const py::array_t& py_outer_indices, const OrtDevice& ort_device) -> std::unique_ptr { - if (1 != py_values.ndim() || 1 != py_inner_indices.ndim() || 1 != py_outer_indices.ndim()) { - ORT_THROW("Expecting all data to be 1-D numpy arrays for CSR format."); - } - - TensorShape dense_shape(py_dense_shape); - auto values_type = GetNumpyArrayType(py_values); - auto ml_type = NumpyToOnnxRuntimeTensorType(values_type); - - std::unique_ptr result; - if (IsNumericNumpyType(values_type)) { - if (!PyArray_ISCONTIGUOUS(reinterpret_cast(py_values.ptr()))) { - throw std::runtime_error("Require contiguous numpy array of values"); - } - - if (!PyArray_ISCONTIGUOUS(reinterpret_cast(py_inner_indices.ptr()))) { - throw std::runtime_error("Require contiguous numpy array of indices"); - } - - if (!PyArray_ISCONTIGUOUS(reinterpret_cast(py_outer_indices.ptr()))) { - throw std::runtime_error("Require contiguous numpy array of indices"); - } - - // go ahead and create references to make sure storage does not disappear - std::vector reference_holders = {py_values, py_inner_indices, py_outer_indices}; - OrtMemoryInfo mem_info = GetMemoryInfoPerDeviceType(ort_device); - TensorShape values_shape{py_values.size()}; - auto sparse_tensor = std::make_unique(ml_type, dense_shape, values_shape, - const_cast(py_values.data()), mem_info); - auto inner_span = gsl::make_span(const_cast(py_inner_indices.data()), py_inner_indices.size()); - auto outer_span = gsl::make_span(const_cast(py_outer_indices.data()), py_outer_indices.size()); - ORT_THROW_IF_ERROR(sparse_tensor->UseCsrIndices(inner_span, outer_span)); - result = std::make_unique(std::move(sparse_tensor), std::move(reference_holders)); - } else if (values_type == NPY_UNICODE || values_type == NPY_STRING) { - if (ort_device.Type() != OrtDevice::CPU) { - throw std::runtime_error("Only CPU based devices are supported for non-numeric datatypes"); - } - auto sparse_tensor = std::make_unique(ml_type, dense_shape, GetAllocator()); - auto mutator = sparse_tensor->MakeCsrData(py_values.size(), py_inner_indices.size(), py_outer_indices.size()); - CopyDataToTensor(py_values, values_type, mutator.Values()); - CopyDataToTensor(py_inner_indices, GetNumpyArrayType(py_inner_indices), mutator.Inner()); - CopyDataToTensor(py_outer_indices, GetNumpyArrayType(py_outer_indices), mutator.Outer()); - result = std::make_unique(std::move(sparse_tensor)); - } else { - ORT_THROW("Unsupported values data type: ", values_type); - } - - return result; - }) + .def_static( + "sparse_csr_from_numpy", + [](const std::vector& py_dense_shape, + const py::array& py_values, + const py::array_t& py_inner_indices, + const py::array_t& py_outer_indices, + const OrtDevice& ort_device) -> std::unique_ptr { + if (1 != py_values.ndim() || 1 != py_inner_indices.ndim() || 1 != py_outer_indices.ndim()) { + ORT_THROW("Expecting all data to be 1-D numpy arrays for CSR format."); + } + + TensorShape dense_shape(py_dense_shape); + auto values_type = GetNumpyArrayType(py_values); + auto ml_type = NumpyToOnnxRuntimeTensorType(values_type); + + std::unique_ptr result; + if (IsNumericNumpyType(values_type)) { + if (!PyArray_ISCONTIGUOUS(reinterpret_cast(py_values.ptr()))) { + throw std::runtime_error("Require contiguous numpy array of values"); + } + + if (!PyArray_ISCONTIGUOUS(reinterpret_cast(py_inner_indices.ptr()))) { + throw std::runtime_error("Require contiguous numpy array of indices"); + } + + if (!PyArray_ISCONTIGUOUS(reinterpret_cast(py_outer_indices.ptr()))) { + throw std::runtime_error("Require contiguous numpy array of indices"); + } + + // go ahead and create references to make sure storage does not disappear + std::vector reference_holders = {py_values, py_inner_indices, py_outer_indices}; + OrtMemoryInfo mem_info = GetMemoryInfoPerDeviceType(ort_device); + TensorShape values_shape{py_values.size()}; + auto sparse_tensor = std::make_unique(ml_type, dense_shape, values_shape, + const_cast(py_values.data()), mem_info); + auto inner_span = gsl::make_span(const_cast(py_inner_indices.data()), py_inner_indices.size()); + auto outer_span = gsl::make_span(const_cast(py_outer_indices.data()), py_outer_indices.size()); + ORT_THROW_IF_ERROR(sparse_tensor->UseCsrIndices(inner_span, outer_span)); + result = std::make_unique(std::move(sparse_tensor), std::move(reference_holders)); + } else if (values_type == NPY_UNICODE || values_type == NPY_STRING) { + if (ort_device.Type() != OrtDevice::CPU) { + throw std::runtime_error("Only CPU based devices are supported for non-numeric datatypes"); + } + auto sparse_tensor = std::make_unique(ml_type, dense_shape, GetAllocator()); + auto mutator = sparse_tensor->MakeCsrData(py_values.size(), py_inner_indices.size(), py_outer_indices.size()); + CopyDataToTensor(py_values, values_type, mutator.Values()); + CopyDataToTensor(py_inner_indices, GetNumpyArrayType(py_inner_indices), mutator.Inner()); + CopyDataToTensor(py_outer_indices, GetNumpyArrayType(py_outer_indices), mutator.Outer()); + result = std::make_unique(std::move(sparse_tensor)); + } else { + ORT_THROW("Unsupported values data type: ", values_type); + } + + return result; + }) // Factory method to create a BlockSparse Tensor from numpy arrays acting as backing storage. // Numeric arrays memory is used as is with reference count increment. All other supported // types are copied and supported only on CPU. @@ -235,44 +251,49 @@ void addSparseTensorMethods(pybind11::module& m) { // ort_device - where the value and indices buffers are allocated. For non-primitive types, // only cpu device is supported. There is not a way to verify that ort_device // accurately describes the memory that is backing values and indices. - .def_static("blocksparse_from_numpy", [](const std::vector& py_dense_shape, const py::array& py_values, const py::array_t& py_indices, const OrtDevice& ort_device) -> std::unique_ptr { - TensorShape dense_shape(py_dense_shape); - TensorShape values_shape = GetShape(py_values); - TensorShape index_shape = GetShape(py_indices); - auto values_type = GetNumpyArrayType(py_values); - auto ml_type = NumpyToOnnxRuntimeTensorType(values_type); - - std::unique_ptr result; - if (IsNumericNumpyType(values_type)) { - if (!PyArray_ISCONTIGUOUS(reinterpret_cast(py_values.ptr()))) { - throw std::runtime_error("Require contiguous numpy array of values"); - } - - if (!PyArray_ISCONTIGUOUS(reinterpret_cast(py_indices.ptr()))) { - throw std::runtime_error("Require contiguous numpy array of indices"); - } - - // create references to make sure storage does not disappear - std::vector reference_holders = {py_values, py_indices}; - OrtMemoryInfo mem_info = GetMemoryInfoPerDeviceType(ort_device); - auto sparse_tensor = std::make_unique(ml_type, dense_shape, values_shape, - const_cast(py_values.data()), mem_info); - ORT_THROW_IF_ERROR(sparse_tensor->UseBlockSparseIndices(index_shape, const_cast(py_indices.data()))); - result = std::make_unique(std::move(sparse_tensor), std::move(reference_holders)); - } else if (values_type == NPY_UNICODE || values_type == NPY_STRING) { - if (ort_device.Type() != OrtDevice::CPU) { - throw std::runtime_error("Only CPU based devices are supported for non-numeric datatypes"); - } - auto sparse_tensor = std::make_unique(ml_type, dense_shape, GetAllocator()); - auto mutator = sparse_tensor->MakeBlockSparseData(values_shape, index_shape); - CopyDataToTensor(py_values, values_type, mutator.Values()); - CopyDataToTensor(py_indices, GetNumpyArrayType(py_indices), mutator.Indices()); - result = std::make_unique(std::move(sparse_tensor)); - } else { - ORT_THROW("Unsupported values data type: ", values_type); - } - return result; - }) + .def_static( + "blocksparse_from_numpy", + [](const std::vector& py_dense_shape, + const py::array& py_values, + const py::array_t& py_indices, + const OrtDevice& ort_device) -> std::unique_ptr { + TensorShape dense_shape(py_dense_shape); + TensorShape values_shape = GetShape(py_values); + TensorShape index_shape = GetShape(py_indices); + auto values_type = GetNumpyArrayType(py_values); + auto ml_type = NumpyToOnnxRuntimeTensorType(values_type); + + std::unique_ptr result; + if (IsNumericNumpyType(values_type)) { + if (!PyArray_ISCONTIGUOUS(reinterpret_cast(py_values.ptr()))) { + throw std::runtime_error("Require contiguous numpy array of values"); + } + + if (!PyArray_ISCONTIGUOUS(reinterpret_cast(py_indices.ptr()))) { + throw std::runtime_error("Require contiguous numpy array of indices"); + } + + // create references to make sure storage does not disappear + std::vector reference_holders = {py_values, py_indices}; + OrtMemoryInfo mem_info = GetMemoryInfoPerDeviceType(ort_device); + auto sparse_tensor = std::make_unique(ml_type, dense_shape, values_shape, + const_cast(py_values.data()), mem_info); + ORT_THROW_IF_ERROR(sparse_tensor->UseBlockSparseIndices(index_shape, const_cast(py_indices.data()))); + result = std::make_unique(std::move(sparse_tensor), std::move(reference_holders)); + } else if (values_type == NPY_UNICODE || values_type == NPY_STRING) { + if (ort_device.Type() != OrtDevice::CPU) { + throw std::runtime_error("Only CPU based devices are supported for non-numeric datatypes"); + } + auto sparse_tensor = std::make_unique(ml_type, dense_shape, GetAllocator()); + auto mutator = sparse_tensor->MakeBlockSparseData(values_shape, index_shape); + CopyDataToTensor(py_values, values_type, mutator.Values()); + CopyDataToTensor(py_indices, GetNumpyArrayType(py_indices), mutator.Indices()); + result = std::make_unique(std::move(sparse_tensor)); + } else { + ORT_THROW("Unsupported values data type: ", values_type); + } + return result; + }) // Returns a numpy array that is backed by SparseTensor values memory // be aware that it may be on GPU .def("values", [](const PySparseTensor* py_tensor) -> py::array { @@ -352,7 +373,8 @@ void addSparseTensorMethods(pybind11::module& m) { } auto cuda_allocator = GetCudaAllocator(ort_device.Id()); auto gpu_transfer = GetGPUDataTransfer(); - auto dest_tensor = std::make_unique(sparse_tensor.DataType(), sparse_tensor.DenseShape(), std::move(cuda_allocator)); + auto dest_tensor = std::make_unique(sparse_tensor.DataType(), sparse_tensor.DenseShape(), + std::move(cuda_allocator)); ORT_THROW_IF_ERROR(sparse_tensor.Copy(*gpu_transfer, *dest_tensor, 0)); auto result = std::make_unique(std::move(dest_tensor)); return result; @@ -406,7 +428,8 @@ void addSparseTensorMethods(pybind11::module& m) { throw std::runtime_error("Can't switch on FormatFlags()"); } return retval; }, [](PySparseTensor*, OrtSparseFormat) -> void { throw std::runtime_error("This is a readonly property"); }); +#endif // !defined(DISABLED_SPARSE_TENSORS) } } // namespace python -} // namespace onnxruntime \ No newline at end of file +} // namespace onnxruntime diff --git a/onnxruntime/python/onnxruntime_pybind_state.cc b/onnxruntime/python/onnxruntime_pybind_state.cc index f7cc9d37c046..f4411def794e 100644 --- a/onnxruntime/python/onnxruntime_pybind_state.cc +++ b/onnxruntime/python/onnxruntime_pybind_state.cc @@ -135,7 +135,7 @@ void GetPyObjFromTensor(const Tensor& rtensor, py::object& obj, PyArray_DATA(reinterpret_cast(obj.ptr()))); if (numpy_type != NPY_OBJECT) { - //if it is not cpu tensor, need to copy to host + // if it is not cpu tensor, need to copy to host auto device_type = rtensor.Location().device.Type(); if (device_type != OrtDevice::CPU) { if (!data_transfer_manager && !mem_cpy_to_host_functions) @@ -190,6 +190,7 @@ const char* GetDeviceName(const OrtDevice& device) { } py::object GetPyObjectFromSparseTensor(size_t pos, const OrtValue& ort_value, const DataTransferManager* data_transfer_manager) { +#if !defined(DISABLE_SPARSE_TENSORS) if (!ort_value.IsSparseTensor()) { ORT_THROW("Must be a sparse tensor"); } @@ -215,6 +216,12 @@ py::object GetPyObjectFromSparseTensor(size_t pos, const OrtValue& ort_value, co py::object result = py::cast(py_sparse_tensor.get(), py::return_value_policy::take_ownership); py_sparse_tensor.release(); return result; +#else + ORT_UNUSED_PARAMETER(pos); + ORT_UNUSED_PARAMETER(ort_value); + ORT_UNUSED_PARAMETER(data_transfer_manager); + ORT_THROW("SparseTensor support is disabled in this build."); +#endif // !defined(DISABLE_SPARSE_TENSORS) } template <> @@ -324,13 +331,13 @@ const CUDAExecutionProviderInfo GetCudaExecutionProviderInfo(ProviderInfo_CUDA* #ifdef USE_ROCM const ROCMExecutionProviderInfo GetRocmExecutionProviderInfo(ProviderInfo_ROCM* rocm_provider_info, - const ProviderOptionsMap& provider_options_map){ + const ProviderOptionsMap& provider_options_map) { ORT_ENFORCE(rocm_provider_info); const auto it = provider_options_map.find(kRocmExecutionProvider); ROCMExecutionProviderInfo info; if (it != provider_options_map.end()) rocm_provider_info->ROCMExecutionProviderInfo__FromProviderOptions(it->second, info); - else{ + else { info.device_id = cuda_device_id; info.gpu_mem_limit = gpu_mem_limit; info.arena_extend_strategy = arena_extend_strategy; @@ -355,156 +362,156 @@ std::unique_ptr CreateExecutionProviderInstance( // If the environment variable 'ORT_TENSORRT_UNAVAILABLE' exists, then we do not load TensorRT. This is set by _ld_preload for the manylinux case // as in that case, trying to load the library itself will result in a crash due to the way that auditwheel strips dependencies. if (Env::Default().GetEnvironmentVar("ORT_TENSORRT_UNAVAILABLE").empty()) { - std::string calibration_table, cache_path, lib_path; - auto it = provider_options_map.find(type); - if (it != provider_options_map.end()) { - OrtTensorRTProviderOptions params{ - 0, - 0, - nullptr, - 1000, - 1, - 1 << 30, - 0, - 0, - nullptr, - 0, - 0, - 0, - 0, - 0, - nullptr, - 0, - nullptr, - 0}; - for (auto option : it->second) { - if (option.first == "device_id") { - if (!option.second.empty()) { - params.device_id = std::stoi(option.second); - } else { - ORT_THROW("[ERROR] [TensorRT] The value for the key 'device_id' should be a number i.e. '0'.\n"); - } - } else if (option.first == "trt_max_partition_iterations") { - if (!option.second.empty()) { - params.trt_max_partition_iterations = std::stoi(option.second); - } else { - ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_max_partition_iterations' should be a positive integer number i.e. '1000'.\n"); - } - } else if (option.first == "trt_min_subgraph_size") { - if (!option.second.empty()) { - params.trt_min_subgraph_size = std::stoi(option.second); - } else { - ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_min_subgraph_size' should be a positive integer number i.e. '1'.\n"); - } - } else if (option.first == "trt_max_workspace_size") { - if (!option.second.empty()) { - params.trt_max_workspace_size = std::stoull(option.second); - } else { - ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_max_workspace_size' should be a number in byte i.e. '1073741824'.\n"); - } - } else if (option.first == "trt_fp16_enable") { - if (option.second == "True" || option.second == "true") { - params.trt_fp16_enable = true; - } else if (option.second == "False" || option.second == "false") { - params.trt_fp16_enable = false; - } else { - ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_fp16_enable' should be a boolean i.e. 'True' or 'False'. Default value is False.\n"); - } - } else if (option.first == "trt_int8_enable") { - if (option.second == "True" || option.second == "true") { - params.trt_int8_enable = true; - } else if (option.second == "False" || option.second == "false") { - params.trt_int8_enable = false; - } else { - ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_int8_enable' should be a boolean i.e. 'True' or 'False'. Default value is False.\n"); - } - } else if (option.first == "trt_int8_calibration_table_name") { - if (!option.second.empty()) { - calibration_table = option.second; - params.trt_int8_calibration_table_name = calibration_table.c_str(); - } else { - ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_int8_calibration_table_name' should be a file name i.e. 'cal_table'.\n"); - } - } else if (option.first == "trt_int8_use_native_calibration_table") { - if (option.second == "True" || option.second == "true") { - params.trt_int8_use_native_calibration_table = true; - } else if (option.second == "False" || option.second == "false") { - params.trt_int8_use_native_calibration_table = false; - } else { - ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_int8_use_native_calibration_table' should be a boolean i.e. 'True' or 'False'. Default value is False.\n"); - } - } else if (option.first == "trt_dla_enable") { - if (option.second == "True" || option.second == "true") { - params.trt_dla_enable = true; - } else if (option.second == "False" || option.second == "false") { - params.trt_dla_enable = false; - } else { - ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_dla_enable' should be a boolean i.e. 'True' or 'False'. Default value is False.\n"); - } - } else if (option.first == "trt_dla_core") { - if (!option.second.empty()) { - params.trt_dla_core = std::stoi(option.second); - } else { - ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_dla_core' should be a positive integer number i.e. '0'.\n"); - } - } else if (option.first == "trt_dump_subgraphs") { - if (option.second == "True" || option.second == "true") { - params.trt_dump_subgraphs = true; - } else if (option.second == "False" || option.second == "false") { - params.trt_dump_subgraphs = false; - } else { - ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_dump_subgraphs' should be a boolean i.e. 'True' or 'False'. Default value is False.\n"); - } - } else if (option.first == "trt_engine_cache_enable") { - if (option.second == "True" || option.second == "true") { - params.trt_engine_cache_enable = true; - } else if (option.second == "False" || option.second == "false") { - params.trt_engine_cache_enable = false; - } else { - ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_engine_cache_enable' should be a boolean i.e. 'True' or 'False'. Default value is False.\n"); - } - } else if (option.first == "trt_engine_cache_path") { - if (!option.second.empty()) { - cache_path = option.second; - params.trt_engine_cache_path = cache_path.c_str(); - } else { - ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_engine_cache_path' should be a path string i.e. 'engine_cache'.\n"); - } - } else if (option.first == "trt_engine_decryption_enable") { - if (option.second == "True" || option.second == "true") { - params.trt_engine_decryption_enable = true; - } else if (option.second == "False" || option.second == "false") { - params.trt_engine_decryption_enable = false; - } else { - ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_engine_decryption_enable' should be a boolean i.e. 'True' or 'False'. Default value is False.\n"); - } - } else if (option.first == "trt_engine_decryption_lib_path") { - if (!option.second.empty()) { - lib_path = option.second; - params.trt_engine_decryption_lib_path = lib_path.c_str(); - } else { - ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_engine_decryption_lib_path' should be a path string i.e. 'decryption_lib'.\n"); - } - } else if (option.first == "trt_force_sequential_engine_build") { - if (option.second == "True" || option.second == "true") { - params.trt_force_sequential_engine_build = true; - } else if (option.second == "False" || option.second == "false") { - params.trt_force_sequential_engine_build = false; - } else { - ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_force_sequential_engine_build' should be a boolean i.e. 'True' or 'False'. Default value is False.\n"); - } + std::string calibration_table, cache_path, lib_path; + auto it = provider_options_map.find(type); + if (it != provider_options_map.end()) { + OrtTensorRTProviderOptions params{ + 0, + 0, + nullptr, + 1000, + 1, + 1 << 30, + 0, + 0, + nullptr, + 0, + 0, + 0, + 0, + 0, + nullptr, + 0, + nullptr, + 0}; + for (auto option : it->second) { + if (option.first == "device_id") { + if (!option.second.empty()) { + params.device_id = std::stoi(option.second); } else { - ORT_THROW("Invalid TensorRT EP option: ", option.first); + ORT_THROW("[ERROR] [TensorRT] The value for the key 'device_id' should be a number i.e. '0'.\n"); } + } else if (option.first == "trt_max_partition_iterations") { + if (!option.second.empty()) { + params.trt_max_partition_iterations = std::stoi(option.second); + } else { + ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_max_partition_iterations' should be a positive integer number i.e. '1000'.\n"); + } + } else if (option.first == "trt_min_subgraph_size") { + if (!option.second.empty()) { + params.trt_min_subgraph_size = std::stoi(option.second); + } else { + ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_min_subgraph_size' should be a positive integer number i.e. '1'.\n"); + } + } else if (option.first == "trt_max_workspace_size") { + if (!option.second.empty()) { + params.trt_max_workspace_size = std::stoull(option.second); + } else { + ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_max_workspace_size' should be a number in byte i.e. '1073741824'.\n"); + } + } else if (option.first == "trt_fp16_enable") { + if (option.second == "True" || option.second == "true") { + params.trt_fp16_enable = true; + } else if (option.second == "False" || option.second == "false") { + params.trt_fp16_enable = false; + } else { + ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_fp16_enable' should be a boolean i.e. 'True' or 'False'. Default value is False.\n"); + } + } else if (option.first == "trt_int8_enable") { + if (option.second == "True" || option.second == "true") { + params.trt_int8_enable = true; + } else if (option.second == "False" || option.second == "false") { + params.trt_int8_enable = false; + } else { + ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_int8_enable' should be a boolean i.e. 'True' or 'False'. Default value is False.\n"); + } + } else if (option.first == "trt_int8_calibration_table_name") { + if (!option.second.empty()) { + calibration_table = option.second; + params.trt_int8_calibration_table_name = calibration_table.c_str(); + } else { + ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_int8_calibration_table_name' should be a file name i.e. 'cal_table'.\n"); + } + } else if (option.first == "trt_int8_use_native_calibration_table") { + if (option.second == "True" || option.second == "true") { + params.trt_int8_use_native_calibration_table = true; + } else if (option.second == "False" || option.second == "false") { + params.trt_int8_use_native_calibration_table = false; + } else { + ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_int8_use_native_calibration_table' should be a boolean i.e. 'True' or 'False'. Default value is False.\n"); + } + } else if (option.first == "trt_dla_enable") { + if (option.second == "True" || option.second == "true") { + params.trt_dla_enable = true; + } else if (option.second == "False" || option.second == "false") { + params.trt_dla_enable = false; + } else { + ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_dla_enable' should be a boolean i.e. 'True' or 'False'. Default value is False.\n"); + } + } else if (option.first == "trt_dla_core") { + if (!option.second.empty()) { + params.trt_dla_core = std::stoi(option.second); + } else { + ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_dla_core' should be a positive integer number i.e. '0'.\n"); + } + } else if (option.first == "trt_dump_subgraphs") { + if (option.second == "True" || option.second == "true") { + params.trt_dump_subgraphs = true; + } else if (option.second == "False" || option.second == "false") { + params.trt_dump_subgraphs = false; + } else { + ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_dump_subgraphs' should be a boolean i.e. 'True' or 'False'. Default value is False.\n"); + } + } else if (option.first == "trt_engine_cache_enable") { + if (option.second == "True" || option.second == "true") { + params.trt_engine_cache_enable = true; + } else if (option.second == "False" || option.second == "false") { + params.trt_engine_cache_enable = false; + } else { + ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_engine_cache_enable' should be a boolean i.e. 'True' or 'False'. Default value is False.\n"); + } + } else if (option.first == "trt_engine_cache_path") { + if (!option.second.empty()) { + cache_path = option.second; + params.trt_engine_cache_path = cache_path.c_str(); + } else { + ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_engine_cache_path' should be a path string i.e. 'engine_cache'.\n"); + } + } else if (option.first == "trt_engine_decryption_enable") { + if (option.second == "True" || option.second == "true") { + params.trt_engine_decryption_enable = true; + } else if (option.second == "False" || option.second == "false") { + params.trt_engine_decryption_enable = false; + } else { + ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_engine_decryption_enable' should be a boolean i.e. 'True' or 'False'. Default value is False.\n"); + } + } else if (option.first == "trt_engine_decryption_lib_path") { + if (!option.second.empty()) { + lib_path = option.second; + params.trt_engine_decryption_lib_path = lib_path.c_str(); + } else { + ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_engine_decryption_lib_path' should be a path string i.e. 'decryption_lib'.\n"); + } + } else if (option.first == "trt_force_sequential_engine_build") { + if (option.second == "True" || option.second == "true") { + params.trt_force_sequential_engine_build = true; + } else if (option.second == "False" || option.second == "false") { + params.trt_force_sequential_engine_build = false; + } else { + ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_force_sequential_engine_build' should be a boolean i.e. 'True' or 'False'. Default value is False.\n"); + } + } else { + ORT_THROW("Invalid TensorRT EP option: ", option.first); } - if (std::shared_ptr tensorrt_provider_factory = onnxruntime::CreateExecutionProviderFactory_Tensorrt(¶ms)) { - return tensorrt_provider_factory->CreateProvider(); - } - } else { - if (std::shared_ptr tensorrt_provider_factory = onnxruntime::CreateExecutionProviderFactory_Tensorrt(cuda_device_id)) { - return tensorrt_provider_factory->CreateProvider(); - } } + if (std::shared_ptr tensorrt_provider_factory = onnxruntime::CreateExecutionProviderFactory_Tensorrt(¶ms)) { + return tensorrt_provider_factory->CreateProvider(); + } + } else { + if (std::shared_ptr tensorrt_provider_factory = onnxruntime::CreateExecutionProviderFactory_Tensorrt(cuda_device_id)) { + return tensorrt_provider_factory->CreateProvider(); + } + } } LOGS_DEFAULT(WARNING) << "Failed to create " << type << ". Please reference https://onnxruntime.ai/docs/execution-providers/TensorRT-ExecutionProvider.html#requirements to ensure all dependencies are met."; #endif @@ -536,20 +543,17 @@ std::unique_ptr CreateExecutionProviderInstance( #endif } else if (type == kRocmExecutionProvider) { #ifdef USE_ROCM - if(auto* rocm_provider_info = TryGetProviderInfo_ROCM()) - { + if (auto* rocm_provider_info = TryGetProviderInfo_ROCM()) { const ROCMExecutionProviderInfo info = GetRocmExecutionProviderInfo(rocm_provider_info, - provider_options_map); - + provider_options_map); + // This variable is never initialized because the APIs by which is it should be initialized are deprecated, however they still // exist are are in-use. Neverthless, it is used to return ROCMAllocator, hence we must try to initialize it here if we can // since FromProviderOptions might contain external ROCM allocator. external_allocator_info = info.external_allocator_info; return rocm_provider_info->CreateExecutionProviderFactory(info)->CreateProvider(); - } - else - { - if(!Env::Default().GetEnvironmentVar("ROCM_PATH").empty()) { + } else { + if (!Env::Default().GetEnvironmentVar("ROCM_PATH").empty()) { ORT_THROW("ROCM_PATH is set but ROCM wasn't able to be loaded. Please install the correct version of ROCM and MIOpen as mentioned in the GPU requirements page, make sure they're in the PATH, and that your GPU is supported."); } } @@ -597,14 +601,12 @@ std::unique_ptr CreateExecutionProviderInstance( } else if (option.first == "blob_dump_path") { blob_dump_path = option.second; params.blob_dump_path = blob_dump_path.c_str(); - } else if (option.first == "context") { - params.context = (void *)(option.second.c_str()); + } else if (option.first == "context") { + params.context = (void*)(option.second.c_str()); } else { ORT_THROW("Invalid OpenVINO EP option: ", option.first); } } - - } if (std::shared_ptr openvino_provider_factory = onnxruntime::CreateExecutionProviderFactory_OpenVINO(¶ms)) { auto p = openvino_provider_factory->CreateProvider(); @@ -1149,7 +1151,7 @@ Applies to session load, initialization, etc. Default is 0.)pbdoc") .def( "add_session_config_entry", [](PySessionOptions* options, const char* config_key, const char* config_value) -> void { - //config_key and config_value will be copied + // config_key and config_value will be copied const Status status = options->config_options.AddConfigEntry(config_key, config_value); if (!status.IsOK()) throw std::runtime_error(status.ErrorMessage()); diff --git a/onnxruntime/python/onnxruntime_pybind_state_common.cc b/onnxruntime/python/onnxruntime_pybind_state_common.cc index e9a81be84c3b..877be55fd810 100644 --- a/onnxruntime/python/onnxruntime_pybind_state_common.cc +++ b/onnxruntime/python/onnxruntime_pybind_state_common.cc @@ -80,6 +80,7 @@ OrtValue FromDlpack(PyObject* dlpack_tensor, const bool is_bool_tensor) { #endif +#if !defined(DISABLE_SPARSE_TENSORS) std::unique_ptr PySparseTensor::AsOrtValue() const { if (instance_) { auto ort_value = std::make_unique(); @@ -108,6 +109,7 @@ PySparseTensor::~PySparseTensor() { } } } +#endif // !defined(DISABLE_SPARSE_TENSORS) } // namespace python } // namespace onnxruntime diff --git a/onnxruntime/python/onnxruntime_pybind_state_common.h b/onnxruntime/python/onnxruntime_pybind_state_common.h index a55c3cb6648f..ca93b1d5980f 100644 --- a/onnxruntime/python/onnxruntime_pybind_state_common.h +++ b/onnxruntime/python/onnxruntime_pybind_state_common.h @@ -202,7 +202,7 @@ extern onnxruntime::ArenaExtendStrategy arena_extend_strategy; #include "core/providers/shared_library/provider_host_api.h" namespace onnxruntime { -#ifndef SHARED_PROVIDER +#if !defined(SHARED_PROVIDER) && !defined(DISABLE_SPARSE_TENSORS) class SparseTensor; #endif namespace python { @@ -307,6 +307,7 @@ inline AllocatorPtr& GetAllocator() { return alloc; } +#if !defined(DISABLE_SPARSE_TENSORS) // This class exposes SparseTensor to Python // The class serves two major purposes // - to be able to map numpy arrays memory and use it on input, this serves as a reference holder @@ -387,6 +388,7 @@ class PySparseTensor { // We create a copy of OrtValue when we obtain it from a run method. OrtValue ort_value_; }; +#endif // !defined(DISABLE_SPARSE_TENSORS) class SessionObjectInitializer { public: diff --git a/tools/ci_build/github/azure-pipelines/linux-cpu-minimal-build-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/linux-cpu-minimal-build-ci-pipeline.yml index fa17df1b270f..f53e688df37d 100644 --- a/tools/ci_build/github/azure-pipelines/linux-cpu-minimal-build-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/linux-cpu-minimal-build-ci-pipeline.yml @@ -14,6 +14,11 @@ # 5. Build baseline minimal ORT for Android arm64-v8a including no kernels and disable exceptions. # This step is to report the baseline binary size for Android. # 6. Build full (6a) and extended minimal (6b) ORT with runtime optimizations enabled. +# 7. Build with all optional features disabled and no kernels. +# 7a: regular build with python enabled checks that the exclusions don't break code paths in a full build. +# 7b: minimal build with exceptions and python disabled checks that the exclusions don't break code paths in a +# minimal build. + jobs: - job: Linux_CPU_Minimal_Build_E2E timeoutInMinutes: 120 @@ -35,6 +40,8 @@ jobs: script: | # Create a folder for all test data mkdir -p $(test_data_directory) + # create empty config used in some parts + touch $(test_data_directory)/include_no_operators.config workingDirectory: $(Build.SourcesDirectory) - template: templates/get-docker-image-steps.yml @@ -245,6 +252,70 @@ jobs: --cmake_extra_defines onnxruntime_ENABLE_ORT_FORMAT_RUNTIME_GRAPH_OPTIMIZATION=ON workingDirectory: $(Build.SourcesDirectory) + - script: git checkout -- . + displayName: Discard local changes to Git repository files + workingDirectory: $(Build.SourcesDirectory) + + - task: CmdLine@2 + displayName: 7a. Regular build with python and all optional features disabled. + inputs: + script: | + docker run --rm \ + --volume $(Build.SourcesDirectory):/onnxruntime_src \ + --volume $(Build.BinariesDirectory):/build \ + --volume $(test_data_directory):/home/onnxruntimedev/.test_data \ + -e ALLOW_RELEASED_ONNX_OPSET_ONLY=1 \ + -e NIGHTLY_BUILD \ + -e BUILD_BUILDNUMBER \ + onnxruntimecpubuild \ + /opt/python/cp37-cp37m/bin/python3 /onnxruntime_src/tools/ci_build/build.py \ + --build_dir /build/7a \ + --cmake_generator Ninja \ + --config MinSizeRel \ + --skip_submodule_sync \ + --build_shared_lib \ + --build_wheel \ + --parallel \ + --skip_tests \ + --disable_ml_ops \ + --include_ops_by_config /home/onnxruntimedev/.test_data/include_no_operators.config \ + --cmake_extra_defines onnxruntime_DISABLE_SPARSE_TENSORS=ON \ + onnxruntime_DISABLE_OPTIONAL_TYPE=ON \ + onnxruntime_ENABLE_ORT_FORMAT_RUNTIME_GRAPH_OPTIMIZATION=OFF \ + onnxruntime_BUILD_UNIT_TESTS=OFF + workingDirectory: $(Build.SourcesDirectory) + + - task: CmdLine@2 + displayName: 7b. Minimal build with all optional features disabled. + inputs: + script: | + docker run --rm \ + --volume $(Build.SourcesDirectory):/onnxruntime_src \ + --volume $(Build.BinariesDirectory):/build \ + --volume $(test_data_directory):/home/onnxruntimedev/.test_data \ + -e ALLOW_RELEASED_ONNX_OPSET_ONLY=1 \ + -e NIGHTLY_BUILD \ + -e BUILD_BUILDNUMBER \ + onnxruntimecpubuild \ + /opt/python/cp37-cp37m/bin/python3 /onnxruntime_src/tools/ci_build/build.py \ + --build_dir /build/7b \ + --cmake_generator Ninja \ + --config MinSizeRel \ + --skip_submodule_sync \ + --build_shared_lib \ + --parallel \ + --minimal_build \ + --disable_exceptions \ + --disable_ml_ops \ + --skip_tests \ + --enable_reduced_operator_type_support \ + --include_ops_by_config /home/onnxruntimedev/.test_data/include_no_operators.config \ + --cmake_extra_defines onnxruntime_DISABLE_SPARSE_TENSORS=ON \ + onnxruntime_DISABLE_OPTIONAL_TYPE=ON \ + onnxruntime_ENABLE_ORT_FORMAT_RUNTIME_GRAPH_OPTIMIZATION=OFF \ + onnxruntime_BUILD_UNIT_TESTS=OFF + workingDirectory: $(Build.SourcesDirectory) + - task: PublishTestResults@2 displayName: 'Publish unit test results' inputs: