mirror of
https://github.com/opencv/opencv.git
synced 2025-06-07 17:44:04 +08:00
Merge pull request #10799 from dkurt:dnn_inference_engine_face_detection
This commit is contained in:
commit
835acd3f31
@ -20,6 +20,9 @@ if(NOT INF_ENGINE_ROOT_DIR OR NOT EXISTS "${INF_ENGINE_ROOT_DIR}/inference_engin
|
|||||||
if(DEFINED ENV{INTEL_CVSDK_DIR})
|
if(DEFINED ENV{INTEL_CVSDK_DIR})
|
||||||
list(APPEND ie_root_paths "$ENV{INTEL_CVSDK_DIR}")
|
list(APPEND ie_root_paths "$ENV{INTEL_CVSDK_DIR}")
|
||||||
endif()
|
endif()
|
||||||
|
if(DEFINED INTEL_CVSDK_DIR)
|
||||||
|
list(APPEND ie_root_paths "${INTEL_CVSDK_DIR}")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(WITH_INF_ENGINE AND NOT ie_root_paths)
|
if(WITH_INF_ENGINE AND NOT ie_root_paths)
|
||||||
list(APPEND ie_root_paths "/opt/intel/deeplearning_deploymenttoolkit/deployment_tools")
|
list(APPEND ie_root_paths "/opt/intel/deeplearning_deploymenttoolkit/deployment_tools")
|
||||||
|
@ -150,6 +150,7 @@ PERF_TEST_P_(DNNTestNetwork, SSD)
|
|||||||
|
|
||||||
PERF_TEST_P_(DNNTestNetwork, OpenFace)
|
PERF_TEST_P_(DNNTestNetwork, OpenFace)
|
||||||
{
|
{
|
||||||
|
if (backend == DNN_BACKEND_HALIDE) throw SkipTestException("");
|
||||||
processNet("dnn/openface_nn4.small2.v1.t7", "", "",
|
processNet("dnn/openface_nn4.small2.v1.t7", "", "",
|
||||||
Mat(cv::Size(96, 96), CV_32FC3), "", "torch");
|
Mat(cv::Size(96, 96), CV_32FC3), "", "torch");
|
||||||
}
|
}
|
||||||
@ -197,6 +198,15 @@ PERF_TEST_P_(DNNTestNetwork, OpenPose_pose_mpi_faster_4_stages)
|
|||||||
Mat(cv::Size(368, 368), CV_32FC3), "", "caffe");
|
Mat(cv::Size(368, 368), CV_32FC3), "", "caffe");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PERF_TEST_P_(DNNTestNetwork, opencv_face_detector)
|
||||||
|
{
|
||||||
|
if (backend == DNN_BACKEND_HALIDE ||
|
||||||
|
backend == DNN_BACKEND_DEFAULT && target == DNN_TARGET_OPENCL)
|
||||||
|
throw SkipTestException("");
|
||||||
|
processNet("dnn/opencv_face_detector.caffemodel", "dnn/opencv_face_detector.prototxt", "",
|
||||||
|
Mat(cv::Size(300, 300), CV_32FC3), "", "caffe");
|
||||||
|
}
|
||||||
|
|
||||||
const tuple<DNNBackend, DNNTarget> testCases[] = {
|
const tuple<DNNBackend, DNNTarget> testCases[] = {
|
||||||
#ifdef HAVE_HALIDE
|
#ifdef HAVE_HALIDE
|
||||||
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_HALIDE, DNN_TARGET_CPU),
|
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_HALIDE, DNN_TARGET_CPU),
|
||||||
|
@ -1077,35 +1077,72 @@ struct Net::Impl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_INF_ENGINE
|
||||||
|
// Before launching Inference Engine graph we need to specify output blobs.
|
||||||
|
// This function requests output blobs based on inputs references of
|
||||||
|
// layers from default backend or layers from different graphs.
|
||||||
|
void addInfEngineNetOutputs(LayerData &ld)
|
||||||
|
{
|
||||||
|
Ptr<InfEngineBackendNet> layerNet;
|
||||||
|
if (ld.backendNodes.find(preferableBackend) != ld.backendNodes.end())
|
||||||
|
{
|
||||||
|
Ptr<BackendNode> node = ld.backendNodes[preferableBackend];
|
||||||
|
if (!node.empty())
|
||||||
|
{
|
||||||
|
Ptr<InfEngineBackendNode> ieNode = node.dynamicCast<InfEngineBackendNode>();
|
||||||
|
CV_Assert(!ieNode.empty(), !ieNode->net.empty());
|
||||||
|
layerNet = ieNode->net;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// For an every input reference we check that it belongs to one of
|
||||||
|
// the Inference Engine backend graphs. Request an output blob if it is.
|
||||||
|
// Do nothing if layer's input is from the same graph.
|
||||||
|
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(), !ieInpNode->net.empty());
|
||||||
|
if (layerNet != ieInpNode->net)
|
||||||
|
{
|
||||||
|
// layerNet is empty or nodes are from different graphs.
|
||||||
|
ieInpNode->net->addOutput(inpLd.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // HAVE_INF_ENGINE
|
||||||
|
|
||||||
void initInfEngineBackend()
|
void initInfEngineBackend()
|
||||||
{
|
{
|
||||||
// Build Inference Engine networks from sets of layers that support this
|
// Build Inference Engine networks from sets of layers that support this
|
||||||
// backend. If an internal layer isn't supported we'll use default
|
// backend. Split a whole model on several Inference Engine networks if
|
||||||
// implementation of it but build a new network after it.
|
// some of layers is not implemented.
|
||||||
CV_TRACE_FUNCTION();
|
CV_TRACE_FUNCTION();
|
||||||
CV_Assert(preferableBackend == DNN_BACKEND_INFERENCE_ENGINE, haveInfEngine());
|
CV_Assert(preferableBackend == DNN_BACKEND_INFERENCE_ENGINE, haveInfEngine());
|
||||||
#ifdef HAVE_INF_ENGINE
|
#ifdef HAVE_INF_ENGINE
|
||||||
MapIdToLayerData::iterator it;
|
MapIdToLayerData::iterator it;
|
||||||
Ptr<InfEngineBackendNet> net;
|
Ptr<InfEngineBackendNet> net;
|
||||||
|
// Set of all input and output blobs wrappers for current network.
|
||||||
|
std::map<int, Ptr<BackendWrapper> > netBlobsWrappers;
|
||||||
for (it = layers.begin(); it != layers.end(); ++it)
|
for (it = layers.begin(); it != layers.end(); ++it)
|
||||||
{
|
{
|
||||||
LayerData &ld = it->second;
|
LayerData &ld = it->second;
|
||||||
ld.skip = true;
|
ld.skip = true; // Initially skip all Inference Engine supported layers.
|
||||||
Ptr<Layer> layer = ld.layerInstance;
|
Ptr<Layer> layer = ld.layerInstance;
|
||||||
|
|
||||||
if (!layer->supportBackend(preferableBackend))
|
if (!layer->supportBackend(preferableBackend))
|
||||||
{
|
{
|
||||||
for (int i = 0; i < ld.outputBlobsWrappers.size(); ++i)
|
addInfEngineNetOutputs(ld);
|
||||||
{
|
|
||||||
auto dataPtr = infEngineDataNode(ld.outputBlobsWrappers[i]);
|
|
||||||
dataPtr->name = ld.name;
|
|
||||||
}
|
|
||||||
ld.skip = false;
|
ld.skip = false;
|
||||||
net = Ptr<InfEngineBackendNet>();
|
net = Ptr<InfEngineBackendNet>();
|
||||||
|
netBlobsWrappers.clear();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check what all inputs are from the same network or from default backend.
|
// Create a new network if one of inputs from different Inference Engine graph.
|
||||||
for (int i = 0; i < ld.inputBlobsId.size(); ++i)
|
for (int i = 0; i < ld.inputBlobsId.size(); ++i)
|
||||||
{
|
{
|
||||||
LayerData &inpLd = layers[ld.inputBlobsId[i].lid];
|
LayerData &inpLd = layers[ld.inputBlobsId[i].lid];
|
||||||
@ -1113,10 +1150,36 @@ struct Net::Impl
|
|||||||
if (!inpNode.empty())
|
if (!inpNode.empty())
|
||||||
{
|
{
|
||||||
Ptr<InfEngineBackendNode> ieInpNode = inpNode.dynamicCast<InfEngineBackendNode>();
|
Ptr<InfEngineBackendNode> ieInpNode = inpNode.dynamicCast<InfEngineBackendNode>();
|
||||||
CV_Assert(!ieInpNode.empty(), net.empty() || net == ieInpNode->net);
|
CV_Assert(!ieInpNode.empty(), !ieInpNode->net.empty());
|
||||||
|
if (ieInpNode->net != net)
|
||||||
|
{
|
||||||
|
net = Ptr<InfEngineBackendNet>();
|
||||||
|
netBlobsWrappers.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The same blobs wrappers cannot be shared between two Inference Engine
|
||||||
|
// networks because of explicit references between layers and blobs.
|
||||||
|
// So we need to rewrap all the external blobs.
|
||||||
|
for (int i = 0; i < ld.inputBlobsId.size(); ++i)
|
||||||
|
{
|
||||||
|
int lid = ld.inputBlobsId[i].lid;
|
||||||
|
LayerData &inpLd = layers[lid];
|
||||||
|
auto it = netBlobsWrappers.find(lid);
|
||||||
|
if (it == netBlobsWrappers.end())
|
||||||
|
{
|
||||||
|
ld.inputBlobsWrappers[i] = wrap(*ld.inputBlobs[i]);
|
||||||
|
auto dataPtr = infEngineDataNode(ld.inputBlobsWrappers[i]);
|
||||||
|
dataPtr->name = inpLd.name;
|
||||||
|
netBlobsWrappers[lid] = ld.inputBlobsWrappers[i];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ld.inputBlobsWrappers[i] = it->second;
|
||||||
|
}
|
||||||
|
netBlobsWrappers[ld.id] = ld.outputBlobsWrappers[0];
|
||||||
|
|
||||||
bool fused = false;
|
bool fused = false;
|
||||||
Ptr<BackendNode> node;
|
Ptr<BackendNode> node;
|
||||||
if (!net.empty())
|
if (!net.empty())
|
||||||
@ -1153,6 +1216,7 @@ struct Net::Impl
|
|||||||
|
|
||||||
if (!fused)
|
if (!fused)
|
||||||
net->addLayer(ieNode->layer);
|
net->addLayer(ieNode->layer);
|
||||||
|
addInfEngineNetOutputs(ld);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize all networks.
|
// Initialize all networks.
|
||||||
|
@ -277,14 +277,12 @@ public:
|
|||||||
#ifdef HAVE_INF_ENGINE
|
#ifdef HAVE_INF_ENGINE
|
||||||
InferenceEngine::LayerParams lp;
|
InferenceEngine::LayerParams lp;
|
||||||
lp.name = name;
|
lp.name = name;
|
||||||
lp.type = "BatchNormalization";
|
lp.type = "ScaleShift";
|
||||||
lp.precision = InferenceEngine::Precision::FP32;
|
lp.precision = InferenceEngine::Precision::FP32;
|
||||||
std::shared_ptr<InferenceEngine::BatchNormalizationLayer> ieLayer(new InferenceEngine::BatchNormalizationLayer(lp));
|
std::shared_ptr<InferenceEngine::ScaleShiftLayer> ieLayer(new InferenceEngine::ScaleShiftLayer(lp));
|
||||||
|
|
||||||
size_t numChannels = weights_.total();
|
ieLayer->_weights = wrapToInfEngineBlob(weights_);
|
||||||
ieLayer->epsilon = epsilon;
|
ieLayer->_biases = wrapToInfEngineBlob(bias_);
|
||||||
ieLayer->_weights = wrapToInfEngineBlob(blobs[1], {numChannels});
|
|
||||||
ieLayer->_biases = wrapToInfEngineBlob(blobs[0], {numChannels});
|
|
||||||
|
|
||||||
return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));
|
return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));
|
||||||
#endif // HAVE_INF_ENGINE
|
#endif // HAVE_INF_ENGINE
|
||||||
|
@ -550,7 +550,7 @@ public:
|
|||||||
for (int i = 1; i < _variance.size(); ++i)
|
for (int i = 1; i < _variance.size(); ++i)
|
||||||
ieLayer->params["variance"] += format(",%f", _variance[i]);
|
ieLayer->params["variance"] += format(",%f", _variance[i]);
|
||||||
|
|
||||||
ieLayer->params["step"] = "0";
|
ieLayer->params["step"] = _stepX == _stepY ? format("%f", _stepX) : "0";
|
||||||
ieLayer->params["step_h"] = _stepY;
|
ieLayer->params["step_h"] = _stepY;
|
||||||
ieLayer->params["step_w"] = _stepX;
|
ieLayer->params["step_w"] = _stepX;
|
||||||
|
|
||||||
|
@ -116,31 +116,6 @@ InferenceEngine::Precision InfEngineBackendNet::getPrecision() noexcept
|
|||||||
// Assume that outputs of network is unconnected blobs.
|
// Assume that outputs of network is unconnected blobs.
|
||||||
void InfEngineBackendNet::getOutputsInfo(InferenceEngine::OutputsDataMap &outputs_) noexcept
|
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;
|
outputs_ = outputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,7 +191,18 @@ InferenceEngine::StatusCode
|
|||||||
InfEngineBackendNet::addOutput(const std::string &layerName, size_t outputIndex,
|
InfEngineBackendNet::addOutput(const std::string &layerName, size_t outputIndex,
|
||||||
InferenceEngine::ResponseDesc *resp) noexcept
|
InferenceEngine::ResponseDesc *resp) noexcept
|
||||||
{
|
{
|
||||||
CV_Error(Error::StsNotImplemented, "");
|
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);
|
||||||
return InferenceEngine::StatusCode::OK;
|
return InferenceEngine::StatusCode::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,6 +240,39 @@ size_t InfEngineBackendNet::getBatchSize() const noexcept
|
|||||||
void InfEngineBackendNet::initEngine()
|
void InfEngineBackendNet::initEngine()
|
||||||
{
|
{
|
||||||
CV_Assert(!isInitialized());
|
CV_Assert(!isInitialized());
|
||||||
|
|
||||||
|
// Add all unconnected blobs to output blobs.
|
||||||
|
InferenceEngine::OutputsDataMap unconnectedOuts;
|
||||||
|
for (const auto& l : layers)
|
||||||
|
{
|
||||||
|
// Add all outputs.
|
||||||
|
for (const InferenceEngine::DataPtr& out : l->outData)
|
||||||
|
{
|
||||||
|
// TODO: Replace to uniquness assertion.
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CV_Assert(layers.empty() || !unconnectedOuts.empty());
|
||||||
|
|
||||||
|
for (auto it = unconnectedOuts.begin(); it != unconnectedOuts.end(); ++it)
|
||||||
|
{
|
||||||
|
outputs[it->first] = it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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];
|
||||||
|
}
|
||||||
|
|
||||||
engine = InferenceEngine::InferenceEnginePluginPtr("libMKLDNNPlugin.so");
|
engine = InferenceEngine::InferenceEnginePluginPtr("libMKLDNNPlugin.so");
|
||||||
InferenceEngine::ResponseDesc resp;
|
InferenceEngine::ResponseDesc resp;
|
||||||
InferenceEngine::StatusCode status = engine->LoadNetwork(*this, &resp);
|
InferenceEngine::StatusCode status = engine->LoadNetwork(*this, &resp);
|
||||||
|
@ -206,9 +206,21 @@ TEST_P(DNNTestNetwork, OpenPose_pose_mpi_faster_4_stages)
|
|||||||
|
|
||||||
TEST_P(DNNTestNetwork, OpenFace)
|
TEST_P(DNNTestNetwork, OpenFace)
|
||||||
{
|
{
|
||||||
|
if (backend == DNN_BACKEND_HALIDE) throw SkipTestException("");
|
||||||
processNet("dnn/openface_nn4.small2.v1.t7", "", Size(96, 96), "", "torch");
|
processNet("dnn/openface_nn4.small2.v1.t7", "", Size(96, 96), "", "torch");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(DNNTestNetwork, opencv_face_detector)
|
||||||
|
{
|
||||||
|
if (backend == DNN_BACKEND_HALIDE ||
|
||||||
|
backend == DNN_BACKEND_DEFAULT && target == DNN_TARGET_OPENCL)
|
||||||
|
throw SkipTestException("");
|
||||||
|
Mat img = imread(findDataFile("gpu/lbpcascade/er.png", false));
|
||||||
|
Mat inp = blobFromImage(img, 1.0, Size(), Scalar(104.0, 177.0, 123.0), false, false);
|
||||||
|
processNet("dnn/opencv_face_detector.caffemodel", "dnn/opencv_face_detector.prototxt",
|
||||||
|
inp, "detection_out", "caffe");
|
||||||
|
}
|
||||||
|
|
||||||
const tuple<DNNBackend, DNNTarget> testCases[] = {
|
const tuple<DNNBackend, DNNTarget> testCases[] = {
|
||||||
#ifdef HAVE_HALIDE
|
#ifdef HAVE_HALIDE
|
||||||
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_HALIDE, DNN_TARGET_CPU),
|
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_HALIDE, DNN_TARGET_CPU),
|
||||||
|
@ -279,9 +279,8 @@ TEST(Test_TensorFlow, Inception_v2_SSD)
|
|||||||
normAssert(detections, ref);
|
normAssert(detections, ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
OCL_TEST(Test_TensorFlow, MobileNet_SSD)
|
OCL_TEST(Test_TensorFlow, DISABLED_MobileNet_SSD)
|
||||||
{
|
{
|
||||||
throw SkipTestException("TODO: test is failed");
|
|
||||||
std::string netPath = findDataFile("dnn/ssd_mobilenet_v1_coco.pb", false);
|
std::string netPath = findDataFile("dnn/ssd_mobilenet_v1_coco.pb", false);
|
||||||
std::string netConfig = findDataFile("dnn/ssd_mobilenet_v1_coco.pbtxt", false);
|
std::string netConfig = findDataFile("dnn/ssd_mobilenet_v1_coco.pbtxt", false);
|
||||||
std::string imgPath = findDataFile("dnn/street.png", false);
|
std::string imgPath = findDataFile("dnn/street.png", false);
|
||||||
|
Loading…
Reference in New Issue
Block a user