Merge pull request #22588 from TolyaTalamanov:at/sync-ie-request-pool

G-API: Add synchronous execution for IE backend
This commit is contained in:
Alexander Smorkalov 2022-10-04 11:32:21 +03:00 committed by GitHub
commit bf5d7c0c10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 251 additions and 156 deletions

View File

@ -52,6 +52,8 @@ enum class TraitAs: int
using IEConfig = std::map<std::string, std::string>; using IEConfig = std::map<std::string, std::string>;
enum InferMode {Sync, Async};
namespace detail { namespace detail {
struct ParamDesc { struct ParamDesc {
std::string model_path; std::string model_path;
@ -89,6 +91,8 @@ struct ParamDesc {
cv::optional<cv::gapi::wip::onevpl::Device> vpl_preproc_device; cv::optional<cv::gapi::wip::onevpl::Device> vpl_preproc_device;
cv::optional<cv::gapi::wip::onevpl::Context> vpl_preproc_ctx; cv::optional<cv::gapi::wip::onevpl::Context> vpl_preproc_ctx;
InferMode mode;
using PrecisionT = int; using PrecisionT = int;
using PrecisionMapT = std::unordered_map<std::string, PrecisionT>; using PrecisionMapT = std::unordered_map<std::string, PrecisionT>;
// NB: This parameter can contain: // NB: This parameter can contain:
@ -100,7 +104,6 @@ struct ParamDesc {
PrecisionT, PrecisionT,
PrecisionMapT>; PrecisionMapT>;
PrecisionVariantT output_precision; PrecisionVariantT output_precision;
}; };
} // namespace detail } // namespace detail
@ -146,7 +149,8 @@ public:
, {} , {}
, {} , {}
, {} , {}
, {}} { , InferMode::Async
, {} } {
}; };
/** @overload /** @overload
@ -171,7 +175,8 @@ public:
, {} , {}
, {} , {}
, {} , {}
, {}} { , InferMode::Async
, {} } {
}; };
/** @brief Specifies sequence of network input layers names for inference. /** @brief Specifies sequence of network input layers names for inference.
@ -366,6 +371,22 @@ public:
return *this; return *this;
} }
/** @brief Specifies which api will be used to run inference.
The function is used to specify mode for OpenVINO inference.
OpenVINO has two options to run inference:
1. Asynchronous (using StartAsync: https://docs.openvino.ai/latest/classInferenceEngine_1_1InferRequest.html#doxid-class-inference-engine-1-1-infer-request-1a405293e8423d82a5b45f642a3bef0d24)
2. Synchronous (using Infer: https://docs.openvino.ai/latest/classInferenceEngine_1_1InferRequest.html#doxid-class-inference-engine-1-1-infer-request-1a3391ce30894abde730523e9ca9371ce8)
By default asynchronous mode is used.
@param mode Inference mode which will be used.
@return reference to this parameter structure.
*/
Params<Net>& cfgInferMode(InferMode mode) {
desc.mode = mode;
return *this;
}
/** @brief Specifies the output precision for model. /** @brief Specifies the output precision for model.
The function is used to set an output precision for model. The function is used to set an output precision for model.
@ -425,7 +446,7 @@ public:
const std::string &device) const std::string &device)
: desc{ model, weights, device, {}, {}, {}, 0u, 0u, : desc{ model, weights, device, {}, {}, {}, 0u, 0u,
detail::ParamDesc::Kind::Load, true, {}, {}, {}, 1u, detail::ParamDesc::Kind::Load, true, {}, {}, {}, 1u,
{}, {}, {}, {}, {}}, {}, {}, {}, {}, InferMode::Async, {} },
m_tag(tag) { m_tag(tag) {
}; };
@ -443,7 +464,7 @@ public:
const std::string &device) const std::string &device)
: desc{ model, {}, device, {}, {}, {}, 0u, 0u, : desc{ model, {}, device, {}, {}, {}, 0u, 0u,
detail::ParamDesc::Kind::Import, true, {}, {}, {}, 1u, detail::ParamDesc::Kind::Import, true, {}, {}, {}, 1u,
{}, {}, {}, {}, {}}, {}, {}, {}, {}, InferMode::Async, {} },
m_tag(tag) { m_tag(tag) {
}; };
@ -516,6 +537,12 @@ public:
return *this; return *this;
} }
/** @see ie::Params::cfgInferAPI */
Params& cfgInferMode(InferMode mode) {
desc.mode = mode;
return *this;
}
/** @see ie::Params::cfgOutputPrecision */ /** @see ie::Params::cfgOutputPrecision */
Params& cfgOutputPrecision(detail::ParamDesc::PrecisionT precision) { Params& cfgOutputPrecision(detail::ParamDesc::PrecisionT precision) {
desc.output_precision = precision; desc.output_precision = precision;

View File

@ -175,6 +175,17 @@ static PLMode strToPLMode(const std::string& mode_str) {
} }
} }
static cv::gapi::ie::InferMode strToInferMode(const std::string& infer_mode) {
if (infer_mode == "async") {
return cv::gapi::ie::InferMode::Async;
} else if (infer_mode == "sync") {
return cv::gapi::ie::InferMode::Sync;
} else {
throw std::logic_error("Unsupported Infer mode: " + infer_mode +
"\nPlease chose between: async and sync");
}
}
template <> template <>
CallParams read<CallParams>(const cv::FileNode& fn) { CallParams read<CallParams>(const cv::FileNode& fn) {
auto name = auto name =
@ -288,7 +299,8 @@ int main(int argc, char* argv[]) {
"{ drop_frames | false | Drop frames if they come earlier than pipeline is completed. }" "{ drop_frames | false | Drop frames if they come earlier than pipeline is completed. }"
"{ exec_list | | A comma-separated list of pipelines that" "{ exec_list | | A comma-separated list of pipelines that"
" will be executed. Spaces around commas" " will be executed. Spaces around commas"
" are prohibited. }"; " are prohibited. }"
"{ infer_mode | async | OpenVINO inference mode (async/sync). }";
cv::CommandLineParser cmd(argc, argv, keys); cv::CommandLineParser cmd(argc, argv, keys);
if (cmd.has("help")) { if (cmd.has("help")) {
@ -304,6 +316,7 @@ int main(int argc, char* argv[]) {
const auto qc = cmd.get<int>("qc"); const auto qc = cmd.get<int>("qc");
const auto app_mode = strToAppMode(cmd.get<std::string>("app_mode")); const auto app_mode = strToAppMode(cmd.get<std::string>("app_mode"));
const auto exec_str = cmd.get<std::string>("exec_list"); const auto exec_str = cmd.get<std::string>("exec_list");
const auto infer_mode = strToInferMode(cmd.get<std::string>("infer_mode"));
const auto drop_frames = cmd.get<bool>("drop_frames"); const auto drop_frames = cmd.get<bool>("drop_frames");
cv::FileStorage fs; cv::FileStorage fs;
@ -394,6 +407,7 @@ int main(int argc, char* argv[]) {
<< call_params.name << std::endl << e.what(); << call_params.name << std::endl << e.what();
throw std::logic_error(ss.str()); throw std::logic_error(ss.str());
} }
infer_params.mode = infer_mode;
builder.addInfer(call_params, infer_params); builder.addInfer(call_params, infer_params);
} else { } else {
throw std::logic_error("Unsupported node type: " + node_type); throw std::logic_error("Unsupported node type: " + node_type);

View File

@ -258,6 +258,7 @@ struct InferParams {
std::vector<std::string> input_layers; std::vector<std::string> input_layers;
std::vector<std::string> output_layers; std::vector<std::string> output_layers;
std::map<std::string, std::string> config; std::map<std::string, std::string> config;
cv::gapi::ie::InferMode mode;
cv::util::optional<int> out_precision; cv::util::optional<int> out_precision;
}; };
@ -363,6 +364,7 @@ void PipelineBuilder::addInfer(const CallParams& call_params,
} }
pp->pluginConfig(infer_params.config); pp->pluginConfig(infer_params.config);
pp->cfgInferMode(infer_params.mode);
if (infer_params.out_precision) { if (infer_params.out_precision) {
pp->cfgOutputPrecision(infer_params.out_precision.value()); pp->cfgOutputPrecision(infer_params.out_precision.value());
} }

View File

@ -392,6 +392,12 @@ struct IEUnit {
params.vpl_preproc_ctx.value()); params.vpl_preproc_ctx.value());
GAPI_LOG_INFO(nullptr, "VPP preproc created successfuly"); GAPI_LOG_INFO(nullptr, "VPP preproc created successfuly");
} }
if (params.mode == cv::gapi::ie::InferMode::Sync &&
params.nireq != 1u) {
throw std::logic_error(
"Failed: cv::gapi::ie::InferMode::Sync works only with nireq equal to 1.");
}
} }
// This method is [supposed to be] called at Island compilation stage // This method is [supposed to be] called at Island compilation stage
@ -843,40 +849,130 @@ std::vector<InferenceEngine::InferRequest> cv::gimpl::ie::IECompiled::createInfe
return requests; return requests;
} }
class cv::gimpl::ie::RequestPool { class IInferExecutor {
public: public:
using RunF = std::function<void(InferenceEngine::InferRequest&)>; using Ptr = std::shared_ptr<IInferExecutor>;
using CallbackF = std::function<void(InferenceEngine::InferRequest&, InferenceEngine::StatusCode)>; using NotifyCallbackF = std::function<void()>;
using SetInputDataF = std::function<void(InferenceEngine::InferRequest&)>;
using ReadOutputDataF = std::function<void(InferenceEngine::InferRequest&, InferenceEngine::StatusCode)>;
// NB: The task is represented by: // NB: The task is represented by:
// RunF - function which is set blobs and run async inference. // SetInputDataF - function which set input data.
// CallbackF - function which is obtain output blobs and post it to output. // ReadOutputDataF - function which read output data.
struct Task { struct Task {
RunF run; SetInputDataF set_input_data;
CallbackF callback; ReadOutputDataF read_output_data;
}; };
explicit RequestPool(std::vector<InferenceEngine::InferRequest>&& requests); IInferExecutor(IE::InferRequest request, NotifyCallbackF notify)
: m_request(std::move(request)),
m_notify(std::move(notify)) {
};
void execute(Task&& t); virtual void execute(const Task& task) = 0;
void waitAll(); virtual ~IInferExecutor() = default;
protected:
IE::InferRequest m_request;
NotifyCallbackF m_notify;
};
class SyncInferExecutor : public IInferExecutor {
using IInferExecutor::IInferExecutor;
virtual void execute(const IInferExecutor::Task& task) override;
};
void SyncInferExecutor::execute(const IInferExecutor::Task& task) {
try {
task.set_input_data(m_request);
m_request.Infer();
task.read_output_data(m_request, IE::StatusCode::OK);
} catch (...) {
m_notify();
throw;
}
// NB: Notify pool that executor has finished.
m_notify();
}
class AsyncInferExecutor : public IInferExecutor {
public:
using IInferExecutor::IInferExecutor;
virtual void execute(const IInferExecutor::Task& task) override;
private: private:
void callback(Task task, void callback(Task task,
size_t id,
IE::InferRequest request, IE::InferRequest request,
IE::StatusCode code) noexcept; IE::StatusCode code) noexcept;
void setup();
QueueClass<size_t> m_idle_ids;
std::vector<InferenceEngine::InferRequest> m_requests;
}; };
// RequestPool implementation ////////////////////////////////////////////// void AsyncInferExecutor::execute(const IInferExecutor::Task& task) {
cv::gimpl::ie::RequestPool::RequestPool(std::vector<InferenceEngine::InferRequest>&& requests) using namespace std::placeholders;
: m_requests(std::move(requests)) { using callback_t = std::function<void(IE::InferRequest, IE::StatusCode)>;
setup(); m_request.SetCompletionCallback(
static_cast<callback_t>(
std::bind(&AsyncInferExecutor::callback, this, task, _1, _2)));
try {
task.set_input_data(m_request);
m_request.StartAsync();
} catch (...) {
m_request.SetCompletionCallback([](){});
m_notify();
throw;
} }
}
void AsyncInferExecutor::callback(IInferExecutor::Task task,
IE::InferRequest request,
IE::StatusCode code) noexcept {
task.read_output_data(request, code);
request.SetCompletionCallback([](){});
// NB: Notify pool that executor has finished.
m_notify();
}
class cv::gimpl::ie::RequestPool {
public:
explicit RequestPool(cv::gapi::ie::InferMode mode,
std::vector<InferenceEngine::InferRequest>&& requests);
IInferExecutor::Ptr getIdleRequest();
void waitAll();
private:
void setup();
void release(const size_t id);
QueueClass<size_t> m_idle_ids;
std::vector<IInferExecutor::Ptr> m_requests;
};
void cv::gimpl::ie::RequestPool::release(const size_t id) {
m_idle_ids.push(id);
}
// RequestPool implementation //////////////////////////////////////////////
cv::gimpl::ie::RequestPool::RequestPool(cv::gapi::ie::InferMode mode,
std::vector<InferenceEngine::InferRequest>&& requests) {
for (size_t i = 0; i < requests.size(); ++i) {
IInferExecutor::Ptr iexec = nullptr;
switch (mode) {
case cv::gapi::ie::InferMode::Async:
iexec = std::make_shared<AsyncInferExecutor>(std::move(requests[i]),
std::bind(&RequestPool::release, this, i));
break;
case cv::gapi::ie::InferMode::Sync:
iexec = std::make_shared<SyncInferExecutor>(std::move(requests[i]),
std::bind(&RequestPool::release, this, i));
break;
default:
GAPI_Assert(false && "Unsupported cv::gapi::ie::InferMode");
}
m_requests.emplace_back(std::move(iexec));
}
setup();
}
void cv::gimpl::ie::RequestPool::setup() { void cv::gimpl::ie::RequestPool::setup() {
for (size_t i = 0; i < m_requests.size(); ++i) { for (size_t i = 0; i < m_requests.size(); ++i) {
@ -884,40 +980,10 @@ void cv::gimpl::ie::RequestPool::setup() {
} }
} }
void cv::gimpl::ie::RequestPool::execute(cv::gimpl::ie::RequestPool::Task&& t) { IInferExecutor::Ptr cv::gimpl::ie::RequestPool::getIdleRequest() {
size_t id = 0u; size_t id = 0u;
m_idle_ids.pop(id); m_idle_ids.pop(id);
return m_requests[id];
auto& request = m_requests[id];
using namespace std::placeholders;
using callback_t = std::function<void(IE::InferRequest, IE::StatusCode)>;
request.SetCompletionCallback(
static_cast<callback_t>(
std::bind(&cv::gimpl::ie::RequestPool::callback, this,
t, id, _1, _2)));
// NB: InferRequest is already marked as busy
// in case of exception need to return it back to the idle.
try {
t.run(request);
} catch (...) {
request.SetCompletionCallback([](){});
m_idle_ids.push(id);
throw;
}
}
void cv::gimpl::ie::RequestPool::callback(cv::gimpl::ie::RequestPool::Task task,
size_t id,
IE::InferRequest request,
IE::StatusCode code) noexcept {
// NB: Inference is over.
// 1. Run callback
// 2. Destroy callback to free resources.
// 3. Mark InferRequest as idle.
task.callback(request, code);
request.SetCompletionCallback([](){});
m_idle_ids.push(id);
} }
// NB: Not thread-safe. // NB: Not thread-safe.
@ -944,7 +1010,7 @@ cv::gimpl::ie::GIEExecutable::GIEExecutable(const ade::Graph &g,
if (this_nh == nullptr) { if (this_nh == nullptr) {
this_nh = nh; this_nh = nh;
this_iec = iem.metadata(this_nh).get<IEUnit>().compile(); this_iec = iem.metadata(this_nh).get<IEUnit>().compile();
m_reqPool.reset(new RequestPool(this_iec.createInferRequests())); m_reqPool.reset(new RequestPool(this_iec.params.mode, this_iec.createInferRequests()));
} }
else else
util::throw_error(std::logic_error("Multi-node inference is not supported!")); util::throw_error(std::logic_error("Multi-node inference is not supported!"));
@ -1356,8 +1422,8 @@ struct Infer: public cv::detail::KernelTag {
static void run(std::shared_ptr<IECallContext> ctx, static void run(std::shared_ptr<IECallContext> ctx,
cv::gimpl::ie::RequestPool &reqPool) { cv::gimpl::ie::RequestPool &reqPool) {
using namespace std::placeholders; using namespace std::placeholders;
reqPool.execute( reqPool.getIdleRequest()->execute(
cv::gimpl::ie::RequestPool::Task { IInferExecutor::Task {
[ctx](InferenceEngine::InferRequest &req) { [ctx](InferenceEngine::InferRequest &req) {
// non-generic version for now: // non-generic version for now:
// - assumes all inputs/outputs are always Mats // - assumes all inputs/outputs are always Mats
@ -1375,9 +1441,6 @@ struct Infer: public cv::detail::KernelTag {
cv::util::optional<cv::Rect>{}); cv::util::optional<cv::Rect>{});
setBlob(req, layer_name, this_blob, *ctx); setBlob(req, layer_name, this_blob, *ctx);
} }
// FIXME: Should it be done by kernel ?
// What about to do that in RequestPool ?
req.StartAsync();
}, },
std::bind(PostOutputs, _1, _2, ctx) std::bind(PostOutputs, _1, _2, ctx)
} }
@ -1470,8 +1533,8 @@ struct InferROI: public cv::detail::KernelTag {
static void run(std::shared_ptr<IECallContext> ctx, static void run(std::shared_ptr<IECallContext> ctx,
cv::gimpl::ie::RequestPool &reqPool) { cv::gimpl::ie::RequestPool &reqPool) {
using namespace std::placeholders; using namespace std::placeholders;
reqPool.execute( reqPool.getIdleRequest()->execute(
cv::gimpl::ie::RequestPool::Task { IInferExecutor::Task {
[ctx](InferenceEngine::InferRequest &req) { [ctx](InferenceEngine::InferRequest &req) {
GAPI_Assert(ctx->uu.params.num_in == 1); GAPI_Assert(ctx->uu.params.num_in == 1);
auto&& this_roi = ctx->inArg<cv::detail::OpaqueRef>(0).rref<cv::Rect>(); auto&& this_roi = ctx->inArg<cv::detail::OpaqueRef>(0).rref<cv::Rect>();
@ -1496,9 +1559,6 @@ struct InferROI: public cv::detail::KernelTag {
*(ctx->uu.params.input_names.begin()), *(ctx->uu.params.input_names.begin()),
this_blob, *ctx); this_blob, *ctx);
} }
// FIXME: Should it be done by kernel ?
// What about to do that in RequestPool ?
req.StartAsync();
}, },
std::bind(PostOutputs, _1, _2, ctx) std::bind(PostOutputs, _1, _2, ctx)
} }
@ -1613,11 +1673,10 @@ struct InferList: public cv::detail::KernelTag {
for (auto&& it : ade::util::indexed(in_roi_vec)) { for (auto&& it : ade::util::indexed(in_roi_vec)) {
auto pos = ade::util::index(it); auto pos = ade::util::index(it);
const auto& rc = ade::util::value(it); const auto& rc = ade::util::value(it);
reqPool.execute( reqPool.getIdleRequest()->execute(
cv::gimpl::ie::RequestPool::Task { IInferExecutor::Task {
[ctx, rc, this_blob](InferenceEngine::InferRequest &req) { [ctx, rc, this_blob](InferenceEngine::InferRequest &req) {
setROIBlob(req, ctx->uu.params.input_names[0u], this_blob, rc, *ctx); setROIBlob(req, ctx->uu.params.input_names[0u], this_blob, rc, *ctx);
req.StartAsync();
}, },
std::bind(callback, std::placeholders::_1, std::placeholders::_2, pos) std::bind(callback, std::placeholders::_1, std::placeholders::_2, pos)
} }
@ -1770,8 +1829,8 @@ struct InferList2: public cv::detail::KernelTag {
PostOutputsList callback(list_size, ctx, std::move(cached_dims)); PostOutputsList callback(list_size, ctx, std::move(cached_dims));
for (const auto &list_idx : ade::util::iota(list_size)) { for (const auto &list_idx : ade::util::iota(list_size)) {
reqPool.execute( reqPool.getIdleRequest()->execute(
cv::gimpl::ie::RequestPool::Task { IInferExecutor::Task {
[ctx, list_idx, list_size, blob_0](InferenceEngine::InferRequest &req) { [ctx, list_idx, list_size, blob_0](InferenceEngine::InferRequest &req) {
for (auto in_idx : ade::util::iota(ctx->uu.params.num_in)) { for (auto in_idx : ade::util::iota(ctx->uu.params.num_in)) {
const auto &this_vec = ctx->inArg<cv::detail::VectorRef>(in_idx+1u); const auto &this_vec = ctx->inArg<cv::detail::VectorRef>(in_idx+1u);
@ -1791,7 +1850,6 @@ struct InferList2: public cv::detail::KernelTag {
"Only Rect and Mat types are supported for infer list 2!"); "Only Rect and Mat types are supported for infer list 2!");
} }
} }
req.StartAsync();
}, },
std::bind(callback, std::placeholders::_1, std::placeholders::_2, list_idx) std::bind(callback, std::placeholders::_1, std::placeholders::_2, list_idx)
} // task } // task

View File

@ -2956,109 +2956,103 @@ TEST(TestAgeGender, ThrowBlobAndInputPrecisionMismatchStreaming)
} }
} }
TEST(TestAgeGenderIE, ChangeOutputPrecision) struct AgeGenderInferTest: public ::testing::Test {
{ cv::Mat m_in_mat;
initDLDTDataPath(); cv::Mat m_gapi_age;
cv::Mat m_gapi_gender;
cv::gapi::ie::detail::ParamDesc params; cv::gimpl::ie::wrap::Plugin m_plugin;
params.model_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml"); IE::CNNNetwork m_net;
params.weights_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin"); cv::gapi::ie::detail::ParamDesc m_params;
params.device_id = "CPU";
cv::Mat in_mat(cv::Size(320, 240), CV_8UC3);
cv::randu(in_mat, 0, 255);
cv::Mat gapi_age, gapi_gender;
// Load & run IE network
IE::Blob::Ptr ie_age, ie_gender;
{
auto plugin = cv::gimpl::ie::wrap::getPlugin(params);
auto net = cv::gimpl::ie::wrap::readNetwork(params);
setNetParameters(net);
for (auto it : net.getOutputsInfo()) {
it.second->setPrecision(IE::Precision::U8);
}
auto this_network = cv::gimpl::ie::wrap::loadNetwork(plugin, net, params);
auto infer_request = this_network.CreateInferRequest();
infer_request.SetBlob("data", cv::gapi::ie::util::to_ie(in_mat));
infer_request.Infer();
ie_age = infer_request.GetBlob("age_conv3");
ie_gender = infer_request.GetBlob("prob");
}
// Configure & run G-API
using AGInfo = std::tuple<cv::GMat, cv::GMat>; using AGInfo = std::tuple<cv::GMat, cv::GMat>;
G_API_NET(AgeGender, <AGInfo(cv::GMat)>, "test-age-gender"); G_API_NET(AgeGender, <AGInfo(cv::GMat)>, "test-age-gender");
cv::GMat in; void SetUp() {
cv::GMat age, gender; initDLDTDataPath();
std::tie(age, gender) = cv::gapi::infer<AgeGender>(in); m_params.model_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
cv::GComputation comp(cv::GIn(in), cv::GOut(age, gender)); m_params.weights_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
m_params.device_id = "CPU";
m_plugin = cv::gimpl::ie::wrap::getPlugin(m_params);
m_net = cv::gimpl::ie::wrap::readNetwork(m_params);
setNetParameters(m_net);
m_in_mat = cv::Mat(cv::Size(320, 240), CV_8UC3);
cv::randu(m_in_mat, 0, 255);
}
cv::GComputation buildGraph() {
cv::GMat in, age, gender;
std::tie(age, gender) = cv::gapi::infer<AgeGender>(in);
return cv::GComputation(cv::GIn(in), cv::GOut(age, gender));
}
void validate() {
IE::Blob::Ptr ie_age, ie_gender;
{
auto this_network = cv::gimpl::ie::wrap::loadNetwork(m_plugin, m_net, m_params);
auto infer_request = this_network.CreateInferRequest();
infer_request.SetBlob("data", cv::gapi::ie::util::to_ie(m_in_mat));
infer_request.Infer();
ie_age = infer_request.GetBlob("age_conv3");
ie_gender = infer_request.GetBlob("prob");
}
// Validate with IE itself (avoid DNN module dependency here)
normAssert(cv::gapi::ie::util::to_ocv(ie_age), m_gapi_age, "Test age output" );
normAssert(cv::gapi::ie::util::to_ocv(ie_gender), m_gapi_gender, "Test gender output");
}
};
TEST_F(AgeGenderInferTest, SyncExecution) {
auto pp = cv::gapi::ie::Params<AgeGender> { auto pp = cv::gapi::ie::Params<AgeGender> {
params.model_path, params.weights_path, params.device_id m_params.model_path, m_params.weights_path, m_params.device_id
}.cfgOutputLayers({ "age_conv3", "prob" }) }.cfgOutputLayers({ "age_conv3", "prob" })
.cfgOutputPrecision(CV_8U); .cfgInferMode(cv::gapi::ie::InferMode::Sync);
comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
cv::compile_args(cv::gapi::networks(pp)));
// Validate with IE itself (avoid DNN module dependency here) buildGraph().apply(cv::gin(m_in_mat), cv::gout(m_gapi_age, m_gapi_gender),
normAssert(cv::gapi::ie::util::to_ocv(ie_age), gapi_age, "Test age output" ); cv::compile_args(cv::gapi::networks(pp)));
normAssert(cv::gapi::ie::util::to_ocv(ie_gender), gapi_gender, "Test gender output");
validate();
} }
TEST(TestAgeGenderIE, ChangeSpecificOutputPrecison) TEST_F(AgeGenderInferTest, ThrowSyncWithNireqNotEqualToOne) {
{ auto pp = cv::gapi::ie::Params<AgeGender> {
initDLDTDataPath(); m_params.model_path, m_params.weights_path, m_params.device_id
}.cfgOutputLayers({ "age_conv3", "prob" })
.cfgInferMode(cv::gapi::ie::InferMode::Sync)
.cfgNumRequests(4u);
cv::gapi::ie::detail::ParamDesc params; EXPECT_ANY_THROW(buildGraph().apply(cv::gin(m_in_mat), cv::gout(m_gapi_age, m_gapi_gender),
params.model_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml"); cv::compile_args(cv::gapi::networks(pp))));
params.weights_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin"); }
params.device_id = "CPU";
cv::Mat in_mat(cv::Size(320, 240), CV_8UC3); TEST_F(AgeGenderInferTest, ChangeOutputPrecision) {
cv::randu(in_mat, 0, 255); auto pp = cv::gapi::ie::Params<AgeGender> {
m_params.model_path, m_params.weights_path, m_params.device_id
}.cfgOutputLayers({ "age_conv3", "prob" })
.cfgOutputPrecision(CV_8U);
cv::Mat gapi_age, gapi_gender; for (auto it : m_net.getOutputsInfo()) {
it.second->setPrecision(IE::Precision::U8);
// Load & run IE network
IE::Blob::Ptr ie_age, ie_gender;
{
auto plugin = cv::gimpl::ie::wrap::getPlugin(params);
auto net = cv::gimpl::ie::wrap::readNetwork(params);
setNetParameters(net);
// NB: Specify precision only for "prob" output.
net.getOutputsInfo().at("prob")->setPrecision(IE::Precision::U8);
auto this_network = cv::gimpl::ie::wrap::loadNetwork(plugin, net, params);
auto infer_request = this_network.CreateInferRequest();
infer_request.SetBlob("data", cv::gapi::ie::util::to_ie(in_mat));
infer_request.Infer();
ie_age = infer_request.GetBlob("age_conv3");
ie_gender = infer_request.GetBlob("prob");
} }
// Configure & run G-API buildGraph().apply(cv::gin(m_in_mat), cv::gout(m_gapi_age, m_gapi_gender),
using AGInfo = std::tuple<cv::GMat, cv::GMat>; cv::compile_args(cv::gapi::networks(pp)));
G_API_NET(AgeGender, <AGInfo(cv::GMat)>, "test-age-gender"); validate();
}
cv::GMat in;
cv::GMat age, gender;
std::tie(age, gender) = cv::gapi::infer<AgeGender>(in);
cv::GComputation comp(cv::GIn(in), cv::GOut(age, gender));
TEST_F(AgeGenderInferTest, ChangeSpecificOutputPrecison) {
auto pp = cv::gapi::ie::Params<AgeGender> { auto pp = cv::gapi::ie::Params<AgeGender> {
params.model_path, params.weights_path, params.device_id m_params.model_path, m_params.weights_path, m_params.device_id
}.cfgOutputLayers({ "age_conv3", "prob" }) }.cfgOutputLayers({ "age_conv3", "prob" })
.cfgOutputPrecision({{"prob", CV_8U}}); .cfgOutputPrecision({{"prob", CV_8U}});
comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
cv::compile_args(cv::gapi::networks(pp)));
// Validate with IE itself (avoid DNN module dependency here) m_net.getOutputsInfo().at("prob")->setPrecision(IE::Precision::U8);
normAssert(cv::gapi::ie::util::to_ocv(ie_age), gapi_age, "Test age output" );
normAssert(cv::gapi::ie::util::to_ocv(ie_gender), gapi_gender, "Test gender output"); buildGraph().apply(cv::gin(m_in_mat), cv::gout(m_gapi_age, m_gapi_gender),
cv::compile_args(cv::gapi::networks(pp)));
validate();
} }
} // namespace opencv_test } // namespace opencv_test