From fe459c82e551b5c2fa68ea534dfea98ed82938cb Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Wed, 5 Dec 2018 18:11:45 +0300 Subject: [PATCH] Merge pull request #13332 from mshabunin:dnn-backends DNN backends registry (#13332) * Added dnn backends registry * dnn: process DLIE/FPGA target --- modules/dnn/include/opencv2/dnn/dnn.hpp | 3 + modules/dnn/perf/perf_net.cpp | 17 ------ modules/dnn/src/dnn.cpp | 98 ++++++++++++++++++++++++++++++++ modules/dnn/test/test_backends.cpp | 2 +- modules/dnn/test/test_caffe_importer.cpp | 8 ++- modules/dnn/test/test_common.hpp | 98 +++++--------------------------- modules/dnn/test/test_googlenet.cpp | 15 +++-- modules/dnn/test/test_ie_models.cpp | 28 ++------- modules/dnn/test/test_misc.cpp | 2 - 9 files changed, 138 insertions(+), 133 deletions(-) diff --git a/modules/dnn/include/opencv2/dnn/dnn.hpp b/modules/dnn/include/opencv2/dnn/dnn.hpp index 3b26bb2..2e34b4a 100644 --- a/modules/dnn/include/opencv2/dnn/dnn.hpp +++ b/modules/dnn/include/opencv2/dnn/dnn.hpp @@ -93,6 +93,9 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN DNN_TARGET_FPGA }; + CV_EXPORTS std::vector< std::pair > getAvailableBackends(); + CV_EXPORTS std::vector 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), diff --git a/modules/dnn/perf/perf_net.cpp b/modules/dnn/perf/perf_net.cpp index 03d7a23..cc95cc5 100644 --- a/modules/dnn/perf/perf_net.cpp +++ b/modules/dnn/perf/perf_net.cpp @@ -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); diff --git a/modules/dnn/src/dnn.cpp b/modules/dnn/src/dnn.cpp index 036726d..d1fdbcc 100644 --- a/modules/dnn/src/dnn.cpp +++ b/modules/dnn/src/dnn.cpp @@ -74,6 +74,104 @@ static int PARAM_DNN_BACKEND_DEFAULT = (int)utils::getConfigurationParameterSize #endif ); +//================================================================================================== + +class BackendRegistry +{ +public: + typedef std::vector< std::pair > 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 > getAvailableBackends() +{ + return BackendRegistry::getRegistry().getBackends(); +} + +std::vector getAvailableTargets(Backend be) +{ + std::vector 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); diff --git a/modules/dnn/test/test_backends.cpp b/modules/dnn/test/test_backends.cpp index a1216a5..ab8f31d 100644 --- a/modules/dnn/test/test_backends.cpp +++ b/modules/dnn/test/test_backends.cpp @@ -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 diff --git a/modules/dnn/test/test_caffe_importer.cpp b/modules/dnn/test/test_caffe_importer.cpp index 4ad3d54..2ed07b3 100644 --- a/modules/dnn/test/test_caffe_importer.cpp +++ b/modules/dnn/test/test_caffe_importer.cpp @@ -300,10 +300,11 @@ INSTANTIATE_TEST_CASE_P(/**/, Reproducibility_ResNet50, typedef testing::TestWithParam 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) { diff --git a/modules/dnn/test/test_common.hpp b/modules/dnn/test/test_common.hpp index 9e9b25e..6e1140b 100644 --- a/modules/dnn/test/test_common.hpp +++ b/modules/dnn/test/test_common.hpp @@ -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 > dnnBackendsAndTargets( +testing::internal::ParamGenerator< tuple > dnnBackendsAndTargets( bool withInferenceEngine = true, bool withHalide = false, bool withCpuOCV = true ) { - std::vector > targets; -#ifdef HAVE_HALIDE + std::vector< tuple > 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 > dnnBackendsAndTargets namespace opencv_test { using namespace cv::dnn; -static inline -testing::internal::ParamGenerator availableDnnTargets() -{ - static std::vector 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 > { 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) { diff --git a/modules/dnn/test/test_googlenet.cpp b/modules/dnn/test/test_googlenet.cpp index 37064c3..3db0c47 100644 --- a/modules/dnn/test/test_googlenet.cpp +++ b/modules/dnn/test/test_googlenet.cpp @@ -55,9 +55,11 @@ static std::string _tf(TString filename) typedef testing::TestWithParam 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 diff --git a/modules/dnn/test/test_ie_models.cpp b/modules/dnn/test/test_ie_models.cpp index a8404e0..db718eb 100644 --- a/modules/dnn/test/test_ie_models.cpp +++ b/modules/dnn/test/test_ie_models.cpp @@ -203,7 +203,8 @@ TEST_P(DNNTestOpenVINO, models) std::map inputsMap; std::map 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 intelModels() return ValuesIn(modelsNames); } -static testing::internal::ParamGenerator dnnDLIETargets() -{ - std::vector 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 diff --git a/modules/dnn/test/test_misc.cpp b/modules/dnn/test/test_misc.cpp index 327de6f..685ee02 100644 --- a/modules/dnn/test/test_misc.cpp +++ b/modules/dnn/test/test_misc.cpp @@ -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(""); -- 2.7.4