mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
473 lines
15 KiB
473 lines
15 KiB
// 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> |
|
#elif defined(ENABLE_PLUGINS) |
|
// using plugin API |
|
#include "backend.hpp" |
|
#include "factory.hpp" |
|
#endif |
|
|
|
#include <opencv2/core/utils/configuration.private.hpp> |
|
#include <opencv2/core/utils/logger.hpp> |
|
|
|
namespace cv { namespace dnn { |
|
|
|
#ifdef HAVE_INF_ENGINE |
|
|
|
CV__DNN_INLINE_NS_BEGIN |
|
|
|
cv::String getInferenceEngineBackendType() |
|
{ |
|
return "NGRAPH"; |
|
} |
|
cv::String setInferenceEngineBackendType(const cv::String& newBackendType) |
|
{ |
|
if (newBackendType != "NGRAPH") |
|
CV_Error(Error::StsNotImplemented, cv::format("DNN/IE: only NGRAPH backend is supported: %s", newBackendType.c_str())); |
|
return newBackendType; |
|
} |
|
|
|
CV__DNN_INLINE_NS_END |
|
|
|
#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1) |
|
namespace InferenceEngine { |
|
|
|
CNNNetwork::CNNNetwork() {} |
|
|
|
CNNNetwork::CNNNetwork(std::shared_ptr<ov::Model> model) : model(model) {} |
|
|
|
std::shared_ptr<ov::Model> CNNNetwork::getFunction() const { |
|
return model; |
|
} |
|
|
|
void CNNNetwork::serialize(const std::string& xmlPath, const std::string& binPath) { |
|
ov::pass::Serialize(xmlPath, binPath).run_on_model(model); |
|
} |
|
|
|
void CNNNetwork::reshape(const std::map<std::string, std::vector<size_t> >& shapes) { |
|
std::map<std::string, ov::PartialShape> partialShapes; |
|
for (const auto& it : shapes) { |
|
ov::PartialShape shape; |
|
shape.insert(shape.begin(), it.second.begin(), it.second.end()); |
|
partialShapes.insert({it.first, shape}); |
|
} |
|
model->reshape(partialShapes); |
|
} |
|
|
|
std::vector<std::string> Core::GetAvailableDevices() { |
|
return get_available_devices(); |
|
} |
|
|
|
void Core::UnregisterPlugin(const std::string& id) { |
|
unload_plugin(id); |
|
} |
|
|
|
CNNNetwork Core::ReadNetwork(const std::string& xmlPath, const std::string& binPath) { |
|
return read_model(xmlPath, binPath); |
|
} |
|
|
|
ExecutableNetwork Core::LoadNetwork(CNNNetwork net, const std::string& device, |
|
const std::map<std::string, std::string>& config) { |
|
ov::AnyMap props; |
|
for (const auto& it : config) { |
|
props.insert(it); |
|
} |
|
return compile_model(net.getFunction(), device, props); |
|
} |
|
|
|
ExecutableNetwork::ExecutableNetwork() {} |
|
|
|
ExecutableNetwork::ExecutableNetwork(const ov::CompiledModel& copy) : CompiledModel(copy) {} |
|
|
|
ov::InferRequest ExecutableNetwork::CreateInferRequest() { return create_infer_request(); } |
|
|
|
} // namespace InferenceEngine |
|
|
|
Mat infEngineBlobToMat(const ov::Tensor& blob) |
|
{ |
|
std::vector<size_t> dims = blob.get_shape(); |
|
std::vector<int> size(dims.begin(), dims.end()); |
|
auto precision = blob.get_element_type(); |
|
|
|
int type = -1; |
|
switch (precision) |
|
{ |
|
case ov::element::f32: type = CV_32F; break; |
|
case ov::element::u8: type = CV_8U; break; |
|
default: |
|
CV_Error(Error::StsNotImplemented, "Unsupported blob precision"); |
|
} |
|
return Mat(size, type, blob.data()); |
|
} |
|
|
|
void infEngineBlobsToMats(const ov::TensorVector& blobs, |
|
std::vector<Mat>& mats) |
|
{ |
|
mats.resize(blobs.size()); |
|
for (int i = 0; i < blobs.size(); ++i) |
|
mats[i] = infEngineBlobToMat(blobs[i]); |
|
} |
|
|
|
#else |
|
|
|
Mat infEngineBlobToMat(const InferenceEngine::Blob::Ptr& blob) |
|
{ |
|
// NOTE: Inference Engine sizes are reversed. |
|
std::vector<size_t> dims = blob->getTensorDesc().getDims(); |
|
std::vector<int> size(dims.begin(), dims.end()); |
|
auto precision = blob->getTensorDesc().getPrecision(); |
|
|
|
int type = -1; |
|
switch (precision) |
|
{ |
|
case InferenceEngine::Precision::FP32: type = CV_32F; break; |
|
case InferenceEngine::Precision::U8: type = CV_8U; break; |
|
default: |
|
CV_Error(Error::StsNotImplemented, "Unsupported blob precision"); |
|
} |
|
return Mat(size, type, (void*)blob->buffer()); |
|
} |
|
|
|
void infEngineBlobsToMats(const std::vector<InferenceEngine::Blob::Ptr>& blobs, |
|
std::vector<Mat>& mats) |
|
{ |
|
mats.resize(blobs.size()); |
|
for (int i = 0; i < blobs.size(); ++i) |
|
mats[i] = infEngineBlobToMat(blobs[i]); |
|
} |
|
#endif // OpenVINO >= 2022.1 |
|
|
|
static bool init_IE_plugins() |
|
{ |
|
// load and hold IE plugins |
|
static InferenceEngine::Core* init_core = new InferenceEngine::Core(); // 'delete' is never called |
|
(void)init_core->GetAvailableDevices(); |
|
return true; |
|
} |
|
static InferenceEngine::Core& retrieveIECore(const std::string& id, std::map<std::string, std::shared_ptr<InferenceEngine::Core> >& cores) |
|
{ |
|
AutoLock lock(getInitializationMutex()); |
|
std::map<std::string, std::shared_ptr<InferenceEngine::Core> >::iterator i = cores.find(id); |
|
if (i == cores.end()) |
|
{ |
|
std::shared_ptr<InferenceEngine::Core> core = std::make_shared<InferenceEngine::Core>(); |
|
cores[id] = core; |
|
return *core.get(); |
|
} |
|
return *(i->second).get(); |
|
} |
|
static InferenceEngine::Core& create_IE_Core_instance(const std::string& id) |
|
{ |
|
static std::map<std::string, std::shared_ptr<InferenceEngine::Core> > cores; |
|
return retrieveIECore(id, cores); |
|
} |
|
static InferenceEngine::Core& create_IE_Core_pointer(const std::string& id) |
|
{ |
|
// load and hold IE plugins |
|
static std::map<std::string, std::shared_ptr<InferenceEngine::Core> >* cores = |
|
new std::map<std::string, std::shared_ptr<InferenceEngine::Core> >(); |
|
return retrieveIECore(id, *cores); |
|
} |
|
InferenceEngine::Core& getCore(const std::string& id) |
|
{ |
|
// to make happy memory leak tools use: |
|
// - OPENCV_DNN_INFERENCE_ENGINE_HOLD_PLUGINS=0 |
|
// - OPENCV_DNN_INFERENCE_ENGINE_CORE_LIFETIME_WORKAROUND=0 |
|
static bool param_DNN_INFERENCE_ENGINE_HOLD_PLUGINS = utils::getConfigurationParameterBool("OPENCV_DNN_INFERENCE_ENGINE_HOLD_PLUGINS", true); |
|
static bool init_IE_plugins_ = param_DNN_INFERENCE_ENGINE_HOLD_PLUGINS && init_IE_plugins(); CV_UNUSED(init_IE_plugins_); |
|
|
|
static bool param_DNN_INFERENCE_ENGINE_CORE_LIFETIME_WORKAROUND = |
|
utils::getConfigurationParameterBool("OPENCV_DNN_INFERENCE_ENGINE_CORE_LIFETIME_WORKAROUND", |
|
#ifdef _WIN32 |
|
true |
|
#else |
|
false |
|
#endif |
|
); |
|
|
|
InferenceEngine::Core& core = param_DNN_INFERENCE_ENGINE_CORE_LIFETIME_WORKAROUND |
|
? create_IE_Core_pointer(id) |
|
: create_IE_Core_instance(id); |
|
return core; |
|
} |
|
|
|
|
|
static bool detectArmPlugin_() |
|
{ |
|
InferenceEngine::Core& ie = getCore("CPU"); |
|
const std::vector<std::string> devices = ie.GetAvailableDevices(); |
|
for (std::vector<std::string>::const_iterator i = devices.begin(); i != devices.end(); ++i) |
|
{ |
|
if (i->find("CPU") != std::string::npos) |
|
{ |
|
#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1) |
|
const std::string name = ie.get_property(*i, ov::device::full_name); |
|
#else |
|
const std::string name = ie.GetMetric(*i, METRIC_KEY(FULL_DEVICE_NAME)).as<std::string>(); |
|
#endif |
|
CV_LOG_INFO(NULL, "CPU plugin: " << name); |
|
return name.find("arm_compute::NEON") != std::string::npos; |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
#if !defined(OPENCV_DNN_IE_VPU_TYPE_DEFAULT) |
|
static bool detectMyriadX_(const std::string& device) |
|
{ |
|
AutoLock lock(getInitializationMutex()); |
|
|
|
// Lightweight detection |
|
InferenceEngine::Core& ie = getCore(device); |
|
const std::vector<std::string> devices = ie.GetAvailableDevices(); |
|
for (std::vector<std::string>::const_iterator i = devices.begin(); i != devices.end(); ++i) |
|
{ |
|
if (i->find(device) != std::string::npos) |
|
{ |
|
#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2022_1) |
|
const std::string name = ie.get_property(*i, ov::device::full_name); |
|
#else |
|
const std::string name = ie.GetMetric(*i, METRIC_KEY(FULL_DEVICE_NAME)).as<std::string>(); |
|
#endif |
|
CV_LOG_INFO(NULL, "Myriad device: " << name); |
|
return name.find("MyriadX") != std::string::npos || name.find("Myriad X") != std::string::npos || name.find("HDDL") != std::string::npos; |
|
} |
|
} |
|
return false; |
|
} |
|
#endif // !defined(OPENCV_DNN_IE_VPU_TYPE_DEFAULT) |
|
|
|
#endif // HAVE_INF_ENGINE |
|
|
|
|
|
CV__DNN_INLINE_NS_BEGIN |
|
|
|
void resetMyriadDevice() |
|
{ |
|
#ifdef HAVE_INF_ENGINE |
|
CV_LOG_INFO(NULL, "DNN: Unregistering both 'MYRIAD' and 'HETERO:MYRIAD,CPU' plugins"); |
|
|
|
AutoLock lock(getInitializationMutex()); |
|
|
|
InferenceEngine::Core& ie = getCore("MYRIAD"); |
|
try |
|
{ |
|
ie.UnregisterPlugin("MYRIAD"); |
|
ie.UnregisterPlugin("HETERO"); |
|
} |
|
catch (...) {} |
|
#endif // HAVE_INF_ENGINE |
|
} |
|
|
|
void releaseHDDLPlugin() |
|
{ |
|
#ifdef HAVE_INF_ENGINE |
|
CV_LOG_INFO(NULL, "DNN: Unregistering both 'HDDL' and 'HETERO:HDDL,CPU' plugins"); |
|
|
|
AutoLock lock(getInitializationMutex()); |
|
|
|
InferenceEngine::Core& ie = getCore("HDDL"); |
|
try |
|
{ |
|
ie.UnregisterPlugin("HDDL"); |
|
ie.UnregisterPlugin("HETERO"); |
|
} |
|
catch (...) {} |
|
#endif // HAVE_INF_ENGINE |
|
} |
|
|
|
#ifdef HAVE_INF_ENGINE |
|
bool isMyriadX() |
|
{ |
|
static bool myriadX = getInferenceEngineVPUType() == CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_X; |
|
return myriadX; |
|
} |
|
|
|
bool isArmComputePlugin() |
|
{ |
|
static bool armPlugin = getInferenceEngineCPUType() == CV_DNN_INFERENCE_ENGINE_CPU_TYPE_ARM_COMPUTE; |
|
return armPlugin; |
|
} |
|
|
|
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 or HDDL. In case of other accelerator types specify 'OPENCV_DNN_IE_VPU_TYPE' parameter"); |
|
try { |
|
bool isMyriadX_ = detectMyriadX_("MYRIAD"); |
|
bool isHDDL_ = detectMyriadX_("HDDL"); |
|
if (isMyriadX_ || isHDDL_) |
|
{ |
|
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; |
|
} |
|
|
|
cv::String getInferenceEngineCPUType() |
|
{ |
|
static cv::String cpu_type = detectArmPlugin_() ? |
|
CV_DNN_INFERENCE_ENGINE_CPU_TYPE_ARM_COMPUTE : |
|
CV_DNN_INFERENCE_ENGINE_CPU_TYPE_X86; |
|
return cpu_type; |
|
} |
|
|
|
|
|
namespace openvino { |
|
|
|
bool checkTarget(Target target) |
|
{ |
|
// Lightweight detection |
|
const std::vector<std::string> devices = getCore("").GetAvailableDevices(); |
|
for (std::vector<std::string>::const_iterator i = devices.begin(); i != devices.end(); ++i) |
|
{ |
|
if (std::string::npos != i->find("MYRIAD") && target == DNN_TARGET_MYRIAD) |
|
return true; |
|
if (std::string::npos != i->find("HDDL") && target == DNN_TARGET_HDDL) |
|
return true; |
|
else if (std::string::npos != i->find("FPGA") && target == DNN_TARGET_FPGA) |
|
return true; |
|
else if (std::string::npos != i->find("CPU") && target == DNN_TARGET_CPU) |
|
return true; |
|
else if (std::string::npos != i->find("GPU") && (target == DNN_TARGET_OPENCL || target == DNN_TARGET_OPENCL_FP16)) |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
} // namespace openvino |
|
|
|
#else // HAVE_INF_ENGINE |
|
|
|
|
|
namespace openvino { |
|
|
|
bool checkTarget(Target target) |
|
{ |
|
#if defined(ENABLE_PLUGINS) |
|
try |
|
{ |
|
auto& networkBackend = dnn_backend::createPluginDNNNetworkBackend("openvino"); |
|
return networkBackend.checkTarget(target); |
|
} |
|
catch (const std::exception& e) |
|
{ |
|
CV_LOG_INFO(NULL, "DNN/OpenVINO: checkTarget failed: " << e.what()) |
|
} |
|
#endif |
|
return false; |
|
} |
|
|
|
} // namespace openvino |
|
|
|
|
|
cv::String getInferenceEngineBackendType() |
|
{ |
|
#if defined(ENABLE_PLUGINS) |
|
try |
|
{ |
|
auto& networkBackend = dnn_backend::createPluginDNNNetworkBackend("openvino"); |
|
CV_UNUSED(networkBackend); |
|
return CV_DNN_BACKEND_INFERENCE_ENGINE_NGRAPH; |
|
} |
|
catch (const std::exception& e) |
|
{ |
|
CV_LOG_INFO(NULL, "DNN/OpenVINO: plugin is not available: " << e.what()) |
|
} |
|
#endif |
|
CV_Error(Error::StsNotImplemented, "This OpenCV build doesn't include InferenceEngine support"); |
|
} |
|
cv::String setInferenceEngineBackendType(const cv::String& newBackendType) |
|
{ |
|
#if defined(ENABLE_PLUGINS) |
|
try |
|
{ |
|
auto& networkBackend = dnn_backend::createPluginDNNNetworkBackend("openvino"); |
|
CV_UNUSED(networkBackend); |
|
CV_Assert(newBackendType == CV_DNN_BACKEND_INFERENCE_ENGINE_NGRAPH); |
|
} |
|
catch (const std::exception& e) |
|
{ |
|
CV_LOG_INFO(NULL, "DNN/OpenVINO: plugin is not available: " << e.what()) |
|
} |
|
#endif |
|
CV_UNUSED(newBackendType); |
|
CV_Error(Error::StsNotImplemented, "This OpenCV build doesn't include InferenceEngine support"); |
|
} |
|
cv::String getInferenceEngineVPUType() |
|
{ |
|
#if defined(ENABLE_PLUGINS) |
|
try |
|
{ |
|
auto& networkBackend = dnn_backend::createPluginDNNNetworkBackend("openvino"); |
|
if (networkBackend.checkTarget(DNN_TARGET_MYRIAD)) |
|
return CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_X; // 2021.4 supports NCS2 only |
|
CV_Error(Error::StsError, "DNN/OpenVINO: DNN_TARGET_MYRIAD is not available"); |
|
} |
|
catch (const std::exception& e) |
|
{ |
|
CV_LOG_INFO(NULL, "DNN/OpenVINO: plugin is not available: " << e.what()) |
|
} |
|
#endif |
|
CV_Error(Error::StsNotImplemented, "This OpenCV build doesn't include InferenceEngine support"); |
|
} |
|
|
|
cv::String getInferenceEngineCPUType() |
|
{ |
|
#if defined(ENABLE_PLUGINS) |
|
try |
|
{ |
|
auto& networkBackend = dnn_backend::createPluginDNNNetworkBackend("openvino"); |
|
CV_UNUSED(networkBackend); |
|
#if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM64) |
|
return CV_DNN_INFERENCE_ENGINE_CPU_TYPE_ARM_COMPUTE; |
|
#else |
|
return CV_DNN_INFERENCE_ENGINE_CPU_TYPE_X86; |
|
#endif |
|
} |
|
catch (const std::exception& e) |
|
{ |
|
CV_LOG_INFO(NULL, "DNN/OpenVINO: plugin is not available: " << e.what()) |
|
} |
|
#endif |
|
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
|
|
|