1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 15:53:03 +04:00

Intel Inference Engine deep learning backend (#10608)

* Intel Inference Engine deep learning backend.

* OpenFace network using Inference Engine backend
This commit is contained in:
Dmitry Kurtaev
2018-02-06 11:57:35 +03:00
committed by Vadim Pisarevsky
parent 292dfc2d72
commit 10e1de74d2
26 changed files with 1379 additions and 49 deletions
+145 -14
View File
@@ -41,6 +41,7 @@
#include "precomp.hpp"
#include "op_halide.hpp"
#include "op_inf_engine.hpp"
#include "halide_scheduler.hpp"
#include <set>
#include <algorithm>
@@ -471,9 +472,9 @@ public:
}
}
void reuseOrCreate(const MatShape& shape, const LayerPin& lp, Mat& dst)
void reuseOrCreate(const MatShape& shape, const LayerPin& lp, Mat& dst, bool forceCreate)
{
if (!DNN_DISABLE_MEMORY_OPTIMIZATIONS)
if (!DNN_DISABLE_MEMORY_OPTIMIZATIONS && !forceCreate)
{
Mat bestBlob;
LayerPin bestBlobPin;
@@ -518,7 +519,8 @@ public:
}
void allocateBlobsForLayer(LayerData &ld, const LayerShapes& layerShapes,
std::vector<LayerPin>& pinsForInternalBlobs)
std::vector<LayerPin>& pinsForInternalBlobs,
bool forceCreate = false)
{
CV_TRACE_FUNCTION();
@@ -589,7 +591,7 @@ public:
reuse(ld.inputBlobsId[0], blobPin);
}
else
reuseOrCreate(shapes[index], blobPin, *blobs[index]);
reuseOrCreate(shapes[index], blobPin, *blobs[index], forceCreate);
}
}
}
@@ -638,6 +640,13 @@ static Ptr<BackendWrapper> wrapMat(int backendId, int targetId, cv::Mat& m)
#ifdef HAVE_HALIDE
return Ptr<BackendWrapper>(new HalideBackendWrapper(targetId, m));
#endif // HAVE_HALIDE
}
else if (backendId == DNN_BACKEND_INFERENCE_ENGINE)
{
CV_Assert(haveInfEngine());
#ifdef HAVE_INF_ENGINE
return Ptr<BackendWrapper>(new InfEngineBackendWrapper(targetId, m));
#endif // HAVE_INF_ENGINE
}
else
CV_Error(Error::StsNotImplemented, "Unknown backend identifier");
@@ -710,6 +719,10 @@ struct Net::Impl
return Ptr<BackendWrapper>(new HalideBackendWrapper(baseBuffer, shape));
#endif // HAVE_HALIDE
}
else if (preferableBackend == DNN_BACKEND_INFERENCE_ENGINE)
{
return wrapMat(preferableBackend, preferableTarget, host);
}
else
CV_Error(Error::StsNotImplemented, "Unknown backend identifier");
}
@@ -999,12 +1012,20 @@ struct Net::Impl
void initBackend()
{
CV_TRACE_FUNCTION();
if (preferableBackend == DNN_BACKEND_DEFAULT)
{
CV_Assert(preferableTarget == DNN_TARGET_CPU || preferableTarget == DNN_TARGET_OPENCL);
return;
}
else if (preferableBackend == DNN_BACKEND_HALIDE)
initHalideBackend();
else if (preferableBackend == DNN_BACKEND_INFERENCE_ENGINE)
initInfEngineBackend();
else
CV_Error(Error::StsNotImplemented, "Unknown backend identifier");
}
void initHalideBackend()
{
CV_TRACE_FUNCTION();
CV_Assert(preferableBackend == DNN_BACKEND_HALIDE, haveHalide());
// Iterator to current layer.
MapIdToLayerData::iterator it = layers.begin();
@@ -1050,17 +1071,115 @@ struct Net::Impl
}
// No layers fusion.
ldTop.skip = false;
if (preferableBackend == DNN_BACKEND_HALIDE)
ldTop.backendNodes[DNN_BACKEND_HALIDE] =
layerTop->initHalide(ldTop.inputBlobsWrappers);
baseIt = it;
}
}
void initInfEngineBackend()
{
// Build Inference Engine networks from sets of layers that support this
// backend. If an internal layer isn't supported we'll use default
// implementation of it but build a new network after it.
CV_TRACE_FUNCTION();
CV_Assert(preferableBackend == DNN_BACKEND_INFERENCE_ENGINE, haveInfEngine());
#ifdef HAVE_INF_ENGINE
MapIdToLayerData::iterator it;
Ptr<InfEngineBackendNet> net;
for (it = layers.begin(); it != layers.end(); ++it)
{
LayerData &ld = it->second;
ld.skip = true;
Ptr<Layer> layer = ld.layerInstance;
if (!layer->supportBackend(preferableBackend))
{
ldTop.backendNodes[DNN_BACKEND_HALIDE] =
layerTop->initHalide(ldTop.inputBlobsWrappers);
baseIt = it;
for (int i = 0; i < ld.outputBlobsWrappers.size(); ++i)
{
auto dataPtr = infEngineDataNode(ld.outputBlobsWrappers[i]);
dataPtr->name = ld.name;
}
ld.skip = false;
net = Ptr<InfEngineBackendNet>();
continue;
}
// Check what all inputs are from the same network or from default backend.
for (int i = 0; i < ld.inputBlobsId.size(); ++i)
{
LayerData &inpLd = layers[ld.inputBlobsId[i].lid];
Ptr<BackendNode> inpNode = inpLd.backendNodes[preferableBackend];
if (!inpNode.empty())
{
Ptr<InfEngineBackendNode> ieInpNode = inpNode.dynamicCast<InfEngineBackendNode>();
CV_Assert(!ieInpNode.empty(), net.empty() || net == ieInpNode->net);
}
}
bool fused = false;
Ptr<BackendNode> node;
if (!net.empty())
{
// Try to fuse.
bool inPlace = ld.inputBlobsId.size() == 1 && ld.outputBlobs.size() == 1 &&
ld.inputBlobs[0]->data == ld.outputBlobs[0].data;
if (inPlace)
{
node = layer->tryAttach(layers[ld.inputBlobsId[0].lid].backendNodes[preferableBackend]);
fused = !node.empty();
if (fused)
ld.inputBlobsWrappers = layers[ld.inputBlobsId[0].lid].inputBlobsWrappers;
}
}
else
net = Ptr<InfEngineBackendNet>(new InfEngineBackendNet());
if (!fused)
{
CV_Error(Error::StsNotImplemented, "Unknown backend identifier");
node = layer->initInfEngine(ld.inputBlobsWrappers);
}
CV_Assert(!node.empty());
ld.backendNodes[preferableBackend] = node;
Ptr<InfEngineBackendNode> ieNode = node.dynamicCast<InfEngineBackendNode>();
CV_Assert(!ieNode.empty());
ieNode->net = net;
ieNode->connect(ld.inputBlobsWrappers, ld.outputBlobsWrappers);
net->addBlobs(ld.inputBlobsWrappers);
net->addBlobs(ld.outputBlobsWrappers);
if (!fused)
net->addLayer(ieNode->layer);
}
// Initialize all networks.
std::set<InfEngineBackendNet> initializedNets;
for (MapIdToLayerData::reverse_iterator it = layers.rbegin(); it != layers.rend(); ++it)
{
LayerData &ld = it->second;
if (ld.backendNodes.find(preferableBackend) == ld.backendNodes.end())
continue;
Ptr<BackendNode> node = ld.backendNodes[preferableBackend];
if (node.empty())
continue;
Ptr<InfEngineBackendNode> ieNode = node.dynamicCast<InfEngineBackendNode>();
if (ieNode.empty())
continue;
CV_Assert(!ieNode->net.empty());
if (!ieNode->net->isInitialized())
{
ieNode->net->initEngine();
ld.skip = false;
}
}
#endif // HAVE_INF_ENGINE
}
void allocateLayer(int lid, const LayersShapesMap& layersShapes)
@@ -1117,7 +1236,8 @@ struct Net::Impl
CV_Assert(layerShapesIt != layersShapes.end());
std::vector<LayerPin> pinsForInternalBlobs;
blobManager.allocateBlobsForLayer(ld, layerShapesIt->second, pinsForInternalBlobs);
blobManager.allocateBlobsForLayer(ld, layerShapesIt->second, pinsForInternalBlobs,
preferableBackend == DNN_BACKEND_INFERENCE_ENGINE);
ld.outputBlobsWrappers.resize(ld.outputBlobs.size());
for (int i = 0; i < ld.outputBlobs.size(); ++i)
{
@@ -1564,6 +1684,10 @@ struct Net::Impl
{
forwardHalide(ld.outputBlobsWrappers, node);
}
else if (preferableBackend == DNN_BACKEND_INFERENCE_ENGINE)
{
forwardInfEngine(node);
}
else
{
CV_Error(Error::StsNotImplemented, "Unknown backend identifier");
@@ -2329,6 +2453,13 @@ Ptr<BackendNode> Layer::initHalide(const std::vector<Ptr<BackendWrapper> > &)
return Ptr<BackendNode>();
}
Ptr<BackendNode> Layer::initInfEngine(const std::vector<Ptr<BackendWrapper> > &)
{
CV_Error(Error::StsNotImplemented, "Inference Engine pipeline of " + type +
" layers is not defined.");
return Ptr<BackendNode>();
}
void Layer::applyHalideScheduler(Ptr<BackendNode>& node, const std::vector<Mat*> &inputs,
const std::vector<Mat> &outputs, int targetId) const
{
+35 -1
View File
@@ -11,6 +11,7 @@ Implementation of Batch Normalization layer.
#include "../precomp.hpp"
#include "op_halide.hpp"
#include "op_inf_engine.hpp"
#include <opencv2/dnn/shape_utils.hpp>
#include "opencl_kernels_dnn.hpp"
@@ -103,7 +104,8 @@ public:
virtual bool supportBackend(int backendId)
{
return backendId == DNN_BACKEND_DEFAULT ||
backendId == DNN_BACKEND_HALIDE && haveHalide();
backendId == DNN_BACKEND_HALIDE && haveHalide() ||
backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine();
}
#ifdef HAVE_OPENCL
@@ -226,6 +228,19 @@ public:
#endif // HAVE_HALIDE
break;
}
case DNN_BACKEND_INFERENCE_ENGINE:
{
#ifdef HAVE_INF_ENGINE
auto base = node.dynamicCast<InfEngineBackendNode>();
auto conv = std::dynamic_pointer_cast<InferenceEngine::ConvolutionLayer>(base->layer);
if (conv)
{
fuseConvWeights(conv, weights_, bias_);
return base;
}
#endif // HAVE_INF_ENGINE
break;
}
}
return Ptr<BackendNode>();
}
@@ -257,6 +272,25 @@ public:
}
#endif // HAVE_HALIDE
virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >&)
{
#ifdef HAVE_INF_ENGINE
InferenceEngine::LayerParams lp;
lp.name = name;
lp.type = "BatchNormalization";
lp.precision = InferenceEngine::Precision::FP32;
std::shared_ptr<InferenceEngine::BatchNormalizationLayer> ieLayer(new InferenceEngine::BatchNormalizationLayer(lp));
size_t numChannels = weights_.total();
ieLayer->epsilon = epsilon;
ieLayer->_weights = wrapToInfEngineBlob(blobs[1], {numChannels});
ieLayer->_biases = wrapToInfEngineBlob(blobs[0], {numChannels});
return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));
#endif // HAVE_INF_ENGINE
return Ptr<BackendNode>();
}
virtual int64 getFLOPS(const std::vector<MatShape> &inputs,
const std::vector<MatShape> &outputs) const
{
+17 -1
View File
@@ -43,6 +43,7 @@
#include "../precomp.hpp"
#include "layers_common.hpp"
#include "op_halide.hpp"
#include "op_inf_engine.hpp"
#include "opencl_kernels_dnn.hpp"
namespace cv
@@ -100,7 +101,8 @@ public:
virtual bool supportBackend(int backendId)
{
return backendId == DNN_BACKEND_DEFAULT ||
backendId == DNN_BACKEND_HALIDE && haveHalide() && axis == 1 && !padding; // By channels
backendId == DNN_BACKEND_HALIDE && haveHalide() && axis == 1 && !padding || // By channels
backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine() && !padding;
}
class ChannelConcatInvoker : public ParallelLoopBody
@@ -295,6 +297,20 @@ public:
#endif // HAVE_HALIDE
return Ptr<BackendNode>();
}
virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >&)
{
#ifdef HAVE_INF_ENGINE
InferenceEngine::LayerParams lp;
lp.name = name;
lp.type = "Concat";
lp.precision = InferenceEngine::Precision::FP32;
std::shared_ptr<InferenceEngine::ConcatLayer> ieLayer(new InferenceEngine::ConcatLayer(lp));
ieLayer->_axis = axis;
return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));
#endif // HAVE_INF_ENGINE
return Ptr<BackendNode>();
}
};
Ptr<ConcatLayer> ConcatLayer::create(const LayerParams& params)
+39 -1
View File
@@ -43,6 +43,7 @@
#include "../precomp.hpp"
#include "layers_common.hpp"
#include "op_halide.hpp"
#include "op_inf_engine.hpp"
#include "opencv2/core/hal/hal.hpp"
#include "opencv2/core/hal/intrin.hpp"
#include <iostream>
@@ -65,7 +66,8 @@ public:
virtual bool supportBackend(int backendId)
{
return backendId == DNN_BACKEND_DEFAULT ||
backendId == DNN_BACKEND_HALIDE && haveHalide();
backendId == DNN_BACKEND_HALIDE && haveHalide() ||
backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine();
}
void finalize(const std::vector<Mat*> &inputs, std::vector<Mat> &outputs)
@@ -335,6 +337,42 @@ public:
return Ptr<BackendNode>();
}
virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> > &inputs)
{
#ifdef HAVE_INF_ENGINE
InferenceEngine::DataPtr input = infEngineDataNode(inputs[0]);
CV_Assert(input->dims.size() == 4);
const int inpCn = input->dims[2]; // NOTE: input->dims are reversed (whcn)
const int outCn = blobs[0].size[0];
const int inpGroupCn = blobs[0].size[1];
const int group = inpCn / inpGroupCn;
InferenceEngine::LayerParams lp;
lp.name = name;
lp.type = "Convolution";
lp.precision = InferenceEngine::Precision::FP32;
std::shared_ptr<InferenceEngine::ConvolutionLayer> ieLayer(new InferenceEngine::ConvolutionLayer(lp));
ieLayer->_kernel_x = kernel.width;
ieLayer->_kernel_y = kernel.height;
ieLayer->_stride_x = stride.width;
ieLayer->_stride_y = stride.height;
ieLayer->_out_depth = outCn;
ieLayer->_padding_x = pad.width;
ieLayer->_padding_y = pad.height;
ieLayer->_dilation_x = dilation.width;
ieLayer->_dilation_y = dilation.height;
ieLayer->_group = group;
ieLayer->_weights = wrapToInfEngineBlob(blobs[0]);
if (hasBias())
ieLayer->_biases = wrapToInfEngineBlob(blobs[1]);
return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));
#endif // HAVE_INF_ENGINE
return Ptr<BackendNode>();
}
class ParallelConv : public cv::ParallelLoopBody
{
public:
@@ -42,6 +42,7 @@
#include "../precomp.hpp"
#include "layers_common.hpp"
#include "op_inf_engine.hpp"
#include <float.h>
#include <string>
#include "../nms.inl.hpp"
@@ -189,6 +190,12 @@ public:
setParamsFrom(params);
}
virtual bool supportBackend(int backendId)
{
return backendId == DNN_BACKEND_DEFAULT ||
backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine();
}
bool getMemoryShapes(const std::vector<MatShape> &inputs,
const int requiredOutputs,
std::vector<MatShape> &outputs,
@@ -203,10 +210,10 @@ public:
// num() and channels() are 1.
// Since the number of bboxes to be kept is unknown before nms, we manually
// set it to (fake) 1.
// set it to maximal number of detections, [keep_top_k] parameter.
// Each row is a 7 dimension std::vector, which stores
// [image_id, label, confidence, xmin, ymin, xmax, ymax]
outputs.resize(1, shape(1, 1, 1, 7));
outputs.resize(1, shape(1, 1, _keepTopK, 7));
return false;
}
@@ -850,6 +857,29 @@ public:
return 0.;
}
}
virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >&)
{
#ifdef HAVE_INF_ENGINE
InferenceEngine::LayerParams lp;
lp.name = name;
lp.type = "DetectionOutput";
lp.precision = InferenceEngine::Precision::FP32;
std::shared_ptr<InferenceEngine::CNNLayer> ieLayer(new InferenceEngine::CNNLayer(lp));
ieLayer->params["num_classes"] = format("%d", _numClasses);
ieLayer->params["share_location"] = _shareLocation ? "1" : "0";
ieLayer->params["background_label_id"] = format("%d", _backgroundLabelId);
ieLayer->params["nms_threshold"] = format("%f", _nmsThreshold);
ieLayer->params["top_k"] = format("%d", _topK);
ieLayer->params["keep_top_k"] = format("%d", _keepTopK);
ieLayer->params["confidence_threshold"] = format("%f", _confidenceThreshold);
ieLayer->params["variance_encoded_in_target"] = _varianceEncodedInTarget ? "1" : "0";
ieLayer->params["code_type"] = "caffe.PriorBoxParameter." + _codeType;
return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));
#endif // HAVE_INF_ENGINE
return Ptr<BackendNode>();
}
};
float util::caffe_box_overlap(const util::NormalizedBBox& a, const util::NormalizedBBox& b)
+91 -1
View File
@@ -43,6 +43,7 @@
#include "../precomp.hpp"
#include "layers_common.hpp"
#include "op_halide.hpp"
#include "op_inf_engine.hpp"
#include "opencv2/imgproc.hpp"
#include <opencv2/dnn/shape_utils.hpp>
#include "opencl_kernels_dnn.hpp"
@@ -112,7 +113,8 @@ public:
virtual bool supportBackend(int backendId)
{
return backendId == DNN_BACKEND_DEFAULT ||
backendId == DNN_BACKEND_HALIDE && haveHalide();
backendId == DNN_BACKEND_HALIDE && haveHalide() ||
backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine();
}
virtual Ptr<BackendNode> tryAttach(const Ptr<BackendNode>& node)
@@ -147,6 +149,17 @@ public:
return Ptr<BackendNode>();
}
virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >&)
{
#ifdef HAVE_INF_ENGINE
InferenceEngine::LayerParams lp;
lp.name = this->name;
lp.precision = InferenceEngine::Precision::FP32;
return Ptr<BackendNode>(new InfEngineBackendNode(func.initInfEngine(lp)));
#endif // HAVE_INF_ENGINE
return Ptr<BackendNode>();
}
bool getMemoryShapes(const std::vector<MatShape> &inputs,
const int requiredOutputs,
std::vector<MatShape> &outputs,
@@ -308,6 +321,15 @@ struct ReLUFunctor
}
#endif // HAVE_HALIDE
#ifdef HAVE_INF_ENGINE
InferenceEngine::CNNLayerPtr initInfEngine(InferenceEngine::LayerParams& lp)
{
lp.type = "ReLU";
std::shared_ptr<InferenceEngine::ReLULayer> ieLayer(new InferenceEngine::ReLULayer(lp));
return ieLayer;
}
#endif // HAVE_INF_ENGINE
int64 getFLOPSPerElement() const { return 1; }
};
@@ -372,6 +394,14 @@ struct ReLU6Functor
}
#endif // HAVE_HALIDE
#ifdef HAVE_INF_ENGINE
InferenceEngine::CNNLayerPtr initInfEngine(InferenceEngine::LayerParams& lp)
{
CV_Error(Error::StsNotImplemented, "ReLU6");
return InferenceEngine::CNNLayerPtr();
}
#endif // HAVE_INF_ENGINE
int64 getFLOPSPerElement() const { return 2; }
};
@@ -427,6 +457,14 @@ struct TanHFunctor
}
#endif // HAVE_HALIDE
#ifdef HAVE_INF_ENGINE
InferenceEngine::CNNLayerPtr initInfEngine(InferenceEngine::LayerParams& lp)
{
CV_Error(Error::StsNotImplemented, "TanH");
return InferenceEngine::CNNLayerPtr();
}
#endif // HAVE_INF_ENGINE
int64 getFLOPSPerElement() const { return 1; }
};
@@ -462,6 +500,14 @@ struct SigmoidFunctor
}
#endif // HAVE_HALIDE
#ifdef HAVE_INF_ENGINE
InferenceEngine::CNNLayerPtr initInfEngine(InferenceEngine::LayerParams& lp)
{
CV_Error(Error::StsNotImplemented, "Sigmoid");
return InferenceEngine::CNNLayerPtr();
}
#endif // HAVE_INF_ENGINE
int64 getFLOPSPerElement() const { return 3; }
};
@@ -499,6 +545,14 @@ struct ELUFunctor
}
#endif // HAVE_HALIDE
#ifdef HAVE_INF_ENGINE
InferenceEngine::CNNLayerPtr initInfEngine(InferenceEngine::LayerParams& lp)
{
CV_Error(Error::StsNotImplemented, "ELU");
return InferenceEngine::CNNLayerPtr();
}
#endif // HAVE_INF_ENGINE
int64 getFLOPSPerElement() const { return 2; }
};
@@ -534,6 +588,14 @@ struct AbsValFunctor
}
#endif // HAVE_HALIDE
#ifdef HAVE_INF_ENGINE
InferenceEngine::CNNLayerPtr initInfEngine(InferenceEngine::LayerParams& lp)
{
CV_Error(Error::StsNotImplemented, "Abs");
return InferenceEngine::CNNLayerPtr();
}
#endif // HAVE_INF_ENGINE
int64 getFLOPSPerElement() const { return 1; }
};
@@ -569,6 +631,14 @@ struct BNLLFunctor
}
#endif // HAVE_HALIDE
#ifdef HAVE_INF_ENGINE
InferenceEngine::CNNLayerPtr initInfEngine(InferenceEngine::LayerParams& lp)
{
CV_Error(Error::StsNotImplemented, "BNLL");
return InferenceEngine::CNNLayerPtr();
}
#endif // HAVE_INF_ENGINE
int64 getFLOPSPerElement() const { return 5; }
};
@@ -658,6 +728,18 @@ struct PowerFunctor
}
#endif // HAVE_HALIDE
#ifdef HAVE_INF_ENGINE
InferenceEngine::CNNLayerPtr initInfEngine(InferenceEngine::LayerParams& lp)
{
lp.type = "Power";
std::shared_ptr<InferenceEngine::PowerLayer> ieLayer(new InferenceEngine::PowerLayer(lp));
ieLayer->power = power;
ieLayer->scale = scale;
ieLayer->offset = shift;
return ieLayer;
}
#endif // HAVE_INF_ENGINE
int64 getFLOPSPerElement() const { return power == 1 ? 2 : 10; }
};
@@ -750,6 +832,14 @@ struct ChannelsPReLUFunctor
}
#endif // HAVE_HALIDE
#ifdef HAVE_INF_ENGINE
InferenceEngine::CNNLayerPtr initInfEngine(InferenceEngine::LayerParams& lp)
{
CV_Error(Error::StsNotImplemented, "PReLU");
return InferenceEngine::CNNLayerPtr();
}
#endif // HAVE_INF_ENGINE
int64 getFLOPSPerElement() const { return 1; }
};
+24 -1
View File
@@ -43,6 +43,7 @@
#include "../precomp.hpp"
#include "layers_common.hpp"
#include "op_halide.hpp"
#include "op_inf_engine.hpp"
#include "opencl_kernels_dnn.hpp"
namespace cv
@@ -93,7 +94,8 @@ public:
virtual bool supportBackend(int backendId)
{
return backendId == DNN_BACKEND_DEFAULT ||
backendId == DNN_BACKEND_HALIDE && haveHalide();
backendId == DNN_BACKEND_HALIDE && haveHalide() ||
backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine();
}
bool getMemoryShapes(const std::vector<MatShape> &inputs,
@@ -402,6 +404,27 @@ public:
return Ptr<BackendNode>();
}
virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >&)
{
#ifdef HAVE_INF_ENGINE
InferenceEngine::LayerParams lp;
lp.name = name;
lp.type = "Eltwise";
lp.precision = InferenceEngine::Precision::FP32;
std::shared_ptr<InferenceEngine::EltwiseLayer> ieLayer(new InferenceEngine::EltwiseLayer(lp));
if (op == SUM)
ieLayer->_operation = InferenceEngine::EltwiseLayer::Sum;
else if (op == PROD)
ieLayer->_operation = InferenceEngine::EltwiseLayer::Prod;
else if (op == MAX)
ieLayer->_operation = InferenceEngine::EltwiseLayer::Max;
else
CV_Error(Error::StsNotImplemented, "Unsupported eltwise operation");
return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));
#endif // HAVE_INF_ENGINE
return Ptr<BackendNode>();
}
virtual int64 getFLOPS(const std::vector<MatShape> &inputs,
const std::vector<MatShape> &outputs) const
{
+22
View File
@@ -42,6 +42,7 @@
#include "../precomp.hpp"
#include "layers_common.hpp"
#include "op_inf_engine.hpp"
#include <float.h>
#include <algorithm>
#include <opencv2/dnn/shape_utils.hpp>
@@ -61,6 +62,12 @@ public:
setParamsFrom(params);
}
virtual bool supportBackend(int backendId)
{
return backendId == DNN_BACKEND_DEFAULT ||
backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine();
}
bool getMemoryShapes(const std::vector<MatShape> &inputs,
const int requiredOutputs,
std::vector<MatShape> &outputs,
@@ -153,6 +160,21 @@ public:
}
}
virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >&)
{
#ifdef HAVE_INF_ENGINE
InferenceEngine::LayerParams lp;
lp.name = name;
lp.type = "Flatten";
lp.precision = InferenceEngine::Precision::FP32;
std::shared_ptr<InferenceEngine::CNNLayer> ieLayer(new InferenceEngine::CNNLayer(lp));
ieLayer->params["axis"] = format("%d", _startAxis);
ieLayer->params["end_axis"] = format("%d", _endAxis);
return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));
#endif // HAVE_INF_ENGINE
return Ptr<BackendNode>();
}
int _startAxis;
int _endAxis;
};
@@ -43,6 +43,7 @@
#include "../precomp.hpp"
#include "layers_common.hpp"
#include "op_halide.hpp"
#include "op_inf_engine.hpp"
#include "opencl_kernels_dnn.hpp"
#include <opencv2/dnn/shape_utils.hpp>
@@ -127,7 +128,8 @@ public:
virtual bool supportBackend(int backendId)
{
return backendId == DNN_BACKEND_DEFAULT ||
backendId == DNN_BACKEND_HALIDE && haveHalide() && axis == 1;
backendId == DNN_BACKEND_HALIDE && haveHalide() && axis == 1 ||
backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine() && axis == 1;
}
virtual bool setActivation(const Ptr<ActivationLayer>& layer)
@@ -395,6 +397,24 @@ public:
return Ptr<BackendNode>();
}
virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >&)
{
#ifdef HAVE_INF_ENGINE
InferenceEngine::LayerParams lp;
lp.name = name;
lp.type = "FullyConnected";
lp.precision = InferenceEngine::Precision::FP32;
std::shared_ptr<InferenceEngine::FullyConnectedLayer> ieLayer(new InferenceEngine::FullyConnectedLayer(lp));
ieLayer->_out_num = blobs[0].size[0];
ieLayer->_weights = wrapToInfEngineBlob(blobs[0]);
if (blobs.size() > 1)
ieLayer->_biases = wrapToInfEngineBlob(blobs[1]);
return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));
#endif // HAVE_INF_ENGINE
return Ptr<BackendNode>();
}
virtual int64 getFLOPS(const std::vector<MatShape> &inputs,
const std::vector<MatShape> &outputs) const
{
+22 -1
View File
@@ -43,6 +43,7 @@
#include "../precomp.hpp"
#include "layers_common.hpp"
#include "op_halide.hpp"
#include "op_inf_engine.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/dnn/shape_utils.hpp"
#include "opencv2/core/hal/hal.hpp"
@@ -90,7 +91,8 @@ public:
virtual bool supportBackend(int backendId)
{
return backendId == DNN_BACKEND_DEFAULT ||
backendId == DNN_BACKEND_HALIDE && haveHalide();
backendId == DNN_BACKEND_HALIDE && haveHalide() ||
backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine();
}
#ifdef HAVE_OPENCL
@@ -369,6 +371,25 @@ public:
#endif // HAVE_HALIDE
}
virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >&)
{
#ifdef HAVE_INF_ENGINE
InferenceEngine::LayerParams lp;
lp.name = name;
lp.type = "Norm";
lp.precision = InferenceEngine::Precision::FP32;
std::shared_ptr<InferenceEngine::NormLayer> ieLayer(new InferenceEngine::NormLayer(lp));
ieLayer->_size = size;
ieLayer->_k = (int)bias;
ieLayer->_beta = beta;
ieLayer->_alpha = alpha;
ieLayer->_isAcrossMaps = (type == CHANNEL_NRM);
return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));
#endif // HAVE_INF_ENGINE
return Ptr<BackendNode>();
}
virtual int64 getFLOPS(const std::vector<MatShape> &inputs,
const std::vector<MatShape> &outputs) const
{
+26
View File
@@ -42,6 +42,7 @@
#include "../precomp.hpp"
#include "layers_common.hpp"
#include "op_inf_engine.hpp"
#include <float.h>
#include <algorithm>
#include "opencl_kernels_dnn.hpp"
@@ -112,6 +113,12 @@ public:
checkNeedForPermutation();
}
virtual bool supportBackend(int backendId)
{
return backendId == DNN_BACKEND_DEFAULT ||
backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine();
}
bool getMemoryShapes(const std::vector<MatShape> &inputs,
const int requiredOutputs,
std::vector<MatShape> &outputs,
@@ -370,6 +377,25 @@ public:
}
}
virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >&)
{
#ifdef HAVE_INF_ENGINE
InferenceEngine::LayerParams lp;
lp.name = name;
lp.type = "Permute";
lp.precision = InferenceEngine::Precision::FP32;
std::shared_ptr<InferenceEngine::CNNLayer> ieLayer(new InferenceEngine::CNNLayer(lp));
CV_Assert(!_order.empty());
ieLayer->params["order"] = format("%d", _order[0]);
for (int i = 1; i < _order.size(); ++i)
ieLayer->params["order"] += format(",%d", _order[i]);
return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));
#endif // HAVE_INF_ENGINE
return Ptr<BackendNode>();
}
size_t _count;
std::vector<size_t> _order;
+32 -1
View File
@@ -44,6 +44,7 @@
#include "layers_common.hpp"
#include "opencv2/core/hal/intrin.hpp"
#include "op_halide.hpp"
#include "op_inf_engine.hpp"
#include "opencl_kernels_dnn.hpp"
#include <float.h>
#include <algorithm>
@@ -130,7 +131,8 @@ public:
{
return backendId == DNN_BACKEND_DEFAULT ||
backendId == DNN_BACKEND_HALIDE && haveHalide() &&
(type == MAX || type == AVE && !pad.width && !pad.height);
(type == MAX || type == AVE && !pad.width && !pad.height) ||
backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine() && (type == MAX || type == AVE);
}
#ifdef HAVE_OPENCL
@@ -222,6 +224,35 @@ public:
return Ptr<BackendNode>();
}
virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >&)
{
#ifdef HAVE_INF_ENGINE
InferenceEngine::LayerParams lp;
lp.name = name;
lp.type = "Pooling";
lp.precision = InferenceEngine::Precision::FP32;
std::shared_ptr<InferenceEngine::PoolingLayer> ieLayer(new InferenceEngine::PoolingLayer(lp));
ieLayer->_kernel_x = kernel.width;
ieLayer->_kernel_y = kernel.height;
ieLayer->_stride_x = stride.width;
ieLayer->_stride_y = stride.height;
ieLayer->_padding_x = pad.width;
ieLayer->_padding_y = pad.height;
ieLayer->_exclude_pad = false;
ieLayer->params["rounding-type"] = ceilMode ? "ceil" : "floor";
if (type == MAX)
ieLayer->_type = InferenceEngine::PoolingLayer::PoolType::MAX;
else if (type == AVE)
ieLayer->_type = InferenceEngine::PoolingLayer::PoolType::AVG;
else
CV_Error(Error::StsNotImplemented, "Unsupported pooling type");
return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));
#endif // HAVE_INF_ENGINE
return Ptr<BackendNode>();
}
class PoolingInvoker : public ParallelLoopBody
{
public:
@@ -42,6 +42,7 @@
#include "../precomp.hpp"
#include "layers_common.hpp"
#include "op_inf_engine.hpp"
#include <float.h>
#include <algorithm>
#include <cmath>
@@ -248,6 +249,12 @@ public:
}
}
virtual bool supportBackend(int backendId)
{
return backendId == DNN_BACKEND_DEFAULT ||
backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine();
}
bool getMemoryShapes(const std::vector<MatShape> &inputs,
const int requiredOutputs,
std::vector<MatShape> &outputs,
@@ -518,6 +525,43 @@ public:
}
}
virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >&)
{
#ifdef HAVE_INF_ENGINE
InferenceEngine::LayerParams lp;
lp.name = name;
lp.type = "PriorBox";
lp.precision = InferenceEngine::Precision::FP32;
std::shared_ptr<InferenceEngine::CNNLayer> ieLayer(new InferenceEngine::CNNLayer(lp));
ieLayer->params["min_size"] = format("%f", _minSize);
ieLayer->params["max_size"] = _maxSize > 0 ? format("%f", _maxSize) : "";
CV_Assert(!_aspectRatios.empty());
ieLayer->params["aspect_ratio"] = format("%f", _aspectRatios[0]);
for (int i = 1; i < _aspectRatios.size(); ++i)
ieLayer->params["aspect_ratio"] += format(",%f", _aspectRatios[i]);
ieLayer->params["flip"] = _flip ? "1" : "0";
ieLayer->params["clip"] = _clip ? "1" : "0";
CV_Assert(!_variance.empty());
ieLayer->params["variance"] = format("%f", _variance[0]);
for (int i = 1; i < _variance.size(); ++i)
ieLayer->params["variance"] += format(",%f", _variance[i]);
ieLayer->params["step"] = "0";
ieLayer->params["step_h"] = _stepY;
ieLayer->params["step_w"] = _stepX;
CV_Assert(_offsetsX.size() == 1, _offsetsY.size() == 1, _offsetsX[0] == _offsetsY[0]);
ieLayer->params["offset"] = format("%f", _offsetsX[0]);;
return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));
#endif // HAVE_INF_ENGINE
return Ptr<BackendNode>();
}
virtual int64 getFLOPS(const std::vector<MatShape> &inputs,
const std::vector<MatShape> &outputs) const
{
+21
View File
@@ -42,6 +42,7 @@
#include "../precomp.hpp"
#include "layers_common.hpp"
#include "op_inf_engine.hpp"
#include <opencv2/dnn/shape_utils.hpp>
namespace cv
@@ -165,6 +166,12 @@ public:
}
}
virtual bool supportBackend(int backendId)
{
return backendId == DNN_BACKEND_DEFAULT ||
backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine();
}
bool getMemoryShapes(const std::vector<MatShape> &inputs,
const int requiredOutputs,
std::vector<MatShape> &outputs,
@@ -231,6 +238,20 @@ public:
srcBlob.reshape(1, shape(outputs[i])).copyTo(outputs[i]);
}
}
virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >&)
{
#ifdef HAVE_INF_ENGINE
InferenceEngine::LayerParams lp;
lp.name = name;
lp.type = "Reshape";
lp.precision = InferenceEngine::Precision::FP32;
std::shared_ptr<InferenceEngine::ReshapeLayer> ieLayer(new InferenceEngine::ReshapeLayer(lp));
ieLayer->shape = newShapeDesc;
return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));
#endif // HAVE_INF_ENGINE
return Ptr<BackendNode>();
}
};
Ptr<ReshapeLayer> ReshapeLayer::create(const LayerParams& params)
+35 -1
View File
@@ -12,6 +12,7 @@ Implementation of Scale layer.
#include "../precomp.hpp"
#include "layers_common.hpp"
#include "op_halide.hpp"
#include "op_inf_engine.hpp"
#include <opencv2/dnn/shape_utils.hpp>
namespace cv
@@ -42,7 +43,8 @@ public:
virtual bool supportBackend(int backendId)
{
return backendId == DNN_BACKEND_DEFAULT ||
backendId == DNN_BACKEND_HALIDE && haveHalide();
backendId == DNN_BACKEND_HALIDE && haveHalide() ||
backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine();
}
void forward(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays internals_arr)
@@ -130,6 +132,20 @@ public:
#endif // HAVE_HALIDE
break;
}
case DNN_BACKEND_INFERENCE_ENGINE:
{
#ifdef HAVE_INF_ENGINE
auto base = node.dynamicCast<InfEngineBackendNode>();
auto conv = std::dynamic_pointer_cast<InferenceEngine::ConvolutionLayer>(base->layer);
if (conv)
{
Mat bias = hasBias ? blobs[1] : Mat();
fuseConvWeights(conv, blobs[0], bias);
return base;
}
#endif // HAVE_INF_ENGINE
break;
}
}
return Ptr<BackendNode>();
}
@@ -167,6 +183,24 @@ public:
}
#endif // HAVE_HALIDE
virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >&)
{
#ifdef HAVE_INF_ENGINE
InferenceEngine::LayerParams lp;
lp.name = name;
lp.type = "ScaleShift";
lp.precision = InferenceEngine::Precision::FP32;
std::shared_ptr<InferenceEngine::ScaleShiftLayer> ieLayer(new InferenceEngine::ScaleShiftLayer(lp));
ieLayer->_weights = wrapToInfEngineBlob(blobs[0]);
if (hasBias)
ieLayer->_biases = wrapToInfEngineBlob(blobs[1]);
return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));
#endif // HAVE_INF_ENGINE
return Ptr<BackendNode>();
}
virtual int64 getFLOPS(const std::vector<MatShape> &inputs,
const std::vector<MatShape> &outputs) const
{
+18 -2
View File
@@ -43,6 +43,7 @@
#include "../precomp.hpp"
#include "layers_common.hpp"
#include "op_halide.hpp"
#include "op_inf_engine.hpp"
#include "opencl_kernels_dnn.hpp"
#include <algorithm>
#include <stdlib.h>
@@ -63,7 +64,7 @@ public:
SoftMaxLayerImpl(const LayerParams& params)
{
axisRaw = params.get<int>("axis", 1);
logSoftMax = params.get<int>("log_softmax", false);
logSoftMax = params.get<bool>("log_softmax", false);
setParamsFrom(params);
}
@@ -87,7 +88,8 @@ public:
virtual bool supportBackend(int backendId)
{
return backendId == DNN_BACKEND_DEFAULT ||
backendId == DNN_BACKEND_HALIDE && haveHalide() && axisRaw == 1;
backendId == DNN_BACKEND_HALIDE && haveHalide() && axisRaw == 1 ||
backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine() && !logSoftMax;
}
#ifdef HAVE_OPENCL
@@ -307,6 +309,20 @@ public:
return Ptr<BackendNode>();
}
virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >&)
{
#ifdef HAVE_INF_ENGINE
InferenceEngine::LayerParams lp;
lp.name = name;
lp.type = "SoftMax";
lp.precision = InferenceEngine::Precision::FP32;
std::shared_ptr<InferenceEngine::SoftMaxLayer> ieLayer(new InferenceEngine::SoftMaxLayer(lp));
ieLayer->axis = axisRaw;
return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));
#endif // HAVE_INF_ENGINE
return Ptr<BackendNode>();
}
int64 getFLOPS(const std::vector<MatShape> &inputs,
const std::vector<MatShape> &outputs) const
{
+360
View File
@@ -0,0 +1,360 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
#include "precomp.hpp"
#include "op_inf_engine.hpp"
#include <opencv2/dnn/shape_utils.hpp>
namespace cv { namespace dnn {
#ifdef HAVE_INF_ENGINE
InfEngineBackendNode::InfEngineBackendNode(const InferenceEngine::CNNLayerPtr& _layer)
: BackendNode(DNN_BACKEND_INFERENCE_ENGINE), layer(_layer) {}
void InfEngineBackendNode::connect(std::vector<Ptr<BackendWrapper> >& inputs,
std::vector<Ptr<BackendWrapper> >& outputs)
{
layer->insData.resize(inputs.size());
for (int i = 0; i < inputs.size(); ++i)
{
InferenceEngine::DataPtr dataPtr = infEngineDataNode(inputs[i]);
layer->insData[i] = InferenceEngine::DataWeakPtr(dataPtr);
dataPtr->inputTo[layer->name] = layer;
}
CV_Assert(!outputs.empty());
layer->outData.resize(1);
InferenceEngine::DataPtr dataPtr = infEngineDataNode(outputs[0]);
dataPtr->name = layer->name;
layer->outData[0] = dataPtr;
dataPtr->creatorLayer = InferenceEngine::CNNLayerWeakPtr(layer);
}
static std::vector<Ptr<InfEngineBackendWrapper> >
infEngineWrappers(const std::vector<Ptr<BackendWrapper> >& ptrs)
{
std::vector<Ptr<InfEngineBackendWrapper> > wrappers(ptrs.size());
for (int i = 0; i < ptrs.size(); ++i)
{
CV_Assert(!ptrs[i].empty());
wrappers[i] = ptrs[i].dynamicCast<InfEngineBackendWrapper>();
CV_Assert(!wrappers[i].empty());
}
return wrappers;
}
static InferenceEngine::DataPtr wrapToInfEngineDataNode(const Mat& m, const std::string& name = "")
{
std::vector<size_t> reversedShape(&m.size[0], &m.size[0] + m.dims);
std::reverse(reversedShape.begin(), reversedShape.end());
return InferenceEngine::DataPtr(
new InferenceEngine::Data(name, reversedShape, InferenceEngine::Precision::FP32)
);
}
InferenceEngine::TBlob<float>::Ptr wrapToInfEngineBlob(const Mat& m, const std::vector<size_t>& shape)
{
return InferenceEngine::make_shared_blob<float>(InferenceEngine::Precision::FP32,
shape, (float*)m.data);
}
InferenceEngine::TBlob<float>::Ptr wrapToInfEngineBlob(const Mat& m)
{
std::vector<size_t> reversedShape(&m.size[0], &m.size[0] + m.dims);
std::reverse(reversedShape.begin(), reversedShape.end());
return wrapToInfEngineBlob(m, reversedShape);
}
InferenceEngine::DataPtr infEngineDataNode(const Ptr<BackendWrapper>& ptr)
{
CV_Assert(!ptr.empty());
Ptr<InfEngineBackendWrapper> p = ptr.dynamicCast<InfEngineBackendWrapper>();
CV_Assert(!p.empty());
return p->dataPtr;
}
InfEngineBackendWrapper::InfEngineBackendWrapper(int targetId, const cv::Mat& m)
: BackendWrapper(DNN_BACKEND_INFERENCE_ENGINE, targetId)
{
dataPtr = wrapToInfEngineDataNode(m);
blob = wrapToInfEngineBlob(m);
}
InfEngineBackendWrapper::~InfEngineBackendWrapper()
{
}
void InfEngineBackendWrapper::copyToHost()
{
}
void InfEngineBackendWrapper::setHostDirty()
{
}
void InfEngineBackendNet::Release() noexcept
{
layers.clear();
inputs.clear();
outputs.clear();
}
InferenceEngine::Precision InfEngineBackendNet::getPrecision() noexcept
{
return InferenceEngine::Precision::FP32;
}
// Assume that outputs of network is unconnected blobs.
void InfEngineBackendNet::getOutputsInfo(InferenceEngine::OutputsDataMap &outputs_) noexcept
{
if (outputs.empty())
{
for (const auto& l : layers)
{
// Add all outputs.
for (const InferenceEngine::DataPtr& out : l->outData)
{
// TODO: Replace to uniquness assertion.
if (outputs.find(out->name) == outputs.end())
outputs[out->name] = out;
}
// Remove internally connected outputs.
for (const InferenceEngine::DataWeakPtr& inp : l->insData)
{
outputs.erase(InferenceEngine::DataPtr(inp)->name);
}
}
CV_Assert(layers.empty() || !outputs.empty());
}
outBlobs.clear();
for (const auto& it : outputs)
{
CV_Assert(allBlobs.find(it.first) != allBlobs.end());
outBlobs[it.first] = allBlobs[it.first];
}
outputs_ = outputs;
}
// Returns input references that aren't connected to internal outputs.
void InfEngineBackendNet::getInputsInfo(InferenceEngine::InputsDataMap &inputs_) noexcept
{
if (inputs.empty())
{
std::map<std::string, InferenceEngine::DataPtr> internalOutputs;
for (const auto& l : layers)
{
for (const InferenceEngine::DataWeakPtr& ptr : l->insData)
{
InferenceEngine::DataPtr inp(ptr);
if (internalOutputs.find(inp->name) == internalOutputs.end())
{
InferenceEngine::InputInfo::Ptr inpInfo(new InferenceEngine::InputInfo());
inpInfo->setInputData(inp);
if (inputs.find(inp->name) == inputs.end())
inputs[inp->name] = inpInfo;
}
}
for (const InferenceEngine::DataPtr& out : l->outData)
{
// TODO: Replace to uniquness assertion.
if (internalOutputs.find(out->name) == internalOutputs.end())
internalOutputs[out->name] = out;
}
}
CV_Assert(layers.empty() || !inputs.empty());
}
inpBlobs.clear();
for (const auto& it : inputs)
{
CV_Assert(allBlobs.find(it.first) != allBlobs.end());
inpBlobs[it.first] = allBlobs[it.first];
}
inputs_ = inputs;
}
InferenceEngine::InputInfo::Ptr InfEngineBackendNet::getInput(const std::string &inputName) noexcept
{
getInputsInfo(inputs);
const auto& it = inputs.find(inputName);
CV_Assert(it != inputs.end());
return it->second;
}
void InfEngineBackendNet::getName(char *pName, size_t len) noexcept
{
CV_Error(Error::StsNotImplemented, "");
}
size_t InfEngineBackendNet::layerCount() noexcept
{
return layers.size();
}
InferenceEngine::DataPtr& InfEngineBackendNet::getData(const char *dname) noexcept
{
CV_Error(Error::StsNotImplemented, "");
return outputs.begin()->second; // Just return something.
}
void InfEngineBackendNet::addLayer(const InferenceEngine::CNNLayerPtr &layer) noexcept
{
layers.push_back(layer);
inputs.clear();
outputs.clear();
}
InferenceEngine::StatusCode
InfEngineBackendNet::addOutput(const std::string &layerName, size_t outputIndex,
InferenceEngine::ResponseDesc *resp) noexcept
{
CV_Error(Error::StsNotImplemented, "");
return InferenceEngine::StatusCode::OK;
}
InferenceEngine::StatusCode
InfEngineBackendNet::getLayerByName(const char *layerName, InferenceEngine::CNNLayerPtr &out,
InferenceEngine::ResponseDesc *resp) noexcept
{
CV_Error(Error::StsNotImplemented, "");
return InferenceEngine::StatusCode::OK;
}
void InfEngineBackendNet::setTargetDevice(InferenceEngine::TargetDevice device) noexcept
{
if (device != InferenceEngine::TargetDevice::eCPU)
CV_Error(Error::StsNotImplemented, "");
}
InferenceEngine::TargetDevice InfEngineBackendNet::getTargetDevice() noexcept
{
return InferenceEngine::TargetDevice::eCPU;
}
InferenceEngine::StatusCode InfEngineBackendNet::setBatchSize(const size_t size) noexcept
{
CV_Error(Error::StsNotImplemented, "");
return InferenceEngine::StatusCode::OK;
}
size_t InfEngineBackendNet::getBatchSize() const noexcept
{
CV_Error(Error::StsNotImplemented, "");
return 0;
}
void InfEngineBackendNet::initEngine()
{
CV_Assert(!isInitialized());
engine = InferenceEngine::InferenceEnginePluginPtr("libMKLDNNPlugin.so");
InferenceEngine::ResponseDesc resp;
InferenceEngine::StatusCode status = engine->LoadNetwork(*this, &resp);
if (status != InferenceEngine::StatusCode::OK)
CV_Error(Error::StsAssert, resp.msg);
}
bool InfEngineBackendNet::isInitialized()
{
return (bool)engine;
}
void InfEngineBackendNet::addBlobs(const std::vector<Ptr<BackendWrapper> >& ptrs)
{
auto wrappers = infEngineWrappers(ptrs);
for (const auto& wrapper : wrappers)
{
allBlobs[wrapper->dataPtr->name] = wrapper->blob;
}
}
void InfEngineBackendNet::forward()
{
InferenceEngine::ResponseDesc resp;
InferenceEngine::StatusCode status = engine->Infer(inpBlobs, outBlobs, &resp);
if (status != InferenceEngine::StatusCode::OK)
CV_Error(Error::StsAssert, resp.msg);
}
static inline Mat infEngineBlobToMat(const InferenceEngine::Blob::Ptr& blob)
{
// NOTE: Inference Engine sizes are reversed.
std::vector<int> size(blob->dims().begin(), blob->dims().end());
std::reverse(size.begin(), size.end());
return Mat(size, CV_32F, (void*)blob->buffer());
}
void fuseConvWeights(const std::shared_ptr<InferenceEngine::ConvolutionLayer>& conv,
const Mat& w, const Mat& b)
{
// Get convolution's weights. Clone the data because Inference Engine can host it
// and conv->_weights->allocate() below will deallocate it.
Mat originWeights = infEngineBlobToMat(conv->_weights).clone();
// Create new weights blob.
conv->_weights = InferenceEngine::make_shared_blob<float>(
InferenceEngine::Precision::FP32, conv->_weights->dims());
conv->_weights->allocate();
// Convolution weights have OIHW data layout.
// (conv(I) + b1 ) * w + b2
// w*conv(I) + b1 * w + b2
Mat fusedWeights = infEngineBlobToMat(conv->_weights);
const int numChannels = fusedWeights.size[0];
// Mat weights = blobs[0].reshape(1, 1);
// Mat bias = hasBias ? blobs[1].reshape(1, 1) : Mat();
CV_Assert(numChannels == w.total());
CV_Assert(b.empty() || numChannels == b.total());
for (int i = 0; i < numChannels; ++i)
{
cv::multiply(slice(originWeights, i), w.at<float>(i), slice(fusedWeights, i));
}
if (conv->_biases)
{
// The same for biases.
Mat originBiases = infEngineBlobToMat(conv->_biases).clone();
conv->_biases = InferenceEngine::make_shared_blob<float>(
InferenceEngine::Precision::FP32, conv->_biases->dims());
conv->_biases->allocate();
Mat fusedBiases = infEngineBlobToMat(conv->_biases);
cv::multiply(w.reshape(1, fusedBiases.dims, &fusedBiases.size[0]), originBiases, fusedBiases);
if (!b.empty())
cv::add(fusedBiases, b.reshape(1, fusedBiases.dims, &fusedBiases.size[0]), fusedBiases);
}
else
conv->_biases = wrapToInfEngineBlob(b);
}
#endif // HAVE_INF_ENGINE
bool haveInfEngine()
{
#ifdef HAVE_INF_ENGINE
return true;
#else
return false;
#endif // HAVE_INF_ENGINE
}
void forwardInfEngine(Ptr<BackendNode>& node)
{
CV_Assert(haveInfEngine());
#ifdef HAVE_INF_ENGINE
CV_Assert(!node.empty());
Ptr<InfEngineBackendNode> ieNode = node.dynamicCast<InfEngineBackendNode>();
CV_Assert(!ieNode.empty());
ieNode->net->forward();
#endif // HAVE_INF_ENGINE
}
}} // namespace dnn, namespace cv
+122
View File
@@ -0,0 +1,122 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
#ifndef __OPENCV_DNN_OP_INF_ENGINE_HPP__
#define __OPENCV_DNN_OP_INF_ENGINE_HPP__
#include "precomp.hpp"
#ifdef HAVE_INF_ENGINE
#include <inference_engine.hpp>
#endif // HAVE_INF_ENGINE
namespace cv { namespace dnn {
#ifdef HAVE_INF_ENGINE
class InfEngineBackendNet : public InferenceEngine::ICNNNetwork
{
public:
virtual void Release() noexcept;
virtual InferenceEngine::Precision getPrecision() noexcept;
virtual void getOutputsInfo(InferenceEngine::OutputsDataMap &out) noexcept;
virtual void getInputsInfo(InferenceEngine::InputsDataMap &inputs) noexcept;
virtual InferenceEngine::InputInfo::Ptr getInput(const std::string &inputName) noexcept;
virtual void getName(char *pName, size_t len) noexcept;
virtual size_t layerCount() noexcept;
virtual InferenceEngine::DataPtr& getData(const char *dname) noexcept;
virtual void addLayer(const InferenceEngine::CNNLayerPtr &layer) noexcept;
virtual InferenceEngine::StatusCode addOutput(const std::string &layerName,
size_t outputIndex = 0,
InferenceEngine::ResponseDesc *resp = nullptr) noexcept;
virtual InferenceEngine::StatusCode getLayerByName(const char *layerName,
InferenceEngine::CNNLayerPtr &out,
InferenceEngine::ResponseDesc *resp) noexcept;
virtual void setTargetDevice(InferenceEngine::TargetDevice device) noexcept;
virtual InferenceEngine::TargetDevice getTargetDevice() noexcept;
virtual InferenceEngine::StatusCode setBatchSize(const size_t size) noexcept;
virtual size_t getBatchSize() const noexcept;
void initEngine();
void addBlobs(const std::vector<Ptr<BackendWrapper> >& wrappers);
void forward();
bool isInitialized();
private:
std::vector<InferenceEngine::CNNLayerPtr> layers;
InferenceEngine::InputsDataMap inputs;
InferenceEngine::OutputsDataMap outputs;
InferenceEngine::BlobMap inpBlobs;
InferenceEngine::BlobMap outBlobs;
InferenceEngine::BlobMap allBlobs;
InferenceEngine::InferenceEnginePluginPtr engine;
};
class InfEngineBackendNode : public BackendNode
{
public:
InfEngineBackendNode(const InferenceEngine::CNNLayerPtr& layer);
void connect(std::vector<Ptr<BackendWrapper> >& inputs,
std::vector<Ptr<BackendWrapper> >& outputs);
InferenceEngine::CNNLayerPtr layer;
// Inference Engine network object that allows to obtain the outputs of this layer.
Ptr<InfEngineBackendNet> net;
};
class InfEngineBackendWrapper : public BackendWrapper
{
public:
InfEngineBackendWrapper(int targetId, const Mat& m);
~InfEngineBackendWrapper();
virtual void copyToHost();
virtual void setHostDirty();
InferenceEngine::DataPtr dataPtr;
InferenceEngine::TBlob<float>::Ptr blob;
};
InferenceEngine::TBlob<float>::Ptr wrapToInfEngineBlob(const Mat& m);
InferenceEngine::TBlob<float>::Ptr wrapToInfEngineBlob(const Mat& m, const std::vector<size_t>& shape);
InferenceEngine::DataPtr infEngineDataNode(const Ptr<BackendWrapper>& ptr);
// Fuses convolution weights and biases with channel-wise scales and shifts.
void fuseConvWeights(const std::shared_ptr<InferenceEngine::ConvolutionLayer>& conv,
const Mat& w, const Mat& b = Mat());
#endif // HAVE_INF_ENGINE
bool haveInfEngine();
void forwardInfEngine(Ptr<BackendNode>& node);
}} // namespace dnn, namespace cv
#endif // __OPENCV_DNN_OP_INF_ENGINE_HPP__