Skip to content

Commit a110ede

Browse files
dmatveevPashchenkov, Maxim
and
Pashchenkov, Maxim
authored
Merge pull request opencv#18716 from dmatveev:dm/upstream_onnx
* G-API: Introduce ONNX backend for Inference - Basic operations are implemented (Infer, -ROI, -List, -List2); - Implemented automatic preprocessing for ONNX models; - Test suite is extended with `OPENCV_GAPI_ONNX_MODEL_PATH` env for test data (test data is an ONNX Model Zoo repo snapshot); - Fixed kernel lookup logic in core G-API: - Lookup NN kernels not in the default package, but in the associated backend's aux package. Now two NN backends can work in the same graph. - Added Infer SSD demo and a combined ONNX/IE demo; * G-API/ONNX: Fix some of CMake issues Co-authored-by: Pashchenkov, Maxim <[email protected]>
1 parent 2a3cdba commit a110ede

File tree

10 files changed

+1920
-6
lines changed

10 files changed

+1920
-6
lines changed

CMakeLists.txt

+17
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,9 @@ OCV_OPTION(WITH_ANDROID_MEDIANDK "Use Android Media NDK for Video I/O (Android)"
439439
OCV_OPTION(WITH_TENGINE "Include Arm Inference Tengine support" OFF
440440
VISIBLE_IF (ARM OR AARCH64) AND (UNIX OR ANDROID) AND NOT IOS
441441
VERIFY HAVE_TENGINE)
442+
OCV_OPTION(WITH_ONNX "Include Microsoft ONNX Runtime support" OFF
443+
VISIBLE_IF TRUE
444+
VERIFY HAVE_ONNX)
442445

443446
# OpenCV build components
444447
# ===================================================
@@ -775,6 +778,11 @@ if(WITH_QUIRC)
775778
add_subdirectory(3rdparty/quirc)
776779
set(HAVE_QUIRC TRUE)
777780
endif()
781+
782+
if(WITH_ONNX)
783+
include(cmake/FindONNX.cmake)
784+
endif()
785+
778786
# ----------------------------------------------------------------------------
779787
# OpenCV HAL
780788
# ----------------------------------------------------------------------------
@@ -1556,6 +1564,15 @@ if(WITH_OPENCL OR HAVE_OPENCL)
15561564
endif()
15571565
endif()
15581566

1567+
if(WITH_ONNX OR HAVE_ONNX)
1568+
status("")
1569+
status(" ONNX:" HAVE_ONNX THEN "YES" ELSE "NO")
1570+
if(HAVE_ONNX)
1571+
status(" Include path:" ONNX_INCLUDE_DIR THEN "${ONNX_INCLUDE_DIR}" ELSE "NO")
1572+
status(" Link libraries:" ONNX_LIBRARIES THEN "${ONNX_LIBRARIES}" ELSE "NO")
1573+
endif()
1574+
endif()
1575+
15591576
# ========================== python ==========================
15601577
if(BUILD_opencv_python2)
15611578
status("")

cmake/FindONNX.cmake

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
ocv_clear_vars(HAVE_ONNX)
2+
3+
set(ONNXRT_ROOT_DIR "" CACHE PATH "ONNX Runtime install directory")
4+
5+
# For now, check the old name ORT_INSTALL_DIR
6+
if(ORT_INSTALL_DIR AND NOT ONNXRT_ROOT_DIR)
7+
set(ONNXRT_ROOT_DIR ORT_INSTALL_DIR)
8+
endif()
9+
10+
if(ONNXRT_ROOT_DIR)
11+
find_library(ORT_LIB onnxruntime
12+
${ONNXRT_ROOT_DIR}/lib
13+
CMAKE_FIND_ROOT_PATH_BOTH)
14+
find_path(ORT_INCLUDE onnxruntime_cxx_api.h
15+
${ONNXRT_ROOT_DIR}/include/onnxruntime/core/session
16+
CMAKE_FIND_ROOT_PATH_BOTH)
17+
endif()
18+
19+
if(ORT_LIB AND ORT_INCLUDE)
20+
set(HAVE_ONNX TRUE)
21+
# For CMake output only
22+
set(ONNX_LIBRARIES "${ORT_LIB}" CACHE STRING "ONNX Runtime libraries")
23+
set(ONNX_INCLUDE_DIR "${ORT_INCLUDE}" CACHE STRING "ONNX Runtime include path")
24+
25+
# Link target with associated interface headers
26+
set(ONNX_LIBRARY "onnxruntime" CACHE STRING "ONNX Link Target")
27+
ocv_add_library(${ONNX_LIBRARY} SHARED IMPORTED)
28+
set_target_properties(${ONNX_LIBRARY} PROPERTIES
29+
INTERFACE_INCLUDE_DIRECTORIES ${ORT_INCLUDE}
30+
IMPORTED_LOCATION ${ORT_LIB}
31+
IMPORTED_IMPLIB ${ORT_LIB})
32+
endif()
33+
34+
if(NOT HAVE_ONNX)
35+
ocv_clear_vars(HAVE_ONNX ORT_LIB ORT_INCLUDE_DIR)
36+
endif()

modules/gapi/CMakeLists.txt

+13
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ set(gapi_srcs
131131
src/backends/ie/giebackend.cpp
132132
src/backends/ie/giebackend/giewrapper.cpp
133133

134+
# ONNX Backend.
135+
src/backends/onnx/gonnxbackend.cpp
136+
134137
# Render Backend.
135138
src/backends/render/grenderocv.cpp
136139
src/backends/render/ft_render.cpp
@@ -205,10 +208,20 @@ if(HAVE_PLAIDML)
205208
ocv_target_include_directories(${the_module} SYSTEM PRIVATE ${PLAIDML_INCLUDE_DIRS})
206209
endif()
207210

211+
208212
if(WIN32)
209213
# Required for htonl/ntohl on Windows
210214
ocv_target_link_libraries(${the_module} PRIVATE wsock32 ws2_32)
211215
endif()
212216

217+
if(HAVE_ONNX)
218+
ocv_target_link_libraries(${the_module} PRIVATE ${ONNX_LIBRARY})
219+
ocv_target_compile_definitions(${the_module} PRIVATE HAVE_ONNX=1)
220+
if(TARGET opencv_test_gapi)
221+
ocv_target_compile_definitions(opencv_test_gapi PRIVATE HAVE_ONNX=1)
222+
ocv_target_link_libraries(opencv_test_gapi PRIVATE ${ONNX_LIBRARY})
223+
endif()
224+
endif()
225+
213226
ocv_add_perf_tests()
214227
ocv_add_samples()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
// This file is part of OpenCV project.
2+
// It is subject to the license terms in the LICENSE file found in the top-level directory
3+
// of this distribution and at http://opencv.org/license.html.
4+
//
5+
// Copyright (C) 2020 Intel Corporation
6+
7+
#ifndef OPENCV_GAPI_INFER_ONNX_HPP
8+
#define OPENCV_GAPI_INFER_ONNX_HPP
9+
10+
#include <unordered_map>
11+
#include <string>
12+
#include <array>
13+
#include <tuple> // tuple, tuple_size
14+
15+
#include <opencv2/gapi/opencv_includes.hpp>
16+
#include <opencv2/gapi/util/any.hpp>
17+
18+
#include <opencv2/core/cvdef.h> // GAPI_EXPORTS
19+
#include <opencv2/gapi/gkernel.hpp> // GKernelPackage
20+
21+
namespace cv {
22+
namespace gapi {
23+
namespace onnx {
24+
25+
GAPI_EXPORTS cv::gapi::GBackend backend();
26+
27+
enum class TraitAs: int {
28+
TENSOR, //!< G-API traits an associated cv::Mat as a raw tensor
29+
// and passes dimensions as-is
30+
IMAGE //!< G-API traits an associated cv::Mat as an image so
31+
// creates an "image" blob (NCHW/NHWC, etc)
32+
};
33+
34+
using PostProc = std::function<void(const std::unordered_map<std::string, cv::Mat> &,
35+
std::unordered_map<std::string, cv::Mat> &)>;
36+
37+
38+
namespace detail {
39+
struct ParamDesc {
40+
std::string model_path;
41+
42+
// NB: nun_* may differ from topology's real input/output port numbers
43+
// (e.g. topology's partial execution)
44+
std::size_t num_in; // How many inputs are defined in the operation
45+
std::size_t num_out; // How many outputs are defined in the operation
46+
47+
// NB: Here order follows the `Net` API
48+
std::vector<std::string> input_names;
49+
std::vector<std::string> output_names;
50+
51+
using ConstInput = std::pair<cv::Mat, TraitAs>;
52+
std::unordered_map<std::string, ConstInput> const_inputs;
53+
54+
std::vector<cv::Scalar> mean;
55+
std::vector<cv::Scalar> stdev;
56+
57+
std::vector<cv::GMatDesc> out_metas;
58+
PostProc custom_post_proc;
59+
60+
std::vector<bool> normalize;
61+
};
62+
} // namespace detail
63+
64+
template<typename Net>
65+
struct PortCfg {
66+
using In = std::array
67+
< std::string
68+
, std::tuple_size<typename Net::InArgs>::value >;
69+
using Out = std::array
70+
< std::string
71+
, std::tuple_size<typename Net::OutArgs>::value >;
72+
using NormCoefs = std::array
73+
< cv::Scalar
74+
, std::tuple_size<typename Net::InArgs>::value >;
75+
using Normalize = std::array
76+
< bool
77+
, std::tuple_size<typename Net::InArgs>::value >;
78+
};
79+
80+
template<typename Net> class Params {
81+
public:
82+
Params(const std::string &model) {
83+
desc.model_path = model;
84+
desc.num_in = std::tuple_size<typename Net::InArgs>::value;
85+
desc.num_out = std::tuple_size<typename Net::OutArgs>::value;
86+
};
87+
88+
// BEGIN(G-API's network parametrization API)
89+
GBackend backend() const { return cv::gapi::onnx::backend(); }
90+
std::string tag() const { return Net::tag(); }
91+
cv::util::any params() const { return { desc }; }
92+
// END(G-API's network parametrization API)
93+
94+
Params<Net>& cfgInputLayers(const typename PortCfg<Net>::In &ll) {
95+
desc.input_names.assign(ll.begin(), ll.end());
96+
return *this;
97+
}
98+
99+
Params<Net>& cfgOutputLayers(const typename PortCfg<Net>::Out &ll) {
100+
desc.output_names.assign(ll.begin(), ll.end());
101+
return *this;
102+
}
103+
104+
Params<Net>& constInput(const std::string &layer_name,
105+
const cv::Mat &data,
106+
TraitAs hint = TraitAs::TENSOR) {
107+
desc.const_inputs[layer_name] = {data, hint};
108+
return *this;
109+
}
110+
111+
Params<Net>& cfgMeanStd(const typename PortCfg<Net>::NormCoefs &m,
112+
const typename PortCfg<Net>::NormCoefs &s) {
113+
desc.mean.assign(m.begin(), m.end());
114+
desc.stdev.assign(s.begin(), s.end());
115+
return *this;
116+
}
117+
118+
Params<Net>& cfgPostProc(const std::vector<cv::GMatDesc> &outs,
119+
const PostProc &pp) {
120+
desc.out_metas = outs;
121+
desc.custom_post_proc = pp;
122+
return *this;
123+
}
124+
125+
Params<Net>& cfgNormalize(const typename PortCfg<Net>::Normalize &n) {
126+
desc.normalize.assign(n.begin(), n.end());
127+
return *this;
128+
}
129+
130+
protected:
131+
detail::ParamDesc desc;
132+
};
133+
134+
} // namespace onnx
135+
} // namespace gapi
136+
} // namespace cv
137+
138+
#endif // OPENCV_GAPI_INFER_HPP

0 commit comments

Comments
 (0)