namespace cv {
namespace dnn {
+
+namespace accessor {
+class DnnNetAccessor; // forward declaration
+}
+
CV__DNN_INLINE_NS_BEGIN
//! @addtogroup dnn
//! @{
*/
CV_WRAP int64 getPerfProfile(CV_OUT std::vector<double>& timings);
- private:
+
struct Impl;
+ inline Impl* getImpl() const { return impl.get(); }
+ inline Impl& getImplRef() const { CV_DbgAssert(impl); return *impl.get(); }
+ friend class accessor::DnnNetAccessor;
+ protected:
Ptr<Impl> impl;
};
CV__DNN_INLINE_NS_END
+
+namespace accessor {
+class DnnNetAccessor
+{
+public:
+ static inline Ptr<Net::Impl>& getImplPtrRef(Net& net)
+ {
+ return net.impl;
+ }
+};
+}
+
}} // namespace
#endif // __OPENCV_DNN_COMMON_HPP__
int getParam_DNN_BACKEND_DEFAULT()
{
static int PARAM_DNN_BACKEND_DEFAULT = (int)utils::getConfigurationParameterSizeT("OPENCV_DNN_BACKEND_DEFAULT",
-#ifdef HAVE_INF_ENGINE
- (size_t)DNN_BACKEND_INFERENCE_ENGINE
-#else
(size_t)DNN_BACKEND_OPENCV
-#endif
);
return PARAM_DNN_BACKEND_DEFAULT;
}
return w.dataPtr;
}
-void forwardNgraph(const std::vector<Ptr<BackendWrapper> >& outBlobsWrappers,
- Ptr<BackendNode>& node, bool isAsync)
-{
- CV_Assert(!node.empty());
- Ptr<InfEngineNgraphNode> ieNode = node.dynamicCast<InfEngineNgraphNode>();
- CV_Assert(!ieNode.empty());
- ieNode->net->forward(outBlobsWrappers, isAsync);
-}
void InfEngineNgraphNet::reset()
{
}
}
-#else
-void forwardNgraph(const std::vector<Ptr<BackendWrapper> >& outBlobsWrappers,
- Ptr<BackendNode>& node, bool isAsync)
-{
- CV_Assert(false && "nGraph is not enabled in this OpenCV build");
-}
#endif
}}
#endif // HAVE_DNN_NGRAPH
-void forwardNgraph(const std::vector<Ptr<BackendWrapper> >& outBlobsWrappers,
- Ptr<BackendNode>& node, bool isAsync);
-
}} // namespace cv::dnn
return layerInstance;
}
+
+ void resetAllocation()
+ {
+ if (id == 0)
+ return; // skip "input" layer (assertion in Net::Impl::allocateLayers)
+
+ layerInstance.release();
+ outputBlobs.clear();
+ inputBlobs.clear();
+ internals.clear();
+
+ outputBlobsWrappers.clear();
+ inputBlobsWrappers.clear();
+ internalBlobsWrappers.clear();
+
+ backendNodes.clear();
+
+ skip = false;
+ flag = 0;
+
+#ifdef HAVE_CUDA
+ cudaD2HBackgroundTransfers.clear();
+#endif
+ }
};
}
else if (backendId == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
{
-#ifdef HAVE_DNN_NGRAPH
- return Ptr<BackendWrapper>(new NgraphBackendWrapper(targetId, m));
-#else
- CV_Error(Error::StsNotImplemented, "This OpenCV version is built without support of OpenVINO / Inference Engine + nGraph");
-#endif
+ CV_Assert(0 && "Internal error: DNN_BACKEND_INFERENCE_ENGINE_NGRAPH must be implemented through inheritance");
}
else if (backendId == DNN_BACKEND_WEBNN)
{
CV_TRACE_FUNCTION();
CV_Assert(impl);
CV_Assert(!empty());
- return impl->quantize(calibData, inputsDtype, outputsDtype, perChannel);
+ return impl->quantize(*this, calibData, inputsDtype, outputsDtype, perChannel);
}
// FIXIT drop from inference API
CV_TRACE_FUNCTION();
CV_TRACE_ARG(backendId);
CV_Assert(impl);
- return impl->setPreferableBackend(backendId);
+ return impl->setPreferableBackend(*this, backendId);
}
void Net::setPreferableTarget(int targetId)
}
+Net::Impl::~Impl()
+{
+ // nothing
+}
+
+
Net::Impl::Impl()
{
// allocate fake net input layer
netWasQuantized = false;
fusion = true;
isAsync = false;
- preferableBackend = DNN_BACKEND_DEFAULT;
+ preferableBackend = (Backend)getParam_DNN_BACKEND_DEFAULT();
preferableTarget = DNN_TARGET_CPU;
- skipInfEngineInit = false;
hasDynamicShapes = false;
}
}
-void Net::Impl::setUpNet(const std::vector<LayerPin>& blobsToKeep_)
+void Net::Impl::validateBackendAndTarget()
{
CV_TRACE_FUNCTION();
- if (dumpLevel && networkDumpCounter == 0)
- {
- dumpNetworkToFile();
- }
-
- if (preferableBackend == DNN_BACKEND_DEFAULT)
- preferableBackend = (Backend)getParam_DNN_BACKEND_DEFAULT();
-#ifdef HAVE_INF_ENGINE
- if (preferableBackend == DNN_BACKEND_INFERENCE_ENGINE)
- preferableBackend = DNN_BACKEND_INFERENCE_ENGINE_NGRAPH; // = getInferenceEngineBackendTypeParam();
-#endif
-
CV_Assert(preferableBackend != DNN_BACKEND_OPENCV ||
preferableTarget == DNN_TARGET_CPU ||
preferableTarget == DNN_TARGET_OPENCL ||
CV_Assert(preferableBackend != DNN_BACKEND_HALIDE ||
preferableTarget == DNN_TARGET_CPU ||
preferableTarget == DNN_TARGET_OPENCL);
-#ifdef HAVE_INF_ENGINE
- if (preferableBackend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
- {
- CV_Assert(
- (preferableTarget == DNN_TARGET_CPU && (!isArmComputePlugin() || preferableBackend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)) ||
- preferableTarget == DNN_TARGET_OPENCL ||
- preferableTarget == DNN_TARGET_OPENCL_FP16 ||
- preferableTarget == DNN_TARGET_MYRIAD ||
- preferableTarget == DNN_TARGET_HDDL ||
- preferableTarget == DNN_TARGET_FPGA
- );
- }
-#endif
#ifdef HAVE_WEBNN
if (preferableBackend == DNN_BACKEND_WEBNN)
{
CV_Assert(preferableBackend != DNN_BACKEND_TIMVX ||
preferableTarget == DNN_TARGET_NPU);
+ CV_Assert(preferableBackend != DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && "Inheritance internal error");
+}
+
+void Net::Impl::setUpNet(const std::vector<LayerPin>& blobsToKeep_)
+{
+ CV_TRACE_FUNCTION();
+
+ if (dumpLevel && networkDumpCounter == 0)
+ {
+ dumpNetworkToFile();
+ }
+
+ validateBackendAndTarget();
+
if (!netWasAllocated || this->blobsToKeep != blobsToKeep_)
{
if (preferableBackend == DNN_BACKEND_OPENCV && IS_DNN_OPENCL_TARGET(preferableTarget))
{
forwardHalide(ld.outputBlobsWrappers, node);
}
-#ifdef HAVE_INF_ENGINE
else if (preferableBackend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
{
- forwardNgraph(ld.outputBlobsWrappers, node, isAsync);
+ CV_Assert(preferableBackend != DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && "Inheritance internal error");
}
-#endif
else if (preferableBackend == DNN_BACKEND_WEBNN)
{
forwardWebnn(ld.outputBlobsWrappers, node, isAsync);
#endif
else
{
- CV_Error(Error::StsNotImplemented, "Unknown backend identifier");
+ CV_Error(Error::StsNotImplemented, cv::format("Unknown backend identifier: %d", preferableBackend));
}
}
AsyncArray Net::Impl::getBlobAsync(const LayerPin& pin)
{
CV_TRACE_FUNCTION();
-#ifdef HAVE_INF_ENGINE
- if (!pin.valid())
- CV_Error(Error::StsObjectNotFound, "Requested blob not found");
-
- LayerData& ld = layers[pin.lid];
- if ((size_t)pin.oid >= ld.outputBlobs.size())
- {
- CV_Error(Error::StsOutOfRange, format("Layer \"%s\" produce only %d outputs, "
- "the #%d was requested",
- ld.name.c_str(), (int)ld.outputBlobs.size(), (int)pin.oid));
- }
- if (preferableTarget != DNN_TARGET_CPU)
- {
- CV_Assert(!ld.outputBlobsWrappers.empty() && !ld.outputBlobsWrappers[pin.oid].empty());
- // Transfer data to CPU if it's require.
- ld.outputBlobsWrappers[pin.oid]->copyToHost();
- }
- CV_Assert(preferableBackend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH);
-
- Ptr<NgraphBackendWrapper> wrapper = ld.outputBlobsWrappers[pin.oid].dynamicCast<NgraphBackendWrapper>();
- return std::move(wrapper->futureMat);
-#else
CV_Error(Error::StsNotImplemented, "DNN: OpenVINO/nGraph backend is required");
-#endif // HAVE_INF_ENGINE
}
typedef std::map<int, LayerShapes> LayersShapesMap;
typedef std::map<int, LayerData> MapIdToLayerData;
+ virtual ~Impl();
Impl();
+ Impl(const Impl&) = delete;
+
+ // Inheritance support
+ Ptr<Net::Impl> basePtr_;
Ptr<DataLayer> netInputLayer;
std::vector<LayerPin> blobsToKeep;
int preferableBackend;
int preferableTarget;
String halideConfigFile;
- bool skipInfEngineInit;
+// bool skipInfEngineInit;
bool hasDynamicShapes;
// Map host data to backend specific wrapper.
std::map<void*, Ptr<BackendWrapper>> backendWrappers;
bool netWasAllocated;
bool netWasQuantized;
bool fusion;
- bool isAsync;
+ bool isAsync; // FIXIT: drop
std::vector<int64> layersTimings;
- bool empty() const;
- void setPreferableBackend(int backendId);
- void setPreferableTarget(int targetId);
+ virtual bool empty() const;
+ virtual void setPreferableBackend(Net& net, int backendId);
+ virtual void setPreferableTarget(int targetId);
// FIXIT use inheritance
- Ptr<BackendWrapper> wrap(Mat& host);
+ virtual Ptr<BackendWrapper> wrap(Mat& host);
+
+ virtual void clear();
- void clear();
+
+ virtual void validateBackendAndTarget();
void setUpNet(const std::vector<LayerPin>& blobsToKeep_ = std::vector<LayerPin>());
void setInputsNames(const std::vector<String>& inputBlobNames);
void setInputShape(const String& inputName, const MatShape& shape);
- void setInput(InputArray blob, const String& name, double scalefactor, const Scalar& mean);
+ virtual void setInput(InputArray blob, const String& name, double scalefactor, const Scalar& mean);
Mat getParam(int layer, int numParam) const;
void setParam(int layer, int numParam, const Mat& blob);
std::vector<Ptr<Layer>> getLayerInputs(int layerId) const;
int getLayersCount(const String& layerType) const;
- // FIXIT use inheritance
- void initBackend(const std::vector<LayerPin>& blobsToKeep_);
+ virtual void initBackend(const std::vector<LayerPin>& blobsToKeep_);
void setHalideScheduler(const String& scheduler);
#ifdef HAVE_HALIDE
void initHalideBackend();
#endif
-#ifdef HAVE_DNN_NGRAPH
- void addNgraphOutputs(LayerData& ld);
- void initNgraphBackend(const std::vector<LayerPin>& blobsToKeep_);
-#endif
-
#ifdef HAVE_WEBNN
void addWebnnOutputs(LayerData& ld);
void initWebnnBackend(const std::vector<LayerPin>& blobsToKeep_);
// TODO add getter
void enableFusion(bool fusion_);
- void fuseLayers(const std::vector<LayerPin>& blobsToKeep_);
+ virtual void fuseLayers(const std::vector<LayerPin>& blobsToKeep_);
void allocateLayers(const std::vector<LayerPin>& blobsToKeep_);
- void forwardLayer(LayerData& ld);
+ virtual void forwardLayer(LayerData& ld);
void forwardToLayer(LayerData& ld, bool clearFlags = true);
Mat getBlob(String outputName) const;
#ifdef CV_CXX11
- AsyncArray getBlobAsync(const LayerPin& pin);
+ virtual AsyncArray getBlobAsync(const LayerPin& pin);
AsyncArray getBlobAsync(String outputName);
#endif // CV_CXX11
-#ifdef HAVE_INF_ENGINE
- static
- Net createNetworkFromModelOptimizer(InferenceEngine::CNNNetwork& ieNet);
-#endif
-
string dump(bool forceAllocation = false) const;
void dumpNetworkToFile() const;
// FIXIT drop from inference API
- Net quantize(InputArrayOfArrays calibData, int inputsDtype, int outputsDtype, bool perChannel) /*const*/;
+ Net quantize(Net& net, InputArrayOfArrays calibData, int inputsDtype, int outputsDtype, bool perChannel) /*const*/;
void getInputDetails(std::vector<float>& scales, std::vector<int>& zeropoints) /*const*/;
void getOutputDetails(std::vector<float>& scales, std::vector<int>& zeropoints) /*const*/;
}
else if (preferableBackend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
{
-#ifdef HAVE_DNN_NGRAPH
- initNgraphBackend(blobsToKeep_);
-#else
- CV_Error(Error::StsNotImplemented, "This OpenCV version is built without support of OpenVINO");
-#endif
+ CV_Assert(0 && "Inheritance must be used with OpenVINO backend");
}
else if (preferableBackend == DNN_BACKEND_WEBNN)
{
}
-void Net::Impl::setPreferableBackend(int backendId)
+void Net::Impl::setPreferableBackend(Net& net, int backendId)
{
if (backendId == DNN_BACKEND_DEFAULT)
backendId = (Backend)getParam_DNN_BACKEND_DEFAULT();
+ if (backendId == DNN_BACKEND_INFERENCE_ENGINE)
+ backendId = DNN_BACKEND_INFERENCE_ENGINE_NGRAPH; // = getInferenceEngineBackendTypeParam();
+
if (netWasQuantized && backendId != DNN_BACKEND_OPENCV && backendId != DNN_BACKEND_TIMVX)
{
CV_LOG_WARNING(NULL, "DNN: Only default and TIMVX backends support quantized networks");
backendId = DNN_BACKEND_OPENCV;
}
-#ifdef HAVE_INF_ENGINE
- if (backendId == DNN_BACKEND_INFERENCE_ENGINE)
- backendId = DNN_BACKEND_INFERENCE_ENGINE_NGRAPH;
-#endif
-
if (preferableBackend != backendId)
{
preferableBackend = backendId;
clear();
+#ifdef HAVE_INF_ENGINE
+ if (backendId == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
+ {
+ switchToOpenVINOBackend(net);
+ }
+#endif
}
}
#ifdef HAVE_INF_ENGINE
+// TODO: use "string" target specifier
+class NetImplOpenVINO CV_FINAL : public Net::Impl
+{
+public:
+ typedef Net::Impl Base;
+
+ // this default constructor is used with OpenVINO native loader
+ // TODO: dedicated Impl?
+ NetImplOpenVINO()
+ : Net::Impl()
+ {
+ preferableBackend = DNN_BACKEND_INFERENCE_ENGINE_NGRAPH;
+ }
+
+ // constructor to derive execution implementation from the loaded network
+ explicit NetImplOpenVINO(const Ptr<Net::Impl>& basePtr)
+ : Net::Impl()
+ {
+ basePtr_ = basePtr;
+ init();
+ }
+
+ void init()
+ {
+ CV_TRACE_FUNCTION();
+ CV_Assert(basePtr_);
+ Net::Impl& base = *basePtr_;
+ CV_Assert(!base.netWasAllocated);
+ CV_Assert(!base.netWasQuantized);
+ netInputLayer = base.netInputLayer;
+ blobsToKeep = base.blobsToKeep;
+ layers = base.layers;
+ for (MapIdToLayerData::iterator it = layers.begin(); it != layers.end(); it++)
+ {
+ LayerData& ld = it->second;
+ ld.resetAllocation();
+ }
+ layerNameToId = base.layerNameToId;
+ outputNameToId = base.outputNameToId;
+ //blobManager = base.blobManager;
+ preferableBackend = DNN_BACKEND_INFERENCE_ENGINE_NGRAPH; //base.preferableBackend;
+ preferableTarget = base.preferableTarget;
+ hasDynamicShapes = base.hasDynamicShapes;
+ CV_Assert(base.backendWrappers.empty()); //backendWrappers = base.backendWrappers;
+ lastLayerId = base.lastLayerId;
+ netWasAllocated = base.netWasAllocated;
+ netWasQuantized = base.netWasQuantized;
+ fusion = base.fusion;
+ }
+
+
+ //bool isAsync; // FIXIT: drop
+
+
+ bool empty() const override
+ {
+ return Base::empty();
+ }
+ void setPreferableBackend(Net& net, int backendId) override
+ {
+ if (backendId == DNN_BACKEND_INFERENCE_ENGINE || backendId == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
+ return; // no-op
+ if (!basePtr_)
+ CV_Error(Error::StsError, "DNN: Can't switch backend of network created by OpenVINO");
+ Ptr<Net::Impl>& impl_ptr_ref = accessor::DnnNetAccessor::getImplPtrRef(net);
+ impl_ptr_ref = basePtr_;
+ return basePtr_->setPreferableBackend(net, backendId);
+ }
+ void setPreferableTarget(int targetId) override
+ {
+ if (preferableTarget != targetId)
+ {
+ preferableTarget = targetId;
+ clear();
+ }
+ }
+
+ Ptr<BackendWrapper> wrap(Mat& host) override
+ {
+ return Ptr<BackendWrapper>(new NgraphBackendWrapper(preferableTarget, host));
+ }
+
+
+ void clear() override
+ {
+ Base::clear();
+ }
+
+ void validateBackendAndTarget() override
+ {
+ CV_TRACE_FUNCTION();
+
+ CV_Assert(preferableBackend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH);
+ CV_Check((int)preferableTarget,
+ preferableTarget == DNN_TARGET_CPU ||
+ preferableTarget == DNN_TARGET_OPENCL ||
+ preferableTarget == DNN_TARGET_OPENCL_FP16 ||
+ preferableTarget == DNN_TARGET_MYRIAD ||
+ preferableTarget == DNN_TARGET_HDDL ||
+ preferableTarget == DNN_TARGET_FPGA,
+ "Unknown OpenVINO target"
+ );
+ }
+
+ //void setUpNet(const std::vector<LayerPin>& blobsToKeep_ = std::vector<LayerPin>()) override;
+
+
+ //void setInput(InputArray blob, const String& name, double scalefactor, const Scalar& mean) override;
+
+ void addNgraphOutputs(LayerData& ld);
+
+ void initBackend(const std::vector<LayerPin>& blobsToKeep_) override;
+
+ void fuseLayers(const std::vector<LayerPin>& blobsToKeep_) override;
+
+ //void allocateLayers(const std::vector<LayerPin>& blobsToKeep_) override;
+
+ void forwardLayer(LayerData& ld) override;
+
+ AsyncArray getBlobAsync(const LayerPin& pin) override;
+
+ //string dump(bool forceAllocation = false) const override;
+
+ static
+ Net createNetworkFromModelOptimizer(InferenceEngine::CNNNetwork& ieNet);
+
+}; // NetImplOpenVINO
+
+
+void NetImplOpenVINO::forwardLayer(LayerData& ld)
+{
+ CV_TRACE_FUNCTION();
+
+ Ptr<Layer> layer = ld.layerInstance;
+
+ if (!ld.skip)
+ {
+ auto it = ld.backendNodes.find(preferableBackend);
+ if (ld.id == 0 || // input layer
+ it == ld.backendNodes.end() // non-supported layer or its mode
+ )
+ {
+ return Base::forwardLayer(ld);
+ }
+
+ CV_Assert(it != ld.backendNodes.end());
+ const Ptr<BackendNode>& node = it->second;
+ CV_Assert(!node.empty());
+ Ptr<InfEngineNgraphNode> ieNode = node.dynamicCast<InfEngineNgraphNode>();
+ CV_Assert(!ieNode.empty());
+ CV_Assert(ieNode->net);
+
+ TickMeter tm;
+ tm.start();
+
+ ieNode->net->forward(ld.outputBlobsWrappers, isAsync);
+
+ tm.stop();
+ int64 t = tm.getTimeTicks();
+ layersTimings[ld.id] = (t > 0) ? t : t + 1; // zero for skipped layers only
+ }
+ else
+ {
+ layersTimings[ld.id] = 0;
+ }
+
+ ld.flag = 1;
+}
+
+AsyncArray NetImplOpenVINO::getBlobAsync(const LayerPin& pin)
+{
+ CV_TRACE_FUNCTION();
+ if (!pin.valid())
+ CV_Error(Error::StsObjectNotFound, "Requested blob not found");
+
+ LayerData& ld = layers[pin.lid];
+ if ((size_t)pin.oid >= ld.outputBlobs.size())
+ {
+ CV_Error(Error::StsOutOfRange, format("Layer \"%s\" produce only %d outputs, "
+ "the #%d was requested",
+ ld.name.c_str(), (int)ld.outputBlobs.size(), (int)pin.oid));
+ }
+ if (preferableTarget != DNN_TARGET_CPU)
+ {
+ CV_Assert(!ld.outputBlobsWrappers.empty() && !ld.outputBlobsWrappers[pin.oid].empty());
+ // Transfer data to CPU if it's require.
+ ld.outputBlobsWrappers[pin.oid]->copyToHost();
+ }
+ CV_Assert(preferableBackend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH);
+
+ Ptr<NgraphBackendWrapper> wrapper = ld.outputBlobsWrappers[pin.oid].dynamicCast<NgraphBackendWrapper>();
+ return std::move(wrapper->futureMat);
+}
+
/** mark input pins as outputs from other subnetworks
* FIXIT must be done by DNN engine not ngraph.
*/
-void Net::Impl::addNgraphOutputs(LayerData& ld)
+void NetImplOpenVINO::addNgraphOutputs(LayerData& ld)
{
CV_TRACE_FUNCTION();
}
}
-void Net::Impl::initNgraphBackend(const std::vector<LayerPin>& blobsToKeep_)
+void NetImplOpenVINO::initBackend(const std::vector<LayerPin>& blobsToKeep_)
{
CV_TRACE_FUNCTION();
CV_CheckEQ(preferableBackend, DNN_BACKEND_INFERENCE_ENGINE_NGRAPH, "");
}
}
- if (skipInfEngineInit)
+ if (!basePtr_) // model is loaded by OpenVINO
{
Ptr<BackendNode> node = layers[lastLayerId].backendNodes[preferableBackend];
CV_Assert(!node.empty());
}
}
-//} // Net::Impl
+
+#if 0
+#define printf_(args) printf args
+#else
+#define printf_(args)
+#endif
+
+void NetImplOpenVINO::fuseLayers(const std::vector<LayerPin>& blobsToKeep_)
+{
+ CV_TRACE_FUNCTION();
+
+ if(!fusion)
+ return;
+
+ CV_Check((int)preferableBackend, preferableBackend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH, "");
+
+#if 0 // FIXIT mode without fusion is broken due to unsupported layers and handling of "custom" nodes
+ return;
+#endif
+
+ // scan through all the layers. If there is convolution layer followed by the activation layer,
+ // we try to embed this activation into the convolution and disable separate execution of the activation
+
+ // FIXIT replace by layersToKeep to avoid hacks like "LayerPin(lid, 0)"
+ std::set<LayerPin> pinsToKeep(blobsToKeep_.begin(),
+ blobsToKeep_.end());
+ for (MapIdToLayerData::const_iterator it = layers.begin(); it != layers.end(); it++)
+ {
+ int lid = it->first;
+ LayerData& ld = layers[lid];
+ if (ld.skip)
+ {
+ printf_(("skipped %s: %s\n", ld.layerInstance->name.c_str(), ld.layerInstance->type.c_str()));
+ continue;
+ }
+ printf_(("analyzing %s: %s\n", ld.layerInstance->name.c_str(), ld.layerInstance->type.c_str()));
+
+ // the optimization #1. try to fuse batch norm, scaling and/or activation layers
+ // with the current layer if they follow it. Normally, the are fused with the convolution layer,
+ // but some of them (like activation) may be fused with fully-connected, elemwise (+) and
+ // some other layers.
+ Ptr<Layer>& currLayer = ld.layerInstance;
+ if (ld.consumers.size() == 1 && pinsToKeep.count(LayerPin(lid, 0)) == 0)
+ {
+ LayerData* nextData = &layers[ld.consumers[0].lid];
+ LayerPin lpNext(ld.consumers[0].lid, 0);
+ while (nextData)
+ {
+ if (preferableBackend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && pinsToKeep.count(lpNext) != 0)
+ {
+ CV_LOG_DEBUG(NULL, "DNN/IE: skip fusing with 'output' node: " << nextData->name << "@" << nextData->type);
+ break;
+ }
+
+ /* we use `tryFuse` member of convolution layer to fuse eltwise later
+ * it's not intended to be fused here; hence, we stop when we encounter eltwise
+ */
+ Ptr<Layer> nextLayer = nextData->layerInstance;
+ if (currLayer->tryFuse(nextLayer))
+ {
+ printf_(("\tfused with %s\n", nextLayer->name.c_str()));
+ nextData->skip = true;
+ ld.outputBlobs = layers[lpNext.lid].outputBlobs;
+ ld.outputBlobsWrappers = layers[lpNext.lid].outputBlobsWrappers;
+ if (nextData->consumers.size() == 1)
+ {
+ int nextLayerId = nextData->consumers[0].lid;
+ nextData = &layers[nextLayerId];
+ lpNext = LayerPin(nextLayerId, 0);
+ }
+ else
+ {
+ nextData = 0;
+ break;
+ }
+ }
+ else
+ break;
+ }
+ }
+ }
+}
+
+
+
+void switchToOpenVINOBackend(Net& net)
+{
+ CV_TRACE_FUNCTION();
+ CV_LOG_INFO(NULL, "DNN: switching to OpenVINO backend...");
+ Ptr<Net::Impl>& impl_ptr_ref = accessor::DnnNetAccessor::getImplPtrRef(net);
+ Ptr<NetImplOpenVINO> openvino_impl_ptr = makePtr<NetImplOpenVINO>(impl_ptr_ref);
+ impl_ptr_ref = openvino_impl_ptr;
+}
+
+
/*static*/
-Net Net::Impl::createNetworkFromModelOptimizer(InferenceEngine::CNNNetwork& ieNet)
+Net NetImplOpenVINO::createNetworkFromModelOptimizer(InferenceEngine::CNNNetwork& ieNet)
{
CV_TRACE_FUNCTION();
}
Net cvNet;
+ Ptr<NetImplOpenVINO> openvino_impl_ptr = makePtr<NetImplOpenVINO>();
+ NetImplOpenVINO& openvino_impl = *openvino_impl_ptr;
+ accessor::DnnNetAccessor::getImplPtrRef(cvNet) = openvino_impl_ptr;
+
cvNet.setInputsNames(inputsNames);
// set empty input to determine input shapes
{
auto fake_node = std::make_shared<ngraph::op::Parameter>(ngraph::element::f32, ngraph::Shape {});
Ptr<InfEngineNgraphNode> backendNodeNGraph(new InfEngineNgraphNode(fake_node));
- backendNodeNGraph->net = Ptr<InfEngineNgraphNet>(new InfEngineNgraphNet(*(cvNet.impl), ieNet));
+ backendNodeNGraph->net = Ptr<InfEngineNgraphNet>(new InfEngineNgraphNet(openvino_impl, ieNet));
backendNode = backendNodeNGraph;
}
LayerParams lp;
int lid = cvNet.addLayer(it.first, "", lp);
- LayerData& ld = cvNet.impl->layers[lid];
+ LayerData& ld = openvino_impl.layers[lid];
{
Ptr<Layer> cvLayer(new NgraphBackendLayer(ieNet));
cvNet.setPreferableBackend(DNN_BACKEND_INFERENCE_ENGINE_NGRAPH);
- cvNet.impl->skipInfEngineInit = true;
return cvNet;
}
#endif // HAVE_INF_ENGINE
InferenceEngine::Core& ie = getCore("");
InferenceEngine::CNNNetwork ieNet = ie.ReadNetwork(xml, bin);
- return Impl::createNetworkFromModelOptimizer(ieNet);
+ return NetImplOpenVINO::createNetworkFromModelOptimizer(ieNet);
#endif // HAVE_INF_ENGINE
}
CV_Error(Error::StsError, std::string("DNN: IE failed to load model: ") + e.what());
}
- return Impl::createNetworkFromModelOptimizer(ieNet);
+ return NetImplOpenVINO::createNetworkFromModelOptimizer(ieNet);
#endif // HAVE_INF_ENGINE
}
}
// FIXIT drop from inference API
-Net Net::Impl::quantize(InputArrayOfArrays calibData, int inputsDtype, int outputsDtype, bool perChannel)
+Net Net::Impl::quantize(Net& net, InputArrayOfArrays calibData, int inputsDtype, int outputsDtype, bool perChannel)
{
// Net can be quantized only once.
if (netWasQuantized)
int prefTarget = preferableTarget;
// Disable fusions and use CPU backend to quantize net
- setPreferableBackend(DNN_BACKEND_OPENCV);
+ // FIXIT: we should not modify original network!
+ setPreferableBackend(net, DNN_BACKEND_OPENCV);
setPreferableTarget(DNN_TARGET_CPU);
enableFusion(false);
Net::Impl& dstNet = *(dstNet_.impl);
dstNet.netWasQuantized = true;
dstNet.setInputsNames(netInputLayer->outNames);
- dstNet.setPreferableBackend(prefBackend);
+ dstNet.setPreferableBackend(dstNet_, prefBackend);
dstNet.setPreferableTarget(prefTarget);
dstNet.enableFusion(originalFusion);
}
}
// Restore FP32 Net's backend, target and fusion
- setPreferableBackend(prefBackend);
+ setPreferableBackend(net, prefBackend);
setPreferableTarget(prefTarget);
enableFusion(originalFusion);
return dstNet_;
CV__DNN_INLINE_NS_BEGIN
+void switchToOpenVINOBackend(Net& net);
+
namespace openvino {
// TODO: use std::string as parameter