diff --git a/modules/dnn/include/opencv2/dnn/dnn.hpp b/modules/dnn/include/opencv2/dnn/dnn.hpp index a4bbffcf41..94e2ada3f1 100644 --- a/modules/dnn/include/opencv2/dnn/dnn.hpp +++ b/modules/dnn/include/opencv2/dnn/dnn.hpp @@ -384,7 +384,7 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN CV_WRAP Net(); //!< Default constructor. CV_WRAP ~Net(); //!< Destructor frees the net only if there aren't references to the net anymore. - /** @brief Create a network from Intel's Model Optimizer intermediate representation. + /** @brief Create a network from Intel's Model Optimizer intermediate representation (IR). * @param[in] xml XML configuration file with network's topology. * @param[in] bin Binary file with trained weights. * Networks imported from Intel's Model Optimizer are launched in Intel's Inference Engine @@ -392,6 +392,25 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN */ CV_WRAP static Net readFromModelOptimizer(const String& xml, const String& bin); + /** @brief Create a network from Intel's Model Optimizer in-memory buffers with intermediate representation (IR). + * @param[in] bufferModelConfig buffer with model's configuration. + * @param[in] bufferWeights buffer with model's trained weights. + * @returns Net object. + */ + CV_WRAP static + Net readFromModelOptimizer(const std::vector& bufferModelConfig, const std::vector& bufferWeights); + + /** @brief Create a network from Intel's Model Optimizer in-memory buffers with intermediate representation (IR). + * @param[in] bufferModelConfigPtr buffer pointer of model's configuration. + * @param[in] bufferModelConfigSize buffer size of model's configuration. + * @param[in] bufferWeightsPtr buffer pointer of model's trained weights. + * @param[in] bufferWeightsSize buffer size of model's trained weights. + * @returns Net object. + */ + static + Net readFromModelOptimizer(const uchar* bufferModelConfigPtr, size_t bufferModelConfigSize, + const uchar* bufferWeightsPtr, size_t bufferWeightsSize); + /** Returns true if there are no layers in the network. */ CV_WRAP bool empty() const; @@ -857,7 +876,31 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN * Networks imported from Intel's Model Optimizer are launched in Intel's Inference Engine * backend. */ - CV_EXPORTS_W Net readNetFromModelOptimizer(const String &xml, const String &bin); + CV_EXPORTS_W + Net readNetFromModelOptimizer(const String &xml, const String &bin); + + /** @brief Load a network from Intel's Model Optimizer intermediate representation. + * @param[in] bufferModelConfig Buffer contains XML configuration with network's topology. + * @param[in] bufferWeights Buffer contains binary data with trained weights. + * @returns Net object. + * Networks imported from Intel's Model Optimizer are launched in Intel's Inference Engine + * backend. + */ + CV_EXPORTS_W + Net readNetFromModelOptimizer(const std::vector& bufferModelConfig, const std::vector& bufferWeights); + + /** @brief Load a network from Intel's Model Optimizer intermediate representation. + * @param[in] bufferModelConfigPtr Pointer to buffer which contains XML configuration with network's topology. + * @param[in] bufferModelConfigSize Binary size of XML configuration data. + * @param[in] bufferWeightsPtr Pointer to buffer which contains binary data with trained weights. + * @param[in] bufferWeightsSize Binary size of trained weights data. + * @returns Net object. + * Networks imported from Intel's Model Optimizer are launched in Intel's Inference Engine + * backend. + */ + CV_EXPORTS + Net readNetFromModelOptimizer(const uchar* bufferModelConfigPtr, size_t bufferModelConfigSize, + const uchar* bufferWeightsPtr, size_t bufferWeightsSize); /** @brief Reads a network model ONNX. * @param onnxFile path to the .onnx file with text description of the network architecture. diff --git a/modules/dnn/src/dnn.cpp b/modules/dnn/src/dnn.cpp index eb87d2c348..462a4b9816 100644 --- a/modules/dnn/src/dnn.cpp +++ b/modules/dnn/src/dnn.cpp @@ -2951,28 +2951,22 @@ struct Net::Impl return getBlobAsync(getPinByAlias(outputName)); } #endif // CV_CXX11 + +#ifdef HAVE_INF_ENGINE + static + Net createNetworkFromModelOptimizer(InferenceEngine::CNNNetwork& ieNet); +#endif }; Net::Net() : impl(new Net::Impl) { } -Net Net::readFromModelOptimizer(const String& xml, const String& bin) +#ifdef HAVE_INF_ENGINE +/*static*/ +Net Net::Impl::createNetworkFromModelOptimizer(InferenceEngine::CNNNetwork& ieNet) { -#ifndef HAVE_INF_ENGINE - CV_Error(Error::StsError, "Build OpenCV with Inference Engine to enable loading models from Model Optimizer."); -#else - -#if INF_ENGINE_VER_MAJOR_LE(INF_ENGINE_RELEASE_2019R3) - InferenceEngine::CNNNetReader reader; - reader.ReadNetwork(xml); - reader.ReadWeights(bin); - - InferenceEngine::CNNNetwork ieNet = reader.getNetwork(); -#else - InferenceEngine::Core& ie = getCore(); - InferenceEngine::CNNNetwork ieNet = ie.ReadNetwork(xml, bin); -#endif + CV_TRACE_FUNCTION(); std::vector inputsNames; std::vector inp_shapes; @@ -3051,9 +3045,95 @@ Net Net::readFromModelOptimizer(const String& xml, const String& bin) cvNet.impl->skipInfEngineInit = true; return cvNet; +} +#endif // HAVE_INF_ENGINE + +Net Net::readFromModelOptimizer(const String& xml, const String& bin) +{ + CV_TRACE_FUNCTION(); +#ifndef HAVE_INF_ENGINE + CV_UNUSED(xml); CV_UNUSED(bin); + CV_Error(Error::StsError, "Build OpenCV with Inference Engine to enable loading models from Model Optimizer."); +#else +#if INF_ENGINE_VER_MAJOR_LE(INF_ENGINE_RELEASE_2019R3) + InferenceEngine::CNNNetReader reader; + reader.ReadNetwork(xml); + reader.ReadWeights(bin); + + InferenceEngine::CNNNetwork ieNet = reader.getNetwork(); +#else + InferenceEngine::Core& ie = getCore(); + InferenceEngine::CNNNetwork ieNet = ie.ReadNetwork(xml, bin); +#endif + + return Impl::createNetworkFromModelOptimizer(ieNet); #endif // HAVE_INF_ENGINE } +Net Net::readFromModelOptimizer(const std::vector& bufferModelConfig, const std::vector& bufferWeights) +{ + CV_TRACE_FUNCTION(); + CV_Assert(!bufferModelConfig.empty()); + CV_Assert(!bufferWeights.empty()); + return readFromModelOptimizer(bufferModelConfig.data(), bufferModelConfig.size(), + bufferWeights.data(), bufferWeights.size()); +} + +Net Net::readFromModelOptimizer( + const uchar* bufferModelConfigPtr, size_t bufferModelConfigSize, + const uchar* bufferWeightsPtr, size_t bufferWeightsSize +) +{ + CV_TRACE_FUNCTION(); +#ifndef HAVE_INF_ENGINE + CV_UNUSED(bufferModelConfigPtr); CV_UNUSED(bufferWeightsPtr); + CV_UNUSED(bufferModelConfigSize); CV_UNUSED(bufferModelConfigSize); + CV_Error(Error::StsError, "Build OpenCV with Inference Engine to enable loading models from Model Optimizer."); +#else + +#if INF_ENGINE_VER_MAJOR_LE(INF_ENGINE_RELEASE_2019R3) + InferenceEngine::CNNNetReader reader; + + try + { + reader.ReadNetwork(bufferModelConfigPtr, bufferModelConfigSize); + + InferenceEngine::TensorDesc tensorDesc(InferenceEngine::Precision::U8, { bufferWeightsSize }, InferenceEngine::Layout::C); + InferenceEngine::TBlob::Ptr weightsBlobPtr(new InferenceEngine::TBlob(tensorDesc)); + weightsBlobPtr->allocate(); + std::memcpy(weightsBlobPtr->buffer(), (uchar*)bufferWeightsPtr, bufferWeightsSize); + reader.SetWeights(weightsBlobPtr); + } + catch (const std::exception& e) + { + CV_Error(Error::StsError, std::string("DNN: IE failed to load model: ") + e.what()); + } + + InferenceEngine::CNNNetwork ieNet = reader.getNetwork(); +#else + InferenceEngine::Core& ie = getCore(); + + std::string model; model.assign((char*)bufferModelConfigPtr, bufferModelConfigSize); + + InferenceEngine::CNNNetwork ieNet; + try + { + InferenceEngine::TensorDesc tensorDesc(InferenceEngine::Precision::U8, { bufferWeightsSize }, InferenceEngine::Layout::C); + InferenceEngine::Blob::CPtr weights_blob = InferenceEngine::make_shared_blob(tensorDesc, (uint8_t*)bufferWeightsPtr, bufferWeightsSize); + + ieNet = ie.ReadNetwork(model, weights_blob); + } + catch (const std::exception& e) + { + CV_Error(Error::StsError, std::string("DNN: IE failed to load model: ") + e.what()); + } +#endif + + return Impl::createNetworkFromModelOptimizer(ieNet); +#endif // HAVE_INF_ENGINE +} + + Net::~Net() { } @@ -4394,7 +4474,7 @@ Net readNet(const String& _framework, const std::vector& bufferModel, else if (framework == "torch") CV_Error(Error::StsNotImplemented, "Reading Torch models from buffers"); else if (framework == "dldt") - CV_Error(Error::StsNotImplemented, "Reading Intel's Model Optimizer models from buffers"); + return readNetFromModelOptimizer(bufferConfig, bufferModel); CV_Error(Error::StsError, "Cannot determine an origin framework with a name " + framework); } @@ -4403,5 +4483,21 @@ Net readNetFromModelOptimizer(const String &xml, const String &bin) return Net::readFromModelOptimizer(xml, bin); } +Net readNetFromModelOptimizer(const std::vector& bufferCfg, const std::vector& bufferModel) +{ + return Net::readFromModelOptimizer(bufferCfg, bufferModel); +} + +Net readNetFromModelOptimizer( + const uchar* bufferModelConfigPtr, size_t bufferModelConfigSize, + const uchar* bufferWeightsPtr, size_t bufferWeightsSize +) +{ + return Net::readFromModelOptimizer( + bufferModelConfigPtr, bufferModelConfigSize, + bufferWeightsPtr, bufferWeightsSize + ); +} + CV__DNN_EXPERIMENTAL_NS_END }} // namespace diff --git a/modules/dnn/test/test_misc.cpp b/modules/dnn/test/test_misc.cpp index 464ef104b3..2069b97419 100644 --- a/modules/dnn/test/test_misc.cpp +++ b/modules/dnn/test/test_misc.cpp @@ -637,6 +637,60 @@ TEST_P(Test_Model_Optimizer, forward_two_nets) normAssert(ref0, ref2, 0, 0); } + +TEST_P(Test_Model_Optimizer, readFromBuffer) +{ + const Backend backendId = get<0>(GetParam()); + const Target targetId = get<1>(GetParam()); + + if (backendId != DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 && backendId != DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) + throw SkipTestException("No support for async forward"); + + const std::string suffix = (targetId == DNN_TARGET_OPENCL_FP16 || targetId == DNN_TARGET_MYRIAD) ? "_fp16" : ""; + const std::string& weightsFile = findDataFile("dnn/layers/layer_convolution" + suffix + ".bin"); + const std::string& modelFile = findDataFile("dnn/layers/layer_convolution" + suffix + ".xml"); + + if (backendId == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019) + setInferenceEngineBackendType(CV_DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_API); + else if (backendId == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) + setInferenceEngineBackendType(CV_DNN_BACKEND_INFERENCE_ENGINE_NGRAPH); + else + FAIL() << "Unknown backendId"; + + Net net1 = readNetFromModelOptimizer(modelFile, weightsFile); + net1.setPreferableBackend(backendId); + net1.setPreferableTarget(targetId); + + + std::vector modelConfig; + readFileContent(modelFile, modelConfig); + std::vector weights; + readFileContent(weightsFile, weights); + + Net net2 = readNetFromModelOptimizer( + (const uchar*)modelConfig.data(), modelConfig.size(), + (const uchar*)weights.data(), weights.size() + ); + net2.setPreferableBackend(backendId); + net2.setPreferableTarget(targetId); + + int blobSize[] = {2, 6, 75, 113}; + Mat input(4, &blobSize[0], CV_32F); + randu(input, 0, 255); + + Mat ref, actual; + { + net1.setInput(input); + ref = net1.forward(); + } + { + net2.setInput(input); + actual = net2.forward(); + } + + normAssert(ref, actual, "", 0, 0); +} + INSTANTIATE_TEST_CASE_P(/**/, Test_Model_Optimizer, dnnBackendsAndTargetsIE() );