mirror of
https://github.com/zebrajr/opencv.git
synced 2025-12-06 12:19:50 +01:00
786 lines
27 KiB
C++
786 lines
27 KiB
C++
// 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-2019, 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>
|
|
|
|
#ifdef HAVE_INF_ENGINE
|
|
#include <ie_extension.h>
|
|
#include <ie_plugin_dispatcher.hpp>
|
|
#endif // HAVE_INF_ENGINE
|
|
|
|
#include <opencv2/core/utils/configuration.private.hpp>
|
|
#include <opencv2/core/utils/logger.hpp>
|
|
|
|
namespace cv { namespace dnn {
|
|
|
|
#ifdef HAVE_INF_ENGINE
|
|
|
|
// For networks with input layer which has an empty name, IE generates a name id[some_number].
|
|
// OpenCV lets users use an empty input name and to prevent unexpected naming,
|
|
// we can use some predefined name.
|
|
static std::string kDefaultInpLayerName = "empty_inp_layer_name";
|
|
|
|
InfEngineBackendNode::InfEngineBackendNode(const InferenceEngine::Builder::Layer& _layer)
|
|
: BackendNode(DNN_BACKEND_INFERENCE_ENGINE), layer(_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;
|
|
}
|
|
|
|
InfEngineBackendNet::InfEngineBackendNet() : netBuilder("")
|
|
{
|
|
hasNetOwner = false;
|
|
targetDevice = InferenceEngine::TargetDevice::eCPU;
|
|
}
|
|
|
|
InfEngineBackendNet::InfEngineBackendNet(InferenceEngine::CNNNetwork& net) : netBuilder(""), cnn(net)
|
|
{
|
|
hasNetOwner = true;
|
|
targetDevice = InferenceEngine::TargetDevice::eCPU;
|
|
}
|
|
|
|
void InfEngineBackendNet::connect(const std::vector<Ptr<BackendWrapper> >& inputs,
|
|
const std::vector<Ptr<BackendWrapper> >& outputs,
|
|
const std::string& layerName)
|
|
{
|
|
std::vector<Ptr<InfEngineBackendWrapper> > inpWrappers = infEngineWrappers(inputs);
|
|
std::map<std::string, int>::iterator it = layers.find(layerName);
|
|
CV_Assert(it != layers.end());
|
|
|
|
const int layerId = it->second;
|
|
for (size_t i = 0; i < inpWrappers.size(); ++i)
|
|
{
|
|
const auto& inp = inpWrappers[i];
|
|
const std::string& inpName = inp->dataPtr->name;
|
|
int inpId;
|
|
it = layers.find(inpName);
|
|
if (it == layers.end())
|
|
{
|
|
InferenceEngine::Builder::InputLayer inpLayer(!inpName.empty() ? inpName : kDefaultInpLayerName);
|
|
|
|
std::vector<size_t> shape(inp->blob->dims());
|
|
std::reverse(shape.begin(), shape.end());
|
|
|
|
inpLayer.setPort(InferenceEngine::Port(shape));
|
|
inpId = netBuilder.addLayer(inpLayer);
|
|
|
|
layers.insert({inpName, inpId});
|
|
}
|
|
else
|
|
inpId = it->second;
|
|
|
|
netBuilder.connect((size_t)inpId, {(size_t)layerId, i});
|
|
unconnectedLayersIds.erase(inpId);
|
|
}
|
|
CV_Assert(!outputs.empty());
|
|
InferenceEngine::DataPtr dataPtr = infEngineDataNode(outputs[0]);
|
|
dataPtr->name = layerName;
|
|
}
|
|
|
|
void InfEngineBackendNet::init(int targetId)
|
|
{
|
|
if (!hasNetOwner)
|
|
{
|
|
CV_Assert(!unconnectedLayersIds.empty());
|
|
for (int id : unconnectedLayersIds)
|
|
{
|
|
InferenceEngine::Builder::OutputLayer outLayer("myconv1");
|
|
#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2019R1)
|
|
// Inference Engine determines network precision by ports.
|
|
InferenceEngine::Precision p = (targetId == DNN_TARGET_MYRIAD ||
|
|
targetId == DNN_TARGET_OPENCL_FP16) ?
|
|
InferenceEngine::Precision::FP16 :
|
|
InferenceEngine::Precision::FP32;
|
|
outLayer.setPort(InferenceEngine::Port({}, p));
|
|
#endif
|
|
netBuilder.addLayer({InferenceEngine::PortInfo(id)}, outLayer);
|
|
}
|
|
cnn = InferenceEngine::CNNNetwork(InferenceEngine::Builder::convertToICNNNetwork(netBuilder.build()));
|
|
}
|
|
|
|
switch (targetId)
|
|
{
|
|
case DNN_TARGET_CPU:
|
|
targetDevice = InferenceEngine::TargetDevice::eCPU;
|
|
break;
|
|
case DNN_TARGET_OPENCL: case DNN_TARGET_OPENCL_FP16:
|
|
targetDevice = InferenceEngine::TargetDevice::eGPU;
|
|
break;
|
|
case DNN_TARGET_MYRIAD:
|
|
targetDevice = InferenceEngine::TargetDevice::eMYRIAD;
|
|
break;
|
|
case DNN_TARGET_FPGA:
|
|
targetDevice = InferenceEngine::TargetDevice::eFPGA;
|
|
break;
|
|
default:
|
|
CV_Error(Error::StsError, format("Unknown target identifier: %d", targetId));
|
|
}
|
|
|
|
for (const auto& name : requestedOutputs)
|
|
{
|
|
cnn.addOutput(name);
|
|
}
|
|
|
|
for (const auto& it : cnn.getInputsInfo())
|
|
{
|
|
const std::string& name = it.first;
|
|
auto blobIt = allBlobs.find(name);
|
|
CV_Assert(blobIt != allBlobs.end());
|
|
it.second->setPrecision(blobIt->second->precision());
|
|
}
|
|
for (const auto& it : cnn.getOutputsInfo())
|
|
{
|
|
const std::string& name = it.first;
|
|
auto blobIt = allBlobs.find(name);
|
|
CV_Assert(blobIt != allBlobs.end());
|
|
it.second->setPrecision(blobIt->second->precision()); // Should be always FP32
|
|
}
|
|
|
|
initPlugin(cnn);
|
|
}
|
|
|
|
void InfEngineBackendNet::addLayer(InferenceEngine::Builder::Layer& layer)
|
|
{
|
|
#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2019R1)
|
|
// Add weights to network and connect them after input blobs.
|
|
std::map<std::string, InferenceEngine::Parameter>& params = layer.getParameters();
|
|
std::vector<int> blobsIds;
|
|
std::vector<int> portIds;
|
|
for (const std::string& name : {"weights", "biases"})
|
|
{
|
|
bool asInput = false;
|
|
int portId = 0;
|
|
for (int i = 0; i < layer.getInputPorts().size(); ++i)
|
|
{
|
|
const auto& port = layer.getInputPorts()[i];
|
|
auto it = port.getParameters().find("type");
|
|
if (it != port.getParameters().end() && it->second == name)
|
|
{
|
|
portId = i;
|
|
asInput = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!asInput)
|
|
continue;
|
|
|
|
auto it = params.find(name);
|
|
if (it != params.end())
|
|
{
|
|
InferenceEngine::Blob::Ptr blob = it->second.as<InferenceEngine::Blob::Ptr>();
|
|
params.erase(it);
|
|
int blobId = netBuilder.addLayer(InferenceEngine::Builder::ConstLayer(name).setData(blob));
|
|
blobsIds.push_back(blobId);
|
|
portIds.push_back(portId);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
int id = netBuilder.addLayer(layer);
|
|
const std::string& layerName = layer.getName();
|
|
CV_Assert(layers.insert({layerName, id}).second);
|
|
unconnectedLayersIds.insert(id);
|
|
|
|
#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2019R1)
|
|
// By default, all the weights are connected to last ports ids.
|
|
for (int i = 0; i < blobsIds.size(); ++i)
|
|
{
|
|
netBuilder.connect((size_t)blobsIds[i], {(size_t)id, (size_t)portIds[i]});
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void InfEngineBackendNet::addOutput(const std::string& name)
|
|
{
|
|
requestedOutputs.push_back(name);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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());
|
|
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()));
|
|
}
|
|
|
|
InferenceEngine::Blob::Ptr wrapToInfEngineBlob(const Mat& m, const std::vector<size_t>& shape,
|
|
InferenceEngine::Layout layout)
|
|
{
|
|
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()));
|
|
}
|
|
|
|
InferenceEngine::Blob::Ptr wrapToInfEngineBlob(const Mat& m, InferenceEngine::Layout layout)
|
|
{
|
|
std::vector<size_t> reversedShape(&m.size[0], &m.size[0] + m.dims);
|
|
std::reverse(reversedShape.begin(), reversedShape.end());
|
|
return wrapToInfEngineBlob(m, reversedShape, layout);
|
|
}
|
|
|
|
InferenceEngine::Blob::Ptr cloneBlob(const InferenceEngine::Blob::Ptr& blob)
|
|
{
|
|
InferenceEngine::Precision precision = blob->precision();
|
|
InferenceEngine::Blob::Ptr copy;
|
|
if (precision == InferenceEngine::Precision::FP32)
|
|
{
|
|
copy = InferenceEngine::make_shared_blob<float>(precision, blob->layout(), blob->dims());
|
|
}
|
|
else if (precision == InferenceEngine::Precision::U8)
|
|
{
|
|
copy = InferenceEngine::make_shared_blob<uint8_t>(precision, blob->layout(), blob->dims());
|
|
}
|
|
else
|
|
CV_Error(Error::StsNotImplemented, "Unsupported blob precision");
|
|
copy->allocate();
|
|
return copy;
|
|
}
|
|
|
|
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, estimateLayout(m));
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
InfEngineBackendWrapper::~InfEngineBackendWrapper()
|
|
{
|
|
|
|
}
|
|
|
|
void InfEngineBackendWrapper::copyToHost()
|
|
{
|
|
|
|
}
|
|
|
|
void InfEngineBackendWrapper::setHostDirty()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
static std::map<InferenceEngine::TargetDevice, InferenceEngine::InferenceEnginePluginPtr>& getSharedPlugins()
|
|
{
|
|
static std::map<InferenceEngine::TargetDevice, InferenceEngine::InferenceEnginePluginPtr> sharedPlugins;
|
|
return sharedPlugins;
|
|
}
|
|
|
|
|
|
#if !defined(OPENCV_DNN_IE_VPU_TYPE_DEFAULT)
|
|
static bool detectMyriadX_()
|
|
{
|
|
InferenceEngine::Builder::Network builder("");
|
|
InferenceEngine::idx_t inpId = builder.addLayer(
|
|
InferenceEngine::Builder::InputLayer().setPort(InferenceEngine::Port({1})));
|
|
|
|
#if INF_ENGINE_RELEASE <= 2018050000
|
|
InferenceEngine::idx_t clampId;
|
|
{
|
|
InferenceEngine::Builder::Layer l = InferenceEngine::Builder::ClampLayer();
|
|
auto& blobs = l.getConstantData();
|
|
auto blob = InferenceEngine::make_shared_blob<int16_t>(
|
|
InferenceEngine::Precision::FP16,
|
|
InferenceEngine::Layout::C, {1});
|
|
blob->allocate();
|
|
blobs[""] = blob;
|
|
clampId = builder.addLayer({inpId}, l);
|
|
}
|
|
builder.addLayer({InferenceEngine::PortInfo(clampId)}, InferenceEngine::Builder::OutputLayer());
|
|
#else
|
|
|
|
InferenceEngine::idx_t clampId = builder.addLayer({inpId}, InferenceEngine::Builder::ClampLayer());
|
|
builder.addLayer({InferenceEngine::PortInfo(clampId)},
|
|
InferenceEngine::Builder::OutputLayer().setPort(InferenceEngine::Port({},
|
|
InferenceEngine::Precision::FP16)));
|
|
#endif
|
|
|
|
InferenceEngine::CNNNetwork cnn = InferenceEngine::CNNNetwork(
|
|
InferenceEngine::Builder::convertToICNNNetwork(builder.build()));
|
|
|
|
InferenceEngine::TargetDevice device = InferenceEngine::TargetDevice::eMYRIAD;
|
|
InferenceEngine::InferenceEnginePluginPtr enginePtr;
|
|
{
|
|
AutoLock lock(getInitializationMutex());
|
|
auto& sharedPlugins = getSharedPlugins();
|
|
auto pluginIt = sharedPlugins.find(device);
|
|
if (pluginIt != sharedPlugins.end()) {
|
|
enginePtr = pluginIt->second;
|
|
} else {
|
|
auto dispatcher = InferenceEngine::PluginDispatcher({""});
|
|
enginePtr = dispatcher.getSuitablePlugin(device);
|
|
sharedPlugins[device] = enginePtr;
|
|
}
|
|
}
|
|
auto plugin = InferenceEngine::InferencePlugin(enginePtr);
|
|
try
|
|
{
|
|
auto netExec = plugin.LoadNetwork(cnn, {{"VPU_PLATFORM", "VPU_2480"}});
|
|
auto infRequest = netExec.CreateInferRequest();
|
|
} catch(...) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
#endif // !defined(OPENCV_DNN_IE_VPU_TYPE_DEFAULT)
|
|
|
|
void InfEngineBackendNet::initPlugin(InferenceEngine::ICNNNetwork& net)
|
|
{
|
|
CV_Assert(!isInitialized());
|
|
|
|
try
|
|
{
|
|
AutoLock lock(getInitializationMutex());
|
|
auto& sharedPlugins = getSharedPlugins();
|
|
auto pluginIt = sharedPlugins.find(targetDevice);
|
|
if (pluginIt != sharedPlugins.end())
|
|
{
|
|
enginePtr = pluginIt->second;
|
|
}
|
|
else
|
|
{
|
|
auto dispatcher = InferenceEngine::PluginDispatcher({""});
|
|
if (targetDevice == InferenceEngine::TargetDevice::eFPGA)
|
|
enginePtr = dispatcher.getPluginByDevice("HETERO:FPGA,CPU");
|
|
else
|
|
enginePtr = dispatcher.getSuitablePlugin(targetDevice);
|
|
sharedPlugins[targetDevice] = enginePtr;
|
|
|
|
std::vector<std::string> candidates;
|
|
|
|
std::string param_pluginPath = utils::getConfigurationParameterString("OPENCV_DNN_IE_EXTRA_PLUGIN_PATH", "");
|
|
if (!param_pluginPath.empty())
|
|
{
|
|
candidates.push_back(param_pluginPath);
|
|
}
|
|
|
|
if (targetDevice == InferenceEngine::TargetDevice::eCPU ||
|
|
targetDevice == InferenceEngine::TargetDevice::eFPGA)
|
|
{
|
|
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
|
|
candidates.push_back("cpu_extension" + suffixes[i] + ".dll");
|
|
#elif defined(__APPLE__)
|
|
candidates.push_back("libcpu_extension" + suffixes[i] + ".so"); // built as loadable module
|
|
candidates.push_back("libcpu_extension" + suffixes[i] + ".dylib"); // built as shared library
|
|
#else
|
|
candidates.push_back("libcpu_extension" + suffixes[i] + ".so");
|
|
#endif // _WIN32
|
|
}
|
|
}
|
|
bool found = false;
|
|
for (size_t i = 0; i != candidates.size(); ++i)
|
|
{
|
|
const std::string& libName = candidates[i];
|
|
try
|
|
{
|
|
InferenceEngine::IExtensionPtr extension =
|
|
InferenceEngine::make_so_pointer<InferenceEngine::IExtension>(libName);
|
|
enginePtr->AddExtension(extension, 0);
|
|
CV_LOG_INFO(NULL, "DNN-IE: Loaded extension plugin: " << libName);
|
|
found = true;
|
|
break;
|
|
}
|
|
catch(...) {}
|
|
}
|
|
if (!found && !candidates.empty())
|
|
{
|
|
CV_LOG_WARNING(NULL, "DNN-IE: Can't load extension plugin (extra layers for some networks). Specify path via OPENCV_DNN_IE_EXTRA_PLUGIN_PATH parameter");
|
|
}
|
|
// Some of networks can work without a library of extra layers.
|
|
}
|
|
plugin = InferenceEngine::InferencePlugin(enginePtr);
|
|
|
|
netExec = plugin.LoadNetwork(net, {});
|
|
}
|
|
catch (const std::exception& ex)
|
|
{
|
|
CV_Error(Error::StsAssert, format("Failed to initialize Inference Engine backend: %s", ex.what()));
|
|
}
|
|
}
|
|
|
|
bool InfEngineBackendNet::isInitialized()
|
|
{
|
|
return (bool)enginePtr;
|
|
}
|
|
|
|
void InfEngineBackendNet::addBlobs(const std::vector<Ptr<BackendWrapper> >& ptrs)
|
|
{
|
|
auto wrappers = infEngineWrappers(ptrs);
|
|
for (const auto& wrapper : wrappers)
|
|
{
|
|
std::string name = wrapper->dataPtr->name;
|
|
name = name.empty() ? kDefaultInpLayerName : name;
|
|
allBlobs.insert({name, wrapper->blob});
|
|
}
|
|
}
|
|
|
|
void InfEngineBackendNet::InfEngineReqWrapper::makePromises(const std::vector<Ptr<BackendWrapper> >& outsWrappers)
|
|
{
|
|
auto outs = infEngineWrappers(outsWrappers);
|
|
outProms.clear();
|
|
outProms.resize(outs.size());
|
|
outsNames.resize(outs.size());
|
|
for (int i = 0; i < outs.size(); ++i)
|
|
{
|
|
outs[i]->futureMat = outProms[i].getArrayResult();
|
|
outsNames[i] = outs[i]->dataPtr->name;
|
|
}
|
|
}
|
|
|
|
void InfEngineBackendNet::forward(const std::vector<Ptr<BackendWrapper> >& outBlobsWrappers,
|
|
bool isAsync)
|
|
{
|
|
// Look for finished requests.
|
|
Ptr<InfEngineReqWrapper> reqWrapper;
|
|
for (auto& wrapper : infRequests)
|
|
{
|
|
if (wrapper->isReady)
|
|
{
|
|
reqWrapper = wrapper;
|
|
break;
|
|
}
|
|
}
|
|
if (reqWrapper.empty())
|
|
{
|
|
reqWrapper = Ptr<InfEngineReqWrapper>(new InfEngineReqWrapper());
|
|
try
|
|
{
|
|
reqWrapper->req = netExec.CreateInferRequest();
|
|
}
|
|
catch (const std::exception& ex)
|
|
{
|
|
CV_Error(Error::StsAssert, format("Failed to initialize Inference Engine backend: %s", ex.what()));
|
|
}
|
|
infRequests.push_back(reqWrapper);
|
|
|
|
InferenceEngine::BlobMap inpBlobs, outBlobs;
|
|
for (const auto& it : cnn.getInputsInfo())
|
|
{
|
|
const std::string& name = it.first;
|
|
auto blobIt = allBlobs.find(name);
|
|
CV_Assert(blobIt != allBlobs.end());
|
|
inpBlobs[name] = isAsync ? cloneBlob(blobIt->second) : blobIt->second;
|
|
}
|
|
for (const auto& it : cnn.getOutputsInfo())
|
|
{
|
|
const std::string& name = it.first;
|
|
auto blobIt = allBlobs.find(name);
|
|
CV_Assert(blobIt != allBlobs.end());
|
|
outBlobs[name] = isAsync ? cloneBlob(blobIt->second) : blobIt->second;
|
|
}
|
|
reqWrapper->req.SetInput(inpBlobs);
|
|
reqWrapper->req.SetOutput(outBlobs);
|
|
|
|
InferenceEngine::IInferRequest::Ptr infRequestPtr = reqWrapper->req;
|
|
infRequestPtr->SetUserData(reqWrapper.get(), 0);
|
|
|
|
infRequestPtr->SetCompletionCallback(
|
|
[](InferenceEngine::IInferRequest::Ptr request, InferenceEngine::StatusCode status)
|
|
{
|
|
InfEngineReqWrapper* wrapper;
|
|
request->GetUserData((void**)&wrapper, 0);
|
|
CV_Assert(wrapper && "Internal error");
|
|
|
|
size_t processedOutputs = 0;
|
|
try
|
|
{
|
|
for (; processedOutputs < wrapper->outProms.size(); ++processedOutputs)
|
|
{
|
|
const std::string& name = wrapper->outsNames[processedOutputs];
|
|
Mat m = infEngineBlobToMat(wrapper->req.GetBlob(name));
|
|
|
|
try
|
|
{
|
|
CV_Assert(status == InferenceEngine::StatusCode::OK);
|
|
wrapper->outProms[processedOutputs].setValue(m.clone());
|
|
}
|
|
catch (...)
|
|
{
|
|
try {
|
|
wrapper->outProms[processedOutputs].setException(std::current_exception());
|
|
} catch(...) {
|
|
CV_LOG_ERROR(NULL, "DNN: Exception occured during async inference exception propagation");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
std::exception_ptr e = std::current_exception();
|
|
for (; processedOutputs < wrapper->outProms.size(); ++processedOutputs)
|
|
{
|
|
try {
|
|
wrapper->outProms[processedOutputs].setException(e);
|
|
} catch(...) {
|
|
CV_LOG_ERROR(NULL, "DNN: Exception occured during async inference exception propagation");
|
|
}
|
|
}
|
|
}
|
|
wrapper->isReady = true;
|
|
}
|
|
);
|
|
}
|
|
if (isAsync)
|
|
{
|
|
// Copy actual data to infer request's input blobs.
|
|
for (const auto& it : cnn.getInputsInfo())
|
|
{
|
|
const std::string& name = it.first;
|
|
auto blobIt = allBlobs.find(name);
|
|
Mat srcMat = infEngineBlobToMat(blobIt->second);
|
|
Mat dstMat = infEngineBlobToMat(reqWrapper->req.GetBlob(name));
|
|
srcMat.copyTo(dstMat);
|
|
}
|
|
|
|
// Set promises to output blobs wrappers.
|
|
reqWrapper->makePromises(outBlobsWrappers);
|
|
|
|
reqWrapper->isReady = false;
|
|
reqWrapper->req.StartAsync();
|
|
}
|
|
else
|
|
{
|
|
reqWrapper->req.Infer();
|
|
}
|
|
}
|
|
|
|
Mat infEngineBlobToMat(const InferenceEngine::Blob::Ptr& blob)
|
|
{
|
|
// NOTE: Inference Engine sizes are reversed.
|
|
std::vector<size_t> dims = blob->dims();
|
|
std::vector<int> size(dims.rbegin(), dims.rend());
|
|
|
|
int type = -1;
|
|
switch (blob->precision())
|
|
{
|
|
case InferenceEngine::Precision::FP32: type = CV_32F; break;
|
|
case InferenceEngine::Precision::U8: type = CV_8U; break;
|
|
default:
|
|
CV_Error(Error::StsNotImplemented, "Unsupported blob precision");
|
|
}
|
|
return Mat(size, type, (void*)blob->buffer());
|
|
}
|
|
|
|
bool InfEngineBackendLayer::getMemoryShapes(const std::vector<MatShape> &inputs,
|
|
const int requiredOutputs,
|
|
std::vector<MatShape> &outputs,
|
|
std::vector<MatShape> &internals) const
|
|
{
|
|
InferenceEngine::ICNNNetwork::InputShapes inShapes = t_net.getInputShapes();
|
|
InferenceEngine::ICNNNetwork::InputShapes::iterator itr;
|
|
bool equal_flag = true;
|
|
size_t i = 0;
|
|
for (itr = inShapes.begin(); itr != inShapes.end(); ++itr)
|
|
{
|
|
InferenceEngine::SizeVector currentInShape(inputs[i].begin(), inputs[i].end());
|
|
if (itr->second != currentInShape)
|
|
{
|
|
itr->second = currentInShape;
|
|
equal_flag = false;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
if (!equal_flag)
|
|
{
|
|
InferenceEngine::CNNNetwork curr_t_net(t_net);
|
|
curr_t_net.reshape(inShapes);
|
|
}
|
|
std::vector<size_t> dims = t_net.getOutputsInfo()[name]->getDims();
|
|
outputs.push_back(MatShape(dims.begin(), dims.end()));
|
|
return false;
|
|
}
|
|
|
|
bool InfEngineBackendLayer::supportBackend(int backendId)
|
|
{
|
|
return backendId == DNN_BACKEND_DEFAULT ||
|
|
(backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine());
|
|
}
|
|
|
|
void InfEngineBackendLayer::forward(InputArrayOfArrays inputs, OutputArrayOfArrays outputs,
|
|
OutputArrayOfArrays internals)
|
|
{
|
|
CV_Error(Error::StsInternal, "Choose Inference Engine as a preferable backend.");
|
|
}
|
|
|
|
InferenceEngine::Blob::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;
|
|
}
|
|
|
|
void addConstantData(const std::string& name, InferenceEngine::Blob::Ptr data,
|
|
InferenceEngine::Builder::Layer& l)
|
|
{
|
|
#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2019R1)
|
|
l.getParameters()[name] = data;
|
|
#else
|
|
l.addConstantData(name, data);
|
|
#endif
|
|
}
|
|
|
|
#endif // HAVE_INF_ENGINE
|
|
|
|
bool haveInfEngine()
|
|
{
|
|
#ifdef HAVE_INF_ENGINE
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif // HAVE_INF_ENGINE
|
|
}
|
|
|
|
void forwardInfEngine(const std::vector<Ptr<BackendWrapper> >& outBlobsWrappers,
|
|
Ptr<BackendNode>& node, bool isAsync)
|
|
{
|
|
CV_Assert(haveInfEngine());
|
|
#ifdef HAVE_INF_ENGINE
|
|
CV_Assert(!node.empty());
|
|
Ptr<InfEngineBackendNode> ieNode = node.dynamicCast<InfEngineBackendNode>();
|
|
CV_Assert(!ieNode.empty());
|
|
ieNode->net->forward(outBlobsWrappers, isAsync);
|
|
#endif // HAVE_INF_ENGINE
|
|
}
|
|
|
|
CV__DNN_INLINE_NS_BEGIN
|
|
|
|
void resetMyriadDevice()
|
|
{
|
|
#ifdef HAVE_INF_ENGINE
|
|
AutoLock lock(getInitializationMutex());
|
|
getSharedPlugins().erase(InferenceEngine::TargetDevice::eMYRIAD);
|
|
#endif // HAVE_INF_ENGINE
|
|
}
|
|
|
|
#ifdef HAVE_INF_ENGINE
|
|
bool isMyriadX()
|
|
{
|
|
static bool myriadX = getInferenceEngineVPUType() == CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_X;
|
|
return myriadX;
|
|
}
|
|
|
|
static std::string getInferenceEngineVPUType_()
|
|
{
|
|
static std::string param_vpu_type = utils::getConfigurationParameterString("OPENCV_DNN_IE_VPU_TYPE", "");
|
|
if (param_vpu_type == "")
|
|
{
|
|
#if defined(OPENCV_DNN_IE_VPU_TYPE_DEFAULT)
|
|
param_vpu_type = OPENCV_DNN_IE_VPU_TYPE_DEFAULT;
|
|
#else
|
|
CV_LOG_INFO(NULL, "OpenCV-DNN: running Inference Engine VPU autodetection: Myriad2/X. In case of other accelerator types specify 'OPENCV_DNN_IE_VPU_TYPE' parameter");
|
|
try {
|
|
bool isMyriadX_ = detectMyriadX_();
|
|
if (isMyriadX_)
|
|
{
|
|
param_vpu_type = CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_X;
|
|
}
|
|
else
|
|
{
|
|
param_vpu_type = CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_2;
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
CV_LOG_WARNING(NULL, "OpenCV-DNN: Failed Inference Engine VPU autodetection. Specify 'OPENCV_DNN_IE_VPU_TYPE' parameter.");
|
|
param_vpu_type.clear();
|
|
}
|
|
#endif
|
|
}
|
|
CV_LOG_INFO(NULL, "OpenCV-DNN: Inference Engine VPU type='" << param_vpu_type << "'");
|
|
return param_vpu_type;
|
|
}
|
|
|
|
cv::String getInferenceEngineVPUType()
|
|
{
|
|
static cv::String vpu_type = getInferenceEngineVPUType_();
|
|
return vpu_type;
|
|
}
|
|
#else // HAVE_INF_ENGINE
|
|
cv::String getInferenceEngineVPUType()
|
|
{
|
|
CV_Error(Error::StsNotImplemented, "This OpenCV build doesn't include InferenceEngine support");
|
|
}
|
|
#endif // HAVE_INF_ENGINE
|
|
|
|
|
|
CV__DNN_INLINE_NS_END
|
|
}} // namespace dnn, namespace cv
|