Add cfgOutputPrecision

pull/22583/head
TolyaTalamanov 2 years ago
parent 96844b0ca5
commit b0b77b3047
  1. 51
      modules/gapi/include/opencv2/gapi/infer/ie.hpp
  2. 6
      modules/gapi/samples/pipeline_modeling_tool.cpp
  3. 4
      modules/gapi/samples/pipeline_modeling_tool/pipeline_builder.hpp
  4. 49
      modules/gapi/src/backends/ie/giebackend.cpp
  5. 105
      modules/gapi/test/infer/gapi_infer_ie_test.cpp

@ -88,6 +88,15 @@ 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;
using precision_t = int;
using precision_map_t = std::unordered_map<std::string, int>;
// NB: cv::util::monostate is default value that means precision wasn't specified.
using precision_variant_t = cv::util::variant<cv::util::monostate,
precision_t,
precision_map_t>;
precision_variant_t output_precision;
}; };
} // namespace detail } // namespace detail
@ -132,6 +141,7 @@ public:
, {} , {}
, {} , {}
, {} , {}
, {}
, {}} { , {}} {
}; };
@ -156,6 +166,7 @@ public:
, {} , {}
, {} , {}
, {} , {}
, {}
, {}} { , {}} {
}; };
@ -351,6 +362,29 @@ public:
return *this; return *this;
} }
/** @brief Specifies the output precision for model.
The function is used to set an output precision for model.
@param precision Precision in OpenCV format.
@return reference to this parameter structure.
*/
Params<Net>& cfgOutputPrecision(detail::ParamDesc::precision_t precision) {
desc.output_precision = precision;
return *this;
}
/** @overload
@param precision_map Map of pairs: name of corresponding output layer and its precision
@return reference to this parameter structure.
*/
Params<Net>&
cfgOutputPrecision(detail::ParamDesc::precision_map_t precision_map) {
desc.output_precision = precision_map;
return *this;
}
// BEGIN(G-API's network parametrization API) // BEGIN(G-API's network parametrization API)
GBackend backend() const { return cv::gapi::ie::backend(); } GBackend backend() const { return cv::gapi::ie::backend(); }
std::string tag() const { return Net::tag(); } std::string tag() const { return Net::tag(); }
@ -385,7 +419,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,
{}, {}, {}, {}}, {}, {}, {}, {}, {}},
m_tag(tag) { m_tag(tag) {
}; };
@ -403,7 +437,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,
{}, {}, {}, {}}, {}, {}, {}, {}, {}},
m_tag(tag) { m_tag(tag) {
}; };
@ -476,6 +510,19 @@ public:
return *this; return *this;
} }
/** @see ie::Params::cfgOutputPrecision */
Params& cfgOutputPrecision(detail::ParamDesc::precision_t precision) {
desc.output_precision = precision;
return *this;
}
/** @overload */
Params&
cfgOutputPrecision(detail::ParamDesc::precision_map_t precision_map) {
desc.output_precision = precision_map;
return *this;
}
// BEGIN(G-API's network parametrization API) // BEGIN(G-API's network parametrization API)
GBackend backend() const { return cv::gapi::ie::backend(); } GBackend backend() const { return cv::gapi::ie::backend(); }
std::string tag() const { return m_tag; } std::string tag() const { return m_tag; }

@ -210,6 +210,12 @@ InferParams read<InferParams>(const cv::FileNode& fn) {
params.input_layers = readList<std::string>(fn, "input_layers", name); params.input_layers = readList<std::string>(fn, "input_layers", name);
params.output_layers = readList<std::string>(fn, "output_layers", name); params.output_layers = readList<std::string>(fn, "output_layers", name);
params.config = readMap<std::string>(fn["config"]); params.config = readMap<std::string>(fn["config"]);
auto out_prec_str = readOpt<std::string>(fn["output_precision"]);
if (out_prec_str.has_value()) {
params.out_precision =
cv::optional<int>(strToPrecision(out_prec_str.value()));
}
return params; return params;
} }

@ -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::util::optional<int> out_precision;
}; };
class PipelineBuilder { class PipelineBuilder {
@ -362,6 +363,9 @@ void PipelineBuilder::addInfer(const CallParams& call_params,
} }
pp->pluginConfig(infer_params.config); pp->pluginConfig(infer_params.config);
if (infer_params.out_precision) {
pp->cfgOutputPrecision(infer_params.out_precision.value());
}
m_state->networks += cv::gapi::networks(*pp); m_state->networks += cv::gapi::networks(*pp);
addCall(call_params, addCall(call_params,

@ -197,6 +197,16 @@ inline IE::Blob::Ptr wrapIE(const cv::MediaFrame::View& view,
template<class MatType> template<class MatType>
inline void copyFromIE(const IE::Blob::Ptr &blob, MatType &mat) { inline void copyFromIE(const IE::Blob::Ptr &blob, MatType &mat) {
const auto& desc = blob->getTensorDesc();
const auto ie_type = toCV(desc.getPrecision());
if (ie_type != mat.type()) {
std::stringstream ss;
ss << "Failed while copying blob from IE to OCV: "
<< "Blobs have different data types.\n"
<< "IE type: " << ie_type << "\n"
<< "OCV type: " << mat.type() << std::endl;
throw std::logic_error(ss.str());
}
switch (blob->getTensorDesc().getPrecision()) { switch (blob->getTensorDesc().getPrecision()) {
#define HANDLE(E,T) \ #define HANDLE(E,T) \
case IE::Precision::E: std::copy_n(blob->buffer().as<T*>(), \ case IE::Precision::E: std::copy_n(blob->buffer().as<T*>(), \
@ -365,6 +375,13 @@ struct IEUnit {
cv::util::throw_error(std::logic_error("Unsupported ParamDesc::Kind")); cv::util::throw_error(std::logic_error("Unsupported ParamDesc::Kind"));
} }
if (params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import &&
!cv::util::holds_alternative<cv::util::monostate>(params.output_precision)) {
cv::util::throw_error(
std::logic_error("Setting output precision isn't supported for imported network"));
}
using namespace cv::gapi::wip::onevpl; using namespace cv::gapi::wip::onevpl;
if (params.vpl_preproc_device.has_value() && params.vpl_preproc_ctx.has_value()) { if (params.vpl_preproc_device.has_value() && params.vpl_preproc_ctx.has_value()) {
using namespace cv::gapi::wip; using namespace cv::gapi::wip;
@ -1122,6 +1139,32 @@ static IE::PreProcessInfo configurePreProcInfo(const IE::InputInfo::CPtr& ii,
return info; return info;
} }
using namespace cv::gapi::ie::detail;
static void configureOutputPrecision(const IE::OutputsDataMap &outputs_info,
const ParamDesc::precision_variant_t &output_precision) {
switch (output_precision.index()) {
case ParamDesc::precision_variant_t::index_of<ParamDesc::precision_t>(): {
auto precision = toIE(cv::util::get<ParamDesc::precision_t>(output_precision));
for (auto it : outputs_info) {
it.second->setPrecision(precision);
}
break;
}
case ParamDesc::precision_variant_t::index_of<ParamDesc::precision_map_t>(): {
const auto& precision_map =
cv::util::get<ParamDesc::precision_map_t>(output_precision);
for (auto it : precision_map) {
outputs_info.at(it.first)->setPrecision(toIE(it.second));
}
break;
}
case ParamDesc::precision_variant_t::index_of<cv::util::monostate>(): {
// Do nothing;
break;
}
}
}
// NB: This is a callback used by async infer // NB: This is a callback used by async infer
// to post outputs blobs (cv::GMat's). // to post outputs blobs (cv::GMat's).
static void PostOutputs(InferenceEngine::InferRequest &request, static void PostOutputs(InferenceEngine::InferRequest &request,
@ -1241,7 +1284,7 @@ struct Infer: public cv::detail::KernelTag {
GAPI_Assert(uu.params.input_names.size() == in_metas.size() GAPI_Assert(uu.params.input_names.size() == in_metas.size()
&& "Known input layers count doesn't match input meta count"); && "Known input layers count doesn't match input meta count");
// NB: Configuring input precision and network reshape must be done // NB: Configuring input/output precision and network reshape must be done
// only in the loadNetwork case. // only in the loadNetwork case.
using namespace cv::gapi::ie::detail; using namespace cv::gapi::ie::detail;
if (uu.params.kind == ParamDesc::Kind::Load) { if (uu.params.kind == ParamDesc::Kind::Load) {
@ -1275,6 +1318,7 @@ struct Infer: public cv::detail::KernelTag {
if (!input_reshape_table.empty()) { if (!input_reshape_table.empty()) {
const_cast<IE::CNNNetwork *>(&uu.net)->reshape(input_reshape_table); const_cast<IE::CNNNetwork *>(&uu.net)->reshape(input_reshape_table);
} }
configureOutputPrecision(uu.net.getOutputsInfo(), uu.params.output_precision);
} else { } else {
GAPI_Assert(uu.params.kind == ParamDesc::Kind::Import); GAPI_Assert(uu.params.kind == ParamDesc::Kind::Import);
auto inputs = uu.this_network.GetInputsInfo(); auto inputs = uu.this_network.GetInputsInfo();
@ -1393,6 +1437,7 @@ struct InferROI: public cv::detail::KernelTag {
const_cast<IEUnit::InputFramesDesc &>(uu.net_input_params) const_cast<IEUnit::InputFramesDesc &>(uu.net_input_params)
.set_param(input_name, ii->getTensorDesc()); .set_param(input_name, ii->getTensorDesc());
} }
configureOutputPrecision(uu.net.getOutputsInfo(), uu.params.output_precision);
} else { } else {
GAPI_Assert(uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import); GAPI_Assert(uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import);
auto inputs = uu.this_network.GetInputsInfo(); auto inputs = uu.this_network.GetInputsInfo();
@ -1513,6 +1558,7 @@ struct InferList: public cv::detail::KernelTag {
if (!input_reshape_table.empty()) { if (!input_reshape_table.empty()) {
const_cast<IE::CNNNetwork *>(&uu.net)->reshape(input_reshape_table); const_cast<IE::CNNNetwork *>(&uu.net)->reshape(input_reshape_table);
} }
configureOutputPrecision(uu.net.getOutputsInfo(), uu.params.output_precision);
} else { } else {
GAPI_Assert(uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import); GAPI_Assert(uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import);
std::size_t idx = 1u; std::size_t idx = 1u;
@ -1667,6 +1713,7 @@ struct InferList2: public cv::detail::KernelTag {
if (!input_reshape_table.empty()) { if (!input_reshape_table.empty()) {
const_cast<IE::CNNNetwork *>(&uu.net)->reshape(input_reshape_table); const_cast<IE::CNNNetwork *>(&uu.net)->reshape(input_reshape_table);
} }
configureOutputPrecision(uu.net.getOutputsInfo(), uu.params.output_precision);
} else { } else {
GAPI_Assert(uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import); GAPI_Assert(uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import);
auto inputs = uu.this_network.GetInputsInfo(); auto inputs = uu.this_network.GetInputsInfo();

@ -2956,6 +2956,111 @@ TEST(TestAgeGender, ThrowBlobAndInputPrecisionMismatchStreaming)
} }
} }
TEST(TestAgeGenderIE, ChangeOutputPrecision)
{
initDLDTDataPath();
cv::gapi::ie::detail::ParamDesc params;
params.model_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
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);
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>;
G_API_NET(AgeGender, <AGInfo(cv::GMat)>, "test-age-gender");
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));
auto pp = cv::gapi::ie::Params<AgeGender> {
params.model_path, params.weights_path, params.device_id
}.cfgOutputLayers({ "age_conv3", "prob" })
.cfgOutputPrecision(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)
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");
}
TEST(TestAgeGenderIE, ChangeSpecificOutputPrecison)
{
initDLDTDataPath();
cv::gapi::ie::detail::ParamDesc params;
params.model_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
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);
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);
// 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
using AGInfo = std::tuple<cv::GMat, cv::GMat>;
G_API_NET(AgeGender, <AGInfo(cv::GMat)>, "test-age-gender");
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));
auto pp = cv::gapi::ie::Params<AgeGender> {
params.model_path, params.weights_path, params.device_id
}.cfgOutputLayers({ "age_conv3", "prob" })
.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)
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");
}
} // namespace opencv_test } // namespace opencv_test
#endif // HAVE_INF_ENGINE #endif // HAVE_INF_ENGINE

Loading…
Cancel
Save