cv::optional<cv::gapi::wip::onevpl::Device> vpl_preproc_device;
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
, {}
, {}
, {}
+ , {}
, {}} {
};
, {}
, {}
, {}
+ , {}
, {}} {
};
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)
GBackend backend() const { return cv::gapi::ie::backend(); }
std::string tag() const { return Net::tag(); }
const std::string &device)
: desc{ model, weights, device, {}, {}, {}, 0u, 0u,
detail::ParamDesc::Kind::Load, true, {}, {}, {}, 1u,
- {}, {}, {}, {}},
+ {}, {}, {}, {}, {}},
m_tag(tag) {
};
const std::string &device)
: desc{ model, {}, device, {}, {}, {}, 0u, 0u,
detail::ParamDesc::Kind::Import, true, {}, {}, {}, 1u,
- {}, {}, {}, {}},
+ {}, {}, {}, {}, {}},
m_tag(tag) {
};
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)
GBackend backend() const { return cv::gapi::ie::backend(); }
std::string tag() const { return m_tag; }
params.input_layers = readList<std::string>(fn, "input_layers", name);
params.output_layers = readList<std::string>(fn, "output_layers", name);
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;
}
std::vector<std::string> input_layers;
std::vector<std::string> output_layers;
std::map<std::string, std::string> config;
+ cv::util::optional<int> out_precision;
};
class PipelineBuilder {
}
pp->pluginConfig(infer_params.config);
+ if (infer_params.out_precision) {
+ pp->cfgOutputPrecision(infer_params.out_precision.value());
+ }
m_state->networks += cv::gapi::networks(*pp);
addCall(call_params,
template<class MatType>
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()) {
#define HANDLE(E,T) \
case IE::Precision::E: std::copy_n(blob->buffer().as<T*>(), \
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;
if (params.vpl_preproc_device.has_value() && params.vpl_preproc_ctx.has_value()) {
using namespace cv::gapi::wip;
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
// to post outputs blobs (cv::GMat's).
static void PostOutputs(InferenceEngine::InferRequest &request,
GAPI_Assert(uu.params.input_names.size() == in_metas.size()
&& "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.
using namespace cv::gapi::ie::detail;
if (uu.params.kind == ParamDesc::Kind::Load) {
if (!input_reshape_table.empty()) {
const_cast<IE::CNNNetwork *>(&uu.net)->reshape(input_reshape_table);
}
+ configureOutputPrecision(uu.net.getOutputsInfo(), uu.params.output_precision);
} else {
GAPI_Assert(uu.params.kind == ParamDesc::Kind::Import);
auto inputs = uu.this_network.GetInputsInfo();
const_cast<IEUnit::InputFramesDesc &>(uu.net_input_params)
.set_param(input_name, ii->getTensorDesc());
}
+ configureOutputPrecision(uu.net.getOutputsInfo(), uu.params.output_precision);
} else {
GAPI_Assert(uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import);
auto inputs = uu.this_network.GetInputsInfo();
if (!input_reshape_table.empty()) {
const_cast<IE::CNNNetwork *>(&uu.net)->reshape(input_reshape_table);
}
+ configureOutputPrecision(uu.net.getOutputsInfo(), uu.params.output_precision);
} else {
GAPI_Assert(uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import);
std::size_t idx = 1u;
if (!input_reshape_table.empty()) {
const_cast<IE::CNNNetwork *>(&uu.net)->reshape(input_reshape_table);
}
+ configureOutputPrecision(uu.net.getOutputsInfo(), uu.params.output_precision);
} else {
GAPI_Assert(uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import);
auto inputs = uu.this_network.GetInputsInfo();
}
}
+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
#endif // HAVE_INF_ENGINE