Skip to content

Commit

Permalink
reimplement resize cpu kernel for image processing (#768)
Browse files Browse the repository at this point in the history
* reimplement resize cpu kernel for image processing

* accuracy fixing and code refinement

* fix the build issues

* fix Linux build issue

* more fixings

* Fix the pipeline issue

* fix the ci script

* try to fix CUDA machine pool
  • Loading branch information
wenbingl authored Jul 23, 2024
1 parent d79299e commit 620050f
Show file tree
Hide file tree
Showing 22 changed files with 1,818 additions and 126 deletions.
4 changes: 0 additions & 4 deletions .pipelines/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -412,10 +412,6 @@ stages:
name: 'onnxruntime-extensions-Windows-CPU'

steps:
# the vcpkg build requires a cmake python module
- script: python -m pip install cmake
displayName: Install cmake python module

- script: |
call .\build.bat -DOCOS_ENABLE_CTEST=ON -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded
cd out/Windows
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -726,7 +726,7 @@ target_link_libraries(ocos_operators PRIVATE ${ocos_libraries})

set (file_patterns "shared/lib/*.cc")
if (OCOS_ENABLE_C_API)
list(APPEND file_patterns "shared/api/*.h*" "shared/api/*.cc")
list(APPEND file_patterns "shared/api/*.h*" "shared/api/*.c" "shared/api/*.cc")
endif()

file(GLOB shared_TARGET_LIB_SRC ${file_patterns})
Expand Down
5 changes: 4 additions & 1 deletion cmake/ext_python.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ if (NOT Python3_FOUND)
message(FATAL_ERROR "Python3 not found!")
endif()

file(GLOB TARGET_SRC_PYOPS "pyop/*.cc" "pyop/*.h" "shared/*.cc")
file(GLOB TARGET_SRC_PYOPS "pyop/pyfunc.cc" "pyop/*.h" "shared/*.cc")
if (OCOS_ENABLE_C_API)
list(APPEND TARGET_SRC_PYOPS "pyop/py_c_api.cc")
endif()
if (WIN32)
list(APPEND TARGET_SRC_PYOPS "pyop/extensions_pydll.def")
endif()
Expand Down
53 changes: 37 additions & 16 deletions cmake/externals/opencv-no-rtti.patch
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
diff --git a/3rdparty/libjpeg-turbo/CMakeLists.txt b/3rdparty/libjpeg-turbo/CMakeLists.txt
index 3c7f29b08e..066ea4e545 100644
--- a/3rdparty/libjpeg-turbo/CMakeLists.txt
+++ b/3rdparty/libjpeg-turbo/CMakeLists.txt
@@ -67,7 +67,7 @@ set(JPEG_LIB_VERSION "${VERSION}-${JPEG_LIB_VERSION}" PARENT_SCOPE)
set(THREAD_LOCAL "") # WITH_TURBOJPEG is not used
diff --git a/3rdparty/libjpeg/CMakeLists.txt b/3rdparty/libjpeg/CMakeLists.txt
index c0524cc38..69a71e416 100644
--- a/3rdparty/libjpeg/CMakeLists.txt
+++ b/3rdparty/libjpeg/CMakeLists.txt
@@ -27,7 +27,6 @@ endif()

if(MSVC)
- add_definitions(-W3 -wd4996 -wd4018)
+ add_definitions(-W3)
endif()
ocv_warnings_disable(CMAKE_C_FLAGS -Wcast-align -Wshadow -Wunused -Wshift-negative-value -Wimplicit-fallthrough)
ocv_warnings_disable(CMAKE_C_FLAGS -Wunused-parameter) # clang
-ocv_warnings_disable(CMAKE_C_FLAGS /wd4013 /wd4244 /wd4267) # vs2005

if(WIN32)
set_target_properties(${JPEG_LIBRARY}
PROPERTIES OUTPUT_NAME ${JPEG_LIBRARY}
diff --git a/3rdparty/zlib/CMakeLists.txt b/3rdparty/zlib/CMakeLists.txt
index 9758861a6b..9e654ba922 100644
index 9758861a6..9e654ba92 100644
--- a/3rdparty/zlib/CMakeLists.txt
+++ b/3rdparty/zlib/CMakeLists.txt
@@ -81,7 +81,6 @@ set_target_properties(${ZLIB_LIBRARY} PROPERTIES DEFINE_SYMBOL ZLIB_DLL)
Expand All @@ -24,7 +23,7 @@ index 9758861a6b..9e654ba922 100644
)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index d95e5db163..db185453df 100644
index d95e5db16..db185453d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -617,11 +617,6 @@ endif()
Expand All @@ -40,7 +39,7 @@ index d95e5db163..db185453df 100644

ocv_cmake_hook(POST_COMPILER_OPTIONS)
diff --git a/cmake/OpenCVDetectCXXCompiler.cmake b/cmake/OpenCVDetectCXXCompiler.cmake
index 7f229cde96..92e204a5b9 100644
index 7f229cde9..92e204a5b 100644
--- a/cmake/OpenCVDetectCXXCompiler.cmake
+++ b/cmake/OpenCVDetectCXXCompiler.cmake
@@ -171,7 +171,7 @@ elseif(MSVC)
Expand All @@ -53,7 +52,7 @@ index 7f229cde96..92e204a5b9 100644
else()
message(WARNING "OpenCV does not recognize MSVC_VERSION \"${MSVC_VERSION}\". Cannot set OpenCV_RUNTIME")
diff --git a/modules/core/include/opencv2/core/ocl.hpp b/modules/core/include/opencv2/core/ocl.hpp
index 4503fa00dd..642b0508d0 100644
index 4503fa00d..642b0508d 100644
--- a/modules/core/include/opencv2/core/ocl.hpp
+++ b/modules/core/include/opencv2/core/ocl.hpp
@@ -302,21 +302,6 @@ public:
Expand All @@ -79,7 +78,7 @@ index 4503fa00dd..642b0508d0 100644
inline Impl* getImpl() const { return (Impl*)p; }
inline bool empty() const { return !p; }
diff --git a/modules/core/src/ocl_disabled.impl.hpp b/modules/core/src/ocl_disabled.impl.hpp
index a217979a1e..0ba30d024c 100644
index a217979a1..0ba30d024 100644
--- a/modules/core/src/ocl_disabled.impl.hpp
+++ b/modules/core/src/ocl_disabled.impl.hpp
@@ -177,11 +177,6 @@ void* Context::getOpenCLContextProperty(int /*propertyId*/) const { OCL_NOT_AVAI
Expand All @@ -94,3 +93,25 @@ index a217979a1e..0ba30d024c 100644
/* static */ Context Context::fromHandle(void* context) { OCL_NOT_AVAILABLE(); }
/* static */ Context Context::fromDevice(const ocl::Device& device) { OCL_NOT_AVAILABLE(); }
/* static */ Context Context::create(const std::string& configuration) { OCL_NOT_AVAILABLE(); }
diff --git a/samples/dnn/dnn_model_runner/dnn_conversion/requirements.txt b/samples/dnn/dnn_model_runner/dnn_conversion/requirements.txt
deleted file mode 100644
index 6887c2ab2..000000000
--- a/samples/dnn/dnn_model_runner/dnn_conversion/requirements.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-# Python 3.7.5
-onnx>=1.7.0
-numpy>=1.19.1
-
-torch>=1.5.1
-torchvision>=0.6.1
-
-tensorflow>=2.1.0
-tensorflow-gpu>=2.1.0
-
-paddlepaddle>=2.0.0
-paddlepaddle-gpu>=2.0.0
-paddlehub>=2.1.0
-paddle2onnx>=0.5.1
-paddleseg>=2.0.0
\ No newline at end of file
2 changes: 1 addition & 1 deletion docs/c_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ Most APIs accept raw data inputs such as audio, image compressed binary formats,

**Image processing:** `OrtxCreateProcessor` can create an image processor object from a pre-defined workflow in JSON format to process image files into a tensor-like data type. An example code snippet can be found [here](../test/pp_api_test/test_processor.cc#L75).

**Audio feature extraction:** `OrtxCreateSpeechFeatureExtractor` creates a speech feature extractor to obtain log mel spectrum data as input for the Whisper model. An example code snippet can be found [here](../test/pp_api_test/test_feature_extractor.cc#L16).
**Audio feature extraction:** `OrtxCreateSpeechFeatureExtractor` creates a speech feature extractor to obtain log mel spectrum data as input for the Whisper model. An example code snippet can be found [here](../test/pp_api_test/test_feature_extraction.cc#L16).
20 changes: 20 additions & 0 deletions include/ortx_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,23 @@ typedef enum {
kOrtxErrorInternal = 9,
kOrtxErrorUnknown = 1000
} extError_t;

typedef enum {
kOrtxUnknownType = 0,
kOrtxFloat = 1,
kOrtxDouble = 2,
kOrtxString = 3,
kOrtxBool = 4,
kOrtxComplex64 = 5,
kOrtxComplex128 = 6,
kOrtxBFloat16 = 7,
kOrtxUint8 = 8,
kOrtxInt8 = 9,
kOrtxUint16 = 10,
kOrtxInt16 = 11,
kOrtxInt32 = 12,
kOrtxUint32 = 13,
kOrtxInt64 = 14,
kOrtxUint64 = 15,
kOrtxFloat16 = 16
} extDataType_t;
13 changes: 13 additions & 0 deletions include/ortx_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,19 @@ extError_t ORTX_API_CALL OrtxDisposeOnly(OrtxObject* object);
*/
extError_t ORTX_API_CALL OrtxTensorResultGetAt(OrtxTensorResult* result, size_t index, OrtxTensor** tensor);

/**
* @brief Retrieves the data type of the given tensor.
*
* This function returns the data type of the specified tensor. The data type is
* stored in the `type` parameter.
*
* @param tensor The tensor for which to retrieve the data type.
* @param type A pointer to a variable that will hold the retrieved data type.
*
* @return An `extError_t` value indicating the success or failure of the operation.
*/
extError_t ORTX_API_CALL OrtxGetTensorType(OrtxTensor* tensor, extDataType_t* type);

/** \brief Get the data from the tensor
*
* \param tensor The tensor object
Expand Down
13 changes: 13 additions & 0 deletions onnxruntime_extensions/pp_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
###############################################################################

from . import _extensions_pydll as _C
if not hasattr(_C, "create_processor"):
raise ImportError("onnxruntime_extensions is not built with pre-processing API")

create_processor = _C.create_processor
load_images = _C.load_images
image_pre_process = _C.image_pre_process
tensor_result_get_at = _C.tensor_result_get_at
114 changes: 114 additions & 0 deletions pyop/py_c_api.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#include <pybind11/iostream.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/numpy.h>
#include <thread>

#include "ortx_utils.h"
#include "ortx_processor.h"
#include "pykernel.h"

namespace py = pybind11;

template <typename T>
int64_t NumOfElement(const T& sp) {
size_t c = 1;
for (auto v : sp) {
c *= v;
}
return c;
}

void AddGlobalMethodsCApi(pybind11::module& m) {
m.def(
"create_processor",
[](const char* processor_def_json) {
OrtxProcessor* processor = nullptr;
auto err = OrtxCreateProcessor(&processor, processor_def_json);
if (err != kOrtxOK) {
throw std::runtime_error(std::string("Failed to create processor") + OrtxGetLastErrorMessage());
}
return reinterpret_cast<std::uintptr_t>(processor);
},
"Create a processor.");

m.def(
"load_images",
[](const std::vector<std::string>& image_paths) {
OrtxRawImages* images = nullptr;
size_t num_images = image_paths.size();
auto image_ptrs = std::make_unique<const char*[]>(num_images);
for (size_t i = 0; i < num_images; ++i) {
image_ptrs[i] = image_paths[i].c_str();
}

auto err = OrtxLoadImages(&images, image_ptrs.get(), num_images, nullptr);
if (err != kOrtxOK) {
throw std::runtime_error(std::string("Failed to load images") + OrtxGetLastErrorMessage());
}
return reinterpret_cast<std::uintptr_t>(images);
},
"Load images.");

m.def(
"image_pre_process",
[](std::uintptr_t processor_h, std::uintptr_t images_h) {
OrtxProcessor* processor = reinterpret_cast<OrtxProcessor*>(processor_h);
OrtxRawImages* images = reinterpret_cast<OrtxRawImages*>(images_h);
OrtxTensorResult* result{};
auto err = OrtxImagePreProcess(processor, images, &result);
if (err != kOrtxOK) {
throw std::runtime_error(std::string("Failed to preprocess images") + OrtxGetLastErrorMessage());
}
return reinterpret_cast<std::uintptr_t>(result);
},
"Preprocess images.");

m.def("tensor_result_get_at", [](std::uintptr_t result_h, size_t index) {
OrtxTensorResult* result = reinterpret_cast<OrtxTensorResult*>(result_h);
OrtxTensor* tensor{};
auto err = OrtxTensorResultGetAt(result, index, &tensor);
if (err != kOrtxOK) {
throw std::runtime_error(std::string("Failed to get tensor") + OrtxGetLastErrorMessage());
}

extDataType_t tensor_type;

OrtxGetTensorType(tensor, &tensor_type);
const int64_t* shape{};
size_t num_dims;
const void* data{};
size_t elem_size = 0;
if (tensor_type == extDataType_t::kOrtxInt64 || tensor_type == extDataType_t::kOrtxFloat) {
OrtxGetTensorData(tensor, reinterpret_cast<const void**>(&data), &shape, &num_dims);
elem_size = 4;
if (tensor_type == extDataType_t::kOrtxInt64) {
elem_size = 8;
}
} else if (tensor_type == extDataType_t::kOrtxUnknownType) {
throw std::runtime_error("Failed to get tensor type");
} else if (tensor_type == extDataType_t::kOrtxUnknownType) {
throw std::runtime_error("unsupported tensor type");
}

std::vector<std::size_t> npy_dims;
for (auto n = num_dims - num_dims; n < num_dims; ++n) {
npy_dims.push_back(shape[n]);
}
py::array obj{};

if (tensor_type == extDataType_t::kOrtxFloat) {
obj = py::array_t<float>(npy_dims);
} else if (tensor_type == extDataType_t::kOrtxInt64) {
obj = py::array_t<int64_t>(npy_dims);
}

void* out_ptr = obj.mutable_data();
memcpy(out_ptr, data, NumOfElement(npy_dims) * elem_size);
return obj;
}, "Get tensor at index.");
}
3 changes: 3 additions & 0 deletions pyop/pyfunc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,9 @@ PYBIND11_MODULE(_extensions_pydll, m) {
m.doc() = "pybind11 stateful interface to ONNXRuntime-Extensions";

AddGlobalMethods(m);
#if defined(ENABLE_C_API)
AddGlobalMethodsCApi(m);
#endif
AddObjectMethods(m);
auto atexit = py::module_::import("atexit");
atexit.attr("register")(py::cpp_function([]() {
Expand Down
4 changes: 4 additions & 0 deletions pyop/pykernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,7 @@ struct PyCustomOpFactory : public OrtCustomOp {
};

bool EnablePyCustomOps(bool enable = true);

#if defined(ENABLE_C_API)
void AddGlobalMethodsCApi(pybind11::module& m);
#endif
29 changes: 23 additions & 6 deletions shared/api/c_api_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -101,28 +101,45 @@ extError_t ORTX_API_CALL OrtxTensorResultGetAt(OrtxTensorResult* result, size_t
return kOrtxErrorInvalidArgument;
}

auto tensor_ptr = std::make_unique<OrtxObjectWrapper<ortc::TensorBase, kOrtxKindTensor>>();
tensor_ptr->SetObject(ts);
auto tensor_ptr = std::make_unique<TensorObject>();
tensor_ptr->SetTensor(ts);
tensor_ptr->SetTensorType(result_ptr->GetTensorType(index));
*tensor = static_cast<OrtxTensor*>(tensor_ptr.release());
return extError_t();
}

extError_t ORTX_API_CALL OrtxGetTensorType(OrtxTensor* tensor, extDataType_t* type) {
if (tensor == nullptr || type == nullptr) {
ReturnableStatus::last_error_message_ = "Invalid argument";
return kOrtxErrorInvalidArgument;
}

auto tensor_impl = static_cast<TensorObject*>(tensor);
if (tensor_impl->ortx_kind() != extObjectKind_t::kOrtxKindTensor) {
ReturnableStatus::last_error_message_ = "Invalid argument";
return kOrtxErrorInvalidArgument;
}

*type = tensor_impl->GetTensorType();
return extError_t();
}

extError_t ORTX_API_CALL OrtxGetTensorData(OrtxTensor* tensor, const void** data, const int64_t** shape,
size_t* num_dims) {
if (tensor == nullptr) {
ReturnableStatus::last_error_message_ = "Invalid argument";
return kOrtxErrorInvalidArgument;
}

auto tensor_impl = static_cast<OrtxObjectWrapper<ortc::TensorBase, kOrtxKindTensor>*>(tensor);
auto tensor_impl = static_cast<TensorObject*>(tensor);
if (tensor_impl->ortx_kind() != extObjectKind_t::kOrtxKindTensor) {
ReturnableStatus::last_error_message_ = "Invalid argument";
return kOrtxErrorInvalidArgument;
}

*data = tensor_impl->GetObject()->DataRaw();
*shape = tensor_impl->GetObject()->Shape().data();
*num_dims = tensor_impl->GetObject()->Shape().size();
*data = tensor_impl->GetTensor()->DataRaw();
*shape = tensor_impl->GetTensor()->Shape().data();
*num_dims = tensor_impl->GetTensor()->Shape().size();
return extError_t();
}

Expand Down
Loading

0 comments on commit 620050f

Please sign in to comment.