Merge pull request #22957 from dkurt:new_openvino_api
authorDmitry Kurtaev <dmitry.kurtaev@gmail.com>
Fri, 23 Dec 2022 16:58:41 +0000 (19:58 +0300)
committerGitHub <noreply@github.com>
Fri, 23 Dec 2022 16:58:41 +0000 (16:58 +0000)
Switch to new OpenVINO API after 2022.1 release

* Pass Layer_Test_Convolution_DLDT.Accuracy/0 test

* Pass test Test_Caffe_layers.Softmax

* Failed 136 tests

* Fix Concat. Failed 120 tests

* Custom nGraph ops. 19 failed tests

* Set and get properties from Core

* Read model from buffer

* Change MaxPooling layer output names. Restore reshape

* Cosmetic changes

* Cosmetic changes

* Override getOutputsInfo

* Fixes for OpenVINO < 2022.1

* Async inference for 2021.4 and less

* Compile model with config

* Fix serialize for 2022.1

* Asynchronous inference with 2022.1

* Handle 1d outputs

* Work with model with dynamic output shape

* Fixes with 1d output for old API

* Control outputs by nGraph function for all OpenVINO versions

* Refer inputs in PrePostProcessor by indices

* Fix cycled dependency between InfEngineNgraphNode and InfEngineNgraphNet.
Add InferRequest callback only for async inference. Do not capture InferRequest object.

* Fix tests thresholds

* Fix HETERO:GPU,CPU plugin issues with unsupported layer

14 files changed:
modules/dnn/src/ie_ngraph.cpp
modules/dnn/src/ie_ngraph.hpp
modules/dnn/src/layers/concat_layer.cpp
modules/dnn/src/layers/nary_eltwise_layers.cpp
modules/dnn/src/layers/resize_layer.cpp
modules/dnn/src/net_openvino.cpp
modules/dnn/src/op_inf_engine.cpp
modules/dnn/src/op_inf_engine.hpp
modules/dnn/test/test_backends.cpp
modules/dnn/test/test_caffe_importer.cpp
modules/dnn/test/test_darknet_importer.cpp
modules/dnn/test/test_ie_models.cpp
modules/dnn/test/test_layers.cpp
modules/dnn/test/test_model.cpp

index bb65faf..9a80c5e 100644 (file)
@@ -35,6 +35,7 @@ static bool DNN_IE_SERIALIZE = utils::getConfigurationParameterBool("OPENCV_DNN_
 static std::string kDefaultInpLayerName = "opencv_ngraph_empty_inp_layer_name";
 static constexpr const char* kOpenCVLayersType = "opencv_ngraph_layer";
 
+#if INF_ENGINE_VER_MAJOR_LT(INF_ENGINE_RELEASE_2022_1)
 static std::string shapesToStr(const std::vector<Mat>& mats)
 {
     std::ostringstream shapes;
@@ -62,6 +63,7 @@ static void strToShapes(const std::string& str, std::vector<std::vector<size_t>
             ss >> shapes[i][j];
     }
 }
+#endif // OpenVINO < 2022.1
 
 static std::vector<Ptr<NgraphBackendWrapper> >
 ngraphWrappers(const std::vector<Ptr<BackendWrapper> >& ptrs)
@@ -76,6 +78,61 @@ ngraphWrappers(const std::vector<Ptr<BackendWrapper> >& ptrs)
     return wrappers;
 }
 
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+
+class NgraphCustomOp: public ov::op::Op {
+public:
+    OPENVINO_OP(kOpenCVLayersType);
+
+    NgraphCustomOp(const ngraph::OutputVector& inputs, Ptr<Layer>& cvLayer, const std::vector<Mat>& outputs, const std::vector<Mat>& internals):
+        Op(inputs), cvLayer(cvLayer), outputs(outputs), internals(internals)
+    {
+        constructor_validate_and_infer_types();
+    }
+
+    void validate_and_infer_types() override
+    {
+        set_output_size(outputs.size());
+        for (int i = 0; i < outputs.size(); ++i)
+        {
+            ov::PartialShape shape;
+            for (int j = 0; j < outputs[i].dims; ++j) {
+                shape.push_back(outputs[i].size[j]);
+            }
+            set_output_type(i, get_input_element_type(0), shape);
+        }
+    }
+
+    std::shared_ptr<ngraph::Node> clone_with_new_inputs(const ngraph::OutputVector& new_args) const override
+    {
+        return std::make_shared<NgraphCustomOp>(new_args, cvLayer, outputs, internals);
+    }
+
+    bool has_evaluate() const {
+        return true;
+    }
+
+    bool evaluate(ov::TensorVector& outputs, const ov::TensorVector& inputs) const override {
+        std::vector<Mat> inpMats, outMats;
+        infEngineBlobsToMats(inputs, inpMats);
+        infEngineBlobsToMats(outputs, outMats);
+        try
+        {
+            cvLayer->forward(inpMats, outMats, internals);
+            return true;
+        }
+        catch (...)
+        {
+            return false;
+        }
+    }
+
+    Ptr<Layer>& cvLayer;
+    std::vector<Mat> outputs, internals;
+};
+
+#else
+
 class NgraphCustomOp: public ngraph::op::Op {
 public:
     const ngraph::NodeTypeInfo& get_type_info() const override
@@ -324,7 +381,7 @@ public:
 #endif
 };
 
-
+#endif // OpenVINO >= 2022.1
 
 InfEngineNgraphNode::InfEngineNgraphNode(std::shared_ptr<ngraph::Node>&& _node)
     : BackendNode(DNN_BACKEND_INFERENCE_ENGINE_NGRAPH), node(std::move(_node)) {}
@@ -337,15 +394,6 @@ InfEngineNgraphNode::InfEngineNgraphNode(const std::vector<Ptr<BackendNode> >& n
                                          std::vector<Mat>& outputs, std::vector<Mat>& internals)
     : BackendNode(DNN_BACKEND_INFERENCE_ENGINE_NGRAPH), cvLayer(cvLayer_)
 {
-    std::ostringstream oss;
-    oss << (size_t)cvLayer.get();
-
-    std::map<std::string, InferenceEngine::Parameter> params = {
-        {"impl", oss.str()},
-        {"outputs", shapesToStr(outputs)},
-        {"internals", shapesToStr(internals)}
-    };
-
 #if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2020_3)
     ngraph::OutputVector inp_nodes;
 #else
@@ -353,7 +401,19 @@ InfEngineNgraphNode::InfEngineNgraphNode(const std::vector<Ptr<BackendNode> >& n
 #endif
     for (const auto& node : nodes)
         inp_nodes.emplace_back(node.dynamicCast<InfEngineNgraphNode>()->node);
+
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+    node = std::make_shared<NgraphCustomOp>(inp_nodes, cvLayer, outputs, internals);
+#else
+    std::ostringstream oss;
+    oss << (size_t)cvLayer.get();
+    std::map<std::string, InferenceEngine::Parameter> params = {
+        {"impl", oss.str()},
+        {"outputs", shapesToStr(outputs)},
+        {"internals", shapesToStr(internals)}
+    };
     node = std::make_shared<NgraphCustomOp>(inp_nodes, params);
+#endif
 
     CV_Assert(!cvLayer->name.empty());
     setName(cvLayer->name);
@@ -383,7 +443,7 @@ void InfEngineNgraphNet::addOutput(const Ptr<InfEngineNgraphNode>& node)
     CV_Assert(node);
     CV_Assert(node->node);
     const std::string& name = node->node->get_friendly_name();
-    requestedOutputs.insert({name, node});
+    requestedOutputs.insert({name, node.get()});
 }
 
 void InfEngineNgraphNet::setNodePtr(std::shared_ptr<ngraph::Node>* ptr) {
@@ -457,6 +517,9 @@ void InfEngineNgraphNet::createNet(Target targetId) {
             CV_LOG_DEBUG(NULL, "DNN/NGRAPH: Add 'Result' output: " << output_node_it->first);
             CV_Assert(output_node_it->second);
             auto out = std::make_shared<ngraph::op::Result>(output_node_it->second->node);
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+            out->set_friendly_name(output_node_it->first + (output_node_it->second->node->get_output_size() == 1 ? "" : ".0"));
+#endif
             outs.push_back(out);
         }
         CV_Assert_N(!inputs_vec.empty(), !outs.empty());
@@ -504,12 +567,20 @@ void InfEngineNgraphNet::createNet(Target targetId) {
     }
 }
 
+#if INF_ENGINE_VER_MAJOR_LT(INF_ENGINE_RELEASE_2022_1)
+static inline
+InferenceEngine::Layout estimateLayout(size_t dims);
+#endif
+
 void InfEngineNgraphNet::init(Target targetId)
 {
     if (!hasNetOwner)
     {
         if (targetId == DNN_TARGET_OPENCL_FP16)
         {
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+            ov::pass::ConvertFP32ToFP16().run_on_model(ngraph_function);
+#else
             auto nodes = ngraph_function->get_ordered_ops();
             for (auto& node : nodes)
             {
@@ -533,6 +604,7 @@ void InfEngineNgraphNet::init(Target targetId)
                 }
             }
             ngraph_function->validate_nodes_and_infer_types();
+#endif  // OpenVINO >= 2022.1
         }
         cnn = InferenceEngine::CNNNetwork(ngraph_function);
 
@@ -580,20 +652,45 @@ void InfEngineNgraphNet::init(Target targetId)
             CV_Error(Error::StsNotImplemented, "Unknown target");
     };
 
-    if (!hasNetOwner) {
-        for (size_t i = 0; i < ngraph_function->get_output_size(); ++i) {
-            auto node = ngraph_function->output(i).get_node();
-            for (size_t j = 0; j < node->get_input_size(); ++j) {
-                std::string name = node->input_value(j).get_node()->get_friendly_name();
-                auto iter = requestedOutputs.find(name);
-                if (iter != requestedOutputs.end()) {
-                    requestedOutputs.erase(iter);
-                    cnn.addOutput(name);
-                }
-            }
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+    auto model = cnn.getFunction();
+    ov::preprocess::PrePostProcessor ppp(model);
+    int i = 0;
+    for (const auto& inp : model->inputs()) {  // TODO: not sure why but ngraph_function->inputs() here causes segfault.
+        const std::string& name = inp.get_node()->get_friendly_name();
+        auto blobIt = allBlobs.find(name);
+        CV_Assert(blobIt != allBlobs.end());
+
+        auto srcT = blobIt->second.get_element_type();
+        if (srcT != inp.get_node()->get_element_type()) {
+            ppp.input(i++).tensor().set_element_type(srcT);
+        }
+    }
+
+    i = 0;
+    for (const auto& it : model->outputs())
+    {
+        const std::string& name = it.get_node()->get_friendly_name();
+        auto blobIt = allBlobs.find(name);
+        CV_Assert(blobIt != allBlobs.end());
+        const auto& src = blobIt->second;
+
+        // A workaround for single dimension output for which OpenCV allocates 2d Mat.
+        // For example, face-detection-0105 with Result of shape {200} while output blob is {200, 1}
+        auto outShape = it.get_partial_shape().get_max_shape();
+        if (outShape != src.get_shape()) {
+            size_t sz = std::accumulate(outShape.begin(), outShape.end(), 1, std::multiplies<size_t>());
+            CV_Assert(sz == src.get_size());
+            allBlobs[name] = ov::Tensor(src.get_element_type(), outShape, src.data());
         }
+
+        ppp.output(i++).tensor().set_element_type(ov::element::f32);  // Should be always FP32
     }
 
+    ppp.build();
+
+#else
+
     for (const auto& it : cnn.getInputsInfo())
     {
         const std::string& name = it.first;
@@ -607,8 +704,16 @@ void InfEngineNgraphNet::init(Target targetId)
         const std::string& name = it.first;
         auto blobIt = allBlobs.find(name);
         CV_Assert(blobIt != allBlobs.end());
+        InferenceEngine::TensorDesc& desc = blobIt->second->getTensorDesc();
+
+        auto outShape = it.second->getDims();
+        if (outShape != desc.getDims()) {
+            desc.reshape(outShape, estimateLayout(outShape.size()));
+        }
+
         it.second->setPrecision(blobIt->second->getTensorDesc().getPrecision());  // Should be always FP32
     }
+#endif // OpenVINO >= 2022.1
 
     initPlugin(cnn);
 }
@@ -660,6 +765,9 @@ void InfEngineNgraphNet::initPlugin(InferenceEngine::CNNNetwork& net)
                 const std::string& libName = candidates[i];
                 try
                 {
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+                    ie.add_extension(libName);
+#else
                     InferenceEngine::IExtensionPtr extension =
 #if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2021_4)
                         std::make_shared<InferenceEngine::Extension>(libName);
@@ -668,6 +776,7 @@ void InfEngineNgraphNet::initPlugin(InferenceEngine::CNNNetwork& net)
 #endif
 
                     ie.AddExtension(extension, "CPU");
+#endif
                     CV_LOG_INFO(NULL, "DNN-IE: Loaded extension plugin: " << libName);
                     found = true;
                     break;
@@ -678,6 +787,7 @@ void InfEngineNgraphNet::initPlugin(InferenceEngine::CNNNetwork& net)
             {
                 CV_LOG_WARNING(NULL, "DNN-IE: Can't load extension plugin (extra layers for some networks). Specify path via OPENCV_DNN_IE_EXTRA_PLUGIN_PATH parameter");
             }
+#if INF_ENGINE_VER_MAJOR_LT(INF_ENGINE_RELEASE_2022_1)
             // Some of networks can work without a library of extra layers.
             // OpenCV fallbacks as extensions.
             try
@@ -688,12 +798,17 @@ void InfEngineNgraphNet::initPlugin(InferenceEngine::CNNNetwork& net)
             {
                 CV_LOG_INFO(NULL, "DNN-IE: Can't register OpenCV custom layers nGraph extension: " << e.what());
             }
+#endif // OpenVINO < 2022.1
 #ifndef _WIN32
             // Limit the number of CPU threads.
             if (device_name == "CPU")
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+                ie.set_property(device_name, ov::inference_num_threads(getNumThreads()));
+#else
                 ie.SetConfig({{
                     InferenceEngine::PluginConfigParams::KEY_CPU_THREADS_NUM, format("%d", getNumThreads()),
                 }}, device_name);
+#endif // OpenVINO >= 2022.1
 #endif
 #if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2021_2)
             if (device_name.find("GPU") == 0)
@@ -706,9 +821,13 @@ void InfEngineNgraphNet::initPlugin(InferenceEngine::CNNNetwork& net)
                 if (!cache_path.empty() && cache_path != "disabled")
                 {
                     CV_LOG_INFO(NULL, "OpenCV/nGraph: using GPU kernels cache: " << cache_path);
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+                    ie.set_property(device_name, ov::cache_dir(cache_path));
+#else
                     ie.SetConfig({{
                         InferenceEngine::PluginConfigParams::KEY_CACHE_DIR, cache_path,
                     }}, device_name);
+#endif // OpenVINO >= 2022.1
                 }
             }
 #endif
@@ -716,9 +835,9 @@ void InfEngineNgraphNet::initPlugin(InferenceEngine::CNNNetwork& net)
         std::map<std::string, std::string> config;
         if (device_name == "MYRIAD" || device_name == "HDDL") {
 #if INF_ENGINE_VER_MAJOR_GT(INF_ENGINE_RELEASE_2020_4)
-            config.emplace("MYRIAD_DETECT_NETWORK_BATCH", CONFIG_VALUE(NO));
+            config.emplace("MYRIAD_DETECT_NETWORK_BATCH", "NO");
 #else
-            config.emplace("VPU_DETECT_NETWORK_BATCH", CONFIG_VALUE(NO));
+            config.emplace("VPU_DETECT_NETWORK_BATCH", "NO");
 #endif
         }
 
@@ -757,16 +876,17 @@ bool NgraphBackendLayer::getMemoryShapes(const std::vector<MatShape> &inputs,
                                             std::vector<MatShape> &outputs,
                                             std::vector<MatShape> &internals) const
 {
-    InferenceEngine::ICNNNetwork::InputShapes inShapes = t_net.getInputShapes();
-    InferenceEngine::ICNNNetwork::InputShapes::iterator itr;
+    auto ngraphFunction = t_net.getFunction();
     bool equal_flag = true;
-    size_t i = 0;
-    for (itr = inShapes.begin(); itr != inShapes.end(); ++itr)
+    std::map<std::string, std::vector<size_t> > inShapes;
+    int i = 0;
+    for (const auto& inp : ngraphFunction->get_parameters())
     {
-        InferenceEngine::SizeVector currentInShape(inputs[i].begin(), inputs[i].end());
-        if (itr->second != currentInShape)
+        std::vector<size_t> oldShape = inp->get_shape();
+        std::vector<size_t> newShape(inputs[i].begin(), inputs[i].end());
+        inShapes.insert({inp->get_friendly_name(), newShape});
+        if (oldShape != newShape)
         {
-            itr->second = currentInShape;
             equal_flag = false;
         }
         i++;
@@ -777,7 +897,18 @@ bool NgraphBackendLayer::getMemoryShapes(const std::vector<MatShape> &inputs,
         InferenceEngine::CNNNetwork curr_t_net(t_net);
         curr_t_net.reshape(inShapes);
     }
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+    std::vector<size_t> dims;
+    for (const auto& it : ngraphFunction->outputs()) {
+        if (it.get_node()->get_friendly_name() == name) {
+            dims = it.get_partial_shape().get_max_shape();
+        }
+    }
+    if (dims.empty())
+        CV_Error(Error::StsError, format("Unable find result with name %s", name.c_str()));
+#else
     std::vector<size_t> dims = t_net.getOutputsInfo()[name]->getDims();
+#endif
     outputs.push_back(MatShape(dims.begin(), dims.end()));
     return false;
 }
@@ -795,6 +926,21 @@ void NgraphBackendLayer::forward(InputArrayOfArrays inputs, OutputArrayOfArrays
     CV_Error(Error::StsInternal, "Choose Inference Engine as a preferable backend.");
 }
 
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+
+ov::Tensor wrapToNgraphBlob(const Mat& m) {
+    std::vector<size_t> shape = getShape<size_t>(m);
+    if (m.type() == CV_32F)
+        return ov::Tensor(ov::element::f32, shape, m.data);
+    else if (m.type() == CV_8U)
+        return ov::Tensor(ov::element::u8, shape, m.data);
+    else if (m.type() == CV_32SC1)
+        return ov::Tensor(ov::element::i32, shape, m.data);
+    else
+        CV_Error(Error::StsNotImplemented, format("Unsupported data type %s", typeToString(m.type()).c_str()));
+}
+
+#else
 
 static InferenceEngine::Layout estimateLayout(int dims)
 {
@@ -823,19 +969,6 @@ InferenceEngine::Layout estimateLayout(const Mat& m)
     return estimateLayout(m.dims);
 }
 
-static InferenceEngine::DataPtr wrapToInfEngineDataNode(const Mat& m, const std::string& name = "")
-{
-    std::vector<size_t> shape = getShape<size_t>(m);
-    if (m.type() == CV_32F)
-        return InferenceEngine::DataPtr(new InferenceEngine::Data(name,
-               {InferenceEngine::Precision::FP32, shape, estimateLayout(m)}));
-    else if (m.type() == CV_8U)
-        return InferenceEngine::DataPtr(new InferenceEngine::Data(name,
-               {InferenceEngine::Precision::U8, shape, estimateLayout(m)}));
-    else
-        CV_Error(Error::StsNotImplemented, format("Unsupported data type %s", typeToString(m.type()).c_str()));
-}
-
 InferenceEngine::Blob::Ptr wrapToNgraphBlob(const Mat& m, const std::vector<size_t>& shape,
                                                InferenceEngine::Layout layout)
 {
@@ -845,6 +978,9 @@ InferenceEngine::Blob::Ptr wrapToNgraphBlob(const Mat& m, const std::vector<size
     else if (m.type() == CV_8U)
         return InferenceEngine::make_shared_blob<uint8_t>(
                {InferenceEngine::Precision::U8, shape, layout}, (uint8_t*)m.data);
+    else if (m.type() == CV_32SC1)
+        return InferenceEngine::make_shared_blob<int32_t>(
+               {InferenceEngine::Precision::I32, shape, layout}, (int32_t*)m.data);
     else
         CV_Error(Error::StsNotImplemented, format("Unsupported data type %s", typeToString(m.type()).c_str()));
 }
@@ -855,12 +991,15 @@ InferenceEngine::Blob::Ptr wrapToNgraphBlob(const Mat& m, InferenceEngine::Layou
     return wrapToNgraphBlob(m, shape, layout);
 }
 
+InferenceEngine::Blob::Ptr wrapToNgraphBlob(const Mat& m) { return wrapToNgraphBlob(m, estimateLayout(m)); }
+
+#endif // OpenVINO >= 2022.1
+
 NgraphBackendWrapper::NgraphBackendWrapper(int targetId, const cv::Mat& m)
     : BackendWrapper(DNN_BACKEND_INFERENCE_ENGINE_NGRAPH, targetId)
     , host((Mat*)&m)
 {
-    dataPtr = wrapToInfEngineDataNode(m);
-    blob = wrapToNgraphBlob(m, estimateLayout(m));
+    blob = wrapToNgraphBlob(m);
 }
 
 NgraphBackendWrapper::NgraphBackendWrapper(Ptr<BackendWrapper> wrapper)
@@ -868,8 +1007,7 @@ NgraphBackendWrapper::NgraphBackendWrapper(Ptr<BackendWrapper> wrapper)
 {
     Ptr<NgraphBackendWrapper> ieWrapper = wrapper.dynamicCast<NgraphBackendWrapper>();
     CV_Assert(!ieWrapper.empty());
-    InferenceEngine::DataPtr srcData = ieWrapper->dataPtr;
-    dataPtr = InferenceEngine::DataPtr(new InferenceEngine::Data(srcData->getName(), srcData->getTensorDesc()));
+    name = ieWrapper->name;
     blob = ieWrapper->blob;
 }
 
@@ -895,6 +1033,12 @@ void NgraphBackendWrapper::setHostDirty()
     //CV_Error(Error::StsNotImplemented, "");
 }
 
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+ov::Tensor copyBlob(const ov::Tensor& blob)
+{
+    return ov::Tensor(blob.get_element_type(), blob.get_shape());
+}
+#else
 InferenceEngine::Blob::Ptr copyBlob(const InferenceEngine::Blob::Ptr& blob)
 {
     InferenceEngine::Blob::Ptr copy;
@@ -918,88 +1062,13 @@ InferenceEngine::Blob::Ptr copyBlob(const InferenceEngine::Blob::Ptr& blob)
     return copy;
 }
 
-InferenceEngine::DataPtr ngraphDataNode(const Ptr<BackendWrapper>& ptr)
-{
-    CV_Assert(!ptr.empty());
-    Ptr<NgraphBackendWrapper> p = ptr.dynamicCast<NgraphBackendWrapper>();
-    CV_Assert(!p.empty());
-    return p->dataPtr;
-}
-
-static
-InferenceEngine::Blob::Ptr reallocateBlob(Mat &m, const InferenceEngine::TensorDesc& description)
-{
-    auto dims = description.getDims();
-    auto layout = estimateLayout(dims.size());
-    MatShape matShape(dims.begin(), dims.end());
-    if (description.getPrecision() == InferenceEngine::Precision::FP32)
-    {
-        m.create(matShape, CV_32FC1);
-        return InferenceEngine::make_shared_blob<float>(
-                {description.getPrecision(), dims, layout}, (float*)m.data);
-    }
-    else if (description.getPrecision() == InferenceEngine::Precision::I32)
-    {
-        m.create(matShape, CV_32SC1);
-        return InferenceEngine::make_shared_blob<int>(
-                {description.getPrecision(), dims, layout}, (int*)m.data);
-    }
-    else if (description.getPrecision() == InferenceEngine::Precision::U8)
-    {
-        m.create(matShape, CV_8UC1);
-        return InferenceEngine::make_shared_blob<uchar>(
-                {description.getPrecision(), dims, layout}, (uchar*)m.data);
-    }
-    std::ostringstream msg;
-    msg << "Unsupported IE precision: " << description.getPrecision();
-    CV_Error(Error::StsNotImplemented, msg.str());
-}
-
-InferenceEngine::DataPtr ngraphDataOutputNode(
-        const Ptr<BackendWrapper>& ptr,
-        const InferenceEngine::TensorDesc& description,
-        const std::string name)
-{
-    CV_Assert(!ptr.empty());
-    Ptr<NgraphBackendWrapper> p = ptr.dynamicCast<NgraphBackendWrapper>();
-    CV_Assert(!p.empty());
-    NgraphBackendWrapper& w = *p;
-    const InferenceEngine::TensorDesc& blobDesc = w.blob.get()->getTensorDesc();
-    auto dims = description.getDims();
-    bool reallocate = false;
-    if (blobDesc.getPrecision() != description.getPrecision())
-    {
-        reallocate = true;
-        CV_LOG_WARNING(NULL, "Reallocate output '" << name << "' blob due to wrong precision: " << blobDesc.getPrecision() << " => " << description.getPrecision() << "  ndims=" << dims.size());
-    }
-    if (dims.size() != blobDesc.getDims().size())
-    {
-        reallocate = true;
-        CV_LOG_WARNING(NULL, "Reallocate output '" << name << "' blob due to wrong dims: " << blobDesc.getDims().size() << " => " << dims.size());
-    }
-    if (reallocate)
-    {
-        auto layout = estimateLayout(dims.size());
-        w.dataPtr = InferenceEngine::DataPtr(new InferenceEngine::Data(name,
-               {description.getPrecision(), dims, layout}));
-        w.blob = reallocateBlob(*w.host, description);
-    }
-    return w.dataPtr;
-}
-
+#endif // OpenVINO < 2022.1
 
 void InfEngineNgraphNet::reset()
 {
     allBlobs.clear();
     infRequests.clear();
     isInit = false;
-
-    outputsDesc.clear();
-    for (const auto& it : cnn.getOutputsInfo())
-    {
-        const std::string& name = it.first;
-        outputsDesc.insert({name, it.second->getTensorDesc()});
-    }
 }
 
 void InfEngineNgraphNet::addBlobs(const std::vector<cv::Ptr<BackendWrapper> >& ptrs)
@@ -1007,7 +1076,7 @@ void InfEngineNgraphNet::addBlobs(const std::vector<cv::Ptr<BackendWrapper> >& p
     auto wrappers = ngraphWrappers(ptrs);
     for (const auto& wrapper : wrappers)
     {
-        std::string name = wrapper->dataPtr->getName();
+        std::string name = wrapper->name;
         name = name.empty() ? kDefaultInpLayerName : name;
         allBlobs.insert({name, wrapper->blob});
     }
@@ -1022,25 +1091,8 @@ void InfEngineNgraphNet::NgraphReqWrapper::makePromises(const std::vector<Ptr<Ba
     for (int i = 0; i < outs.size(); ++i)
     {
         outs[i]->futureMat = outProms[i].getArrayResult();
-        outsNames[i] = outs[i]->dataPtr->getName();
-    }
-}
-
-Mat ngraphBlobToMat(const InferenceEngine::Blob::Ptr& blob)
-{
-    std::vector<size_t> dims = blob->getTensorDesc().getDims();
-    std::vector<int> size(dims.begin(), dims.end());
-    auto precision = blob->getTensorDesc().getPrecision();
-
-    int type = -1;
-    switch (precision)
-    {
-        case InferenceEngine::Precision::FP32: type = CV_32F; break;
-        case InferenceEngine::Precision::U8: type = CV_8U; break;
-        default:
-            CV_Error(Error::StsNotImplemented, "Unsupported blob precision");
+        outsNames[i] = outs[i]->name;
     }
-    return Mat(size, type, (void*)blob->buffer());
 }
 
 void InfEngineNgraphNet::forward(const std::vector<Ptr<BackendWrapper> >& outBlobsWrappers, bool isAsync)
@@ -1070,6 +1122,25 @@ void InfEngineNgraphNet::forward(const std::vector<Ptr<BackendWrapper> >& outBlo
         }
         infRequests.push_back(reqWrapper);
 
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+        int i = 0;
+        for (const auto& it : netExec.inputs())
+        {
+            const std::string& name = it.get_node()->get_friendly_name();
+            auto blobIt = allBlobs.find(name);
+            CV_Assert(blobIt != allBlobs.end());
+            reqWrapper->req.set_input_tensor(i++, isAsync ? copyBlob(blobIt->second) : blobIt->second);
+        }
+
+        i = 0;
+        for (const auto& it : netExec.outputs())
+        {
+            const std::string& name = it.get_node()->get_friendly_name();
+            auto blobIt = allBlobs.find(name);
+            CV_Assert(blobIt != allBlobs.end());
+            reqWrapper->req.set_output_tensor(i++, isAsync ? copyBlob(blobIt->second) : blobIt->second);
+        }
+#else
         InferenceEngine::BlobMap inpBlobs, outBlobs;
         for (const auto& it : cnn.getInputsInfo())
         {
@@ -1087,6 +1158,53 @@ void InfEngineNgraphNet::forward(const std::vector<Ptr<BackendWrapper> >& outBlo
         }
         reqWrapper->req.SetInput(inpBlobs);
         reqWrapper->req.SetOutput(outBlobs);
+#endif
+
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+    if (isAsync) {
+        bool* isReady = &reqWrapper->isReady;
+        auto* promises = &reqWrapper->outProms;
+        auto* req = &reqWrapper->req;
+        reqWrapper->req.set_callback([isReady, promises, req](std::exception_ptr ex) {
+            CV_LOG_DEBUG(NULL, "DNN(nGraph): completionCallback(" << (int)status << ")");
+
+            size_t processedOutputs = 0;
+            try
+            {
+                for (; processedOutputs < promises->size(); ++processedOutputs)
+                {
+                    Mat m = infEngineBlobToMat(req->get_output_tensor(processedOutputs));
+
+                    try
+                    {
+                        (*promises)[processedOutputs].setValue(m.clone());
+                    }
+                    catch (...)
+                    {
+                        try {
+                            (*promises)[processedOutputs].setException(std::current_exception());
+                        } catch(...) {
+                            CV_LOG_ERROR(NULL, "DNN: Exception occurred during async inference exception propagation");
+                        }
+                    }
+                }
+            }
+            catch (...)
+            {
+                std::exception_ptr e = std::current_exception();
+                for (; processedOutputs < promises->size(); ++processedOutputs)
+                {
+                    try {
+                        (*promises)[processedOutputs].setException(e);
+                    } catch(...) {
+                        CV_LOG_ERROR(NULL, "DNN: Exception occurred during async inference exception propagation");
+                    }
+                }
+            }
+            *isReady = true;
+        });
+    }
+#else // OpenVINO >= 2022.1
 
 #if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2021_4)
         InferenceEngine::InferRequest infRequest = reqWrapper->req;
@@ -1125,7 +1243,7 @@ void InfEngineNgraphNet::forward(const std::vector<Ptr<BackendWrapper> >& outBlo
                     for (; processedOutputs < wrapper.outProms.size(); ++processedOutputs)
                     {
                         const std::string& name = wrapper.outsNames[processedOutputs];
-                        Mat m = ngraphBlobToMat(wrapper.req.GetBlob(name));
+                        Mat m = infEngineBlobToMat(wrapper.req.GetBlob(name));
 
                         try
                         {
@@ -1157,8 +1275,34 @@ void InfEngineNgraphNet::forward(const std::vector<Ptr<BackendWrapper> >& outBlo
                 wrapper.isReady = true;
             }
         );
+#endif // OpenVINO >= 2022.1
     }
 
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+    if (isAsync)
+    {
+        // Copy actual data to infer request's input blobs.
+        int i = 0;
+        for (const auto& it : cnn.getFunction()->get_parameters())
+        {
+            const std::string& name = it->get_friendly_name();
+            auto blobIt = allBlobs.find(name);
+            Mat srcMat = infEngineBlobToMat(blobIt->second);
+            Mat dstMat = infEngineBlobToMat(reqWrapper->req.get_input_tensor(i++));
+            srcMat.copyTo(dstMat);
+        }
+
+        // Set promises to output blobs wrappers.
+        reqWrapper->makePromises(outBlobsWrappers);
+
+        reqWrapper->isReady = false;
+        reqWrapper->req.start_async();
+    }
+    else
+    {
+        reqWrapper->req.infer();
+    }
+#else
     if (isAsync)
     {
         // Copy actual data to infer request's input blobs.
@@ -1166,8 +1310,8 @@ void InfEngineNgraphNet::forward(const std::vector<Ptr<BackendWrapper> >& outBlo
         {
             const std::string& name = it.first;
             auto blobIt = allBlobs.find(name);
-            Mat srcMat = ngraphBlobToMat(blobIt->second);
-            Mat dstMat = ngraphBlobToMat(reqWrapper->req.GetBlob(name));
+            Mat srcMat = infEngineBlobToMat(blobIt->second);
+            Mat dstMat = infEngineBlobToMat(reqWrapper->req.GetBlob(name));
             srcMat.copyTo(dstMat);
         }
 
@@ -1181,6 +1325,7 @@ void InfEngineNgraphNet::forward(const std::vector<Ptr<BackendWrapper> >& outBlo
     {
         reqWrapper->req.Infer();
     }
+#endif // OpenVINO >= 2022.1
 }
 
 #endif
index 9ccc182..09afc7f 100644 (file)
@@ -68,7 +68,11 @@ public:
     std::unordered_map<std::string, std::shared_ptr<ngraph::Node>* > all_nodes;
 
     InferenceEngine::ExecutableNetwork netExec;
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+    std::map<std::string, ov::Tensor> allBlobs;
+#else
     InferenceEngine::BlobMap allBlobs;
+#endif
     std::string device_name;
     bool isInit = false;
 
@@ -87,9 +91,7 @@ public:
 
     InferenceEngine::CNNNetwork cnn;
     bool hasNetOwner;
-    std::unordered_map<std::string, Ptr<InfEngineNgraphNode> > requestedOutputs;
-
-    std::map<std::string, InferenceEngine::TensorDesc> outputsDesc;
+    std::unordered_map<std::string, InfEngineNgraphNode*> requestedOutputs;
 };
 
 class InfEngineNgraphNode : public BackendNode
@@ -123,17 +125,15 @@ public:
     virtual void setHostDirty() CV_OVERRIDE;
 
     Mat* host;
-    InferenceEngine::DataPtr dataPtr;
+    std::string name;
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+    ov::Tensor blob;
+#else
     InferenceEngine::Blob::Ptr blob;
+#endif
     AsyncArray futureMat;
 };
 
-InferenceEngine::DataPtr ngraphDataNode(const Ptr<BackendWrapper>& ptr);
-InferenceEngine::DataPtr ngraphDataOutputNode(
-        const Ptr<BackendWrapper>& ptr,
-        const InferenceEngine::TensorDesc& description,
-        const std::string name);
-
 // This is a fake class to run networks from Model Optimizer. Objects of that
 // class simulate responses of layers are imported by OpenCV and supported by
 // Inference Engine. The main difference is that they do not perform forward pass.
index 1b520cf..52330a8 100644 (file)
@@ -403,8 +403,7 @@ public:
     virtual Ptr<BackendNode> initNgraph(const std::vector<Ptr<BackendWrapper> >& inputs,
                                         const std::vector<Ptr<BackendNode> >& nodes) CV_OVERRIDE
     {
-        InferenceEngine::DataPtr data = ngraphDataNode(inputs[0]);
-        const int numDims = data->getDims().size();
+        const int numDims = nodes[0].dynamicCast<InfEngineNgraphNode>()->node->get_shape().size();
         const int cAxis = normalize_axis(axis, numDims);
         std::vector<size_t> maxDims(numDims, 0);
 
@@ -412,16 +411,17 @@ public:
         ngraph::OutputVector inp_nodes;
         for (int i = 0; i < nodes.size(); ++i)
         {
-            inp_nodes.push_back(nodes[i].dynamicCast<InfEngineNgraphNode>()->node);
+            auto inp = nodes[i].dynamicCast<InfEngineNgraphNode>()->node;
+            inp_nodes.push_back(inp);
 
-            std::vector<size_t> inpShape = ngraphDataNode(inputs[i])->getDims();
+            std::vector<size_t> inpShape = inp->get_shape();
             for (int i = 0; i < numDims; ++i)
                 maxDims[i] = std::max(maxDims[i], inpShape[i]);
         }
         for (int i = 0; i < inp_nodes.size(); ++i)
         {
             bool needPadding = false;
-            std::vector<size_t> inpShape = ngraphDataNode(inputs[i])->getDims();
+            std::vector<size_t> inpShape = inp_nodes[i].get_shape();
             std::vector<int64_t> begins(inpShape.size(), 0), ends(inpShape.size(), 0);
             for (int j = 0; j < inpShape.size(); ++j)
             {
index 6850cd5..3f43c02 100644 (file)
@@ -6,6 +6,7 @@
 #include "layers_common.hpp"
 #include "../op_cuda.hpp"
 #include "../op_cann.hpp"
+#include "../ie_ngraph.hpp"
 
 #include <opencv2/dnn/shape_utils.hpp>
 
@@ -104,6 +105,12 @@ public:
             return op == OPERATION::ADD || op == OPERATION::PROD || op == OPERATION::DIV ||
                    op == OPERATION::DIV || op == OPERATION::MAX  || op == OPERATION::MIN;
 #endif
+        if (backendId == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
+            return (op == OPERATION::ADD ||
+                    op == OPERATION::PROD ||
+                    op == OPERATION::GREATER_EQUAL ||
+                    op == OPERATION::LESS_EQUAL
+            );
         if (op == OPERATION::MAX || op == OPERATION::MIN || op == OPERATION::SUM ||
             op == OPERATION::PROD || op == OPERATION::DIV)
             return backendId == DNN_BACKEND_OPENCV || backendId == DNN_BACKEND_CUDA;
@@ -743,6 +750,37 @@ public:
         CV_Assert(inputs.size());
         return inputs.size() * total(outputs[0]);
     }
+
+#ifdef HAVE_DNN_NGRAPH
+    virtual Ptr<BackendNode> initNgraph(const std::vector<Ptr<BackendWrapper> >& inputs, const std::vector<Ptr<BackendNode> >& nodes) CV_OVERRIDE
+    {
+        CV_Assert(inputs.size() == 2);
+        auto& inp0 = nodes[0].dynamicCast<InfEngineNgraphNode>()->node;
+        auto& inp1 = nodes[1].dynamicCast<InfEngineNgraphNode>()->node;
+
+        if (inp0->get_element_type() != inp1->get_element_type()) {
+            auto dtype = preferableTarget == DNN_TARGET_OPENCL_FP16 || preferableTarget == DNN_TARGET_MYRIAD ?
+                        ngraph::element::f16 : ngraph::element::f32;
+            if (inp0->get_element_type() != dtype)
+                inp0 = std::make_shared<ngraph::op::v0::Convert>(inp0, dtype);
+            if (inp1->get_element_type() != dtype)
+                inp1 = std::make_shared<ngraph::op::v0::Convert>(inp1, dtype);
+        }
+
+        std::shared_ptr<ngraph::Node> node;
+        if (op == OPERATION::ADD)
+            node = std::make_shared<ngraph::op::v1::Add>(inp0, inp1);
+        else if (op == OPERATION::PROD)
+            node = std::make_shared<ngraph::op::v1::Multiply>(inp0, inp1);
+        else if (op == OPERATION::GREATER_EQUAL)
+            node = std::make_shared<ngraph::op::v1::GreaterEqual>(inp0, inp1);
+        else if (op == OPERATION::LESS_EQUAL)
+            node = std::make_shared<ngraph::op::v1::LessEqual>(inp0, inp1);
+        else
+            CV_Error(Error::StsNotImplemented, "Operation is not implemented for nGraph backend");
+        return Ptr<BackendNode>(new InfEngineNgraphNode(node));
+    }
+#endif
 };
 
 Ptr<NaryEltwiseLayer> NaryEltwiseLayer::create(const LayerParams& params)
index 356b193..4342b51 100644 (file)
@@ -401,6 +401,24 @@ public:
 #else
         ngraph::op::v4::Interpolate::InterpolateAttrs attrs;
 
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+        if (interpolation == "nearest") {
+            attrs.mode = ngraph::op::v4::Interpolate::InterpolateMode::NEAREST;
+            attrs.coordinate_transformation_mode = ngraph::op::v4::Interpolate::CoordinateTransformMode::HALF_PIXEL;
+        } else if (interpolation == "bilinear") {
+            attrs.mode = ngraph::op::v4::Interpolate::InterpolateMode::LINEAR_ONNX;
+            attrs.coordinate_transformation_mode = ngraph::op::v4::Interpolate::CoordinateTransformMode::ASYMMETRIC;
+        } else {
+            CV_Error(Error::StsNotImplemented, format("Unsupported interpolation: %s", interpolation.c_str()));
+        }
+        attrs.shape_calculation_mode = ngraph::op::v4::Interpolate::ShapeCalcMode::SIZES;
+
+        if (alignCorners) {
+            attrs.coordinate_transformation_mode = ngraph::op::v4::Interpolate::CoordinateTransformMode::ALIGN_CORNERS;
+        }
+
+        attrs.nearest_mode = ngraph::op::v4::Interpolate::NearestMode::ROUND_PREFER_FLOOR;
+#else
         if (interpolation == "nearest") {
             attrs.mode = ngraph::op::v4::Interpolate::InterpolateMode::nearest;
             attrs.coordinate_transformation_mode = ngraph::op::v4::Interpolate::CoordinateTransformMode::half_pixel;
@@ -417,6 +435,7 @@ public:
         }
 
         attrs.nearest_mode = ngraph::op::v4::Interpolate::NearestMode::round_prefer_floor;
+#endif // OpenVINO >= 2022.1
 
         std::vector<int64_t> shape = {outHeight, outWidth};
         auto out_shape = std::make_shared<ngraph::op::Constant>(ngraph::element::i64, ngraph::Shape{2}, shape.data());
index d55c26a..5704cb9 100644 (file)
@@ -275,19 +275,17 @@ void NetImplOpenVINO::initBackend(const std::vector<LayerPin>& blobsToKeep_)
                       (netInputLayer->outNames.size() == ld.outputBlobsWrappers.size()));
             for (int i = 0; i < ld.outputBlobsWrappers.size(); ++i)
             {
-                InferenceEngine::DataPtr dataPtr = ngraphDataNode(ld.outputBlobsWrappers[i]);
                 std::string outputName = netInputLayer->outNames.empty() ? ld.name : netInputLayer->outNames[i];
                 outputName = ld.outputBlobsWrappers.size() > 1 ? (outputName + "." + std::to_string(i)) : outputName;
-                dataPtr->setName(outputName);
+                ld.outputBlobsWrappers[i].dynamicCast<NgraphBackendWrapper>()->name = outputName;
             }
         }
         else
         {
             for (int i = 0; i < ld.outputBlobsWrappers.size(); ++i)
             {
-                InferenceEngine::DataPtr dataPtr = ngraphDataNode(ld.outputBlobsWrappers[i]);
                 std::string outputName = ld.outputBlobsWrappers.size() > 1 ? (ld.name + "." + std::to_string(i)) : ld.name;
-                dataPtr->setName(outputName);
+                ld.outputBlobsWrappers[i].dynamicCast<NgraphBackendWrapper>()->name = outputName;
             }
         }
     }
@@ -311,26 +309,7 @@ void NetImplOpenVINO::initBackend(const std::vector<LayerPin>& blobsToKeep_)
             {
                 for (int i = 0; i < ld.inputBlobsWrappers.size(); ++i)
                 {
-                    InferenceEngine::DataPtr dataPtr = ngraphDataNode(ld.inputBlobsWrappers[i]);
-                    dataPtr->setName(netInputLayer->outNames[i]);
-                }
-            }
-            else
-            {
-                for (int i = 0; i < ld.outputBlobsWrappers.size(); ++i)
-                {
-                    auto it = ienet.outputsDesc.find(ld.name);
-                    if (it != ienet.outputsDesc.end())
-                    {
-                        const InferenceEngine::TensorDesc& descriptor = it->second;
-                        InferenceEngine::DataPtr dataPtr = ngraphDataOutputNode(ld.outputBlobsWrappers[i], descriptor, ld.name);
-                        dataPtr->setName(ld.name);
-                    }
-                    else
-                    {
-                        InferenceEngine::DataPtr dataPtr = ngraphDataNode(ld.outputBlobsWrappers[i]);
-                        dataPtr->setName(ld.name);
-                    }
+                    ld.inputBlobsWrappers[i].dynamicCast<NgraphBackendWrapper>()->name = netInputLayer->outNames[i];
                 }
             }
             ienet.addBlobs(ld.inputBlobsWrappers);
@@ -456,10 +435,10 @@ void NetImplOpenVINO::initBackend(const std::vector<LayerPin>& blobsToKeep_)
                                                                  dynamicCast<NgraphBackendWrapper>();
                     CV_Assert(!inpWrapper.empty());
                     auto iter = std::find(inputNames.begin(), inputNames.end(),
-                            inpWrapper->dataPtr->getName());
+                            inpWrapper->name);
                     if (iter == inputNames.end())
                     {
-                        inputNames.push_back(inpWrapper->dataPtr->getName());
+                        inputNames.push_back(inpWrapper->name);
                         inputs.push_back(inpLd.outputBlobs[cons_inp]);
                     }
                     curr_pos = cons + 1;
@@ -505,7 +484,12 @@ void NetImplOpenVINO::initBackend(const std::vector<LayerPin>& blobsToKeep_)
                 CV_LOG_DEBUG(NULL, "DNN/IE: bind output port " << lid << ":" << oid << " (" << ngraph_input_node->get_friendly_name() << ":" << ngraph_input_node->get_type_info().name << ")");
 
                 // Handle parameters from other subnets. Output port is not used in this case
+#if INF_ENGINE_VER_MAJOR_GT(INF_ENGINE_RELEASE_2020_4)
                 if ((ngraph::op::is_parameter(ngraph_input_node) || ngraph::op::is_constant(ngraph_input_node)) &&
+#else
+                if ((ngraph_input_node->is_parameter() || ngraph_input_node->is_constant()) &&
+#endif
+
                         ngraph_input_node->get_output_size() == 1)
                 {
                     inputNodes[i] = Ptr<BackendNode>(new InfEngineNgraphNode(ngraph_input_node));
@@ -702,14 +686,33 @@ Net NetImplOpenVINO::createNetworkFromModelOptimizer(InferenceEngine::CNNNetwork
 
     CV_TRACE_REGION("register_inputs");
 
+    auto ngraphFunction = ieNet.getFunction();
+    CV_Assert(ngraphFunction);
+
     std::vector<String> inputsNames;
     std::vector<MatShape> inp_shapes;
-    for (auto& it : ieNet.getInputsInfo())
+    for (auto& it : ngraphFunction->get_parameters())
     {
-        inputsNames.push_back(it.first);
-        std::vector<size_t> dims = it.second->getTensorDesc().getDims();
+        inputsNames.push_back(it->get_friendly_name());
+        std::vector<size_t> dims = it->get_shape();
         inp_shapes.push_back(std::vector<int>(dims.begin(), dims.end()));
     }
+    // nGraph models produce output "Result" layers which have "/sink_port" suffix in their names.
+    // Their inputs are actual model outputs and we change friendly name to it.
+    // By this workaround, we produce similar outputs names comparing to ieNet.getOutputsInfo()
+    for (int i = 0; i < ngraphFunction->get_output_size(); ++i) {
+        auto res = ngraphFunction->output(i);
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+        const std::string& name = res.get_any_name();
+#else
+        auto out = res.get_node()->input(0).get_source_output();
+        std::string name = out.get_node()->get_friendly_name();
+        if (out.get_node()->get_output_size() > 1)
+            name += "." + std::to_string(out.get_index());
+#endif
+        if (res.get_node()->get_friendly_name() != name)
+            res.get_node()->set_friendly_name(name);
+    }
 
     Net cvNet;
     Ptr<NetImplOpenVINO> openvino_impl_ptr = makePtr<NetImplOpenVINO>();
@@ -736,17 +739,15 @@ Net NetImplOpenVINO::createNetworkFromModelOptimizer(InferenceEngine::CNNNetwork
 
     CV_TRACE_REGION_NEXT("register_outputs");
 
-    auto ngraphFunction = ieNet.getFunction();
-    CV_Assert(ngraphFunction);
     std::vector<std::shared_ptr<ngraph::Node>> ngraphOperations = ngraphFunction->get_ops();
 
-    for (auto& it : ieNet.getOutputsInfo())
+    for (auto& it : ngraphFunction->get_results())
     {
         CV_TRACE_REGION("output");
-        const auto& outputName = it.first;
+        const auto& outputName = it->get_friendly_name();
 
         LayerParams lp;
-        int lid = cvNet.addLayer(it.first, "", lp);
+        int lid = cvNet.addLayer(outputName, "", lp);
 
         LayerData& ld = openvino_impl.layers[lid];
 
@@ -835,10 +836,15 @@ Net openvino_readNetwork(
     InferenceEngine::CNNNetwork ieNet;
     try
     {
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+        ov::Tensor weights_blob(ov::element::u8, {bufferWeightsSize}, (void*)bufferWeightsPtr);
+        ieNet = ie.read_model(model, weights_blob);
+#else
         InferenceEngine::TensorDesc tensorDesc(InferenceEngine::Precision::U8, { bufferWeightsSize }, InferenceEngine::Layout::C);
         InferenceEngine::Blob::CPtr weights_blob = InferenceEngine::make_shared_blob<uint8_t>(tensorDesc, (uint8_t*)bufferWeightsPtr, bufferWeightsSize);
 
         ieNet = ie.ReadNetwork(model, weights_blob);
+#endif
     }
     catch (const std::exception& e)
     {
index e237be0..f9e3993 100644 (file)
@@ -39,6 +39,86 @@ cv::String setInferenceEngineBackendType(const cv::String& newBackendType)
 
 CV__DNN_INLINE_NS_END
 
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+namespace InferenceEngine {
+
+CNNNetwork::CNNNetwork() {}
+
+CNNNetwork::CNNNetwork(std::shared_ptr<ov::Model> model) : model(model) {}
+
+std::shared_ptr<ov::Model> CNNNetwork::getFunction() const {
+    return model;
+}
+
+void CNNNetwork::serialize(const std::string& xmlPath, const std::string& binPath) {
+    ov::pass::Serialize(xmlPath, binPath).run_on_model(model);
+}
+
+void CNNNetwork::reshape(const std::map<std::string, std::vector<size_t> >& shapes) {
+    std::map<std::string, ov::PartialShape> partialShapes;
+    for (const auto& it : shapes) {
+        ov::PartialShape shape;
+        shape.insert(shape.begin(), it.second.begin(), it.second.end());
+        partialShapes.insert({it.first, shape});
+    }
+    model->reshape(partialShapes);
+}
+
+std::vector<std::string> Core::GetAvailableDevices() {
+    return get_available_devices();
+}
+
+void Core::UnregisterPlugin(const std::string& id) {
+    unload_plugin(id);
+}
+
+CNNNetwork Core::ReadNetwork(const std::string& xmlPath, const std::string& binPath) {
+    return read_model(xmlPath, binPath);
+}
+
+ExecutableNetwork Core::LoadNetwork(CNNNetwork net, const std::string& device,
+                                    const std::map<std::string, std::string>& config) {
+    ov::AnyMap props;
+    for (const auto& it : config) {
+        props.insert(it);
+    }
+    return compile_model(net.getFunction(), device, props);
+}
+
+ExecutableNetwork::ExecutableNetwork() {}
+
+ExecutableNetwork::ExecutableNetwork(const ov::CompiledModel& copy) : CompiledModel(copy) {}
+
+ov::InferRequest ExecutableNetwork::CreateInferRequest() { return create_infer_request(); }
+
+}  // namespace InferenceEngine
+
+Mat infEngineBlobToMat(const ov::Tensor& blob)
+{
+    std::vector<size_t> dims = blob.get_shape();
+    std::vector<int> size(dims.begin(), dims.end());
+    auto precision = blob.get_element_type();
+
+    int type = -1;
+    switch (precision)
+    {
+        case ov::element::f32: type = CV_32F; break;
+        case ov::element::u8: type = CV_8U; break;
+        default:
+            CV_Error(Error::StsNotImplemented, "Unsupported blob precision");
+    }
+    return Mat(size, type, blob.data());
+}
+
+void infEngineBlobsToMats(const ov::TensorVector& blobs,
+                          std::vector<Mat>& mats)
+{
+    mats.resize(blobs.size());
+    for (int i = 0; i < blobs.size(); ++i)
+        mats[i] = infEngineBlobToMat(blobs[i]);
+}
+
+#else
 
 Mat infEngineBlobToMat(const InferenceEngine::Blob::Ptr& blob)
 {
@@ -65,7 +145,7 @@ void infEngineBlobsToMats(const std::vector<InferenceEngine::Blob::Ptr>& blobs,
     for (int i = 0; i < blobs.size(); ++i)
         mats[i] = infEngineBlobToMat(blobs[i]);
 }
-
+#endif // OpenVINO >= 2022.1
 
 static bool init_IE_plugins()
 {
@@ -130,7 +210,11 @@ static bool detectArmPlugin_()
     {
         if (i->find("CPU") != std::string::npos)
         {
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+            const std::string name = ie.get_property(*i, ov::device::full_name);
+#else
             const std::string name = ie.GetMetric(*i, METRIC_KEY(FULL_DEVICE_NAME)).as<std::string>();
+#endif
             CV_LOG_INFO(NULL, "CPU plugin: " << name);
             return name.find("arm_compute::NEON") != std::string::npos;
         }
@@ -150,7 +234,11 @@ static bool detectMyriadX_(const std::string& device)
     {
         if (i->find(device) != std::string::npos)
         {
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+            const std::string name = ie.get_property(*i, ov::device::full_name);
+#else
             const std::string name = ie.GetMetric(*i, METRIC_KEY(FULL_DEVICE_NAME)).as<std::string>();
+#endif
             CV_LOG_INFO(NULL, "Myriad device: " << name);
             return name.find("MyriadX") != std::string::npos || name.find("Myriad X") != std::string::npos || name.find("HDDL") != std::string::npos;
         }
index 6ac4d95..45913d3 100644 (file)
 
 #ifdef HAVE_INF_ENGINE
 
-#define INF_ENGINE_RELEASE_2018R5 2018050000
-#define INF_ENGINE_RELEASE_2019R1 2019010000
-#define INF_ENGINE_RELEASE_2019R2 2019020000
-#define INF_ENGINE_RELEASE_2019R3 2019030000
-#define INF_ENGINE_RELEASE_2020_1 2020010000
 #define INF_ENGINE_RELEASE_2020_2 2020020000
 #define INF_ENGINE_RELEASE_2020_3 2020030000
 #define INF_ENGINE_RELEASE_2020_4 2020040000
@@ -31,6 +26,7 @@
 #define INF_ENGINE_RELEASE_2021_2 2021020000
 #define INF_ENGINE_RELEASE_2021_3 2021030000
 #define INF_ENGINE_RELEASE_2021_4 2021040000
+#define INF_ENGINE_RELEASE_2022_1 2022010000
 
 #ifndef INF_ENGINE_RELEASE
 #warning("IE version have not been provided via command-line. Using 2021.4 by default")
 #pragma GCC diagnostic ignored "-Wsuggest-override"
 #endif
 
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+#include <openvino/openvino.hpp>
+#include <openvino/pass/serialize.hpp>
+#include <openvino/pass/convert_fp32_to_fp16.hpp>
+#else
 #include <inference_engine.hpp>
+#endif
 
 #if defined(__GNUC__) && __GNUC__ >= 5
 //#pragma GCC diagnostic pop
@@ -73,11 +75,17 @@ CV__DNN_INLINE_NS_END
 
 Backend& getInferenceEngineBackendTypeParam();
 
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+Mat infEngineBlobToMat(const ov::Tensor& blob);
+
+void infEngineBlobsToMats(const ov::TensorVector& blobs,
+                          std::vector<Mat>& mats);
+#else
 Mat infEngineBlobToMat(const InferenceEngine::Blob::Ptr& blob);
 
 void infEngineBlobsToMats(const std::vector<InferenceEngine::Blob::Ptr>& blobs,
                           std::vector<Mat>& mats);
-
+#endif  // OpenVINO >= 2022.1
 
 
 CV__DNN_INLINE_NS_BEGIN
@@ -90,6 +98,52 @@ bool isArmComputePlugin();
 
 CV__DNN_INLINE_NS_END
 
+// A series of wrappers for classes from OpenVINO API 2.0.
+// Need just for less conditional compilation inserts.
+#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1)
+namespace InferenceEngine {
+
+class CNNNetwork {
+public:
+    CNNNetwork();
+
+    CNNNetwork(std::shared_ptr<ov::Model> model);
+
+    std::shared_ptr<ov::Model> getFunction() const;
+
+    void serialize(const std::string& xmlPath, const std::string& binPath);
+
+    void reshape(const std::map<std::string, std::vector<size_t> >& shapes);
+
+private:
+    std::shared_ptr<ov::Model> model = nullptr;
+};
+
+typedef ov::InferRequest InferRequest;
+
+class ExecutableNetwork : public ov::CompiledModel {
+public:
+    ExecutableNetwork();
+
+    ExecutableNetwork(const ov::CompiledModel& copy);
+
+    ov::InferRequest CreateInferRequest();
+};
+
+class Core : public ov::Core {
+public:
+    std::vector<std::string> GetAvailableDevices();
+
+    void UnregisterPlugin(const std::string& id);
+
+    CNNNetwork ReadNetwork(const std::string& xmlPath, const std::string& binPath);
+
+    ExecutableNetwork LoadNetwork(CNNNetwork net, const std::string& device,
+                                  const std::map<std::string, std::string>& config);
+};
+
+}
+#endif // OpenVINO >= 2022.1
 
 InferenceEngine::Core& getCore(const std::string& id);
 
index 9b8765b..7aa9c75 100644 (file)
@@ -531,7 +531,7 @@ TEST_P(DNNTestNetwork, FastNeuralStyle_eccv16)
     if (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD)
     {
         l1 = 0.4;
-        lInf = 7.45;
+        lInf = 7.46;
     }
     else if (target == DNN_TARGET_CUDA_FP16)
     {
index 4043bd1..8059fc6 100644 (file)
@@ -725,18 +725,21 @@ TEST_P(Test_Caffe_nets, FasterRCNN_vgg16)
         applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION);
 #endif
 
+    double scoreDiff = 0.0;
 #if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2022010000)
     // Check 'backward_compatible_check || in_out_elements_equal' failed at core/src/op/reshape.cpp:427:
     // While validating node 'v1::Reshape bbox_pred_reshape (bbox_pred[0]:f32{1,84}, Constant_265242[0]:i64{4}) -> (f32{?,?,?,?})' with friendly_name 'bbox_pred_reshape':
     // Requested output shape {1,6300,4,1} is incompatible with input shape {1, 84}
     if (target == DNN_TARGET_MYRIAD)
         applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION);
+    if (target == DNN_TARGET_OPENCL_FP16)
+        scoreDiff = 0.02;
 #endif
 
     static Mat ref = (Mat_<float>(3, 7) << 0, 2, 0.949398, 99.2454, 210.141, 601.205, 462.849,
                                            0, 7, 0.997022, 481.841, 92.3218, 722.685, 175.953,
                                            0, 12, 0.993028, 133.221, 189.377, 350.994, 563.166);
-    testFaster("faster_rcnn_vgg16.prototxt", "VGG16_faster_rcnn_final.caffemodel", ref);
+    testFaster("faster_rcnn_vgg16.prototxt", "VGG16_faster_rcnn_final.caffemodel", ref, scoreDiff);
 }
 
 TEST_P(Test_Caffe_nets, FasterRCNN_zf)
index 0b4c1bc..2160c81 100644 (file)
@@ -638,6 +638,11 @@ TEST_P(Test_Darknet_nets, YOLOv3)
     double scoreDiff = 8e-5, iouDiff = 3e-4;
     if (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD)
     {
+#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_GE(2022010000)
+        if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
+            scoreDiff = 0.009;
+        else
+#endif
         scoreDiff = 0.006;
         iouDiff = 0.042;
     }
@@ -771,6 +776,7 @@ TEST_P(Test_Darknet_nets, YOLOv4)
     // accuracy (batch 2)
     if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL_FP16)
     {
+        scoreDiff = 0.008f;
         iouDiff = 0.05f;
     }
     // accuracy
index 3622f69..135caa9 100644 (file)
@@ -438,6 +438,9 @@ TEST_P(DNNTestOpenVINO, models)
     {
         auto dstIt = cvOutputsMap.find(srcIt.first);
         CV_Assert(dstIt != cvOutputsMap.end());
+
+        dstIt->second.convertTo(dstIt->second, srcIt.second.type());
+
         double normInf = cvtest::norm(srcIt.second, dstIt->second, cv::NORM_INF);
         EXPECT_LE(normInf, eps) << "output=" << srcIt.first;
     }
index a54c2fe..6afb3a8 100644 (file)
@@ -1292,7 +1292,7 @@ TEST_P(Layer_Test_Convolution_DLDT, Accuracy)
     if (backendId == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019)
         ASSERT_EQ(net.getLayer(outLayers[0])->type, "Convolution");
     else
-        ASSERT_EQ(net.getLayer(outLayers[0])->type, "Add");
+        ASSERT_EQ(net.getLayer(outLayers[0])->type, "Result");
 }
 
 TEST_P(Layer_Test_Convolution_DLDT, setInput_uint8)
index d7fc2af..d3217a0 100644 (file)
@@ -447,6 +447,10 @@ TEST_P(Test_Model, DetectionOutput)
     {
         if (backend == DNN_BACKEND_OPENCV)
             scoreDiff = 4e-3;
+#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_GE(2022010000)
+        else if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
+            scoreDiff = 4e-2;
+#endif
         else
             scoreDiff = 2e-2;
         iouDiff = 1.8e-1;