diff --git a/modules/dnn/src/caffe/caffe_importer.cpp b/modules/dnn/src/caffe/caffe_importer.cpp index 26374ce698..fdd39468a1 100644 --- a/modules/dnn/src/caffe/caffe_importer.cpp +++ b/modules/dnn/src/caffe/caffe_importer.cpp @@ -424,6 +424,36 @@ public: } dstNet.setInputsNames(netInputs); + std::vector inp_shapes; + if (net.input_shape_size() > 0 || (layersSize > 0 && net.layer(0).has_input_param() && + net.layer(0).input_param().shape_size() > 0)) { + + int size = (net.input_shape_size() > 0) ? net.input_shape_size() : + net.layer(0).input_param().shape_size(); + for (int inp_id = 0; inp_id < size; inp_id++) + { + const caffe::BlobShape &_input_shape = (net.input_shape_size() > 0) ? + net.input_shape(inp_id) : + net.layer(0).input_param().shape(inp_id); + MatShape shape; + for (int i = 0; i < _input_shape.dim_size(); i++) { + shape.push_back((int)_input_shape.dim(i)); + } + inp_shapes.push_back(shape); + } + } + else if (net.input_dim_size() > 0) { + MatShape shape; + for (int dim = 0; dim < net.input_dim_size(); dim++) { + shape.push_back(net.input_dim(dim)); + } + inp_shapes.push_back(shape); + } + + for (int inp_id = 0; inp_id < inp_shapes.size(); inp_id++) { + dstNet.setInput(Mat(inp_shapes[inp_id], CV_32F), netInputs[inp_id]); + } + addedBlobs.clear(); } diff --git a/modules/dnn/src/dnn.cpp b/modules/dnn/src/dnn.cpp index 84c9b4dbbc..3c0b8cff26 100644 --- a/modules/dnn/src/dnn.cpp +++ b/modules/dnn/src/dnn.cpp @@ -2455,6 +2455,18 @@ struct Net::Impl { std::vector& inputLayerIds = layers[id].inputBlobsId; + if (inOutShapes[0].in[0].empty() && !layers[0].outputBlobs.empty()) + { + ShapesVec shapes; + for (int i = 0; i < layers[0].outputBlobs.size(); i++) + { + Mat& inp = layers[0].outputBlobs[i]; + CV_Assert(inp.total()); + shapes.push_back(shape(inp)); + } + inOutShapes[0].in = shapes; + } + if (inOutShapes[id].in.empty()) { for(int i = 0; i < inputLayerIds.size(); i++) @@ -2595,14 +2607,23 @@ Net Net::readFromModelOptimizer(const String& xml, const String& bin) InferenceEngine::CNNNetwork ieNet = reader.getNetwork(); std::vector inputsNames; + std::vector inp_shapes; for (auto& it : ieNet.getInputsInfo()) { inputsNames.push_back(it.first); + std::vector dims = it.second->getTensorDesc().getDims(); + inp_shapes.push_back(std::vector(dims.begin(), dims.end())); } Net cvNet; cvNet.setInputsNames(inputsNames); + // set empty input to determine input shapes + for (int inp_id = 0; inp_id < inputsNames.size(); ++inp_id) + { + cvNet.setInput(Mat(inp_shapes[inp_id], CV_32F), inputsNames[inp_id]); + } + Ptr backendNode(new InfEngineBackendNode(InferenceEngine::Builder::Layer(""))); backendNode->net = Ptr(new InfEngineBackendNet(ieNet)); for (auto& it : ieNet.getOutputsInfo()) diff --git a/modules/dnn/src/model.cpp b/modules/dnn/src/model.cpp index 3aeb3a2b2a..55a9cda1fd 100644 --- a/modules/dnn/src/model.cpp +++ b/modules/dnn/src/model.cpp @@ -47,12 +47,22 @@ Model::Model(const String& model, const String& config) : Net(readNet(model, config)), impl(new Impl) { impl->outNames = getUnconnectedOutLayersNames(); -} + std::vector inLayerShapes; + std::vector outLayerShapes; + getLayerShapes(MatShape(), 0, inLayerShapes, outLayerShapes); + if (!inLayerShapes.empty() && inLayerShapes[0].size() == 4) + impl->size = Size(inLayerShapes[0][3], inLayerShapes[0][2]); +}; Model::Model(const Net& network) : Net(network), impl(new Impl) { impl->outNames = getUnconnectedOutLayersNames(); -} + std::vector inLayerShapes; + std::vector outLayerShapes; + getLayerShapes(MatShape(), 0, inLayerShapes, outLayerShapes); + if (!inLayerShapes.empty() && inLayerShapes[0].size() == 4) + impl->size = Size(inLayerShapes[0][3], inLayerShapes[0][2]); +}; Model& Model::setInputSize(const Size& size) { diff --git a/modules/dnn/test/test_caffe_importer.cpp b/modules/dnn/test/test_caffe_importer.cpp index 22cedbb9d3..161db4d787 100644 --- a/modules/dnn/test/test_caffe_importer.cpp +++ b/modules/dnn/test/test_caffe_importer.cpp @@ -479,18 +479,17 @@ TEST_P(Test_Caffe_nets, DenseNet_121) applyTestTag(CV_TEST_TAG_MEMORY_512MB); checkBackend(); const string proto = findDataFile("dnn/DenseNet_121.prototxt", false); - const string model = findDataFile("dnn/DenseNet_121.caffemodel", false); + const string weights = findDataFile("dnn/DenseNet_121.caffemodel", false); Mat inp = imread(_tf("dog416.png")); - inp = blobFromImage(inp, 1.0 / 255, Size(224, 224), Scalar(), true, true); + Model model(proto, weights); + model.setInputScale(1.0 / 255).setInputSwapRB(true).setInputCrop(true); + std::vector outs; Mat ref = blobFromNPY(_tf("densenet_121_output.npy")); - Net net = readNetFromCaffe(proto, model); - net.setPreferableBackend(backend); - net.setPreferableTarget(target); - - net.setInput(inp); - Mat out = net.forward(); + model.setPreferableBackend(backend); + model.setPreferableTarget(target); + model.predict(inp, outs); // Reference is an array of 1000 values from a range [-6.16, 7.9] float l1 = default_l1, lInf = default_lInf; @@ -506,9 +505,9 @@ TEST_P(Test_Caffe_nets, DenseNet_121) { l1 = 0.11; lInf = 0.5; } - normAssert(out, ref, "", l1, lInf); + normAssert(outs[0], ref, "", l1, lInf); if (target != DNN_TARGET_MYRIAD || getInferenceEngineVPUType() != CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_X) - expectNoFallbacksFromIE(net); + expectNoFallbacksFromIE(model); } TEST(Test_Caffe, multiple_inputs) diff --git a/modules/dnn/test/test_ie_models.cpp b/modules/dnn/test/test_ie_models.cpp index 26983707b1..f3cf6c9e3b 100644 --- a/modules/dnn/test/test_ie_models.cpp +++ b/modules/dnn/test/test_ie_models.cpp @@ -240,20 +240,6 @@ void runIE(Target target, const std::string& xmlPath, const std::string& binPath infRequest.Infer(); } -std::vector getOutputsNames(const Net& net) -{ - std::vector names; - if (names.empty()) - { - std::vector outLayers = net.getUnconnectedOutLayers(); - std::vector layersNames = net.getLayerNames(); - names.resize(outLayers.size()); - for (size_t i = 0; i < outLayers.size(); ++i) - names[i] = layersNames[outLayers[i] - 1]; - } - return names; -} - void runCV(Target target, const std::string& xmlPath, const std::string& binPath, const std::map& inputsMap, std::map& outputsMap) @@ -263,7 +249,7 @@ void runCV(Target target, const std::string& xmlPath, const std::string& binPath net.setInput(it.second, it.first); net.setPreferableTarget(target); - std::vector outNames = getOutputsNames(net); + std::vector outNames = net.getUnconnectedOutLayersNames(); std::vector outs; net.forward(outs, outNames); @@ -319,5 +305,46 @@ INSTANTIATE_TEST_CASE_P(/**/, ) ); +typedef TestWithParam DNNTestHighLevelAPI; +TEST_P(DNNTestHighLevelAPI, predict) +{ + initDLDTDataPath(); + + Target target = (dnn::Target)(int)GetParam(); + bool isFP16 = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD); + + OpenVINOModelTestCaseInfo modelInfo = getOpenVINOTestModels().find("age-gender-recognition-retail-0013")->second; + + std::string modelPath = isFP16 ? modelInfo.modelPathFP16 : modelInfo.modelPathFP32; + + std::string xmlPath = findDataFile(modelPath + ".xml"); + std::string binPath = findDataFile(modelPath + ".bin"); + + Model model(xmlPath, binPath); + Mat frame = imread(findDataFile("dnn/googlenet_1.png")); + std::vector outs; + model.setPreferableBackend(DNN_BACKEND_INFERENCE_ENGINE); + model.setPreferableTarget(target); + model.predict(frame, outs); + + Net net = readNet(xmlPath, binPath); + Mat input = blobFromImage(frame, 1.0, Size(62, 62)); + net.setInput(input); + net.setPreferableBackend(DNN_BACKEND_INFERENCE_ENGINE); + net.setPreferableTarget(target); + + std::vector outNames = net.getUnconnectedOutLayersNames(); + std::vector refs; + net.forward(refs, outNames); + + CV_Assert(refs.size() == outs.size()); + for (int i = 0; i < refs.size(); ++i) + normAssert(outs[i], refs[i]); +} + +INSTANTIATE_TEST_CASE_P(/**/, + DNNTestHighLevelAPI, testing::ValuesIn(getAvailableTargets(DNN_BACKEND_INFERENCE_ENGINE)) +); + }} #endif // HAVE_INF_ENGINE