Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PYTHON API] update InferQueue #8513

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
2df7b7d
Bind exec core ov (#50)
bszmelcz Oct 21, 2021
5998235
Output const node python tests (#52)
bszmelcz Oct 26, 2021
74ca084
rename ie_version to version
akuporos Oct 29, 2021
dec4cb0
Pszmel/bind infer request (#51)
pszmel Nov 3, 2021
c6c7d9b
fix get_version
akuporos Nov 3, 2021
dd6dbc9
fix opaque issue
akuporos Nov 3, 2021
573d367
some cosmetic changes
akuporos Nov 3, 2021
9c06d10
fix codestyle in tests
akuporos Nov 3, 2021
5b2b9a0
make tests green
akuporos Nov 3, 2021
a610fac
Merge branch 'develop/new-python-api' of https://github.com/akuporos/…
Nov 4, 2021
5fe62ee
Extend python InferRequest
Nov 5, 2021
6998cbd
Extend python Function
Nov 5, 2021
c541d2d
Change return value of infer call
Nov 5, 2021
d83f73f
Fix missing precisions conversions in CPU plugin
Nov 5, 2021
3ddd264
Rework of runtime for new tests
Nov 5, 2021
0c6a519
Fixed onnx reading in python tests
Nov 5, 2021
127f0b9
Edit compatibility tests
Nov 5, 2021
695104e
Edit tests
Nov 5, 2021
7f457ed
Add FLOAT_LIKE xfails
Nov 5, 2021
7456077
Merge remote-tracking branch 'upstream/master' into develop/new-pytho…
Nov 5, 2021
a6e21e4
Merge remote-tracking branch 'upstream/master' into develop/new-pytho…
akuporos Nov 5, 2021
9cebdc7
[Python API] bind ProfilingInfo (#55)
Nov 8, 2021
f2d8e88
fix codestyle
akuporos Nov 8, 2021
a55c939
Merge remote-tracking branch 'upstream/master' into develop/new-pytho…
akuporos Nov 8, 2021
e62512f
Infer new request method (#56)
bszmelcz Nov 8, 2021
3621e39
add add_extension from path
akuporos Nov 8, 2021
efd844d
codestyle
akuporos Nov 8, 2021
ab9c678
Merge remote-tracking branch 'upstream/master' into develop/new-pytho…
akuporos Nov 9, 2021
1c208ba
fix win build
akuporos Nov 9, 2021
b5d8303
add inputs-outputs to function
akuporos Nov 9, 2021
a9a0e7f
update infer queue
Nov 10, 2021
adf1844
Merge remote-tracking branch 'upstream/master' into develop/new-pytho…
akuporos Nov 10, 2021
08c5719
Merge remote-tracking branch 'akuporos/develop/new-python-api' into a…
Nov 10, 2021
90b49f9
fix code style
Nov 10, 2021
22b0a75
Hot-fix CPU plugin with precision
Nov 10, 2021
1cbf144
fix start_async
akuporos Nov 10, 2021
530d164
add performance hint to time infer (#8480)
Nov 10, 2021
ae72199
Updated common migration pipeline (#8176)
ilyachur Nov 10, 2021
f55e3b2
Avoid redundant graph nodes scans (#8415)
t-jankowski Nov 10, 2021
372a424
Refactor work with env variables (#8208)
Nov 10, 2021
3c31285
[IE Sample Scripts] Use cmake to build samples (#8442)
dpigasin Nov 10, 2021
f069af7
Remove opset8 from compatibility ngraph python API (#8452)
Nov 10, 2021
4051fdc
[GPU] OneDNN gpu submodule update to version 2.5 (#8449)
lznamens Nov 10, 2021
1319384
Install rules for static libraries case (#8384)
ilya-lavrenov Nov 10, 2021
010106b
Merge remote-tracking branch 'upstream/master' into develop/new-pytho…
akuporos Nov 11, 2021
28d83b4
fix codestyle
akuporos Nov 11, 2021
3525a0b
rename all methods in this class to snake_case
Nov 11, 2021
84fda21
resolve conflicts
Nov 11, 2021
37b048f
some updates
Nov 11, 2021
ee4a8cf
code style
Nov 11, 2021
26ef61b
fix code style in tests
Nov 11, 2021
976ab13
Merge remote-tracking branch 'upstream/master' into develop/new-pytho…
akuporos Nov 11, 2021
3a8bf18
Merge branch 'develop/new-python-api' of https://github.com/akuporos/…
akuporos Nov 11, 2021
a5f8dee
Merge remote-tracking branch 'akuporos/develop/new-python-api' into a…
Nov 11, 2021
fd9f0b0
compute latency in callback
Nov 13, 2021
0547e21
Fix get_idle_request
Nov 13, 2021
2d027da
resolve conflicts
Nov 13, 2021
fa5bdea
fix latency
Nov 13, 2021
6f7187b
Fix code style
Nov 13, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions runtime/bindings/python/src/openvino/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
from openvino.pyopenvino import DataPtr
from openvino.pyopenvino import TensorDesc
from openvino.pyopenvino import get_version
#from openvino.pyopenvino import InferQueue
from openvino.pyopenvino import AsyncInferQueue
from openvino.pyopenvino import InferRequest # TODO: move to ie_api?
from openvino.pyopenvino import Blob
from openvino.pyopenvino import PreProcessInfo
Expand Down Expand Up @@ -83,5 +83,5 @@
# Patching InferRequest
InferRequest.infer = infer
InferRequest.start_async = start_async
# Patching InferQueue
#InferQueue.async_infer = async_infer
# Patching AsyncInferQueue
AsyncInferQueue.start_async = start_async
5 changes: 3 additions & 2 deletions runtime/bindings/python/src/openvino/ie_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import numpy as np
import copy
from typing import List
from typing import List, Union

from openvino.pyopenvino import TBlobFloat32
from openvino.pyopenvino import TBlobFloat64
Expand All @@ -17,6 +17,7 @@
from openvino.pyopenvino import TBlobUint8
from openvino.pyopenvino import TensorDesc
from openvino.pyopenvino import InferRequest
from openvino.pyopenvino import AsyncInferQueue
from openvino.pyopenvino import ExecutableNetwork
from openvino.pyopenvino import Tensor

Expand Down Expand Up @@ -57,7 +58,7 @@ def infer_new_request(exec_net: ExecutableNetwork, inputs: dict = None) -> List[
return [copy.deepcopy(tensor.data) for tensor in res]

# flake8: noqa: D102
def start_async(request: InferRequest, inputs: dict = {}, userdata: dict = None) -> None: # type: ignore
def start_async(request: Union[InferRequest, AsyncInferQueue], inputs: dict = {}, userdata: dict = None) -> None: # type: ignore
request._start_async(inputs=normalize_inputs(inputs), userdata=userdata)

# flake8: noqa: C901
Expand Down
205 changes: 205 additions & 0 deletions runtime/bindings/python/src/pyopenvino/core/async_infer_queue.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
// Copyright (C) 2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#include "pyopenvino/core/async_infer_queue.hpp"

#include <ie_common.h>
#include <pybind11/functional.h>
#include <pybind11/stl.h>

#include <chrono>
#include <condition_variable>
#include <mutex>
#include <queue>
#include <string>
#include <vector>

#include "pyopenvino/core/common.hpp"
#include "pyopenvino/core/infer_request.hpp"

namespace py = pybind11;

class AsyncInferQueue {
public:
AsyncInferQueue(std::vector<InferRequestWrapper> requests,
std::queue<size_t> idle_handles,
std::vector<py::object> user_ids)
: _requests(requests),
_idle_handles(idle_handles),
_user_ids(user_ids) {
this->set_default_callbacks();
}

~AsyncInferQueue() {
_requests.clear();
}

bool _is_ready() {
py::gil_scoped_release release;
std::unique_lock<std::mutex> lock(_mutex);
_cv.wait(lock, [this] {
return !(_idle_handles.empty());
});

return !(_idle_handles.empty());
}

size_t get_idle_request_id() {
// Wait for any of _idle_handles
py::gil_scoped_release release;
std::unique_lock<std::mutex> lock(_mutex);
_cv.wait(lock, [this] {
return !(_idle_handles.empty());
});

return _idle_handles.front();
;
}

void wait_all() {
// Wait for all requests to return with callback thus updating
// _idle_handles so it matches the size of requests
py::gil_scoped_release release;
std::unique_lock<std::mutex> lock(_mutex);
_cv.wait(lock, [this] {
return _idle_handles.size() == _requests.size();
});
}

void set_default_callbacks() {
for (size_t handle = 0; handle < _requests.size(); handle++) {
_requests[handle]._request.set_callback([this, handle /* ... */](std::exception_ptr exception_ptr) {
_requests[handle]._end_time = Time::now();
// Add idle handle to queue
_idle_handles.push(handle);
// Notify locks in getIdleRequestId() or waitAll() functions
_cv.notify_one();
});
}
}

void set_custom_callbacks(py::function f_callback) {
for (size_t handle = 0; handle < _requests.size(); handle++) {
_requests[handle]._request.set_callback([this, f_callback, handle](std::exception_ptr exception_ptr) {
_requests[handle]._end_time = Time::now();
try {
if (exception_ptr) {
std::rethrow_exception(exception_ptr);
}
} catch (const std::exception& e) {
throw ov::Exception(e.what());
}
// Acquire GIL, execute Python function
py::gil_scoped_acquire acquire;
f_callback(_requests[handle], _user_ids[handle]);
// Add idle handle to queue
_idle_handles.push(handle);
// Notify locks in getIdleRequestId() or waitAll() functions
_cv.notify_one();
});
}
}

std::vector<InferRequestWrapper> _requests;
std::queue<size_t> _idle_handles;
std::vector<py::object> _user_ids; // user ID can be any Python object
std::mutex _mutex;
std::condition_variable _cv;
};

void regclass_AsyncInferQueue(py::module m) {
py::class_<AsyncInferQueue, std::shared_ptr<AsyncInferQueue>> cls(m, "AsyncInferQueue");

cls.def(py::init([](ov::runtime::ExecutableNetwork& net, size_t jobs) {
if (jobs == 0) {
jobs = (size_t)Common::get_optimal_number_of_requests(net);
}

std::vector<InferRequestWrapper> requests;
std::queue<size_t> idle_handles;
std::vector<py::object> user_ids(jobs);

for (size_t handle = 0; handle < jobs; handle++) {
auto request = InferRequestWrapper(net.create_infer_request());
// Get Inputs and Outputs info from executable network
request._inputs = net.inputs();
request._outputs = net.outputs();

requests.push_back(request);
idle_handles.push(handle);
}

return new AsyncInferQueue(requests, idle_handles, user_ids);
}),
py::arg("network"),
py::arg("jobs") = 0);

cls.def(
"_start_async",
[](AsyncInferQueue& self, const py::dict inputs, py::object userdata) {
// getIdleRequestId function has an intention to block InferQueue
// until there is at least one idle (free to use) InferRequest
auto handle = self.get_idle_request_id();
self._idle_handles.pop();
// Set new inputs label/id from user
self._user_ids[handle] = userdata;
// Update inputs if there are any
if (!inputs.empty()) {
if (py::isinstance<std::string>(inputs.begin()->first)) {
auto inputs_map = Common::cast_to_tensor_name_map(inputs);
for (auto&& input : inputs_map) {
self._requests[handle]._request.set_tensor(input.first, input.second);
}
} else if (py::isinstance<int>(inputs.begin()->first)) {
auto inputs_map = Common::cast_to_tensor_index_map(inputs);
for (auto&& input : inputs_map) {
self._requests[handle]._request.set_input_tensor(input.first, input.second);
}
}
}
// Now GIL can be released - we are NOT working with Python objects in this block
{
py::gil_scoped_release release;
self._requests[handle]._start_time = Time::now();
// Start InferRequest in asynchronus mode
self._requests[handle]._request.start_async();
}
},
py::arg("inputs"),
py::arg("userdata"));

cls.def("is_ready", [](AsyncInferQueue& self) {
return self._is_ready();
});

cls.def("wait_all", [](AsyncInferQueue& self) {
return self.wait_all();
});

cls.def("get_idle_request_id", [](AsyncInferQueue& self) {
return self.get_idle_request_id();
});

cls.def("set_callback", [](AsyncInferQueue& self, py::function f_callback) {
self.set_custom_callbacks(f_callback);
});

cls.def("__len__", [](AsyncInferQueue& self) {
return self._requests.size();
});

cls.def(
"__iter__",
[](AsyncInferQueue& self) {
return py::make_iterator(self._requests.begin(), self._requests.end());
},
py::keep_alive<0, 1>()); /* Keep set alive while iterator is used */

cls.def("__getitem__", [](AsyncInferQueue& self, size_t i) {
return self._requests[i];
});

cls.def_property_readonly("userdata", [](AsyncInferQueue& self) {
return self._user_ids;
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@

namespace py = pybind11;

void regclass_InferQueue(py::module m);
void regclass_AsyncInferQueue(py::module m);
6 changes: 3 additions & 3 deletions runtime/bindings/python/src/pyopenvino/core/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,13 +321,13 @@ void set_request_blobs(InferenceEngine::InferRequest& request, const py::dict& d
}
}

uint32_t get_optimal_number_of_requests(const InferenceEngine::ExecutableNetwork& actual) {
uint32_t get_optimal_number_of_requests(const ov::runtime::ExecutableNetwork& actual) {
try {
auto parameter_value = actual.GetMetric(METRIC_KEY(SUPPORTED_METRICS));
auto parameter_value = actual.get_metric(METRIC_KEY(SUPPORTED_METRICS));
auto supported_metrics = parameter_value.as<std::vector<std::string>>();
const std::string key = METRIC_KEY(OPTIMAL_NUMBER_OF_INFER_REQUESTS);
if (std::find(supported_metrics.begin(), supported_metrics.end(), key) != supported_metrics.end()) {
parameter_value = actual.GetMetric(key);
parameter_value = actual.get_metric(key);
if (parameter_value.is<unsigned int>())
return parameter_value.as<unsigned int>();
else
Expand Down
3 changes: 2 additions & 1 deletion runtime/bindings/python/src/pyopenvino/core/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "Python.h"
#include "ie_common.h"
#include "openvino/runtime/tensor.hpp"
#include "openvino/runtime/executable_network.hpp"
#include "pyopenvino/core/containers.hpp"

namespace py = pybind11;
Expand Down Expand Up @@ -60,5 +61,5 @@ namespace Common

void set_request_blobs(InferenceEngine::InferRequest& request, const py::dict& dictonary);

uint32_t get_optimal_number_of_requests(const InferenceEngine::ExecutableNetwork& actual);
uint32_t get_optimal_number_of_requests(const ov::runtime::ExecutableNetwork& actual);
}; // namespace Common
Loading