Merge pull request #10799 from dkurt:dnn_inference_engine_face_detection

This commit is contained in:
Vadim Pisarevsky 2018-02-07 13:42:08 +00:00
commit 835acd3f31
8 changed files with 150 additions and 45 deletions

View File

@ -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})
list(APPEND ie_root_paths "$ENV{INTEL_CVSDK_DIR}")
endif()
if(DEFINED INTEL_CVSDK_DIR)
list(APPEND ie_root_paths "${INTEL_CVSDK_DIR}")
endif()
if(WITH_INF_ENGINE AND NOT ie_root_paths)
list(APPEND ie_root_paths "/opt/intel/deeplearning_deploymenttoolkit/deployment_tools")

View File

@ -150,6 +150,7 @@ PERF_TEST_P_(DNNTestNetwork, SSD)
PERF_TEST_P_(DNNTestNetwork, OpenFace)
{
if (backend == DNN_BACKEND_HALIDE) throw SkipTestException("");
processNet("dnn/openface_nn4.small2.v1.t7", "", "",
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");
}
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[] = {
#ifdef HAVE_HALIDE
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_HALIDE, DNN_TARGET_CPU),

View File

@ -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()
{
// 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.
// backend. Split a whole model on several Inference Engine networks if
// some of layers is not implemented.
CV_TRACE_FUNCTION();
CV_Assert(preferableBackend == DNN_BACKEND_INFERENCE_ENGINE, haveInfEngine());
#ifdef HAVE_INF_ENGINE
MapIdToLayerData::iterator it;
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)
{
LayerData &ld = it->second;
ld.skip = true;
ld.skip = true; // Initially skip all Inference Engine supported layers.
Ptr<Layer> layer = ld.layerInstance;
if (!layer->supportBackend(preferableBackend))
{
for (int i = 0; i < ld.outputBlobsWrappers.size(); ++i)
{
auto dataPtr = infEngineDataNode(ld.outputBlobsWrappers[i]);
dataPtr->name = ld.name;
}
addInfEngineNetOutputs(ld);
ld.skip = false;
net = Ptr<InfEngineBackendNet>();
netBlobsWrappers.clear();
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)
{
LayerData &inpLd = layers[ld.inputBlobsId[i].lid];
@ -1113,10 +1150,36 @@ struct Net::Impl
if (!inpNode.empty())
{
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;
Ptr<BackendNode> node;
if (!net.empty())
@ -1153,6 +1216,7 @@ struct Net::Impl
if (!fused)
net->addLayer(ieNode->layer);
addInfEngineNetOutputs(ld);
}
// Initialize all networks.

View File

@ -277,14 +277,12 @@ public:
#ifdef HAVE_INF_ENGINE
InferenceEngine::LayerParams lp;
lp.name = name;
lp.type = "BatchNormalization";
lp.type = "ScaleShift";
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->epsilon = epsilon;
ieLayer->_weights = wrapToInfEngineBlob(blobs[1], {numChannels});
ieLayer->_biases = wrapToInfEngineBlob(blobs[0], {numChannels});
ieLayer->_weights = wrapToInfEngineBlob(weights_);
ieLayer->_biases = wrapToInfEngineBlob(bias_);
return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));
#endif // HAVE_INF_ENGINE

View File

@ -550,7 +550,7 @@ public:
for (int i = 1; i < _variance.size(); ++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_w"] = _stepX;

View File

@ -116,31 +116,6 @@ InferenceEngine::Precision InfEngineBackendNet::getPrecision() noexcept
// 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;
}
@ -216,7 +191,18 @@ InferenceEngine::StatusCode
InfEngineBackendNet::addOutput(const std::string &layerName, size_t outputIndex,
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;
}
@ -254,6 +240,39 @@ size_t InfEngineBackendNet::getBatchSize() const noexcept
void InfEngineBackendNet::initEngine()
{
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");
InferenceEngine::ResponseDesc resp;
InferenceEngine::StatusCode status = engine->LoadNetwork(*this, &resp);

View File

@ -206,9 +206,21 @@ TEST_P(DNNTestNetwork, OpenPose_pose_mpi_faster_4_stages)
TEST_P(DNNTestNetwork, OpenFace)
{
if (backend == DNN_BACKEND_HALIDE) throw SkipTestException("");
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[] = {
#ifdef HAVE_HALIDE
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_HALIDE, DNN_TARGET_CPU),

View File

@ -279,9 +279,8 @@ TEST(Test_TensorFlow, Inception_v2_SSD)
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 netConfig = findDataFile("dnn/ssd_mobilenet_v1_coco.pbtxt", false);
std::string imgPath = findDataFile("dnn/street.png", false);