Merge pull request #13332 from mshabunin:dnn-backends
authorMaksim Shabunin <maksim.shabunin@gmail.com>
Wed, 5 Dec 2018 15:11:45 +0000 (18:11 +0300)
committerAlexander Alekhin <alexander.a.alekhin@gmail.com>
Wed, 5 Dec 2018 15:11:45 +0000 (18:11 +0300)
DNN backends registry (#13332)

* Added dnn backends registry

* dnn: process DLIE/FPGA target

modules/dnn/include/opencv2/dnn/dnn.hpp
modules/dnn/perf/perf_net.cpp
modules/dnn/src/dnn.cpp
modules/dnn/test/test_backends.cpp
modules/dnn/test/test_caffe_importer.cpp
modules/dnn/test/test_common.hpp
modules/dnn/test/test_googlenet.cpp
modules/dnn/test/test_ie_models.cpp
modules/dnn/test/test_misc.cpp

index 3b26bb2..2e34b4a 100644 (file)
@@ -93,6 +93,9 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
         DNN_TARGET_FPGA
     };
 
+    CV_EXPORTS std::vector< std::pair<Backend, Target> > getAvailableBackends();
+    CV_EXPORTS std::vector<Target> getAvailableTargets(Backend be);
+
     /** @brief This class provides all data needed to initialize layer.
      *
      * It includes dictionary with scalar params (which can be read by using Dict interface),
index 03d7a23..cc95cc5 100644 (file)
@@ -31,23 +31,6 @@ public:
     void processNet(std::string weights, std::string proto, std::string halide_scheduler,
                     const Mat& input, const std::string& outputLayer = "")
     {
-        if (backend == DNN_BACKEND_OPENCV && (target == DNN_TARGET_OPENCL || target == DNN_TARGET_OPENCL_FP16))
-        {
-#if defined(HAVE_OPENCL)
-            if (!cv::ocl::useOpenCL())
-#endif
-            {
-                throw cvtest::SkipTestException("OpenCL is not available/disabled in OpenCV");
-            }
-        }
-        if (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD)
-        {
-            if (!checkIETarget(DNN_TARGET_MYRIAD))
-            {
-                throw SkipTestException("Myriad is not available/disabled in OpenCV");
-            }
-        }
-
         randu(input, 0.0f, 1.0f);
 
         weights = findDataFile(weights, false);
index 036726d..d1fdbcc 100644 (file)
@@ -74,6 +74,104 @@ static int PARAM_DNN_BACKEND_DEFAULT = (int)utils::getConfigurationParameterSize
 #endif
 );
 
+//==================================================================================================
+
+class BackendRegistry
+{
+public:
+    typedef std::vector< std::pair<Backend, Target> > BackendsList;
+    const BackendsList & getBackends() const { return backends; }
+    static BackendRegistry & getRegistry()
+    {
+        static BackendRegistry impl;
+        return impl;
+    }
+private:
+    BackendRegistry()
+    {
+#ifdef HAVE_HALIDE
+        backends.push_back(std::make_pair(DNN_BACKEND_HALIDE, DNN_TARGET_CPU));
+#  ifdef HAVE_OPENCL
+        if (cv::ocl::useOpenCL())
+            backends.push_back(std::make_pair(DNN_BACKEND_HALIDE, DNN_TARGET_OPENCL));
+#  endif
+#endif // HAVE_HALIDE
+
+#ifdef HAVE_INF_ENGINE
+        if (checkIETarget(DNN_TARGET_CPU))
+            backends.push_back(std::make_pair(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_CPU));
+        if (checkIETarget(DNN_TARGET_MYRIAD))
+            backends.push_back(std::make_pair(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_MYRIAD));
+        if (checkIETarget(DNN_TARGET_FPGA))
+            backends.push_back(std::make_pair(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_FPGA));
+#  ifdef HAVE_OPENCL
+        if (cv::ocl::useOpenCL() && ocl::Device::getDefault().isIntel())
+        {
+            if (checkIETarget(DNN_TARGET_OPENCL))
+                backends.push_back(std::make_pair(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL));
+            if (checkIETarget(DNN_TARGET_OPENCL_FP16))
+                backends.push_back(std::make_pair(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL_FP16));
+        }
+#  endif
+#endif // HAVE_INF_ENGINE
+
+#ifdef HAVE_OPENCL
+        if (cv::ocl::useOpenCL())
+        {
+            backends.push_back(std::make_pair(DNN_BACKEND_OPENCV, DNN_TARGET_OPENCL));
+            backends.push_back(std::make_pair(DNN_BACKEND_OPENCV, DNN_TARGET_OPENCL_FP16));
+        }
+#endif
+
+        backends.push_back(std::make_pair(DNN_BACKEND_OPENCV, DNN_TARGET_CPU));
+    }
+    static inline bool checkIETarget(int target)
+    {
+#ifndef HAVE_INF_ENGINE
+        return false;
+#else
+        cv::dnn::Net net;
+        cv::dnn::LayerParams lp;
+        net.addLayerToPrev("testLayer", "Identity", lp);
+        net.setPreferableBackend(cv::dnn::DNN_BACKEND_INFERENCE_ENGINE);
+        net.setPreferableTarget(target);
+        static int inpDims[] = {1, 2, 3, 4};
+        net.setInput(cv::Mat(4, &inpDims[0], CV_32FC1, cv::Scalar(0)));
+        try
+        {
+            net.forward();
+        }
+        catch(...)
+        {
+            return false;
+        }
+        return true;
+#endif
+    }
+
+    BackendsList backends;
+};
+
+
+std::vector< std::pair<Backend, Target> > getAvailableBackends()
+{
+    return BackendRegistry::getRegistry().getBackends();
+}
+
+std::vector<Target> getAvailableTargets(Backend be)
+{
+    std::vector<Target> result;
+    const BackendRegistry::BackendsList all_backends = getAvailableBackends();
+    for(BackendRegistry::BackendsList::const_iterator i = all_backends.begin(); i != all_backends.end(); ++i )
+    {
+        if (i->first == be)
+            result.push_back(i->second);
+    }
+    return result;
+}
+
+//==================================================================================================
+
 // Additional checks (slowdowns execution!)
 static bool DNN_CHECK_NAN_INF = utils::getConfigurationParameterBool("OPENCV_DNN_CHECK_NAN_INF", false);
 static bool DNN_CHECK_NAN_INF_DUMP = utils::getConfigurationParameterBool("OPENCV_DNN_CHECK_NAN_INF_DUMP", false);
index a1216a5..ab8f31d 100644 (file)
@@ -292,6 +292,6 @@ TEST_P(DNNTestNetwork, FastNeuralStyle_eccv16)
     processNet("dnn/fast_neural_style_eccv16_starry_night.t7", "", inp, "", "", l1, lInf);
 }
 
-INSTANTIATE_TEST_CASE_P(/*nothing*/, DNNTestNetwork, dnnBackendsAndTargets(true, true, false));
+INSTANTIATE_TEST_CASE_P(/*nothing*/, DNNTestNetwork, dnnBackendsAndTargets());
 
 }} // namespace
index 4ad3d54..2ed07b3 100644 (file)
@@ -300,10 +300,11 @@ INSTANTIATE_TEST_CASE_P(/**/, Reproducibility_ResNet50,
 typedef testing::TestWithParam<Target> Reproducibility_SqueezeNet_v1_1;
 TEST_P(Reproducibility_SqueezeNet_v1_1, Accuracy)
 {
+    int targetId = GetParam();
+    if(targetId == DNN_TARGET_OPENCL_FP16)
+        throw SkipTestException("This test does not support FP16");
     Net net = readNetFromCaffe(findDataFile("dnn/squeezenet_v1.1.prototxt", false),
                                findDataFile("dnn/squeezenet_v1.1.caffemodel", false));
-
-    int targetId = GetParam();
     net.setPreferableBackend(DNN_BACKEND_OPENCV);
     net.setPreferableTarget(targetId);
 
@@ -324,7 +325,8 @@ TEST_P(Reproducibility_SqueezeNet_v1_1, Accuracy)
     Mat ref = blobFromNPY(_tf("squeezenet_v1.1_prob.npy"));
     normAssert(ref, out);
 }
-INSTANTIATE_TEST_CASE_P(/**/, Reproducibility_SqueezeNet_v1_1, availableDnnTargets());
+INSTANTIATE_TEST_CASE_P(/**/, Reproducibility_SqueezeNet_v1_1,
+    testing::ValuesIn(getAvailableTargets(DNN_BACKEND_OPENCV)));
 
 TEST(Reproducibility_AlexNet_fp16, Accuracy)
 {
index 9e9b25e..6e1140b 100644 (file)
@@ -189,30 +189,6 @@ static inline void normAssertDetections(cv::Mat ref, cv::Mat out, const char *co
                          testBoxes, comment, confThreshold, scores_diff, boxes_iou_diff);
 }
 
-static inline bool checkIETarget(int target)
-{
-#ifndef HAVE_INF_ENGINE
-    return false;
-#else
-    cv::dnn::Net net;
-    cv::dnn::LayerParams lp;
-    net.addLayerToPrev("testLayer", "Identity", lp);
-    net.setPreferableBackend(cv::dnn::DNN_BACKEND_INFERENCE_ENGINE);
-    net.setPreferableTarget(target);
-    static int inpDims[] = {1, 2, 3, 4};
-    net.setInput(cv::Mat(4, &inpDims[0], CV_32FC1, cv::Scalar(0)));
-    try
-    {
-        net.forward();
-    }
-    catch(...)
-    {
-        return false;
-    }
-    return true;
-#endif
-}
-
 static inline bool readFileInMemory(const std::string& filename, std::string& content)
 {
     std::ios::openmode mode = std::ios::in | std::ios::binary;
@@ -237,49 +213,31 @@ namespace opencv_test {
 using namespace cv::dnn;
 
 static inline
-testing::internal::ParamGenerator<tuple<Backend, Target> > dnnBackendsAndTargets(
+testing::internal::ParamGenerator< tuple<Backend, Target> > dnnBackendsAndTargets(
         bool withInferenceEngine = true,
         bool withHalide = false,
         bool withCpuOCV = true
 )
 {
-    std::vector<tuple<Backend, Target> > targets;
-#ifdef HAVE_HALIDE
+    std::vector< tuple<Backend, Target> > targets;
+    std::vector< Target > available;
     if (withHalide)
     {
-        targets.push_back(make_tuple(DNN_BACKEND_HALIDE, DNN_TARGET_CPU));
-#ifdef HAVE_OPENCL
-        if (cv::ocl::useOpenCL())
-            targets.push_back(make_tuple(DNN_BACKEND_HALIDE, DNN_TARGET_OPENCL));
-#endif
+        available = getAvailableTargets(DNN_BACKEND_HALIDE);
+        for (std::vector< Target >::const_iterator i = available.begin(); i != available.end(); ++i)
+            targets.push_back(make_tuple(DNN_BACKEND_HALIDE, *i));
     }
-#endif
-#ifdef HAVE_INF_ENGINE
     if (withInferenceEngine)
     {
-        targets.push_back(make_tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_CPU));
-#ifdef HAVE_OPENCL
-        if (cv::ocl::useOpenCL() && ocl::Device::getDefault().isIntel())
-        {
-            targets.push_back(make_tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL));
-            targets.push_back(make_tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL_FP16));
-        }
-#endif
-        if (checkIETarget(DNN_TARGET_MYRIAD))
-            targets.push_back(make_tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_MYRIAD));
+        available = getAvailableTargets(DNN_BACKEND_INFERENCE_ENGINE);
+        for (std::vector< Target >::const_iterator i = available.begin(); i != available.end(); ++i)
+            targets.push_back(make_tuple(DNN_BACKEND_INFERENCE_ENGINE, *i));
     }
-#endif
-    if (withCpuOCV)
-        targets.push_back(make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_CPU));
-#ifdef HAVE_OPENCL
-    if (cv::ocl::useOpenCL())
     {
-        targets.push_back(make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_OPENCL));
-        targets.push_back(make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_OPENCL_FP16));
+        available = getAvailableTargets(DNN_BACKEND_OPENCV);
+        for (std::vector< Target >::const_iterator i = available.begin(); i != available.end(); ++i)
+            targets.push_back(make_tuple(DNN_BACKEND_OPENCV, *i));
     }
-#endif
-    if (targets.empty())  // validate at least CPU mode
-        targets.push_back(make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_CPU));
     return testing::ValuesIn(targets);
 }
 
@@ -289,21 +247,6 @@ testing::internal::ParamGenerator<tuple<Backend, Target> > dnnBackendsAndTargets
 namespace opencv_test {
 using namespace cv::dnn;
 
-static inline
-testing::internal::ParamGenerator<Target> availableDnnTargets()
-{
-    static std::vector<Target> targets;
-    if (targets.empty())
-    {
-        targets.push_back(DNN_TARGET_CPU);
-#ifdef HAVE_OPENCL
-        if (cv::ocl::useOpenCL())
-            targets.push_back(DNN_TARGET_OPENCL);
-#endif
-    }
-    return testing::ValuesIn(targets);
-}
-
 class DNNTestLayer : public TestWithParam<tuple<Backend, Target> >
 {
 public:
@@ -332,23 +275,10 @@ public:
        }
    }
 
-   static void checkBackend(int backend, int target, Mat* inp = 0, Mat* ref = 0)
-   {
-       if (backend == DNN_BACKEND_OPENCV && (target == DNN_TARGET_OPENCL || target == DNN_TARGET_OPENCL_FP16))
-       {
-#ifdef HAVE_OPENCL
-           if (!cv::ocl::useOpenCL())
-#endif
-           {
-               throw SkipTestException("OpenCL is not available/disabled in OpenCV");
-           }
-       }
+    static void checkBackend(int backend, int target, Mat* inp = 0, Mat* ref = 0)
+    {
        if (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD)
        {
-           if (!checkIETarget(DNN_TARGET_MYRIAD))
-           {
-               throw SkipTestException("Myriad is not available/disabled in OpenCV");
-           }
 #if defined(INF_ENGINE_RELEASE) && INF_ENGINE_RELEASE < 2018030000
            if (inp && ref && inp->size[0] != 1)
            {
index 37064c3..3db0c47 100644 (file)
@@ -55,9 +55,11 @@ static std::string _tf(TString filename)
 typedef testing::TestWithParam<Target> Reproducibility_GoogLeNet;
 TEST_P(Reproducibility_GoogLeNet, Batching)
 {
+    const int targetId = GetParam();
+    if(targetId == DNN_TARGET_OPENCL_FP16)
+        throw SkipTestException("This test does not support FP16");
     Net net = readNetFromCaffe(findDataFile("dnn/bvlc_googlenet.prototxt", false),
                                findDataFile("dnn/bvlc_googlenet.caffemodel", false));
-    int targetId = GetParam();
     net.setPreferableBackend(DNN_BACKEND_OPENCV);
     net.setPreferableTarget(targetId);
 
@@ -84,9 +86,11 @@ TEST_P(Reproducibility_GoogLeNet, Batching)
 
 TEST_P(Reproducibility_GoogLeNet, IntermediateBlobs)
 {
+    const int targetId = GetParam();
+    if(targetId == DNN_TARGET_OPENCL_FP16)
+        throw SkipTestException("This test does not support FP16");
     Net net = readNetFromCaffe(findDataFile("dnn/bvlc_googlenet.prototxt", false),
                                findDataFile("dnn/bvlc_googlenet.caffemodel", false));
-    int targetId = GetParam();
     net.setPreferableBackend(DNN_BACKEND_OPENCV);
     net.setPreferableTarget(targetId);
 
@@ -113,9 +117,11 @@ TEST_P(Reproducibility_GoogLeNet, IntermediateBlobs)
 
 TEST_P(Reproducibility_GoogLeNet, SeveralCalls)
 {
+    const int targetId = GetParam();
+    if(targetId == DNN_TARGET_OPENCL_FP16)
+        throw SkipTestException("This test does not support FP16");
     Net net = readNetFromCaffe(findDataFile("dnn/bvlc_googlenet.prototxt", false),
                                findDataFile("dnn/bvlc_googlenet.caffemodel", false));
-    int targetId = GetParam();
     net.setPreferableBackend(DNN_BACKEND_OPENCV);
     net.setPreferableTarget(targetId);
 
@@ -143,6 +149,7 @@ TEST_P(Reproducibility_GoogLeNet, SeveralCalls)
     normAssert(outs[0], ref, "", 1E-4, 1E-2);
 }
 
-INSTANTIATE_TEST_CASE_P(/**/, Reproducibility_GoogLeNet, availableDnnTargets());
+INSTANTIATE_TEST_CASE_P(/**/, Reproducibility_GoogLeNet,
+    testing::ValuesIn(getAvailableTargets(DNN_BACKEND_OPENCV)));
 
 }} // namespace
index a8404e0..db718eb 100644 (file)
@@ -203,7 +203,8 @@ TEST_P(DNNTestOpenVINO, models)
     std::map<std::string, cv::Mat> inputsMap;
     std::map<std::string, cv::Mat> ieOutputsMap, cvOutputsMap;
     // Single Myriad device cannot be shared across multiple processes.
-    resetMyriadDevice();
+    if (target == DNN_TARGET_MYRIAD)
+        resetMyriadDevice();
     runIE(target, xmlPath, binPath, inputsMap, ieOutputsMap);
     runCV(target, xmlPath, binPath, inputsMap, cvOutputsMap);
 
@@ -245,27 +246,10 @@ static testing::internal::ParamGenerator<String> intelModels()
     return ValuesIn(modelsNames);
 }
 
-static testing::internal::ParamGenerator<Target> dnnDLIETargets()
-{
-    std::vector<Target> targets;
-    targets.push_back(DNN_TARGET_CPU);
-#ifdef HAVE_OPENCL
-    if (cv::ocl::useOpenCL() && ocl::Device::getDefault().isIntel())
-    {
-        targets.push_back(DNN_TARGET_OPENCL);
-        targets.push_back(DNN_TARGET_OPENCL_FP16);
-    }
-#endif
-    if (checkIETarget(DNN_TARGET_MYRIAD))
-        targets.push_back(DNN_TARGET_MYRIAD);
-    if (checkIETarget(DNN_TARGET_FPGA))
-        targets.push_back(DNN_TARGET_FPGA);
-    return testing::ValuesIn(targets);
-}
-
-INSTANTIATE_TEST_CASE_P(/**/, DNNTestOpenVINO, Combine(
-    dnnDLIETargets(), intelModels()
-));
+INSTANTIATE_TEST_CASE_P(/**/,
+    DNNTestOpenVINO,
+    Combine(testing::ValuesIn(getAvailableTargets(DNN_BACKEND_INFERENCE_ENGINE)), intelModels())
+);
 
 }}
 #endif  // HAVE_INF_ENGINE
index 327de6f..685ee02 100644 (file)
@@ -157,8 +157,6 @@ TEST_P(setInput, normalization)
     const int target   = get<1>(get<3>(GetParam()));
     const bool kSwapRB = true;
 
-    if (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD && !checkIETarget(DNN_TARGET_MYRIAD))
-        throw SkipTestException("Myriad is not available/disabled in OpenCV");
     if (backend == DNN_BACKEND_OPENCV && target == DNN_TARGET_OPENCL_FP16 && dtype != CV_32F)
         throw SkipTestException("");