2018-02-06 16:57:35 +08:00
|
|
|
// 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>
|
|
|
|
|
2018-04-09 21:22:19 +08:00
|
|
|
#ifdef HAVE_INF_ENGINE
|
|
|
|
#include <ie_extension.h>
|
|
|
|
#include <ie_plugin_dispatcher.hpp>
|
|
|
|
#endif // HAVE_INF_ENGINE
|
|
|
|
|
2018-02-06 16:57:35 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-05-31 19:05:21 +08:00
|
|
|
static InferenceEngine::Layout estimateLayout(const Mat& m)
|
|
|
|
{
|
|
|
|
if (m.dims == 4)
|
|
|
|
return InferenceEngine::Layout::NCHW;
|
|
|
|
else if (m.dims == 2)
|
|
|
|
return InferenceEngine::Layout::NC;
|
|
|
|
else
|
|
|
|
return InferenceEngine::Layout::ANY;
|
|
|
|
}
|
|
|
|
|
2018-02-06 16:57:35 +08:00
|
|
|
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());
|
2018-06-05 04:51:28 +08:00
|
|
|
if (m.type() == CV_32F)
|
|
|
|
return InferenceEngine::DataPtr(
|
|
|
|
new InferenceEngine::Data(name, reversedShape, InferenceEngine::Precision::FP32, estimateLayout(m))
|
|
|
|
);
|
|
|
|
else if (m.type() == CV_8U)
|
|
|
|
return InferenceEngine::DataPtr(
|
|
|
|
new InferenceEngine::Data(name, reversedShape, InferenceEngine::Precision::U8, estimateLayout(m))
|
|
|
|
);
|
|
|
|
else
|
|
|
|
CV_Error(Error::StsNotImplemented, format("Unsupported data type %d", m.type()));
|
2018-02-06 16:57:35 +08:00
|
|
|
}
|
|
|
|
|
2018-06-05 04:51:28 +08:00
|
|
|
InferenceEngine::Blob::Ptr wrapToInfEngineBlob(const Mat& m, const std::vector<size_t>& shape,
|
|
|
|
InferenceEngine::Layout layout)
|
2018-02-06 16:57:35 +08:00
|
|
|
{
|
2018-06-05 04:51:28 +08:00
|
|
|
if (m.type() == CV_32F)
|
|
|
|
return InferenceEngine::make_shared_blob<float>(InferenceEngine::Precision::FP32,
|
|
|
|
layout, shape, (float*)m.data);
|
|
|
|
else if (m.type() == CV_8U)
|
|
|
|
return InferenceEngine::make_shared_blob<uint8_t>(InferenceEngine::Precision::U8,
|
|
|
|
layout, shape, (uint8_t*)m.data);
|
|
|
|
else
|
|
|
|
CV_Error(Error::StsNotImplemented, format("Unsupported data type %d", m.type()));
|
2018-02-06 16:57:35 +08:00
|
|
|
}
|
|
|
|
|
2018-06-05 04:51:28 +08:00
|
|
|
InferenceEngine::Blob::Ptr wrapToInfEngineBlob(const Mat& m, InferenceEngine::Layout layout)
|
2018-02-06 16:57:35 +08:00
|
|
|
{
|
|
|
|
std::vector<size_t> reversedShape(&m.size[0], &m.size[0] + m.dims);
|
|
|
|
std::reverse(reversedShape.begin(), reversedShape.end());
|
2018-03-12 22:35:28 +08:00
|
|
|
return wrapToInfEngineBlob(m, reversedShape, layout);
|
2018-02-06 16:57:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2018-05-31 19:05:21 +08:00
|
|
|
blob = wrapToInfEngineBlob(m, estimateLayout(m));
|
2018-02-06 16:57:35 +08:00
|
|
|
}
|
|
|
|
|
2018-06-05 04:51:28 +08:00
|
|
|
InfEngineBackendWrapper::InfEngineBackendWrapper(Ptr<BackendWrapper> wrapper)
|
|
|
|
: BackendWrapper(DNN_BACKEND_INFERENCE_ENGINE, wrapper->targetId)
|
|
|
|
{
|
|
|
|
Ptr<InfEngineBackendWrapper> ieWrapper = wrapper.dynamicCast<InfEngineBackendWrapper>();
|
|
|
|
CV_Assert(!ieWrapper.empty());
|
|
|
|
InferenceEngine::DataPtr srcData = ieWrapper->dataPtr;
|
|
|
|
dataPtr = InferenceEngine::DataPtr(
|
|
|
|
new InferenceEngine::Data(srcData->name, srcData->dims, srcData->precision,
|
|
|
|
srcData->layout)
|
|
|
|
);
|
|
|
|
blob = ieWrapper->blob;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ptr<BackendWrapper> InfEngineBackendWrapper::create(Ptr<BackendWrapper> wrapper)
|
|
|
|
{
|
|
|
|
return Ptr<BackendWrapper>(new InfEngineBackendWrapper(wrapper));
|
|
|
|
}
|
|
|
|
|
2018-02-06 16:57:35 +08:00
|
|
|
InfEngineBackendWrapper::~InfEngineBackendWrapper()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void InfEngineBackendWrapper::copyToHost()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void InfEngineBackendWrapper::setHostDirty()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-03-17 00:27:04 +08:00
|
|
|
InfEngineBackendNet::InfEngineBackendNet()
|
|
|
|
{
|
2018-03-12 22:35:28 +08:00
|
|
|
targetDevice = InferenceEngine::TargetDevice::eCPU;
|
|
|
|
precision = InferenceEngine::Precision::FP32;
|
2018-03-17 00:27:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
InfEngineBackendNet::InfEngineBackendNet(InferenceEngine::CNNNetwork& net)
|
|
|
|
{
|
2018-03-12 22:35:28 +08:00
|
|
|
targetDevice = InferenceEngine::TargetDevice::eCPU;
|
|
|
|
precision = InferenceEngine::Precision::FP32;
|
2018-03-17 00:27:04 +08:00
|
|
|
inputs = net.getInputsInfo();
|
|
|
|
outputs = net.getOutputsInfo();
|
|
|
|
layers.resize(net.layerCount()); // A hack to execute InfEngineBackendNet::layerCount correctly.
|
2018-08-29 18:26:43 +08:00
|
|
|
netOwner = net;
|
2018-03-17 00:27:04 +08:00
|
|
|
}
|
|
|
|
|
2018-02-06 16:57:35 +08:00
|
|
|
void InfEngineBackendNet::Release() noexcept
|
|
|
|
{
|
|
|
|
layers.clear();
|
|
|
|
inputs.clear();
|
|
|
|
outputs.clear();
|
|
|
|
}
|
|
|
|
|
2018-03-12 22:35:28 +08:00
|
|
|
void InfEngineBackendNet::setPrecision(InferenceEngine::Precision p) noexcept
|
|
|
|
{
|
|
|
|
precision = p;
|
|
|
|
}
|
|
|
|
|
2018-02-06 16:57:35 +08:00
|
|
|
InferenceEngine::Precision InfEngineBackendNet::getPrecision() noexcept
|
|
|
|
{
|
2018-03-12 22:35:28 +08:00
|
|
|
return precision;
|
2018-02-06 16:57:35 +08:00
|
|
|
}
|
|
|
|
|
2018-07-20 00:22:23 +08:00
|
|
|
InferenceEngine::Precision InfEngineBackendNet::getPrecision() const noexcept
|
|
|
|
{
|
|
|
|
return precision;
|
|
|
|
}
|
|
|
|
|
2018-02-06 16:57:35 +08:00
|
|
|
// Assume that outputs of network is unconnected blobs.
|
|
|
|
void InfEngineBackendNet::getOutputsInfo(InferenceEngine::OutputsDataMap &outputs_) noexcept
|
|
|
|
{
|
2018-07-20 00:22:23 +08:00
|
|
|
const_cast<const InfEngineBackendNet*>(this)->getOutputsInfo(outputs_);
|
2018-02-06 16:57:35 +08:00
|
|
|
}
|
2018-03-15 21:16:56 +08:00
|
|
|
void InfEngineBackendNet::getOutputsInfo(InferenceEngine::OutputsDataMap &outputs_) const noexcept
|
|
|
|
{
|
|
|
|
outputs_ = outputs;
|
|
|
|
}
|
2018-02-06 16:57:35 +08:00
|
|
|
|
|
|
|
// Returns input references that aren't connected to internal outputs.
|
|
|
|
void InfEngineBackendNet::getInputsInfo(InferenceEngine::InputsDataMap &inputs_) noexcept
|
|
|
|
{
|
2018-07-20 00:22:23 +08:00
|
|
|
const_cast<const InfEngineBackendNet*>(this)->getInputsInfo(inputs_);
|
2018-02-06 16:57:35 +08:00
|
|
|
}
|
|
|
|
|
2018-02-14 19:17:44 +08:00
|
|
|
// Returns input references that aren't connected to internal outputs.
|
|
|
|
void InfEngineBackendNet::getInputsInfo(InferenceEngine::InputsDataMap &inputs_) const noexcept
|
|
|
|
{
|
|
|
|
inputs_ = inputs;
|
|
|
|
}
|
|
|
|
|
2018-02-06 16:57:35 +08:00
|
|
|
InferenceEngine::InputInfo::Ptr InfEngineBackendNet::getInput(const std::string &inputName) noexcept
|
|
|
|
{
|
2018-07-20 00:22:23 +08:00
|
|
|
return const_cast<const InfEngineBackendNet*>(this)->getInput(inputName);
|
|
|
|
}
|
|
|
|
|
|
|
|
InferenceEngine::InputInfo::Ptr InfEngineBackendNet::getInput(const std::string &inputName) const noexcept
|
|
|
|
{
|
2018-02-06 16:57:35 +08:00
|
|
|
const auto& it = inputs.find(inputName);
|
|
|
|
CV_Assert(it != inputs.end());
|
|
|
|
return it->second;
|
|
|
|
}
|
|
|
|
|
2018-03-12 22:35:28 +08:00
|
|
|
void InfEngineBackendNet::getName(char*, size_t) noexcept
|
2018-02-06 16:57:35 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-05-22 20:18:18 +08:00
|
|
|
void InfEngineBackendNet::getName(char*, size_t) const noexcept
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-07-20 00:22:23 +08:00
|
|
|
const std::string& InfEngineBackendNet::getName() const noexcept
|
|
|
|
{
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2018-02-06 16:57:35 +08:00
|
|
|
size_t InfEngineBackendNet::layerCount() noexcept
|
2018-07-20 00:22:23 +08:00
|
|
|
{
|
|
|
|
return const_cast<const InfEngineBackendNet*>(this)->layerCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t InfEngineBackendNet::layerCount() const noexcept
|
2018-02-06 16:57:35 +08:00
|
|
|
{
|
|
|
|
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
|
|
|
|
{
|
2018-02-06 21:23:18 +08:00
|
|
|
for (const auto& l : layers)
|
|
|
|
{
|
|
|
|
for (const InferenceEngine::DataPtr& out : l->outData)
|
|
|
|
{
|
|
|
|
if (out->name == layerName)
|
|
|
|
{
|
|
|
|
outputs[out->name] = out;
|
|
|
|
return InferenceEngine::StatusCode::OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CV_Error(Error::StsObjectNotFound, "Cannot find a layer " + layerName);
|
2018-02-06 16:57:35 +08:00
|
|
|
return InferenceEngine::StatusCode::OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
InferenceEngine::StatusCode
|
|
|
|
InfEngineBackendNet::getLayerByName(const char *layerName, InferenceEngine::CNNLayerPtr &out,
|
|
|
|
InferenceEngine::ResponseDesc *resp) noexcept
|
2018-07-20 00:22:23 +08:00
|
|
|
{
|
|
|
|
return const_cast<const InfEngineBackendNet*>(this)->getLayerByName(layerName, out, resp);
|
|
|
|
}
|
|
|
|
|
|
|
|
InferenceEngine::StatusCode InfEngineBackendNet::getLayerByName(const char *layerName,
|
|
|
|
InferenceEngine::CNNLayerPtr &out,
|
|
|
|
InferenceEngine::ResponseDesc *resp) const noexcept
|
2018-02-06 16:57:35 +08:00
|
|
|
{
|
2018-04-19 20:04:57 +08:00
|
|
|
for (auto& l : layers)
|
|
|
|
{
|
|
|
|
if (l->name == layerName)
|
|
|
|
{
|
|
|
|
out = l;
|
|
|
|
return InferenceEngine::StatusCode::OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CV_Error(Error::StsObjectNotFound, cv::format("Cannot find a layer %s", layerName));
|
|
|
|
return InferenceEngine::StatusCode::NOT_FOUND;
|
2018-02-06 16:57:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void InfEngineBackendNet::setTargetDevice(InferenceEngine::TargetDevice device) noexcept
|
|
|
|
{
|
2018-03-12 22:35:28 +08:00
|
|
|
if (device != InferenceEngine::TargetDevice::eCPU &&
|
2018-05-31 19:05:21 +08:00
|
|
|
device != InferenceEngine::TargetDevice::eGPU &&
|
2018-11-16 22:09:54 +08:00
|
|
|
device != InferenceEngine::TargetDevice::eMYRIAD &&
|
|
|
|
device != InferenceEngine::TargetDevice::eFPGA)
|
2018-02-06 16:57:35 +08:00
|
|
|
CV_Error(Error::StsNotImplemented, "");
|
2018-03-12 22:35:28 +08:00
|
|
|
targetDevice = device;
|
2018-02-06 16:57:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
InferenceEngine::TargetDevice InfEngineBackendNet::getTargetDevice() noexcept
|
|
|
|
{
|
2018-10-23 00:23:50 +08:00
|
|
|
return const_cast<const InfEngineBackendNet*>(this)->getTargetDevice();
|
2018-02-06 16:57:35 +08:00
|
|
|
}
|
|
|
|
|
2018-07-20 00:22:23 +08:00
|
|
|
InferenceEngine::TargetDevice InfEngineBackendNet::getTargetDevice() const noexcept
|
|
|
|
{
|
2018-11-16 22:09:54 +08:00
|
|
|
return targetDevice == InferenceEngine::TargetDevice::eFPGA ?
|
|
|
|
InferenceEngine::TargetDevice::eHETERO : targetDevice;
|
2018-07-20 00:22:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
InferenceEngine::StatusCode InfEngineBackendNet::setBatchSize(const size_t) noexcept
|
2018-02-06 16:57:35 +08:00
|
|
|
{
|
|
|
|
CV_Error(Error::StsNotImplemented, "");
|
|
|
|
return InferenceEngine::StatusCode::OK;
|
|
|
|
}
|
|
|
|
|
2018-07-28 00:56:35 +08:00
|
|
|
InferenceEngine::StatusCode InfEngineBackendNet::setBatchSize(size_t size, InferenceEngine::ResponseDesc *responseDesc) noexcept
|
|
|
|
{
|
|
|
|
CV_Error(Error::StsNotImplemented, "");
|
|
|
|
return InferenceEngine::StatusCode::OK;
|
|
|
|
}
|
|
|
|
|
2018-02-06 16:57:35 +08:00
|
|
|
size_t InfEngineBackendNet::getBatchSize() const noexcept
|
|
|
|
{
|
2018-10-17 19:02:37 +08:00
|
|
|
size_t batchSize = 0;
|
|
|
|
for (const auto& inp : inputs)
|
|
|
|
{
|
|
|
|
CV_Assert(inp.second);
|
|
|
|
std::vector<size_t> dims = inp.second->getDims();
|
|
|
|
CV_Assert(!dims.empty());
|
|
|
|
if (batchSize != 0)
|
|
|
|
CV_Assert(batchSize == dims.back());
|
|
|
|
else
|
|
|
|
batchSize = dims.back();
|
|
|
|
}
|
|
|
|
return batchSize;
|
2018-02-06 16:57:35 +08:00
|
|
|
}
|
|
|
|
|
2018-07-30 23:21:17 +08:00
|
|
|
#if INF_ENGINE_VER_MAJOR_GT(INF_ENGINE_RELEASE_2018R2)
|
2018-07-28 00:56:35 +08:00
|
|
|
InferenceEngine::StatusCode InfEngineBackendNet::AddExtension(const InferenceEngine::IShapeInferExtensionPtr &extension, InferenceEngine::ResponseDesc *resp) noexcept
|
|
|
|
{
|
|
|
|
CV_Error(Error::StsNotImplemented, "");
|
|
|
|
return InferenceEngine::StatusCode::OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
InferenceEngine::StatusCode InfEngineBackendNet::reshape(const InferenceEngine::ICNNNetwork::InputShapes &inputShapes, InferenceEngine::ResponseDesc *resp) noexcept
|
|
|
|
{
|
|
|
|
CV_Error(Error::StsNotImplemented, "");
|
|
|
|
return InferenceEngine::StatusCode::OK;
|
|
|
|
}
|
2018-07-30 23:21:17 +08:00
|
|
|
#endif
|
2018-07-28 00:56:35 +08:00
|
|
|
|
2018-03-12 22:35:28 +08:00
|
|
|
void InfEngineBackendNet::init(int targetId)
|
2018-02-06 16:57:35 +08:00
|
|
|
{
|
2018-03-17 00:27:04 +08:00
|
|
|
if (inputs.empty())
|
2018-02-07 16:28:45 +08:00
|
|
|
{
|
2018-03-17 00:27:04 +08:00
|
|
|
// Collect all external input blobs.
|
|
|
|
inputs.clear();
|
|
|
|
std::map<std::string, InferenceEngine::DataPtr> internalOutputs;
|
|
|
|
for (const auto& l : layers)
|
2018-02-07 16:28:45 +08:00
|
|
|
{
|
2018-03-17 00:27:04 +08:00
|
|
|
for (const InferenceEngine::DataWeakPtr& ptr : l->insData)
|
2018-02-07 16:28:45 +08:00
|
|
|
{
|
2018-03-17 00:27:04 +08:00
|
|
|
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)
|
|
|
|
{
|
2018-06-03 07:21:08 +08:00
|
|
|
// TODO: Replace to uniqueness assertion.
|
2018-03-17 00:27:04 +08:00
|
|
|
if (internalOutputs.find(out->name) == internalOutputs.end())
|
|
|
|
internalOutputs[out->name] = out;
|
2018-02-07 16:28:45 +08:00
|
|
|
}
|
|
|
|
}
|
2018-03-17 00:27:04 +08:00
|
|
|
CV_Assert(!inputs.empty());
|
2018-10-23 00:23:50 +08:00
|
|
|
|
|
|
|
#if INF_ENGINE_VER_MAJOR_GT(INF_ENGINE_RELEASE_2018R3)
|
|
|
|
for (const auto& inp : inputs)
|
|
|
|
{
|
|
|
|
InferenceEngine::LayerParams lp;
|
|
|
|
lp.name = inp.first;
|
|
|
|
lp.type = "Input";
|
|
|
|
lp.precision = InferenceEngine::Precision::FP32;
|
|
|
|
std::shared_ptr<InferenceEngine::CNNLayer> inpLayer(new InferenceEngine::CNNLayer(lp));
|
|
|
|
|
|
|
|
layers.push_back(inpLayer);
|
|
|
|
|
|
|
|
InferenceEngine::DataPtr dataPtr = inp.second->getInputData();
|
|
|
|
// TODO: remove precision dependency (see setInput.normalization tests)
|
|
|
|
if (dataPtr->precision == InferenceEngine::Precision::FP32)
|
|
|
|
{
|
|
|
|
inpLayer->outData.assign(1, dataPtr);
|
|
|
|
dataPtr->creatorLayer = InferenceEngine::CNNLayerWeakPtr(inpLayer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2018-02-07 16:28:45 +08:00
|
|
|
}
|
2018-02-06 21:23:18 +08:00
|
|
|
|
2018-03-17 00:27:04 +08:00
|
|
|
if (outputs.empty())
|
2018-02-06 21:23:18 +08:00
|
|
|
{
|
2018-03-17 00:27:04 +08:00
|
|
|
// Add all unconnected blobs to output blobs.
|
|
|
|
InferenceEngine::OutputsDataMap unconnectedOuts;
|
|
|
|
for (const auto& l : layers)
|
2018-02-06 21:23:18 +08:00
|
|
|
{
|
2018-03-17 00:27:04 +08:00
|
|
|
// Add all outputs.
|
|
|
|
for (const InferenceEngine::DataPtr& out : l->outData)
|
|
|
|
{
|
2018-06-03 07:21:08 +08:00
|
|
|
// TODO: Replace to uniqueness assertion.
|
2018-03-17 00:27:04 +08:00
|
|
|
if (unconnectedOuts.find(out->name) == unconnectedOuts.end())
|
|
|
|
unconnectedOuts[out->name] = out;
|
|
|
|
}
|
|
|
|
// Remove internally connected outputs.
|
|
|
|
for (const InferenceEngine::DataWeakPtr& inp : l->insData)
|
|
|
|
{
|
|
|
|
unconnectedOuts.erase(InferenceEngine::DataPtr(inp)->name);
|
|
|
|
}
|
2018-02-06 21:23:18 +08:00
|
|
|
}
|
2018-03-17 00:27:04 +08:00
|
|
|
CV_Assert(!unconnectedOuts.empty());
|
|
|
|
|
|
|
|
for (auto it = unconnectedOuts.begin(); it != unconnectedOuts.end(); ++it)
|
2018-02-06 21:23:18 +08:00
|
|
|
{
|
2018-03-17 00:27:04 +08:00
|
|
|
outputs[it->first] = it->second;
|
2018-02-06 21:23:18 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-07 16:28:45 +08:00
|
|
|
// Set up input blobs.
|
|
|
|
inpBlobs.clear();
|
|
|
|
for (const auto& it : inputs)
|
|
|
|
{
|
|
|
|
CV_Assert(allBlobs.find(it.first) != allBlobs.end());
|
|
|
|
inpBlobs[it.first] = allBlobs[it.first];
|
2018-06-05 04:51:28 +08:00
|
|
|
it.second->setPrecision(inpBlobs[it.first]->precision());
|
2018-02-07 16:28:45 +08:00
|
|
|
}
|
|
|
|
|
2018-02-06 21:23:18 +08:00
|
|
|
// Set up output blobs.
|
|
|
|
outBlobs.clear();
|
|
|
|
for (const auto& it : outputs)
|
|
|
|
{
|
|
|
|
CV_Assert(allBlobs.find(it.first) != allBlobs.end());
|
|
|
|
outBlobs[it.first] = allBlobs[it.first];
|
|
|
|
}
|
|
|
|
|
2018-03-12 22:35:28 +08:00
|
|
|
switch (targetId)
|
|
|
|
{
|
|
|
|
case DNN_TARGET_CPU: setTargetDevice(InferenceEngine::TargetDevice::eCPU); break;
|
2018-07-20 00:22:23 +08:00
|
|
|
case DNN_TARGET_OPENCL_FP16:
|
|
|
|
setPrecision(InferenceEngine::Precision::FP16);
|
|
|
|
/* Falls through. */
|
2018-03-12 22:35:28 +08:00
|
|
|
case DNN_TARGET_OPENCL: setTargetDevice(InferenceEngine::TargetDevice::eGPU); break;
|
2018-05-31 19:05:21 +08:00
|
|
|
case DNN_TARGET_MYRIAD:
|
|
|
|
{
|
|
|
|
setPrecision(InferenceEngine::Precision::FP16);
|
|
|
|
setTargetDevice(InferenceEngine::TargetDevice::eMYRIAD); break;
|
|
|
|
}
|
2018-11-16 22:09:54 +08:00
|
|
|
case DNN_TARGET_FPGA:
|
|
|
|
{
|
|
|
|
setPrecision(InferenceEngine::Precision::FP16);
|
|
|
|
setTargetDevice(InferenceEngine::TargetDevice::eFPGA); break;
|
|
|
|
}
|
2018-03-12 22:35:28 +08:00
|
|
|
default:
|
|
|
|
CV_Error(Error::StsError, format("Unknown target identifier: %d", targetId));
|
|
|
|
}
|
|
|
|
|
2018-03-17 00:27:04 +08:00
|
|
|
if (!isInitialized())
|
|
|
|
initPlugin(*this);
|
|
|
|
}
|
|
|
|
|
2018-09-18 16:21:08 +08:00
|
|
|
static std::map<InferenceEngine::TargetDevice, InferenceEngine::InferenceEnginePluginPtr> sharedPlugins;
|
|
|
|
|
2018-03-17 00:27:04 +08:00
|
|
|
void InfEngineBackendNet::initPlugin(InferenceEngine::ICNNNetwork& net)
|
|
|
|
{
|
|
|
|
CV_Assert(!isInitialized());
|
2018-04-09 21:22:19 +08:00
|
|
|
|
2018-06-05 22:18:14 +08:00
|
|
|
try
|
2018-06-01 19:10:32 +08:00
|
|
|
{
|
2018-07-20 23:58:37 +08:00
|
|
|
auto pluginIt = sharedPlugins.find(targetDevice);
|
2018-06-05 22:18:14 +08:00
|
|
|
if (pluginIt != sharedPlugins.end())
|
|
|
|
{
|
|
|
|
enginePtr = pluginIt->second;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-11-16 22:09:54 +08:00
|
|
|
auto dispatcher = InferenceEngine::PluginDispatcher({""});
|
|
|
|
if (targetDevice == InferenceEngine::TargetDevice::eFPGA)
|
|
|
|
enginePtr = dispatcher.getPluginByDevice("HETERO:FPGA,CPU");
|
|
|
|
else
|
|
|
|
enginePtr = dispatcher.getSuitablePlugin(targetDevice);
|
2018-07-20 23:58:37 +08:00
|
|
|
sharedPlugins[targetDevice] = enginePtr;
|
2018-04-09 21:22:19 +08:00
|
|
|
|
2018-11-16 22:09:54 +08:00
|
|
|
if (targetDevice == InferenceEngine::TargetDevice::eCPU ||
|
|
|
|
targetDevice == InferenceEngine::TargetDevice::eFPGA)
|
2018-06-05 22:18:14 +08:00
|
|
|
{
|
|
|
|
std::string suffixes[] = {"_avx2", "_sse4", ""};
|
|
|
|
bool haveFeature[] = {
|
|
|
|
checkHardwareSupport(CPU_AVX2),
|
|
|
|
checkHardwareSupport(CPU_SSE4_2),
|
|
|
|
true
|
|
|
|
};
|
|
|
|
for (int i = 0; i < 3; ++i)
|
|
|
|
{
|
|
|
|
if (!haveFeature[i])
|
|
|
|
continue;
|
|
|
|
#ifdef _WIN32
|
|
|
|
std::string libName = "cpu_extension" + suffixes[i] + ".dll";
|
|
|
|
#else
|
|
|
|
std::string libName = "libcpu_extension" + suffixes[i] + ".so";
|
|
|
|
#endif // _WIN32
|
|
|
|
try
|
|
|
|
{
|
|
|
|
InferenceEngine::IExtensionPtr extension =
|
|
|
|
InferenceEngine::make_so_pointer<InferenceEngine::IExtension>(libName);
|
|
|
|
enginePtr->AddExtension(extension, 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
catch(...) {}
|
|
|
|
}
|
|
|
|
// Some of networks can work without a library of extra layers.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
plugin = InferenceEngine::InferencePlugin(enginePtr);
|
|
|
|
|
|
|
|
netExec = plugin.LoadNetwork(net, {});
|
|
|
|
infRequest = netExec.CreateInferRequest();
|
|
|
|
infRequest.SetInput(inpBlobs);
|
|
|
|
infRequest.SetOutput(outBlobs);
|
|
|
|
}
|
|
|
|
catch (const std::exception& ex)
|
2018-04-09 21:22:19 +08:00
|
|
|
{
|
2018-06-05 22:18:14 +08:00
|
|
|
CV_Error(Error::StsAssert, format("Failed to initialize Inference Engine backend: %s", ex.what()));
|
2018-04-09 21:22:19 +08:00
|
|
|
}
|
2018-02-06 16:57:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool InfEngineBackendNet::isInitialized()
|
|
|
|
{
|
2018-06-01 19:10:32 +08:00
|
|
|
return (bool)enginePtr;
|
2018-02-06 16:57:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void InfEngineBackendNet::addBlobs(const std::vector<Ptr<BackendWrapper> >& ptrs)
|
|
|
|
{
|
|
|
|
auto wrappers = infEngineWrappers(ptrs);
|
|
|
|
for (const auto& wrapper : wrappers)
|
|
|
|
{
|
2018-06-05 04:51:28 +08:00
|
|
|
allBlobs.insert({wrapper->dataPtr->name, wrapper->blob});
|
2018-02-06 16:57:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InfEngineBackendNet::forward()
|
|
|
|
{
|
2018-06-01 19:10:32 +08:00
|
|
|
infRequest.Infer();
|
2018-02-06 16:57:35 +08:00
|
|
|
}
|
|
|
|
|
2018-03-12 22:35:28 +08:00
|
|
|
Mat infEngineBlobToMat(const InferenceEngine::Blob::Ptr& blob)
|
2018-02-06 16:57:35 +08:00
|
|
|
{
|
|
|
|
// NOTE: Inference Engine sizes are reversed.
|
2018-02-07 16:28:45 +08:00
|
|
|
std::vector<size_t> dims = blob->dims();
|
2018-08-02 16:12:22 +08:00
|
|
|
std::vector<int> size(dims.rbegin(), dims.rend());
|
2018-02-06 16:57:35 +08:00
|
|
|
return Mat(size, CV_32F, (void*)blob->buffer());
|
|
|
|
}
|
|
|
|
|
2018-03-17 00:27:04 +08:00
|
|
|
InfEngineBackendLayer::InfEngineBackendLayer(const InferenceEngine::DataPtr& output_)
|
|
|
|
{
|
|
|
|
output = output_;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool InfEngineBackendLayer::getMemoryShapes(const std::vector<MatShape> &inputs,
|
|
|
|
const int requiredOutputs,
|
|
|
|
std::vector<MatShape> &outputs,
|
|
|
|
std::vector<MatShape> &internals) const
|
|
|
|
{
|
|
|
|
std::vector<size_t> dims = output->dims;
|
2018-08-02 16:12:22 +08:00
|
|
|
std::vector<int> shape(dims.rbegin(), dims.rend());
|
2018-03-17 00:27:04 +08:00
|
|
|
outputs.assign(1, shape);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool InfEngineBackendLayer::supportBackend(int backendId)
|
|
|
|
{
|
|
|
|
return backendId == DNN_BACKEND_DEFAULT ||
|
2018-11-15 04:25:23 +08:00
|
|
|
(backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine());
|
2018-03-17 00:27:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void InfEngineBackendLayer::forward(InputArrayOfArrays inputs, OutputArrayOfArrays outputs,
|
|
|
|
OutputArrayOfArrays internals)
|
|
|
|
{
|
|
|
|
CV_Error(Error::StsInternal, "Choose Inference Engine as a preferable backend.");
|
|
|
|
}
|
|
|
|
|
2018-03-12 22:35:28 +08:00
|
|
|
InferenceEngine::TBlob<int16_t>::Ptr convertFp16(const InferenceEngine::Blob::Ptr& blob)
|
|
|
|
{
|
|
|
|
auto halfs = InferenceEngine::make_shared_blob<int16_t>(InferenceEngine::Precision::FP16, blob->layout(), blob->dims());
|
|
|
|
halfs->allocate();
|
|
|
|
Mat floatsData(1, blob->size(), CV_32F, blob->buffer());
|
|
|
|
Mat halfsData(1, blob->size(), CV_16SC1, halfs->buffer());
|
|
|
|
convertFp16(floatsData, halfsData);
|
|
|
|
return halfs;
|
|
|
|
}
|
|
|
|
|
2018-02-06 16:57:35 +08:00
|
|
|
#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
|
|
|
|
}
|
|
|
|
|
2018-09-18 16:21:08 +08:00
|
|
|
CV__DNN_EXPERIMENTAL_NS_BEGIN
|
|
|
|
|
|
|
|
void resetMyriadDevice()
|
|
|
|
{
|
|
|
|
#ifdef HAVE_INF_ENGINE
|
|
|
|
sharedPlugins.erase(InferenceEngine::TargetDevice::eMYRIAD);
|
|
|
|
#endif // HAVE_INF_ENGINE
|
|
|
|
}
|
|
|
|
|
|
|
|
CV__DNN_EXPERIMENTAL_NS_END
|
2018-02-06 16:57:35 +08:00
|
|
|
}} // namespace dnn, namespace cv
|