diff --git a/modules/dnn/CMakeLists.txt b/modules/dnn/CMakeLists.txt index 76f4515f9a..dbe3d5e04c 100644 --- a/modules/dnn/CMakeLists.txt +++ b/modules/dnn/CMakeLists.txt @@ -504,7 +504,7 @@ set(dnn_plugin_srcs ${dnn_srcs} ${dnn_int_hdrs}) ocv_list_filterout_ex(dnn_plugin_srcs "/src/dnn.cpp$|/src/dnn_utils.cpp$|/src/dnn_read.cpp$|/src/registry.cpp$|/src/backend.cpp$" # importers - "/src/(caffe|darknet|onnx|tensorflow)/" + "/src/(caffe|onnx|tensorflow)/" # executors "/src/(cuda|cuda4dnn|ocl4dnn|vkcom|webnn)/" ) diff --git a/modules/dnn/include/opencv2/dnn/dnn.hpp b/modules/dnn/include/opencv2/dnn/dnn.hpp index bac8032481..9f7a515f7a 100644 --- a/modules/dnn/include/opencv2/dnn/dnn.hpp +++ b/modules/dnn/include/opencv2/dnn/dnn.hpp @@ -1066,31 +1066,6 @@ CV__DNN_INLINE_NS_BEGIN ENGINE_ORT=4 //!< Try to use ONNX Runtime wrapper (ONNX only, requires build with WITH_ONNXRUNTIME=ON). }; - /** @brief Reads a network model stored in Darknet model files. - * @param cfgFile path to the .cfg file with text description of the network architecture. - * @param darknetModel path to the .weights file with learned network. - * @returns Network object that ready to do forward, throw an exception in failure cases. - */ - CV_EXPORTS_W Net readNetFromDarknet(CV_WRAP_FILE_PATH const String &cfgFile, CV_WRAP_FILE_PATH const String &darknetModel = String()); - - /** @brief Reads a network model stored in Darknet model files. - * @param bufferCfg A buffer contains a content of .cfg file with text description of the network architecture. - * @param bufferModel A buffer contains a content of .weights file with learned network. - * @returns Net object. - */ - CV_EXPORTS_W Net readNetFromDarknet(const std::vector& bufferCfg, - const std::vector& bufferModel = std::vector()); - - /** @brief Reads a network model stored in Darknet model files. - * @param bufferCfg A buffer contains a content of .cfg file with text description of the network architecture. - * @param lenCfg Number of bytes to read from bufferCfg - * @param bufferModel A buffer contains a content of .weights file with learned network. - * @param lenModel Number of bytes to read from bufferModel - * @returns Net object. - */ - CV_EXPORTS Net readNetFromDarknet(const char *bufferCfg, size_t lenCfg, - const char *bufferModel = NULL, size_t lenModel = 0); - /** @brief Reads a network model stored in Caffe framework's format. * @param prototxt path to the .prototxt file with text description of the network architecture. * @param caffeModel path to the .caffemodel file with learned network. @@ -1204,14 +1179,12 @@ CV__DNN_INLINE_NS_BEGIN * extensions are expected for models from different frameworks: * * `*.caffemodel` (Caffe, http://caffe.berkeleyvision.org/) * * `*.pb` (TensorFlow, https://www.tensorflow.org/) - * * `*.weights` (Darknet, https://pjreddie.com/darknet/) * * `*.bin` | `*.onnx` (OpenVINO, https://software.intel.com/openvino-toolkit) * * `*.onnx` (ONNX, https://onnx.ai/) * @param[in] config Text file contains network configuration. It could be a * file with the following extensions: * * `*.prototxt` (Caffe, http://caffe.berkeleyvision.org/) * * `*.pbtxt` (TensorFlow, https://www.tensorflow.org/) - * * `*.cfg` (Darknet, https://pjreddie.com/darknet/) * * `*.xml` (OpenVINO, https://software.intel.com/openvino-toolkit) * @param[in] framework Explicit framework name tag to determine a format. * @param[in] engine select DNN engine to be used. With auto selection the new engine is used first and falls back to classic. @@ -1220,9 +1193,8 @@ CV__DNN_INLINE_NS_BEGIN * @returns Net object. * * This function automatically detects an origin framework of trained model - * and calls an appropriate function such @ref readNetFromCaffe, @ref readNetFromTensorflow - * or @ref readNetFromDarknet. An order of @p model and @p config - * arguments does not matter. + * and calls an appropriate function such @ref readNetFromCaffe, @ref readNetFromTensorflow. + * An order of @p model and @p config arguments does not matter. */ CV_EXPORTS_W Net readNet(CV_WRAP_FILE_PATH const String& model, CV_WRAP_FILE_PATH const String& config = "", diff --git a/modules/dnn/misc/js/gen_dict.json b/modules/dnn/misc/js/gen_dict.json index 4b83a0e102..e1b7f2ae2d 100644 --- a/modules/dnn/misc/js/gen_dict.json +++ b/modules/dnn/misc/js/gen_dict.json @@ -2,7 +2,7 @@ "whitelist": { "dnn_Net": ["setInput", "forward", "setPreferableBackend","getUnconnectedOutLayersNames"], - "": ["readNetFromCaffe", "readNetFromTensorflow", "readNetFromTorch", "readNetFromDarknet", + "": ["readNetFromCaffe", "readNetFromTensorflow", "readNetFromTorch", "readNetFromONNX", "readNetFromTFLite", "readNet", "blobFromImage"] }, "namespace_prefix_override": diff --git a/modules/dnn/misc/objc/gen_dict.json b/modules/dnn/misc/objc/gen_dict.json index 9e47677206..b94846bb2c 100644 --- a/modules/dnn/misc/objc/gen_dict.json +++ b/modules/dnn/misc/objc/gen_dict.json @@ -3,8 +3,6 @@ "Dnn": { "(Net*)readNetFromCaffe:(NSString*)prototxt caffeModel:(NSString*)caffeModel engine:(int)engine" : { "readNetFromCaffe" : {"name" : "readNetFromCaffeFile"} }, "(Net*)readNetFromCaffe:(ByteVector*)bufferProto bufferModel:(ByteVector*)bufferModel engine:(int)engine" : { "readNetFromCaffe" : {"name" : "readNetFromCaffeBuffer"} }, - "(Net*)readNetFromDarknet:(NSString*)cfgFile darknetModel:(NSString*)darknetModel" : { "readNetFromDarknet" : {"name" : "readNetFromDarknetFile"} }, - "(Net*)readNetFromDarknet:(ByteVector*)bufferCfg bufferModel:(ByteVector*)bufferModel" : { "readNetFromDarknet" : {"name" : "readNetFromDarknetBuffer"} }, "(Net*)readNetFromONNX:(NSString*)onnxFile engine:(int)engine" : { "readNetFromONNX" : {"name" : "readNetFromONNXFile"} }, "(Net*)readNetFromONNX:(ByteVector*)buffer engine:(int)engine" : { "readNetFromONNX" : {"name" : "readNetFromONNXBuffer"} }, "(Net*)readNetFromTensorflow:(NSString*)model config:(NSString*)config engine:(int)engine extraOutputs:(NSArray*)extraOutputs" : { "readNetFromTensorflow" : {"name" : "readNetFromTensorflowFile"} }, diff --git a/modules/dnn/perf/perf_net.cpp b/modules/dnn/perf/perf_net.cpp index 7a38ed4f49..357b930861 100644 --- a/modules/dnn/perf/perf_net.cpp +++ b/modules/dnn/perf/perf_net.cpp @@ -212,8 +212,9 @@ PERF_TEST_P_(DNNTestNetwork, YOLOv3) #endif Mat sample = imread(findDataFile("dnn/dog416.png")); + cv::resize(sample, sample, Size(640, 640)); Mat inp = blobFromImage(sample, 1.0 / 255.0, Size(), Scalar(), true); - processNet("dnn/yolov3.weights", "dnn/yolov3.cfg", inp); + processNet("dnn/yolov3.onnx", "", inp); } PERF_TEST_P_(DNNTestNetwork, YOLOv4) @@ -231,8 +232,9 @@ PERF_TEST_P_(DNNTestNetwork, YOLOv4) throw SkipTestException("Test is disabled in OpenVINO 2020.4"); #endif Mat sample = imread(findDataFile("dnn/dog416.png")); + cv::resize(sample, sample, Size(608, 608)); Mat inp = blobFromImage(sample, 1.0 / 255.0, Size(), Scalar(), true); - processNet("dnn/yolov4.weights", "dnn/yolov4.cfg", inp); + processNet("dnn/yolov4.onnx", "", inp); } PERF_TEST_P_(DNNTestNetwork, YOLOv4_tiny) @@ -243,7 +245,7 @@ PERF_TEST_P_(DNNTestNetwork, YOLOv4_tiny) #endif Mat sample = imread(findDataFile("dnn/dog416.png")); Mat inp = blobFromImage(sample, 1.0 / 255.0, Size(), Scalar(), true); - processNet("dnn/yolov4-tiny-2020-12.weights", "dnn/yolov4-tiny-2020-12.cfg", inp); + processNet("dnn/yolov4-tiny.onnx", "", inp); } PERF_TEST_P_(DNNTestNetwork, YOLOv5) { diff --git a/modules/dnn/src/darknet/darknet_importer.cpp b/modules/dnn/src/darknet/darknet_importer.cpp deleted file mode 100644 index 024c0b6c50..0000000000 --- a/modules/dnn/src/darknet/darknet_importer.cpp +++ /dev/null @@ -1,258 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// (3-clause BSD License) -// -// Copyright (C) 2017, Intel Corporation, all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * Neither the names of the copyright holders nor the names of the contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall copyright holders or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#include "../precomp.hpp" - -#include -#include -#include -#include -#include - -#include "darknet_io.hpp" - -#include - -namespace cv { -namespace dnn { -CV__DNN_INLINE_NS_BEGIN - -namespace -{ - -class DarknetImporter -{ - FPDenormalsIgnoreHintScope fp_denormals_ignore_scope; - - darknet::NetParameter net; - -public: - - DarknetImporter() {} - - DarknetImporter(std::istream &cfgStream, std::istream &darknetModelStream) - { - CV_TRACE_FUNCTION(); - - ReadNetParamsFromCfgStreamOrDie(cfgStream, &net); - ReadNetParamsFromBinaryStreamOrDie(darknetModelStream, &net); - } - - DarknetImporter(std::istream &cfgStream) - { - CV_TRACE_FUNCTION(); - - ReadNetParamsFromCfgStreamOrDie(cfgStream, &net); - } - - struct BlobNote - { - BlobNote(const std::string &_name, int _layerId, int _outNum) : - name(_name), layerId(_layerId), outNum(_outNum) {} - - std::string name; - int layerId, outNum; - }; - - std::vector addedBlobs; - std::map layerCounter; - - void populateNet(Net dstNet) - { - CV_TRACE_FUNCTION(); - - int layersSize = net.layer_size(); - layerCounter.clear(); - addedBlobs.clear(); - addedBlobs.reserve(layersSize + 1); - - //setup input layer names - { - std::vector netInputs(net.input_size()); - for (int inNum = 0; inNum < net.input_size(); inNum++) - { - addedBlobs.push_back(BlobNote(net.input(inNum), 0, inNum)); - netInputs[inNum] = net.input(inNum); - } - dstNet.setInputsNames(netInputs); - } - - for (int li = 0; li < layersSize; li++) - { - const darknet::LayerParameter &layer = net.layer(li); - String name = layer.name(); - String type = layer.type(); - LayerParams layerParams = layer.getLayerParams(); - - int repetitions = layerCounter[name]++; - if (repetitions) - name += cv::format("_%d", repetitions); - - int id = dstNet.addLayer(name, type, layerParams); - - // iterate many bottoms layers (for example for: route -1, -4) - for (int inNum = 0; inNum < layer.bottom_size(); inNum++) - addInput(layer.bottom(inNum), id, inNum, dstNet, layer.name()); - - for (int outNum = 0; outNum < layer.top_size(); outNum++) - addOutput(layer, id, outNum); - } - - addedBlobs.clear(); - } - - void addOutput(const darknet::LayerParameter &layer, int layerId, int outNum) - { - const std::string &name = layer.top(outNum); - - bool haveDups = false; - for (int idx = (int)addedBlobs.size() - 1; idx >= 0; idx--) - { - if (addedBlobs[idx].name == name) - { - haveDups = true; - break; - } - } - - if (haveDups) - { - bool isInplace = layer.bottom_size() > outNum && layer.bottom(outNum) == name; - if (!isInplace) - CV_Error(Error::StsBadArg, "Duplicate blobs produced by multiple sources"); - } - - addedBlobs.push_back(BlobNote(name, layerId, outNum)); - } - - void addInput(const std::string &name, int layerId, int inNum, Net &dstNet, std::string nn) - { - int idx; - for (idx = (int)addedBlobs.size() - 1; idx >= 0; idx--) - { - if (addedBlobs[idx].name == name) - break; - } - - if (idx < 0) - { - CV_Error(Error::StsObjectNotFound, "Can't find output blob \"" + name + "\""); - return; - } - - dstNet.connect(addedBlobs[idx].layerId, addedBlobs[idx].outNum, layerId, inNum); - } -}; - -static Net readNetFromDarknet(std::istream &cfgFile, std::istream &darknetModel) -{ - Net net; - DarknetImporter darknetImporter(cfgFile, darknetModel); - darknetImporter.populateNet(net); - return net; -} - -static Net readNetFromDarknet(std::istream &cfgFile) -{ - Net net; - DarknetImporter darknetImporter(cfgFile); - darknetImporter.populateNet(net); - return net; -} - -} - -Net readNetFromDarknet(const String &cfgFile, const String &darknetModel /*= String()*/) -{ - std::ifstream cfgStream(cfgFile.c_str()); - if (!cfgStream.is_open()) - { - CV_Error(cv::Error::StsParseError, "Failed to open NetParameter file: " + std::string(cfgFile)); - } - if (darknetModel != String()) - { - std::ifstream darknetModelStream(darknetModel.c_str(), std::ios::binary); - if (!darknetModelStream.is_open()) - { - CV_Error(cv::Error::StsParseError, "Failed to parse NetParameter file: " + std::string(darknetModel)); - } - return readNetFromDarknet(cfgStream, darknetModelStream); - } - else - return readNetFromDarknet(cfgStream); -} - -struct BufferStream : public std::streambuf -{ - BufferStream(const char* s, std::size_t n) - { - char* ptr = const_cast(s); - setg(ptr, ptr, ptr + n); - } -}; - -Net readNetFromDarknet(const char *bufferCfg, size_t lenCfg, const char *bufferModel, size_t lenModel) -{ - BufferStream cfgBufferStream(bufferCfg, lenCfg); - std::istream cfgStream(&cfgBufferStream); - if (lenModel) - { - BufferStream weightsBufferStream(bufferModel, lenModel); - std::istream weightsStream(&weightsBufferStream); - return readNetFromDarknet(cfgStream, weightsStream); - } - else - return readNetFromDarknet(cfgStream); -} - -Net readNetFromDarknet(const std::vector& bufferCfg, const std::vector& bufferModel) -{ - const char* bufferCfgPtr = reinterpret_cast(&bufferCfg[0]); - const char* bufferModelPtr = bufferModel.empty() ? NULL : - reinterpret_cast(&bufferModel[0]); - return readNetFromDarknet(bufferCfgPtr, bufferCfg.size(), - bufferModelPtr, bufferModel.size()); -} - -CV__DNN_INLINE_NS_END -}} // namespace diff --git a/modules/dnn/src/darknet/darknet_io.cpp b/modules/dnn/src/darknet/darknet_io.cpp deleted file mode 100644 index 674f2c2807..0000000000 --- a/modules/dnn/src/darknet/darknet_io.cpp +++ /dev/null @@ -1,1107 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// (3-clause BSD License) -// -// Copyright (C) 2017, Intel Corporation, all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * Neither the names of the copyright holders nor the names of the contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall copyright holders or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -/*M/////////////////////////////////////////////////////////////////////////////////////// -//MIT License -// -//Copyright (c) 2017 Joseph Redmon -// -//Permission is hereby granted, free of charge, to any person obtaining a copy -//of this software and associated documentation files (the "Software"), to deal -//in the Software without restriction, including without limitation the rights -//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -//copies of the Software, and to permit persons to whom the Software is -//furnished to do so, subject to the following conditions: -// -//The above copyright notice and this permission notice shall be included in all -//copies or substantial portions of the Software. -// -//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -//SOFTWARE. -// -//M*/ - -#include "../precomp.hpp" -#include - -#include -#include -#include - -#include "darknet_io.hpp" - -namespace cv { - namespace dnn { - namespace darknet { - - template - T getParam(const std::map ¶ms, const std::string param_name, T init_val) - { - std::map::const_iterator it = params.find(param_name); - if (it != params.end()) { - std::stringstream ss(it->second); - ss >> init_val; - } - return init_val; - } - - static const std::string kFirstLayerName = "data"; - - class setLayersParams { - - NetParameter *net; - int layer_id; - std::string last_layer; - std::vector fused_layer_names; - - public: - setLayersParams(NetParameter *_net) : - net(_net), layer_id(0), last_layer(kFirstLayerName) - {} - - void setLayerBlobs(int i, std::vector blobs) - { - cv::dnn::LayerParams ¶ms = net->layers[i].layerParams; - params.blobs = blobs; - } - - void setBatchNorm() - { - cv::dnn::LayerParams bn_param; - - bn_param.name = "BatchNorm-name"; - bn_param.type = "BatchNorm"; - bn_param.set("has_weight", true); - bn_param.set("has_bias", true); - bn_param.set("eps", 1E-6); // .000001f in Darknet Yolo - - darknet::LayerParameter lp; - std::string layer_name = cv::format("bn_%d", layer_id); - lp.layer_name = layer_name; - lp.layer_type = bn_param.type; - lp.layerParams = bn_param; - lp.bottom_indexes.push_back(last_layer); - last_layer = layer_name; - net->layers.push_back(lp); - } - - cv::dnn::LayerParams getParamConvolution(int kernel, int pad, - int stride, int filters_num) - { - cv::dnn::LayerParams params; - params.name = "Convolution-name"; - params.type = "Convolution"; - - params.set("kernel_size", kernel); - params.set("pad", pad); - params.set("stride", stride); - - params.set("bias_term", false); // true only if(BatchNorm == false) - params.set("num_output", filters_num); - - return params; - } - - - void setConvolution(int kernel, int pad, int stride, - int filters_num, int channels_num, int groups, int use_batch_normalize) - { - cv::dnn::LayerParams conv_param = - getParamConvolution(kernel, pad, stride, filters_num); - - darknet::LayerParameter lp; - std::string layer_name = cv::format("conv_%d", layer_id); - - // use BIAS in any case - if (!use_batch_normalize) { - conv_param.set("bias_term", true); - } - - conv_param.set("group", groups); - - lp.layer_name = layer_name; - lp.layer_type = conv_param.type; - lp.layerParams = conv_param; - lp.bottom_indexes.push_back(last_layer); - last_layer = layer_name; - net->layers.push_back(lp); - - if (use_batch_normalize) - setBatchNorm(); - - layer_id++; - fused_layer_names.push_back(last_layer); - } - - cv::dnn::LayerParams getParamFullyConnected(int output) - { - cv::dnn::LayerParams params; - params.name = "FullyConnected-name"; - params.type = "InnerProduct"; - - params.set("bias_term", false); // true only if(BatchNorm == false) - params.set("num_output", output); - - return params; - } - - void setFullyConnected(int output, int use_batch_normalize) - { - cv::dnn::LayerParams fullyconnected_param = - getParamFullyConnected(output); - - darknet::LayerParameter lp; - std::string layer_name = cv::format("fullyConnected_%d", layer_id); - - // use BIAS in any case - if (!use_batch_normalize) { - fullyconnected_param.set("bias_term", true); - } - - lp.layer_name = layer_name; - lp.layer_type = fullyconnected_param.type; - lp.layerParams = fullyconnected_param; - lp.bottom_indexes.push_back(last_layer); - last_layer = layer_name; - net->layers.push_back(lp); - - if (use_batch_normalize) - setBatchNorm(); - - layer_id++; - fused_layer_names.push_back(last_layer); - } - - void setActivation(String type) - { - cv::dnn::LayerParams activation_param; - if (type == "relu") - { - activation_param.type = "ReLU"; - } - else if (type == "leaky") - { - activation_param.set("negative_slope", 0.1f); - activation_param.type = "ReLU"; - } - else if (type == "swish" || type == "silu") // swish is an extension of silu. - { - activation_param.type = "Swish"; - } - else if (type == "mish") - { - activation_param.type = "Mish"; - } - else if (type == "logistic") - { - activation_param.type = "Sigmoid"; - } - else if (type == "tanh") - { - activation_param.type = "TanH"; - } - else - { - CV_Error(cv::Error::StsParseError, "Unsupported activation: " + type); - } - - std::string layer_name = cv::format("%s_%d", type.c_str(), layer_id); - - darknet::LayerParameter lp; - lp.layer_name = layer_name; - lp.layer_type = activation_param.type; - lp.layerParams = activation_param; - lp.bottom_indexes.push_back(last_layer); - last_layer = layer_name; - net->layers.push_back(lp); - - fused_layer_names.back() = last_layer; - } - - void setMaxpool(int kernel, int pad, int stride) - { - cv::dnn::LayerParams maxpool_param; - maxpool_param.set("pool", "max"); - maxpool_param.set("kernel_size", kernel); - maxpool_param.set("pad_l", floor((float)pad / 2)); - maxpool_param.set("pad_r", ceil((float)pad / 2)); - maxpool_param.set("pad_t", floor((float)pad / 2)); - maxpool_param.set("pad_b", ceil((float)pad / 2)); - maxpool_param.set("ceil_mode", false); - maxpool_param.set("stride", stride); - maxpool_param.name = "Pooling-name"; - maxpool_param.type = "Pooling"; - - darknet::LayerParameter lp; - std::string layer_name = cv::format("pool_%d", layer_id); - lp.layer_name = layer_name; - lp.layer_type = maxpool_param.type; - lp.layerParams = maxpool_param; - lp.bottom_indexes.push_back(last_layer); - last_layer = layer_name; - net->layers.push_back(lp); - layer_id++; - fused_layer_names.push_back(last_layer); - } - - void setAvgpool() - { - cv::dnn::LayerParams avgpool_param; - avgpool_param.set("pool", "ave"); - avgpool_param.set("global_pooling", true); - avgpool_param.name = "Pooling-name"; - avgpool_param.type = "Pooling"; - darknet::LayerParameter lp; - - std::string layer_name = cv::format("avgpool_%d", layer_id); - lp.layer_name = layer_name; - lp.layer_type = avgpool_param.type; - lp.layerParams = avgpool_param; - lp.bottom_indexes.push_back(last_layer); - last_layer = layer_name; - net->layers.push_back(lp); - layer_id++; - fused_layer_names.push_back(last_layer); - } - - void setCrop(int crop_height, int crop_width, int inp_height, int inp_width, bool noadjust) - { - cv::dnn::LayerParams crop_param; - crop_param.name = "CropLayer-name"; - std::vector begin = {0, 0, (inp_height - crop_height) / 2, (inp_width - crop_width) / 2}; - std::vector sizes = {-1, -1, crop_height, crop_width}; - crop_param.set("begin", DictValue::arrayInt(&begin[0], begin.size())); - crop_param.set("size", DictValue::arrayInt(&sizes[0], sizes.size())); - crop_param.type = "Slice"; - - darknet::LayerParameter lp; - std::string layer_name = cv::format("crop_%d", layer_id); - lp.layer_name = layer_name; - lp.layer_type = crop_param.type; - lp.layerParams = crop_param; - lp.bottom_indexes.push_back(last_layer); - last_layer = layer_name; - net->layers.push_back(lp); - layer_id++; - - if (!noadjust) - { - cv::dnn::LayerParams params; - params.set("bias_term", true); - params.blobs = { - Mat(1, 1, CV_32F, Scalar(2)), - Mat(1, 1, CV_32F, Scalar(-1)) - }; - - darknet::LayerParameter lp; - std::string layer_name = cv::format("adjust_crop_%d", layer_id); - lp.layer_name = layer_name; - lp.layer_type = "Scale"; - lp.layerParams = params; - lp.bottom_indexes.push_back(last_layer); - last_layer = layer_name; - net->layers.push_back(lp); - layer_id++; - } - fused_layer_names.push_back(last_layer); - } - - void setSoftmax() - { - cv::dnn::LayerParams softmax_param; - softmax_param.name = "Softmax-name"; - softmax_param.type = "Softmax"; - // set default axis to 1 - if(!softmax_param.has("axis")) - softmax_param.set("axis", 1); - darknet::LayerParameter lp; - - std::string layer_name = cv::format("softmax_%d", layer_id); - lp.layer_name = layer_name; - lp.layer_type = softmax_param.type; - lp.layerParams = softmax_param; - lp.bottom_indexes.push_back(last_layer); - last_layer = layer_name; - net->layers.push_back(lp); - layer_id++; - fused_layer_names.push_back(last_layer); - } - - void setConcat(int number_of_inputs, int *input_indexes) - { - cv::dnn::LayerParams concat_param; - concat_param.name = "Concat-name"; - concat_param.type = "Concat"; - concat_param.set("axis", 1); // channels are in axis = 1 - - darknet::LayerParameter lp; - - std::string layer_name = cv::format("concat_%d", layer_id); - lp.layer_name = layer_name; - lp.layer_type = concat_param.type; - lp.layerParams = concat_param; - for (int i = 0; i < number_of_inputs; ++i) - lp.bottom_indexes.push_back(fused_layer_names.at(input_indexes[i])); - - last_layer = layer_name; - net->layers.push_back(lp); - - layer_id++; - fused_layer_names.push_back(last_layer); - } - - void setIdentity(int bottom_index) - { - cv::dnn::LayerParams identity_param; - identity_param.name = "Identity-name"; - identity_param.type = "Identity"; - - darknet::LayerParameter lp; - - std::string layer_name = cv::format("identity_%d", layer_id); - lp.layer_name = layer_name; - lp.layer_type = identity_param.type; - lp.layerParams = identity_param; - lp.bottom_indexes.push_back(fused_layer_names.at(bottom_index)); - - last_layer = layer_name; - net->layers.push_back(lp); - - layer_id++; - fused_layer_names.push_back(last_layer); - } - - void setSlice(int input_index, int split_size, int group_id) - { - int begin[] = {0, split_size * group_id, 0, 0}; - cv::dnn::DictValue paramBegin = cv::dnn::DictValue::arrayInt(begin, 4); - - int end[] = {INT_MAX, begin[1] + split_size, INT_MAX, INT_MAX}; - cv::dnn::DictValue paramEnd = cv::dnn::DictValue::arrayInt(end, 4); - - darknet::LayerParameter lp; - lp.layer_name = cv::format("slice_%d", layer_id); - lp.layer_type = "Slice"; - lp.layerParams.set("begin", paramBegin); - lp.layerParams.set("end", paramEnd); - - lp.bottom_indexes.push_back(fused_layer_names.at(input_index)); - net->layers.push_back(lp); - - layer_id++; - last_layer = lp.layer_name; - fused_layer_names.push_back(last_layer); - } - - void setReorg(int stride) - { - cv::dnn::LayerParams reorg_params; - reorg_params.name = "Reorg-name"; - reorg_params.type = "Reorg"; - reorg_params.set("reorg_stride", stride); - - darknet::LayerParameter lp; - std::string layer_name = cv::format("reorg_%d", layer_id); - lp.layer_name = layer_name; - lp.layer_type = reorg_params.type; - lp.layerParams = reorg_params; - lp.bottom_indexes.push_back(last_layer); - last_layer = layer_name; - - net->layers.push_back(lp); - - layer_id++; - fused_layer_names.push_back(last_layer); - } - - void setPermute(bool isDarknetLayer = true) - { - cv::dnn::LayerParams permute_params; - permute_params.name = "Permute-name"; - permute_params.type = "Permute"; - int permute[] = { 0, 2, 3, 1 }; - cv::dnn::DictValue paramOrder = cv::dnn::DictValue::arrayInt(permute, 4); - - permute_params.set("order", paramOrder); - - darknet::LayerParameter lp; - std::string layer_name = cv::format("permute_%d", layer_id); - lp.layer_name = layer_name; - lp.layer_type = permute_params.type; - lp.layerParams = permute_params; - lp.bottom_indexes.push_back(last_layer); - last_layer = layer_name; - net->layers.push_back(lp); - - if (isDarknetLayer) - { - layer_id++; - fused_layer_names.push_back(last_layer); - } - } - - void setRegion(float thresh, int coords, int classes, int anchors, int classfix, int softmax, int softmax_tree, float *biasData) - { - cv::dnn::LayerParams region_param; - region_param.name = "Region-name"; - region_param.type = "Region"; - - region_param.set("thresh", thresh); - region_param.set("coords", coords); - region_param.set("classes", classes); - region_param.set("anchors", anchors); - region_param.set("classfix", classfix); - region_param.set("softmax_tree", softmax_tree); - region_param.set("softmax", softmax); - - cv::Mat biasData_mat = cv::Mat(1, anchors * 2, CV_32F, biasData).clone(); - region_param.blobs.push_back(biasData_mat); - - darknet::LayerParameter lp; - std::string layer_name = "detection_out"; - lp.layer_name = layer_name; - lp.layer_type = region_param.type; - lp.layerParams = region_param; - lp.bottom_indexes.push_back(last_layer); - last_layer = layer_name; - net->layers.push_back(lp); - - layer_id++; - fused_layer_names.push_back(last_layer); - } - - void setYolo(int classes, const std::vector& mask, const std::vector& anchors, float thresh, float nms_threshold, float scale_x_y, int new_coords) - { - cv::dnn::LayerParams region_param; - region_param.name = "Region-name"; - region_param.type = "Region"; - - const int numAnchors = mask.size(); - - region_param.set("classes", classes); - region_param.set("anchors", numAnchors); - region_param.set("logistic", true); - region_param.set("thresh", thresh); - region_param.set("nms_threshold", nms_threshold); - region_param.set("scale_x_y", scale_x_y); - region_param.set("new_coords", new_coords); - - std::vector usedAnchors(numAnchors * 2); - for (int i = 0; i < numAnchors; ++i) - { - usedAnchors[i * 2] = anchors[mask[i] * 2]; - usedAnchors[i * 2 + 1] = anchors[mask[i] * 2 + 1]; - } - - cv::Mat biasData_mat = cv::Mat(1, numAnchors * 2, CV_32F, &usedAnchors[0]).clone(); - region_param.blobs.push_back(biasData_mat); - - darknet::LayerParameter lp; - std::string layer_name = cv::format("yolo_%d", layer_id); - lp.layer_name = layer_name; - lp.layer_type = region_param.type; - lp.layerParams = region_param; - lp.bottom_indexes.push_back(last_layer); - lp.bottom_indexes.push_back(kFirstLayerName); - last_layer = layer_name; - net->layers.push_back(lp); - - layer_id++; - fused_layer_names.push_back(last_layer); - } - - void setShortcut(int from, float alpha) - { - cv::dnn::LayerParams shortcut_param; - shortcut_param.name = "Shortcut-name"; - shortcut_param.type = "Eltwise"; - - if (alpha != 1) - { - std::vector coeffs(2, 1); - coeffs[0] = alpha; - shortcut_param.set("coeff", DictValue::arrayReal(&coeffs[0], coeffs.size())); - } - - shortcut_param.set("op", "sum"); - shortcut_param.set("output_channels_mode", "input_0_truncate"); - - darknet::LayerParameter lp; - std::string layer_name = cv::format("shortcut_%d", layer_id); - lp.layer_name = layer_name; - lp.layer_type = shortcut_param.type; - lp.layerParams = shortcut_param; - lp.bottom_indexes.push_back(last_layer); - lp.bottom_indexes.push_back(fused_layer_names.at(from)); - last_layer = layer_name; - net->layers.push_back(lp); - - layer_id++; - fused_layer_names.push_back(last_layer); - } - - void setScaleChannels(int from) - { - cv::dnn::LayerParams shortcut_param; - shortcut_param.type = "Scale"; - - darknet::LayerParameter lp; - std::string layer_name = cv::format("scale_channels_%d", layer_id); - lp.layer_name = layer_name; - lp.layer_type = shortcut_param.type; - lp.layerParams = shortcut_param; - lp.bottom_indexes.push_back(fused_layer_names.at(from)); - lp.bottom_indexes.push_back(last_layer); - last_layer = layer_name; - net->layers.push_back(lp); - - layer_id++; - fused_layer_names.push_back(last_layer); - } - - void setSAM(int from) - { - cv::dnn::LayerParams eltwise_param; - eltwise_param.name = "SAM-name"; - eltwise_param.type = "Eltwise"; - - eltwise_param.set("operation", "prod"); - eltwise_param.set("output_channels_mode", "same"); - - darknet::LayerParameter lp; - std::string layer_name = cv::format("sam_%d", layer_id); - lp.layer_name = layer_name; - lp.layer_type = eltwise_param.type; - lp.layerParams = eltwise_param; - lp.bottom_indexes.push_back(last_layer); - lp.bottom_indexes.push_back(fused_layer_names.at(from)); - last_layer = layer_name; - net->layers.push_back(lp); - - layer_id++; - fused_layer_names.push_back(last_layer); - } - - void setUpsample(int scaleFactor) - { - cv::dnn::LayerParams param; - param.name = "Upsample-name"; - param.type = "Resize"; - - param.set("zoom_factor", scaleFactor); - param.set("interpolation", "nearest"); - - darknet::LayerParameter lp; - std::string layer_name = cv::format("upsample_%d", layer_id); - lp.layer_name = layer_name; - lp.layer_type = param.type; - lp.layerParams = param; - lp.bottom_indexes.push_back(last_layer); - last_layer = layer_name; - net->layers.push_back(lp); - - layer_id++; - fused_layer_names.push_back(last_layer); - } - }; - - std::string escapeString(const std::string &src) - { - std::string dst; - for (size_t i = 0; i < src.size(); ++i) - if (src[i] > ' ' && src[i] <= 'z') - dst += src[i]; - return dst; - } - - template - std::vector getNumbers(const std::string &src) - { - std::vector dst; - std::stringstream ss(src); - - for (std::string str; std::getline(ss, str, ',');) { - std::stringstream line(str); - T val; - line >> val; - dst.push_back(val); - } - return dst; - } - - bool ReadDarknetFromCfgStream(std::istream &ifile, NetParameter *net) - { - bool read_net = false; - int layers_counter = -1; - for (std::string line; std::getline(ifile, line);) { - line = escapeString(line); - if (line.empty()) continue; - switch (line[0]) { - case '\0': break; - case '#': break; - case ';': break; - case '[': - if (line == "[net]") { - read_net = true; - } - else { - // read section - read_net = false; - ++layers_counter; - const size_t layer_type_size = line.find(']') - 1; - CV_Assert(layer_type_size < line.size()); - std::string layer_type = line.substr(1, layer_type_size); - net->layers_cfg[layers_counter]["layer_type"] = layer_type; - } - break; - default: - // read entry - const size_t separator_index = line.find('='); - CV_Assert(separator_index < line.size()); - if (separator_index != std::string::npos) { - std::string name = line.substr(0, separator_index); - std::string value = line.substr(separator_index + 1, line.size() - (separator_index + 1)); - name = escapeString(name); - value = escapeString(value); - if (name.empty() || value.empty()) continue; - if (read_net) - net->net_cfg[name] = value; - else - net->layers_cfg[layers_counter][name] = value; - } - } - } - - std::string anchors = net->layers_cfg[net->layers_cfg.size() - 1]["anchors"]; - std::vector vec = getNumbers(anchors); - std::map &net_params = net->net_cfg; - net->width = getParam(net_params, "width", 416); - net->height = getParam(net_params, "height", 416); - net->channels = getParam(net_params, "channels", 3); - CV_Assert(net->width > 0 && net->height > 0 && net->channels > 0); - - MatShape tensor_shape(3); - tensor_shape[0] = net->channels; - tensor_shape[1] = net->height; - tensor_shape[2] = net->width; - net->out_channels_vec.resize(net->layers_cfg.size()); - - layers_counter = -1; - - setLayersParams setParams(net); - - typedef std::map >::iterator it_type; - for (it_type i = net->layers_cfg.begin(); i != net->layers_cfg.end(); ++i) { - ++layers_counter; - std::map &layer_params = i->second; - std::string layer_type = layer_params["layer_type"]; - - if (layer_type == "convolutional") - { - int kernel_size = getParam(layer_params, "size", -1); - int pad = getParam(layer_params, "pad", 0); - int padding = getParam(layer_params, "padding", 0); - int stride = getParam(layer_params, "stride", 1); - int filters = getParam(layer_params, "filters", -1); - int groups = getParam(layer_params, "groups", 1); - bool batch_normalize = getParam(layer_params, "batch_normalize", 0) == 1; - int flipped = getParam(layer_params, "flipped", 0); - if (flipped == 1) - CV_Error(cv::Error::StsNotImplemented, "Transpose the convolutional weights is not implemented"); - - if (pad) - padding = kernel_size / 2; - - // Cannot divide 0 - CV_Assert(stride > 0); - CV_Assert(kernel_size > 0 && filters > 0); - CV_Assert(tensor_shape[0] > 0); - CV_Assert(tensor_shape[0] % groups == 0); - - setParams.setConvolution(kernel_size, padding, stride, filters, tensor_shape[0], - groups, batch_normalize); - - tensor_shape[0] = filters; - tensor_shape[1] = (tensor_shape[1] - kernel_size + 2 * padding) / stride + 1; - tensor_shape[2] = (tensor_shape[2] - kernel_size + 2 * padding) / stride + 1; - } - else if (layer_type == "connected") - { - int output = getParam(layer_params, "output", 1); - bool batch_normalize = getParam(layer_params, "batch_normalize", 0) == 1; - - CV_Assert(output > 0); - - setParams.setFullyConnected(output, batch_normalize); - - if(layers_counter && tensor_shape[1] > 1) - net->out_channels_vec[layers_counter-1] = total(tensor_shape); - - tensor_shape[0] = output; - tensor_shape[1] = 1; - tensor_shape[2] = 1; - } - else if (layer_type == "maxpool") - { - int kernel_size = getParam(layer_params, "size", 2); - int stride = getParam(layer_params, "stride", 2); - int padding = getParam(layer_params, "padding", kernel_size - 1); - // Cannot divide 0 - CV_Assert(stride > 0); - - setParams.setMaxpool(kernel_size, padding, stride); - - tensor_shape[1] = (tensor_shape[1] - kernel_size + padding) / stride + 1; - tensor_shape[2] = (tensor_shape[2] - kernel_size + padding) / stride + 1; - } - else if (layer_type == "avgpool") - { - setParams.setAvgpool(); - tensor_shape[1] = 1; - tensor_shape[2] = 1; - } - else if (layer_type == "crop") - { - int crop_height = getParam(layer_params, "crop_height", 0); - int crop_width = getParam(layer_params, "crop_width", 0); - bool noadjust = getParam(layer_params, "noadjust", false); - CV_CheckGT(crop_height, 0, ""); - CV_CheckGT(crop_width, 0, ""); - - setParams.setCrop(crop_height, crop_width, tensor_shape[1], tensor_shape[2], noadjust); - - tensor_shape[1] = crop_height; - tensor_shape[2] = crop_width; - } - else if (layer_type == "softmax") - { - int groups = getParam(layer_params, "groups", 1); - if (groups != 1) - CV_Error(Error::StsNotImplemented, "Softmax from Darknet with groups != 1"); - setParams.setSoftmax(); - } - else if (layer_type == "route") - { - std::string bottom_layers = getParam(layer_params, "layers", ""); - CV_Assert(!bottom_layers.empty()); - int groups = getParam(layer_params, "groups", 1); - std::vector layers_vec = getNumbers(bottom_layers); - - tensor_shape[0] = 0; - for (size_t k = 0; k < layers_vec.size(); ++k) { - layers_vec[k] = layers_vec[k] >= 0 ? layers_vec[k] : (layers_vec[k] + layers_counter); - tensor_shape[0] += net->out_channels_vec[layers_vec[k]]; - } - - if (groups > 1) - { - int group_id = getParam(layer_params, "group_id", 0); - tensor_shape[0] /= groups; - int split_size = tensor_shape[0] / layers_vec.size(); - for (size_t k = 0; k < layers_vec.size(); ++k) - setParams.setSlice(layers_vec[k], split_size, group_id); - - if (layers_vec.size() > 1) - { - // layer ids in layers_vec - inputs of Slice layers - // after adding offset to layers_vec: layer ids - outputs of Slice layers - for (size_t k = 0; k < layers_vec.size(); ++k) - layers_vec[k] += layers_vec.size(); - - setParams.setConcat(layers_vec.size(), layers_vec.data()); - } - } - else - { - if (layers_vec.size() == 1) - setParams.setIdentity(layers_vec.at(0)); - else - setParams.setConcat(layers_vec.size(), layers_vec.data()); - } - } - else if (layer_type == "dropout" || layer_type == "cost") - { - setParams.setIdentity(layers_counter-1); - } - else if (layer_type == "reorg") - { - int stride = getParam(layer_params, "stride", 2); - // Cannot divide 0 - CV_Assert(stride > 0); - tensor_shape[0] = tensor_shape[0] * (stride * stride); - tensor_shape[1] = tensor_shape[1] / stride; - tensor_shape[2] = tensor_shape[2] / stride; - - setParams.setReorg(stride); - } - else if (layer_type == "region") - { - float thresh = getParam(layer_params, "thresh", 0.001); - int coords = getParam(layer_params, "coords", 4); - int classes = getParam(layer_params, "classes", -1); - int num_of_anchors = getParam(layer_params, "num", -1); - int classfix = getParam(layer_params, "classfix", 0); - bool softmax = (getParam(layer_params, "softmax", 0) == 1); - bool softmax_tree = (getParam(layer_params, "tree", "").size() > 0); - - std::string anchors_values = getParam(layer_params, "anchors", std::string()); - CV_Assert(!anchors_values.empty()); - std::vector anchors_vec = getNumbers(anchors_values); - - CV_Assert(classes > 0 && num_of_anchors > 0 && (num_of_anchors * 2) == anchors_vec.size()); - - setParams.setPermute(false); - setParams.setRegion(thresh, coords, classes, num_of_anchors, classfix, softmax, softmax_tree, anchors_vec.data()); - } - else if (layer_type == "shortcut") - { - std::string bottom_layer = getParam(layer_params, "from", ""); - float alpha = getParam(layer_params, "alpha", 1); - float beta = getParam(layer_params, "beta", 0); - if (beta != 0) - CV_Error(Error::StsNotImplemented, "Non-zero beta"); - CV_Assert(!bottom_layer.empty()); - int from = std::atoi(bottom_layer.c_str()); - - from = from < 0 ? from + layers_counter : from; - setParams.setShortcut(from, alpha); - } - else if (layer_type == "scale_channels") - { - std::string bottom_layer = getParam(layer_params, "from", ""); - CV_Assert(!bottom_layer.empty()); - int from = std::atoi(bottom_layer.c_str()); - from = from < 0 ? from + layers_counter : from; - setParams.setScaleChannels(from); - } - else if (layer_type == "sam") - { - std::string bottom_layer = getParam(layer_params, "from", ""); - CV_Assert(!bottom_layer.empty()); - int from = std::atoi(bottom_layer.c_str()); - from = from < 0 ? from + layers_counter : from; - setParams.setSAM(from); - } - else if (layer_type == "upsample") - { - int scaleFactor = getParam(layer_params, "stride", 1); - setParams.setUpsample(scaleFactor); - tensor_shape[1] = tensor_shape[1] * scaleFactor; - tensor_shape[2] = tensor_shape[2] * scaleFactor; - } - else if (layer_type == "yolo") - { - int classes = getParam(layer_params, "classes", -1); - int num_of_anchors = getParam(layer_params, "num", -1); - float thresh = getParam(layer_params, "thresh", 0.2); - float nms_threshold = getParam(layer_params, "nms_threshold", 0.0); - float scale_x_y = getParam(layer_params, "scale_x_y", 1.0); - int new_coords = getParam(layer_params, "new_coords", 0); - - std::string anchors_values = getParam(layer_params, "anchors", std::string()); - CV_Assert(!anchors_values.empty()); - std::vector anchors_vec = getNumbers(anchors_values); - - std::string mask_values = getParam(layer_params, "mask", std::string()); - CV_Assert(!mask_values.empty()); - std::vector mask_vec = getNumbers(mask_values); - - CV_Assert(classes > 0 && num_of_anchors > 0 && (num_of_anchors * 2) == anchors_vec.size()); - - setParams.setPermute(false); - setParams.setYolo(classes, mask_vec, anchors_vec, thresh, nms_threshold, scale_x_y, new_coords); - } - else { - CV_Error(cv::Error::StsParseError, "Unknown layer type: " + layer_type); - } - - std::string activation = getParam(layer_params, "activation", "linear"); - if (activation != "linear") - setParams.setActivation(activation); - - net->out_channels_vec[layers_counter] = tensor_shape[0]; - } - - return true; - } - - bool ReadDarknetFromWeightsStream(std::istream &ifile, NetParameter *net) - { - int32_t major_ver, minor_ver, revision; - ifile.read(reinterpret_cast(&major_ver), sizeof(int32_t)); - ifile.read(reinterpret_cast(&minor_ver), sizeof(int32_t)); - ifile.read(reinterpret_cast(&revision), sizeof(int32_t)); - - uint64_t seen; - if ((major_ver * 10 + minor_ver) >= 2) { - ifile.read(reinterpret_cast(&seen), sizeof(uint64_t)); - } - else { - int32_t iseen = 0; - ifile.read(reinterpret_cast(&iseen), sizeof(int32_t)); - seen = iseen; - } - bool transpose = (major_ver > 1000) || (minor_ver > 1000); - if(transpose) - CV_Error(cv::Error::StsNotImplemented, "Transpose the weights (except for convolutional) is not implemented"); - - MatShape tensor_shape(3); - tensor_shape[0] = net->channels; - tensor_shape[1] = net->height; - tensor_shape[2] = net->width; - int cv_layers_counter = -1; - int darknet_layers_counter = -1; - - setLayersParams setParams(net); - - typedef std::map >::iterator it_type; - for (it_type i = net->layers_cfg.begin(); i != net->layers_cfg.end(); ++i) { - ++darknet_layers_counter; - ++cv_layers_counter; - std::map &layer_params = i->second; - std::string layer_type = layer_params["layer_type"]; - - if (layer_type == "convolutional" || layer_type == "connected") - { - int filters; - bool use_batch_normalize; - cv::Mat weightsBlob; - if(layer_type == "convolutional") - { - int kernel_size = getParam(layer_params, "size", -1); - filters = getParam(layer_params, "filters", -1); - int groups = getParam(layer_params, "groups", 1); - use_batch_normalize = getParam(layer_params, "batch_normalize", 0) == 1; - - CV_Assert(kernel_size > 0 && filters > 0); - CV_Assert(tensor_shape[0] > 0); - CV_Assert(tensor_shape[0] % groups == 0); - - int sizes_weights[] = { filters, tensor_shape[0] / groups, kernel_size, kernel_size }; - weightsBlob.create(4, sizes_weights, CV_32F); - } - else - { - filters = getParam(layer_params, "output", 1); - use_batch_normalize = getParam(layer_params, "batch_normalize", 0) == 1; - - CV_Assert(filters>0); - - int sizes_weights[] = { filters, total(tensor_shape) }; - weightsBlob.create(2, sizes_weights, CV_32F); - } - CV_Assert(weightsBlob.isContinuous()); - - cv::Mat meanData_mat(1, filters, CV_32F); // mean - cv::Mat stdData_mat(1, filters, CV_32F); // variance - cv::Mat weightsData_mat(1, filters, CV_32F);// scale - cv::Mat biasData_mat(1, filters, CV_32F); // bias - - ifile.read(reinterpret_cast(biasData_mat.ptr()), sizeof(float)*filters); - if (use_batch_normalize) { - ifile.read(reinterpret_cast(weightsData_mat.ptr()), sizeof(float)*filters); - ifile.read(reinterpret_cast(meanData_mat.ptr()), sizeof(float)*filters); - ifile.read(reinterpret_cast(stdData_mat.ptr()), sizeof(float)*filters); - } - ifile.read(reinterpret_cast(weightsBlob.ptr()), sizeof(float)*weightsBlob.total()); - - // set conv/connected weights - std::vector layer_blobs; - layer_blobs.push_back(weightsBlob); - if (!use_batch_normalize) { - // use BIAS in any case - layer_blobs.push_back(biasData_mat); - } - setParams.setLayerBlobs(cv_layers_counter, layer_blobs); - - // set batch normalize (mean, variance, scale, bias) - if (use_batch_normalize) { - ++cv_layers_counter; - std::vector bn_blobs; - bn_blobs.push_back(meanData_mat); - bn_blobs.push_back(stdData_mat); - bn_blobs.push_back(weightsData_mat); - bn_blobs.push_back(biasData_mat); - setParams.setLayerBlobs(cv_layers_counter, bn_blobs); - } - } - if (layer_type == "region" || layer_type == "yolo") - { - ++cv_layers_counter; // For permute. - } - - std::string activation = getParam(layer_params, "activation", "linear"); - if (activation != "linear") - ++cv_layers_counter; // For ReLU, Swish, Mish, Sigmoid, etc - - if(!darknet_layers_counter) - tensor_shape.resize(1); - - tensor_shape[0] = net->out_channels_vec[darknet_layers_counter]; - } - return true; - } - - } - - - void ReadNetParamsFromCfgStreamOrDie(std::istream &ifile, darknet::NetParameter *net) - { - if (!darknet::ReadDarknetFromCfgStream(ifile, net)) { - CV_Error(cv::Error::StsParseError, "Failed to parse NetParameter stream"); - } - } - - void ReadNetParamsFromBinaryStreamOrDie(std::istream &ifile, darknet::NetParameter *net) - { - if (!darknet::ReadDarknetFromWeightsStream(ifile, net)) { - CV_Error(cv::Error::StsParseError, "Failed to parse NetParameter stream"); - } - } - } -} diff --git a/modules/dnn/src/darknet/darknet_io.hpp b/modules/dnn/src/darknet/darknet_io.hpp deleted file mode 100644 index f783ca7b49..0000000000 --- a/modules/dnn/src/darknet/darknet_io.hpp +++ /dev/null @@ -1,117 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// (3-clause BSD License) -// -// Copyright (C) 2017, Intel Corporation, all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * Neither the names of the copyright holders nor the names of the contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall copyright holders or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -/*M/////////////////////////////////////////////////////////////////////////////////////// -//MIT License -// -//Copyright (c) 2017 Joseph Redmon -// -//Permission is hereby granted, free of charge, to any person obtaining a copy -//of this software and associated documentation files (the "Software"), to deal -//in the Software without restriction, including without limitation the rights -//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -//copies of the Software, and to permit persons to whom the Software is -//furnished to do so, subject to the following conditions: -// -//The above copyright notice and this permission notice shall be included in all -//copies or substantial portions of the Software. -// -//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -//SOFTWARE. -// -//M*/ - -#ifndef __OPENCV_DNN_DARKNET_IO_HPP__ -#define __OPENCV_DNN_DARKNET_IO_HPP__ - -#include - -namespace cv { - namespace dnn { - namespace darknet { - - class LayerParameter { - std::string layer_name, layer_type; - std::vector bottom_indexes; - cv::dnn::LayerParams layerParams; - public: - friend class setLayersParams; - cv::dnn::LayerParams getLayerParams() const { return layerParams; } - std::string name() const { return layer_name; } - std::string type() const { return layer_type; } - int bottom_size() const { return bottom_indexes.size(); } - std::string bottom(const int index) const { return bottom_indexes.at(index); } - int top_size() const { return 1; } - std::string top(const int index) const { return layer_name; } - }; - - class NetParameter { - public: - int width, height, channels; - std::vector layers; - std::vector out_channels_vec; - - std::map > layers_cfg; - std::map net_cfg; - - NetParameter() : width(0), height(0), channels(0) {} - - int layer_size() const { return layers.size(); } - - int input_size() const { return 1; } - std::string input(const int index) const { return "data"; } - LayerParameter layer(const int index) const { return layers.at(index); } - }; - } - - // Read parameters from a stream into a NetParameter message. - void ReadNetParamsFromCfgStreamOrDie(std::istream &ifile, darknet::NetParameter *net); - void ReadNetParamsFromBinaryStreamOrDie(std::istream &ifile, darknet::NetParameter *net); - } -} -#endif diff --git a/modules/dnn/src/dnn_read.cpp b/modules/dnn/src/dnn_read.cpp index f28f7d0188..c3fcb9e147 100644 --- a/modules/dnn/src/dnn_read.cpp +++ b/modules/dnn/src/dnn_read.cpp @@ -37,7 +37,7 @@ Net readNet(const String& _model, const String& _config, const String& _framewor { if (modelExt == "cfg" || configExt == "weights") std::swap(model, config); - return readNetFromDarknet(config, model); + CV_Error(Error::StsError, "Darknet importer has been removed. Please use readNet(\"darknet\", ...) with ONNX-converted models or use an older OpenCV version."); } if (framework == "dldt" || framework == "openvino" || modelExt == "bin" || configExt == "bin" || @@ -65,7 +65,7 @@ Net readNet(const String& _framework, const std::vector& bufferModel, else if (framework == "tensorflow") return readNetFromTensorflow(bufferModel, bufferConfig, engine); else if (framework == "darknet") - return readNetFromDarknet(bufferConfig, bufferModel); + CV_Error(Error::StsError, "Darknet importer has been removed. Please use ONNX-converted models or use an older OpenCV version."); else if (framework == "dldt" || framework == "openvino") return readNetFromModelOptimizer(bufferConfig, bufferModel); else if (framework == "tflite") diff --git a/modules/dnn/test/test_common.hpp b/modules/dnn/test/test_common.hpp index f58aae736b..03c2354053 100644 --- a/modules/dnn/test/test_common.hpp +++ b/modules/dnn/test/test_common.hpp @@ -6,6 +6,7 @@ #define __OPENCV_TEST_COMMON_HPP__ #include "opencv2/dnn/utils/inference_engine.hpp" +#include #ifdef HAVE_OPENCL #include "opencv2/core/ocl.hpp" @@ -247,6 +248,23 @@ protected: void runLayer(cv::Ptr layer, std::vector &inpBlobs, std::vector &outBlobs); +inline std::string getCurrentTestNameNoParams() +{ + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + if (!test_info) + return std::string(); + std::string suite = test_info->test_case_name(); + std::string name = test_info->name(); + const auto suite_slash = suite.find('/'); + if (suite_slash != std::string::npos) + suite = suite.substr(0, suite_slash); + const auto name_slash = name.find('/'); + if (name_slash != std::string::npos) + name = name.substr(0, name_slash); + return suite + "." + name; +} + } // namespace #endif diff --git a/modules/dnn/test/test_darknet_importer.cpp b/modules/dnn/test/test_darknet_importer.cpp index 49982ec956..7970392103 100644 --- a/modules/dnn/test/test_darknet_importer.cpp +++ b/modules/dnn/test/test_darknet_importer.cpp @@ -53,145 +53,45 @@ static std::string _tf(TString filename) return (getOpenCVExtraDir() + "/dnn/") + filename; } -TEST(Test_Darknet, read_tiny_yolo_voc) +TEST(Test_YOLO, read_yolov4_onnx) { - Net net = readNetFromDarknet(_tf("tiny-yolo-voc.cfg")); + auto engine_forced = static_cast( + cv::utils::getConfigurationParameterSizeT("OPENCV_FORCE_DNN_ENGINE", cv::dnn::ENGINE_AUTO)); + if (engine_forced == cv::dnn::ENGINE_CLASSIC) + { + applyTestTag(CV_TEST_TAG_DNN_SKIP_PARSER); + return; + } + Net net = readNet(findDataFile("dnn/yolov4.onnx", false)); ASSERT_FALSE(net.empty()); } -TEST(Test_Darknet, read_yolo_voc) -{ - Net net = readNetFromDarknet(_tf("yolo-voc.cfg")); - ASSERT_FALSE(net.empty()); -} - -TEST(Test_Darknet, read_yolo_voc_stream) -{ - applyTestTag( - CV_TEST_TAG_MEMORY_1GB, - CV_TEST_TAG_DEBUG_VERYLONG - ); - Mat ref; - Mat sample = imread(_tf("dog416.png")); - Mat inp = blobFromImage(sample, 1.0/255, Size(416, 416), Scalar(), true, false); - const std::string cfgFile = findDataFile("dnn/yolo-voc.cfg"); - const std::string weightsFile = findDataFile("dnn/yolo-voc.weights", false); - // Import by paths. - { - Net net = readNetFromDarknet(cfgFile, weightsFile); - net.setInput(inp); - net.setPreferableBackend(DNN_BACKEND_OPENCV); - net.enableWinograd(false); - ref = net.forward(); - } - // Import from bytes array. - { - std::vector cfg, weights; - readFileContent(cfgFile, cfg); - readFileContent(weightsFile, weights); - - Net net = readNetFromDarknet(cfg.data(), cfg.size(), weights.data(), weights.size()); - net.setInput(inp); - net.setPreferableBackend(DNN_BACKEND_OPENCV); - net.enableWinograd(false); - Mat out = net.forward(); - normAssert(ref, out); - } -} - -class Test_Darknet_layers : public DNNTestLayer +class Test_YOLO_nets : public DNNTestLayer { public: - void testDarknetLayer(const std::string& name, bool hasWeights = false, bool testBatchProcessing = true, - double l1 = 0.0, double lInf = 0.0) + // Test object detection network from ONNX model. + void testYOLOModel(const std::string& model, + const std::vector >& refClassIds, + const std::vector >& refConfidences, + const std::vector >& refBoxes, + double scoreDiff, double iouDiff, float confThreshold = 0.24, + float nmsThreshold = 0.4, bool useWinograd = true, + int zeroPadW = 0, Size inputSize = Size()) { - SCOPED_TRACE(name); - Mat inp = blobFromNPY(findDataFile("dnn/darknet/" + name + "_in.npy")); - Mat ref = blobFromNPY(findDataFile("dnn/darknet/" + name + "_out.npy")); - l1 = l1 ? l1 : default_l1; - lInf = lInf ? lInf : default_lInf; - - std::string cfg = findDataFile("dnn/darknet/" + name + ".cfg"); - std::string model = ""; - if (hasWeights) - model = findDataFile("dnn/darknet/" + name + ".weights"); - - checkBackend(&inp, &ref); - - Net net = readNet(cfg, model); - net.setPreferableBackend(backend); - net.setPreferableTarget(target); - net.setInput(inp); - Mat out = net.forward(); - normAssert(out, ref, "", l1, lInf); - - if (inp.size[0] == 1 && testBatchProcessing) // test handling of batch size + auto engine_forced = static_cast( + cv::utils::getConfigurationParameterSizeT("OPENCV_FORCE_DNN_ENGINE", cv::dnn::ENGINE_AUTO)); + if (engine_forced == cv::dnn::ENGINE_CLASSIC) { - SCOPED_TRACE("batch size 2"); - -#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_LT(2021040000) - if (target == DNN_TARGET_MYRIAD && name == "shortcut") - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD); -#endif - - MatShape sz2 = shape(inp); - sz2[0] = 2; - - Net net2 = readNet(cfg, model); - net2.setPreferableBackend(backend); - net2.setPreferableTarget(target); - Range ranges0[4] = { Range(0, 1), Range::all(), Range::all(), Range::all() }; - Range ranges1[4] = { Range(1, 2), Range::all(), Range::all(), Range::all() }; - Mat inp2(sz2, inp.type(), Scalar::all(0)); - inp.copyTo(inp2(ranges0)); - inp.copyTo(inp2(ranges1)); - net2.setInput(inp2); - Mat out2 = net2.forward(); - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) - { - EXPECT_LT(cv::norm(out2(ranges0), out2(ranges1), NORM_INF), 1e-4) << "Batch result is not similar: " << name; - } - else - { - EXPECT_EQ(0, cv::norm(out2(ranges0), out2(ranges1), NORM_INF)) << "Batch result is not equal: " << name; - } - - Mat ref2 = ref; - if (ref.dims == 2 && out2.dims == 3) - { - int ref_3d_sizes[3] = {1, ref.rows, ref.cols}; - ref2 = Mat(3, ref_3d_sizes, ref.type(), (void*)ref.data); - } - /*else if (ref.dims == 3 && out2.dims == 4) - { - int ref_4d_sizes[4] = {1, ref.size[0], ref.size[1], ref.size[2]}; - ref2 = Mat(4, ref_4d_sizes, ref.type(), (void*)ref.data); - }*/ - ASSERT_EQ(out2.dims, ref2.dims) << ref.dims; - - normAssert(out2(ranges0), ref2, "", l1, lInf); - normAssert(out2(ranges1), ref2, "", l1, lInf); + applyTestTag(CV_TEST_TAG_DNN_SKIP_PARSER); + return; } - } -}; -class Test_Darknet_nets : public DNNTestLayer -{ -public: - // Test object detection network from Darknet framework. - void testDarknetModel(const std::string& cfg, const std::string& weights, - const std::vector >& refClassIds, - const std::vector >& refConfidences, - const std::vector >& refBoxes, - double scoreDiff, double iouDiff, float confThreshold = 0.24, - float nmsThreshold = 0.4, bool useWinograd = true, - int zeroPadW = 0) - { checkBackend(); Mat img1 = imread(_tf("dog416.png")); Mat img2 = imread(_tf("street.png")); - cv::resize(img2, img2, Size(416, 416)); + cv::resize(img1, img1, inputSize); + cv::resize(img2, img2, inputSize); // Pad images by black pixel at the right to test not equal width and height sizes if (zeroPadW) { @@ -209,8 +109,7 @@ public: Mat inp = blobFromImages(samples, 1.0/255, Size(), Scalar(), true, false); - Net net = readNet(findDataFile("dnn/" + cfg), - findDataFile("dnn/" + weights, false)); + Net net = readNet(findDataFile("dnn/" + model, false)); net.setPreferableBackend(backend); net.setPreferableTarget(target); net.enableWinograd(useWinograd); @@ -218,41 +117,118 @@ public: std::vector outs; net.forward(outs, net.getUnconnectedOutLayersNames()); + // Detect output format: pytorch-YOLOv4 exports "boxes" [batch, N, 1, 4] + "confs" [batch, N, classes] + bool isBoxConfsFormat = (outs.size() == 2 && outs[0].dims == 4 && outs[0].size[outs[0].dims - 1] == 4); + // Detect 3-output format: boxes [batch, N, 4] + scores [batch, N] + class_idx [batch, N] + bool isBoxScoresIdxFormat = (outs.size() == 3 && outs[0].dims == 3 && outs[0].size[2] == 4); + for (int b = 0; b < batch_size; ++b) { std::vector classIds; std::vector confidences; std::vector boxes; - for (int i = 0; i < outs.size(); ++i) + if (isBoxScoresIdxFormat) { - Mat out; - if (batch_size > 1){ - // get the sample slice from 3D matrix (batch, box, classes+5) - Range ranges[3] = {Range(b, b+1), Range::all(), Range::all()}; - out = outs[i](ranges).reshape(1, outs[i].size[1]); - }else{ - out = outs[i]; - } - for (int j = 0; j < out.rows; ++j) + // yolov3-style format: boxes [batch, N, 4] + scores [batch, N] + class_idx [batch, N] + // boxes are [x1, y1, x2, y2] in pixel coords (relative to model input size) + int N = outs[0].size[1]; + float* boxesPtr = outs[0].ptr(b); + float* scoresPtr = outs[1].ptr(b); + float* classIdxPtr = outs[2].ptr(b); + + float modelW = (float)inp.size[3]; + float modelH = (float)inp.size[2]; + + for (int j = 0; j < N; ++j) { - Mat scores = out.row(j).colRange(5, out.cols); + float score = scoresPtr[j]; + if (score > confThreshold) + { + float x1 = boxesPtr[j * 4 + 0] / modelW; + float y1 = boxesPtr[j * 4 + 1] / modelH; + float x2 = boxesPtr[j * 4 + 2] / modelW; + float y2 = boxesPtr[j * 4 + 3] / modelH; + boxes.push_back(Rect2d(x1, y1, x2 - x1, y2 - y1)); + confidences.push_back(score); + classIds.push_back((int)classIdxPtr[j]); + } + } + } + else if (isBoxConfsFormat) + { + // boxes [batch, N, 1, 4] (x1,y1,x2,y2), confs [batch, N, num_classes] + Mat boxesMat = outs[0]; + Mat confsMat = outs[1]; + if (batch_size > 1) + { + if (boxesMat.dims == 4) { + Range boxRanges[4] = {Range(b, b+1), Range::all(), Range::all(), Range::all()}; + boxesMat = boxesMat(boxRanges); + } else { + Range boxRanges[3] = {Range(b, b+1), Range::all(), Range::all()}; + boxesMat = boxesMat(boxRanges); + } + Range confRanges[3] = {Range(b, b+1), Range::all(), Range::all()}; + confsMat = confsMat(confRanges); + } + + int numBoxes = (int)(boxesMat.total() / 4); + boxesMat = boxesMat.reshape(1, numBoxes); + confsMat = confsMat.reshape(1, numBoxes); + + for (int j = 0; j < numBoxes; ++j) + { + Mat scores = confsMat.row(j); double confidence; Point maxLoc; minMaxLoc(scores, 0, &confidence, 0, &maxLoc); if (confidence > confThreshold) { - float* detection = out.ptr(j); - double centerX = detection[0]; - double centerY = detection[1]; - double width = detection[2]; - double height = detection[3]; - boxes.push_back(Rect2d(centerX - 0.5 * width, centerY - 0.5 * height, - width, height)); + float* box = boxesMat.ptr(j); + double x1 = box[0]; + double y1 = box[1]; + double x2 = box[2]; + double y2 = box[3]; + boxes.push_back(Rect2d(x1, y1, x2 - x1, y2 - y1)); confidences.push_back(confidence); classIds.push_back(maxLoc.x); } } } + else + { + for (int i = 0; i < (int)outs.size(); ++i) + { + Mat out; + if (batch_size > 1){ + Range ranges[3] = {Range(b, b+1), Range::all(), Range::all()}; + out = outs[i](ranges).reshape(1, outs[i].size[1]); + }else{ + out = outs[i]; + } + for (int j = 0; j < out.rows; ++j) + { + float objConf = out.at(j, 4); + Mat scores = out.row(j).colRange(5, out.cols); + double maxClsScore; + Point maxLoc; + minMaxLoc(scores, 0, &maxClsScore, 0, &maxLoc); + double confidence = objConf * maxClsScore; + + if (confidence > confThreshold) { + float* detection = out.ptr(j); + double centerX = detection[0]; + double centerY = detection[1]; + double width = detection[2]; + double height = detection[3]; + boxes.push_back(Rect2d(centerX - 0.5 * width, centerY - 0.5 * height, + width, height)); + confidences.push_back(confidence); + classIds.push_back(maxLoc.x); + } + } + } + } // here we need NMS of boxes std::vector indices; @@ -300,25 +276,25 @@ public: } } - void testDarknetModel(const std::string& cfg, const std::string& weights, - const std::vector& refClassIds, - const std::vector& refConfidences, - const std::vector& refBoxes, - double scoreDiff, double iouDiff, float confThreshold = 0.24, - float nmsThreshold = 0.4, bool useWinograd = true, - int zeroPadW = 0) + void testYOLOModel(const std::string& model, + const std::vector& refClassIds, + const std::vector& refConfidences, + const std::vector& refBoxes, + double scoreDiff, double iouDiff, float confThreshold = 0.24, + float nmsThreshold = 0.4, bool useWinograd = true, + int zeroPadW = 0, Size inputSize = Size()) { - testDarknetModel(cfg, weights, - std::vector >(1, refClassIds), - std::vector >(1, refConfidences), - std::vector >(1, refBoxes), - scoreDiff, iouDiff, confThreshold, nmsThreshold, useWinograd, zeroPadW); + testYOLOModel(model, + std::vector >(1, refClassIds), + std::vector >(1, refConfidences), + std::vector >(1, refBoxes), + scoreDiff, iouDiff, confThreshold, nmsThreshold, useWinograd, zeroPadW, inputSize); } - void testDarknetModel(const std::string& cfg, const std::string& weights, - const cv::Mat& ref, double scoreDiff, double iouDiff, - float confThreshold = 0.24, float nmsThreshold = 0.4, bool useWinograd = true, - int zeroPadW = 0) + void testYOLOModel(const std::string& model, + const cv::Mat& ref, double scoreDiff, double iouDiff, + float confThreshold = 0.24, float nmsThreshold = 0.4, bool useWinograd = true, + int zeroPadW = 0, Size inputSize = Size()) { CV_Assert(ref.cols == 7); std::vector > refClassIds; @@ -334,7 +310,7 @@ public: float right = ref.at(i, 5); float bottom = ref.at(i, 6); Rect2d box(left, top, right - left, bottom - top); - if (batchId >= refClassIds.size()) + if (batchId >= (int)refClassIds.size()) { refClassIds.resize(batchId + 1); refScores.resize(batchId + 1); @@ -344,381 +320,12 @@ public: refScores[batchId].push_back(score); refBoxes[batchId].push_back(box); } - testDarknetModel(cfg, weights, refClassIds, refScores, refBoxes, - scoreDiff, iouDiff, confThreshold, nmsThreshold, useWinograd, zeroPadW); + testYOLOModel(model, refClassIds, refScores, refBoxes, + scoreDiff, iouDiff, confThreshold, nmsThreshold, useWinograd, zeroPadW, inputSize); } }; -TEST_P(Test_Darknet_nets, YoloVoc) -{ - applyTestTag( -#if defined(OPENCV_32BIT_CONFIGURATION) && defined(HAVE_OPENCL) - CV_TEST_TAG_MEMORY_2GB, -#else - CV_TEST_TAG_MEMORY_1GB, -#endif - CV_TEST_TAG_LONG, - CV_TEST_TAG_DEBUG_VERYLONG - ); - -#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2020040000) // nGraph compilation failure - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL, CV_TEST_TAG_DNN_SKIP_IE_VERSION); - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL_FP16) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#elif defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_GE(2019010000) - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 && target == DNN_TARGET_OPENCL_FP16) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16); -#elif defined(INF_ENGINE_RELEASE) - if ((backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 || backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) && - target == DNN_TARGET_MYRIAD && getInferenceEngineVPUType() == CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_X) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD_X); // need to update check function -#endif - - // batchId, classId, confidence, left, top, right, bottom - Mat ref = (Mat_(6, 7) << 0, 6, 0.750469f, 0.577374f, 0.127391f, 0.902949f, 0.300809f, // a car - 0, 1, 0.780879f, 0.270762f, 0.264102f, 0.732475f, 0.745412f, // a bicycle - 0, 11, 0.901615f, 0.1386f, 0.338509f, 0.421337f, 0.938789f, // a dog - 1, 14, 0.623813f, 0.183179f, 0.381921f, 0.247726f, 0.625847f, // a person - 1, 6, 0.667770f, 0.446555f, 0.453578f, 0.499986f, 0.519167f, // a car - 1, 6, 0.844947f, 0.637058f, 0.460398f, 0.828508f, 0.66427f); // a car - - double nmsThreshold = (target == DNN_TARGET_MYRIAD || target == DNN_TARGET_CPU_FP16) ? 0.397 : 0.4; - double scoreDiff = 8e-5, iouDiff = 3e-4; - if (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD || target == DNN_TARGET_CPU_FP16) - { - scoreDiff = 1e-2; - iouDiff = 0.018; - } - else if (target == DNN_TARGET_CUDA_FP16) - { - scoreDiff = 0.03; - iouDiff = 0.018; - } -#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2022010000) - // accuracy - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL_FP16) - { - iouDiff = std::numeric_limits::quiet_NaN(); - } - // accuracy - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_MYRIAD) - { - iouDiff = std::numeric_limits::quiet_NaN(); - } -#elif defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2021040000) - // accuracy - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL_FP16) - { - iouDiff = std::numeric_limits::quiet_NaN(); - } - // accuracy - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_MYRIAD) - { - iouDiff = std::numeric_limits::quiet_NaN(); - } -#endif - - std::string config_file = "yolo-voc.cfg"; - std::string weights_file = "yolo-voc.weights"; - - { - SCOPED_TRACE("batch size 1"); - testDarknetModel(config_file, weights_file, ref.rowRange(0, 3), scoreDiff, iouDiff, 0.24, 0.4, false); - } - -#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2022010000) - // Exception: input != output - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_MYRIAD) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#elif defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2021040000) - // [ GENERAL_ERROR ] AssertionFailed: input != output - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_MYRIAD) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#endif - { - SCOPED_TRACE("batch size 2"); - testDarknetModel(config_file, weights_file, ref, scoreDiff, iouDiff, 0.24, nmsThreshold, false); - } - -#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2022010000) - // accuracy - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL_FP16) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#elif defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2021040000) - // accuracy - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL_FP16) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#endif -} - -TEST_P(Test_Darknet_nets, TinyYoloVoc) -{ - applyTestTag(CV_TEST_TAG_MEMORY_512MB); - -#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2020040000) // nGraph compilation failure - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL, CV_TEST_TAG_DNN_SKIP_IE_VERSION); - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL_FP16) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#endif -#if defined(INF_ENGINE_RELEASE) - if ((backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 || backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) && - target == DNN_TARGET_MYRIAD && getInferenceEngineVPUType() == CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_X) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD_X); // need to update check function -#endif - // batchId, classId, confidence, left, top, right, bottom - Mat ref = (Mat_(4, 7) << 0, 6, 0.761967f, 0.579042f, 0.159161f, 0.894482f, 0.31994f, // a car - 0, 11, 0.780595f, 0.129696f, 0.386467f, 0.445275f, 0.920994f, // a dog - 1, 6, 0.651450f, 0.460526f, 0.458019f, 0.522527f, 0.5341f, // a car - 1, 6, 0.928758f, 0.651024f, 0.463539f, 0.823784f, 0.654998f); // a car - - double scoreDiff = 8e-5, iouDiff = 3e-4; - bool useWinograd = true; - if (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) - { - scoreDiff = 8e-3; - iouDiff = 0.018; - } - else if(target == DNN_TARGET_CUDA_FP16) - { - scoreDiff = 0.008; - iouDiff = 0.02; - } - else if (target == DNN_TARGET_CPU_FP16) - { - useWinograd = false; - scoreDiff = 8e-3; - iouDiff = 0.018; - } - - std::string config_file = "tiny-yolo-voc.cfg"; - std::string weights_file = "tiny-yolo-voc.weights"; - - { - SCOPED_TRACE("batch size 1"); - testDarknetModel(config_file, weights_file, ref.rowRange(0, 2), scoreDiff, iouDiff, 0.24, 0.4, useWinograd); - } - - { - SCOPED_TRACE("batch size 2"); - testDarknetModel(config_file, weights_file, ref, scoreDiff, iouDiff, 0.24, 0.4, useWinograd); - } -} - -#ifdef HAVE_INF_ENGINE -static const std::chrono::milliseconds async_timeout(10000); - -typedef testing::TestWithParam > > Test_Darknet_nets_async; -TEST_P(Test_Darknet_nets_async, Accuracy) -{ - Backend backendId = get<0>(get<1>(GetParam())); - Target targetId = get<1>(get<1>(GetParam())); - std::string prefix = get<0>(GetParam()); - - applyTestTag(CV_TEST_TAG_MEMORY_512MB); - -#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_LT(2021040000) - if (INF_ENGINE_VER_MAJOR_LT(2019020000) && backendId == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_NN_BUILDER); - - if (backendId == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_NGRAPH); -#endif - - if (backendId != DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 && backendId != DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) - throw SkipTestException("No support for async forward"); - -#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2022010000) - if (targetId == DNN_TARGET_MYRIAD && prefix == "yolov3") // NC_OUT_OF_MEMORY - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#elif defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2021040000) - if (targetId == DNN_TARGET_MYRIAD && prefix == "yolov3") // NC_OUT_OF_MEMORY - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#elif defined(INF_ENGINE_RELEASE) - if (targetId == DNN_TARGET_MYRIAD && prefix == "yolov4") // NC_OUT_OF_MEMORY - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#endif - - const int numInputs = 2; - std::vector inputs(numInputs); - int blobSize[] = {1, 3, 416, 416}; - for (int i = 0; i < numInputs; ++i) - { - inputs[i].create(4, &blobSize[0], CV_32F); - randu(inputs[i], 0, 1); - } - - Net netSync = readNet(findDataFile("dnn/" + prefix + ".cfg"), - findDataFile("dnn/" + prefix + ".weights", false)); - netSync.setPreferableBackend(backendId); - netSync.setPreferableTarget(targetId); - - // Run synchronously. - std::vector refs(numInputs); - for (int i = 0; i < numInputs; ++i) - { - netSync.setInput(inputs[i]); - refs[i] = netSync.forward().clone(); - } - - Net netAsync = readNet(findDataFile("dnn/" + prefix + ".cfg"), - findDataFile("dnn/" + prefix + ".weights", false)); - netAsync.setPreferableBackend(backendId); - netAsync.setPreferableTarget(targetId); - - double l1 = 0.0; - double lInf = 0.0; -#if defined(INF_ENGINE_RELEASE) - if (backendId == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) - { - if (targetId == DNN_TARGET_MYRIAD && prefix == "yolo-voc") - { - l1 = 0.02; - lInf = 0.15; - } - if (targetId == DNN_TARGET_OPENCL_FP16 && prefix == "yolo-voc") - { - l1 = 0.02; - lInf = 0.1; - } - if (targetId == DNN_TARGET_OPENCL_FP16 && prefix == "yolov3") - { - l1 = 0.001; - lInf = 0.007; - } - if (targetId == DNN_TARGET_OPENCL_FP16 && prefix == "yolov4") - { - l1 = 0.001; - lInf = 0.005; - } - if (INF_ENGINE_VER_MAJOR_EQ(2021040000) && targetId == DNN_TARGET_OPENCL_FP16 && prefix == "yolov4-tiny-2020-12") // FIXIT: 4.x only, 3.4 branch works well - { - l1 = 0.001; - lInf = 0.005; - } - if (INF_ENGINE_VER_MAJOR_EQ(2022010000) && targetId == DNN_TARGET_OPENCL_FP16 && prefix == "yolov4-tiny-2020-12") // FIXIT: 4.x only, 3.4 branch works well - { - l1 = 0.001; - lInf = 0.005; - } - if (targetId == DNN_TARGET_MYRIAD && prefix == "yolov4") - { - l1 = 0.005; - lInf = 1.6f; // |ref| = 0.95431125164031982 - } - } -#endif - - // Run asynchronously. To make test more robust, process inputs in the reversed order. - for (int i = numInputs - 1; i >= 0; --i) - { - netAsync.setInput(inputs[i]); - - AsyncArray out = netAsync.forwardAsync(); - ASSERT_TRUE(out.valid()); - Mat result; - EXPECT_TRUE(out.get(result, async_timeout)); - normAssert(refs[i], result, format("Index: %d", i).c_str(), l1, lInf); - } -} - -INSTANTIATE_TEST_CASE_P(/**/, Test_Darknet_nets_async, Combine( - Values("yolo-voc", "tiny-yolo-voc", "yolov3", "yolov4", "yolov4-tiny-2020-12"), - dnnBackendsAndTargets() -)); - -#endif - -TEST_P(Test_Darknet_nets, YOLOv3) -{ - applyTestTag( - CV_TEST_TAG_LONG, - CV_TEST_TAG_MEMORY_2GB, - CV_TEST_TAG_DEBUG_VERYLONG - ); - -#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2020040000) // nGraph compilation failure - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL, CV_TEST_TAG_DNN_SKIP_IE_VERSION); - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL_FP16) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#endif - - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_MYRIAD) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH); - - // batchId, classId, confidence, left, top, right, bottom - const int N0 = 3; - const int N1 = 6; - static const float ref_[/* (N0 + N1) * 7 */] = { -0, 16, 0.998836f, 0.160024f, 0.389964f, 0.417885f, 0.943716f, -0, 1, 0.987908f, 0.150913f, 0.221933f, 0.742255f, 0.746261f, -0, 7, 0.952983f, 0.614621f, 0.150257f, 0.901368f, 0.289251f, - -1, 2, 0.997412f, 0.647584f, 0.459939f, 0.821037f, 0.663947f, -1, 2, 0.989633f, 0.450719f, 0.463353f, 0.496306f, 0.522258f, -1, 0, 0.980053f, 0.195856f, 0.378454f, 0.258626f, 0.629257f, -1, 9, 0.785341f, 0.665503f, 0.373543f, 0.688893f, 0.439244f, -1, 9, 0.733275f, 0.376029f, 0.315694f, 0.401776f, 0.395165f, -1, 9, 0.384815f, 0.659824f, 0.372389f, 0.673927f, 0.429412f, - }; - Mat ref(N0 + N1, 7, CV_32FC1, (void*)ref_); - - double scoreDiff = 8e-5, iouDiff = 3e-4; - if (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD || target == DNN_TARGET_CPU_FP16) - { -#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_GE(2022010000) - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) - scoreDiff = 0.009; - else -#endif - scoreDiff = 0.006; - iouDiff = 0.042; - } - else if (target == DNN_TARGET_CUDA_FP16) - { - scoreDiff = 0.04; - iouDiff = 0.03; - } - std::string config_file = "yolov3.cfg"; - std::string weights_file = "yolov3.weights"; - -#if defined(INF_ENGINE_RELEASE) - if ((backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 || - backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) && target == DNN_TARGET_MYRIAD && - getInferenceEngineVPUType() == CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_X) - { - scoreDiff = 0.04; - iouDiff = 0.2; - } -#endif - - { - SCOPED_TRACE("batch size 1"); - testDarknetModel(config_file, weights_file, ref.rowRange(0, N0), scoreDiff, iouDiff, 0.24, 0.4, false); - } - -#if defined(INF_ENGINE_RELEASE) - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019) - { - if (target == DNN_TARGET_OPENCL) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL, CV_TEST_TAG_DNN_SKIP_IE_VERSION); - else if (target == DNN_TARGET_OPENCL_FP16 && INF_ENGINE_VER_MAJOR_LE(202010000)) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_VERSION); - else if (target == DNN_TARGET_MYRIAD && - getInferenceEngineVPUType() == CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_X) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD_X); - } -#endif - - { - SCOPED_TRACE("batch size 2"); - testDarknetModel(config_file, weights_file, ref, scoreDiff, iouDiff, 0.24, 0.4, false); - } -} - -TEST_P(Test_Darknet_nets, YOLOv4) +TEST_P(Test_YOLO_nets, YOLOv4) { applyTestTag( CV_TEST_TAG_LONG, @@ -726,32 +333,20 @@ TEST_P(Test_Darknet_nets, YOLOv4) CV_TEST_TAG_DEBUG_VERYLONG ); -#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2020040000) // nGraph compilation failure - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL, CV_TEST_TAG_DNN_SKIP_IE_VERSION); - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL_FP16) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#endif -#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_LT(2022010000) - if (target == DNN_TARGET_MYRIAD) // NC_OUT_OF_MEMORY - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#endif - // batchId, classId, confidence, left, top, right, bottom const int N0 = 3; - const int N1 = 7; + const int N1 = 6; static const float ref_[/* (N0 + N1) * 7 */] = { -0, 16, 0.992194f, 0.172375f, 0.402458f, 0.403918f, 0.932801f, -0, 1, 0.988326f, 0.166708f, 0.228236f, 0.737208f, 0.735803f, -0, 7, 0.94639f, 0.602523f, 0.130399f, 0.901623f, 0.298452f, +0, 16, 0.968371f, 0.167918f, 0.394843f, 0.40767f, 0.942042f, +0, 1, 0.963549f, 0.146538f, 0.227724f, 0.745242f, 0.736494f, +0, 7, 0.951405f, 0.606025f, 0.133886f, 0.895092f, 0.294835f, -1, 2, 0.99761f, 0.646556f, 0.45985f, 0.816041f, 0.659067f, -1, 0, 0.988913f, 0.201726f, 0.360282f, 0.266181f, 0.631728f, -1, 2, 0.98233f, 0.452007f, 0.462217f, 0.495612f, 0.521687f, -1, 9, 0.919195f, 0.374642f, 0.316524f, 0.398126f, 0.393714f, -1, 9, 0.856303f, 0.666842f, 0.372215f, 0.685539f, 0.44141f, -1, 9, 0.313516f, 0.656791f, 0.374734f, 0.671959f, 0.438371f, -1, 9, 0.256625f, 0.940232f, 0.326931f, 0.967586f, 0.374002f, +1, 2, 0.99849f, 0.651516f, 0.456526f, 0.812706f, 0.66287f, +1, 0, 0.996791f, 0.200903f, 0.362404f, 0.264643f, 0.627633f, +1, 2, 0.987972f, 0.450125f, 0.464126f, 0.495712f, 0.519708f, +1, 9, 0.85872f, 0.375374f, 0.314192f, 0.399161f, 0.39453f, +1, 9, 0.841318f, 0.667602f, 0.377284f, 0.686024f, 0.440855f, +1, 9, 0.502608f, 0.656728f, 0.378153f, 0.668251f, 0.432035f, }; Mat ref(N0 + N1, 7, CV_32FC1, (void*)ref_); @@ -763,106 +358,65 @@ TEST_P(Test_Darknet_nets, YOLOv4) iouDiff = 0.03; } - std::string config_file = "yolov4.cfg"; - std::string weights_file = "yolov4.weights"; - - -#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2022010000) - // accuracy (batch 1): no detections - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL_FP16) - { - iouDiff = std::numeric_limits::quiet_NaN(); - } - // accuracy - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_MYRIAD) - { - iouDiff = std::numeric_limits::quiet_NaN(); - } -#elif defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2021040000) - // accuracy (batch 1) - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL_FP16) - { - iouDiff = std::numeric_limits::quiet_NaN(); - } -#elif defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_LT(2022010000) - if ((backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 || - backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) && target == DNN_TARGET_MYRIAD && - getInferenceEngineVPUType() == CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_X) - { - scoreDiff = 0.04; - iouDiff = 0.2; - } -#endif + std::string model_file = "yolov4.onnx"; { SCOPED_TRACE("batch size 1"); - testDarknetModel(config_file, weights_file, ref.rowRange(0, N0), scoreDiff, iouDiff, 0.24, 0.4, false); - // Test not equal width and height applying zero padding - testDarknetModel(config_file, weights_file, ref.rowRange(0, N0), 0.006, 0.008, 0.24, 0.4, false, /*zeroPadW*/ 32); + testYOLOModel(model_file, ref.rowRange(0, N0), scoreDiff, iouDiff, 0.3, 0.4, false, 0, Size(608, 608)); } { SCOPED_TRACE("batch size 2"); - -#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2022010000) - // accuracy (batch 2) - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL_FP16) - { - scoreDiff = 0.008f; - iouDiff = 0.05f; + testYOLOModel(model_file, ref, scoreDiff, iouDiff, 0.3, 0.4, false, 0, Size(608, 608)); } - // accuracy - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_MYRIAD) - { - iouDiff = std::numeric_limits::quiet_NaN(); - } -#elif defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2021040000) - // accuracy (batch 2) - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL_FP16) - { - iouDiff = 0.45f; - } -#elif defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_LT(2022010000) - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019) - { - if (target == DNN_TARGET_OPENCL) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL, CV_TEST_TAG_DNN_SKIP_IE_VERSION); - else if (target == DNN_TARGET_OPENCL_FP16 && INF_ENGINE_VER_MAJOR_LE(202010000)) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_VERSION); - else if (target == DNN_TARGET_MYRIAD && - getInferenceEngineVPUType() == CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_X) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD_X); - } -#endif - - testDarknetModel(config_file, weights_file, ref, scoreDiff, iouDiff, 0.24, 0.4, false); - } - -#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2022010000) - // accuracy - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL_FP16) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION); - // accuracy - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_MYRIAD) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#elif defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2021040000) - // accuracy - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL_FP16) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#endif } -TEST_P(Test_Darknet_nets, YOLOv4_tiny) +TEST_P(Test_YOLO_nets, YOLOv3) +{ + applyTestTag( + CV_TEST_TAG_LONG, + CV_TEST_TAG_MEMORY_2GB, + CV_TEST_TAG_DEBUG_VERYLONG + ); + + if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_MYRIAD) + applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH); + + // batchId, classId, confidence, left, top, right, bottom + const int N0 = 3; + const int N1 = 0; + static const float ref_[/* (N0 + N1) * 7 */] = { +0, 7, 0.606292f, 0.612037f, 0.149921f, 0.910763f, 0.300503f, +0, 16, 0.55195f, 0.17069f, 0.356024f, 0.471459f, 0.877178f, +0, 1, 0.433444f, 0.199235f, 0.301175f, 0.753253f, 0.744156f, + }; + Mat ref(N0 + N1, 7, CV_32FC1, (void*)ref_); + + double scoreDiff = 8e-5, iouDiff = 3e-4; + if (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD || target == DNN_TARGET_CPU_FP16) + { + scoreDiff = 0.006; + iouDiff = 0.042; + } + else if (target == DNN_TARGET_CUDA_FP16) + { + scoreDiff = 0.04; + iouDiff = 0.03; + } + std::string model_file = "yolov3.onnx"; + + { + SCOPED_TRACE("batch size 1"); + testYOLOModel(model_file, ref.rowRange(0, N0), scoreDiff, iouDiff, 0.24, 0.4, false, 0, Size(640, 640)); + } +} + +TEST_P(Test_YOLO_nets, YOLOv4_tiny) { applyTestTag( target == DNN_TARGET_CPU ? CV_TEST_TAG_MEMORY_512MB : CV_TEST_TAG_MEMORY_1GB ); -#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_GE(2021010000) // nGraph compilation failure - if (target == DNN_TARGET_MYRIAD) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#endif - const double confThreshold = 0.5; // batchId, classId, confidence, left, top, right, bottom const int N0 = 3; @@ -883,41 +437,20 @@ TEST_P(Test_Darknet_nets, YOLOv4_tiny) if (target == DNN_TARGET_CUDA_FP16) iouDiff = 0.02; - std::string config_file = "yolov4-tiny-2020-12.cfg"; - std::string weights_file = "yolov4-tiny-2020-12.weights"; - -#if defined(INF_ENGINE_RELEASE) - if (target == DNN_TARGET_MYRIAD) // bad accuracy - iouDiff = std::numeric_limits::quiet_NaN(); - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 && target == DNN_TARGET_OPENCL) - iouDiff = std::numeric_limits::quiet_NaN(); - if ((backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 || - backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) && target == DNN_TARGET_OPENCL_FP16) - iouDiff = std::numeric_limits::quiet_NaN(); -#endif + std::string model_file = "yolov4-tiny.onnx"; { SCOPED_TRACE("batch size 1"); - testDarknetModel(config_file, weights_file, ref.rowRange(0, N0), scoreDiff, iouDiff, confThreshold, 0.4, false); + testYOLOModel(model_file, ref.rowRange(0, N0), scoreDiff, iouDiff, confThreshold, 0.4, false, 0, Size(416, 416)); } { SCOPED_TRACE("batch size 2"); - testDarknetModel(config_file, weights_file, ref, scoreDiff, iouDiff, confThreshold, 0.4, false); + testYOLOModel(model_file, ref, scoreDiff, iouDiff, confThreshold, 0.4, false, 0, Size(416, 416)); } - -#if defined(INF_ENGINE_RELEASE) - if (target == DNN_TARGET_MYRIAD) // bad accuracy - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_VERSION); - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 && target == DNN_TARGET_OPENCL) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL, CV_TEST_TAG_DNN_SKIP_IE_VERSION); - if ((backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 || - backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) && target == DNN_TARGET_OPENCL_FP16) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#endif } -TEST_P(Test_Darknet_nets, YOLOv4x_mish) +TEST_P(Test_YOLO_nets, YOLOv4x_mish) { applyTestTag( CV_TEST_TAG_MEMORY_2GB, @@ -925,37 +458,19 @@ TEST_P(Test_Darknet_nets, YOLOv4x_mish) CV_TEST_TAG_DEBUG_VERYLONG ); -#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2021040000) - // IE exception: Ngraph operation Transpose with name permute_168 has dynamic output shape on 0 port, but CPU plug-in supports only static shape - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && (target == DNN_TARGET_OPENCL || target == DNN_TARGET_OPENCL_FP16)) - applyTestTag(target == DNN_TARGET_OPENCL ? CV_TEST_TAG_DNN_SKIP_IE_OPENCL : CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, - CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION - ); -#endif -#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2020040000) // nGraph compilation failure - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL, CV_TEST_TAG_DNN_SKIP_IE_VERSION); - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL_FP16) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#endif -#if defined(INF_ENGINE_RELEASE) - if (target == DNN_TARGET_MYRIAD) // NC_OUT_OF_MEMORY - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#endif - // batchId, classId, confidence, left, top, right, bottom const int N0 = 3; const int N1 = 5; static const float ref_[/* (N0 + N1) * 7 */] = { -0, 16, 0.925536f, 0.17188f, 0.386832f, 0.406138f, 0.941696f, -0, 1, 0.912028f, 0.162125f, 0.208863f, 0.741316f, 0.729332f, -0, 7, 0.841018f, 0.608953f, 0.128653f, 0.900692f, 0.295657f, +0, 1, 0.93241f, 0.161592f, 0.232638f, 0.738411f, 0.731285f, +0, 16, 0.929881f, 0.171312f, 0.385948f, 0.405568f, 0.940067f, +0, 7, 0.812158f, 0.60486f, 0.129621f, 0.895285f, 0.296402f, -1, 2, 0.925697f, 0.650438f, 0.458118f, 0.813927f, 0.661775f, -1, 0, 0.882156f, 0.203644f, 0.365763f, 0.265473f, 0.632195f, -1, 2, 0.848857f, 0.451044f, 0.462997f, 0.496629f, 0.522719f, -1, 9, 0.736015f, 0.374503f, 0.316029f, 0.399358f, 0.392883f, -1, 9, 0.727129f, 0.662469f, 0.373687f, 0.687877f, 0.441335f, +1, 2, 0.929241f, 0.651517f, 0.457701f, 0.8147f, 0.660816f, +1, 0, 0.918966f, 0.200175f, 0.35915f, 0.265996f, 0.631935f, +1, 2, 0.881782f, 0.45082f, 0.461253f, 0.495884f, 0.522369f, +1, 9, 0.746081f, 0.661127f, 0.372649f, 0.686827f, 0.441998f, +1, 9, 0.730318f, 0.373671f, 0.314795f, 0.401108f, 0.397822f, }; Mat ref(N0 + N1, 7, CV_32FC1, (void*)ref_); @@ -968,190 +483,19 @@ TEST_P(Test_Darknet_nets, YOLOv4x_mish) iouDiff = 0.042; } - std::string config_file = "yolov4x-mish.cfg"; - std::string weights_file = "yolov4x-mish.weights"; - -#if defined(INF_ENGINE_RELEASE) - if ((backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 || - backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) && target == DNN_TARGET_MYRIAD && - getInferenceEngineVPUType() == CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_X) - { - scoreDiff = 0.04; - iouDiff = 0.2; - } -#endif + std::string model_file = "yolov4x-mish.onnx"; { SCOPED_TRACE("batch size 1"); - testDarknetModel(config_file, weights_file, ref.rowRange(0, N0), scoreDiff, iouDiff, 0.24, 0.4, false); + testYOLOModel(model_file, ref.rowRange(0, N0), scoreDiff, iouDiff, 0.24, 0.4, false, 0, Size(640, 640)); } { SCOPED_TRACE("batch size 2"); - -#if defined(INF_ENGINE_RELEASE) - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019) - { - if (target == DNN_TARGET_OPENCL) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL, CV_TEST_TAG_DNN_SKIP_IE_VERSION); - else if (target == DNN_TARGET_OPENCL_FP16 && INF_ENGINE_VER_MAJOR_LE(202010000)) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_VERSION); - else if (target == DNN_TARGET_MYRIAD && - getInferenceEngineVPUType() == CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_X) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD_X); - } -#endif - - testDarknetModel(config_file, weights_file, ref, scoreDiff, iouDiff, 0.24, 0.4, false); + testYOLOModel(model_file, ref, scoreDiff, iouDiff, 0.24, 0.4, false, 0, Size(640, 640)); } } - -INSTANTIATE_TEST_CASE_P(/**/, Test_Darknet_nets, dnnBackendsAndTargets()); - -TEST_P(Test_Darknet_layers, shortcut) -{ - testDarknetLayer("shortcut"); -} -TEST_P(Test_Darknet_layers, shortcut_leaky) -{ - testDarknetLayer("shortcut_leaky"); -} -TEST_P(Test_Darknet_layers, shortcut_unequal) -{ - testDarknetLayer("shortcut_unequal"); -} -TEST_P(Test_Darknet_layers, shortcut_unequal_2) -{ - testDarknetLayer("shortcut_unequal_2"); -} - -TEST_P(Test_Darknet_layers, upsample) -{ -#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2021030000) - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_MYRIAD) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH); // exception -#endif - testDarknetLayer("upsample"); -} - -TEST_P(Test_Darknet_layers, mish) -{ - testDarknetLayer("mish", true); -} - -TEST_P(Test_Darknet_layers, tanh) -{ - testDarknetLayer("tanh"); -} - -TEST_P(Test_Darknet_layers, avgpool_softmax) -{ - testDarknetLayer("avgpool_softmax"); -} - -TEST_P(Test_Darknet_layers, crop) -{ - testDarknetLayer("crop"); -} - -TEST_P(Test_Darknet_layers, region) -{ -#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_LT(2021040000) - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && INF_ENGINE_VER_MAJOR_GE(2020020000)) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#endif - -#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_GE(2022010000) - // accuracy on CPU, OpenCL - // Expected: (normL1) <= (l1), actual: 0.000358148 vs 1e-05 - // |ref| = 1.207319974899292 - // Expected: (normInf) <= (lInf), actual: 0.763223 vs 0.0001 - // |ref| = 1.207319974899292 - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_CPU) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_CPU, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION); - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && (target == DNN_TARGET_OPENCL || target == DNN_TARGET_OPENCL_FP16)) - applyTestTag(target == DNN_TARGET_OPENCL ? CV_TEST_TAG_DNN_SKIP_IE_OPENCL : CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, - CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION - ); -#elif defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2021040000) - // accuracy on CPU, OpenCL - // Expected: (normInf) <= (lInf), actual: 0.763223 vs 0.0001 - // |ref| = 1.207319974899292 - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_CPU) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_CPU, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION); - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && (target == DNN_TARGET_OPENCL || target == DNN_TARGET_OPENCL_FP16)) - applyTestTag(target == DNN_TARGET_OPENCL ? CV_TEST_TAG_DNN_SKIP_IE_OPENCL : CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, - CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION - ); -#endif - - testDarknetLayer("region"); -} - -TEST_P(Test_Darknet_layers, reorg) -{ - testDarknetLayer("reorg"); -} - -TEST_P(Test_Darknet_layers, route) -{ - testDarknetLayer("route"); - testDarknetLayer("route_multi"); -} - -TEST_P(Test_Darknet_layers, maxpool) -{ -#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_GE(2020020000) - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_MYRIAD) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#endif - testDarknetLayer("maxpool"); -} - -TEST_P(Test_Darknet_layers, convolutional) -{ -#if defined(INF_ENGINE_RELEASE) - if (target == DNN_TARGET_MYRIAD) - { - default_l1 = 0.01f; - } -#endif - testDarknetLayer("convolutional", true); -} - -TEST_P(Test_Darknet_layers, scale_channels) -{ - bool testBatches = backend == DNN_BACKEND_CUDA; - testDarknetLayer("scale_channels", false, testBatches); -} - -TEST_P(Test_Darknet_layers, connected) -{ - if (backend == DNN_BACKEND_OPENCV && target == DNN_TARGET_OPENCL_FP16) - applyTestTag(CV_TEST_TAG_DNN_SKIP_OPENCL_FP16); - if (backend == DNN_BACKEND_OPENCV && target == DNN_TARGET_CPU_FP16) - applyTestTag(CV_TEST_TAG_DNN_SKIP_CPU_FP16); - double l1 = 0.0; - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL) - { - l1 = 3e-5; - } - testDarknetLayer("connected", true, true, l1); -} - -TEST_P(Test_Darknet_layers, relu) -{ - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 && target == DNN_TARGET_MYRIAD) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD); - testDarknetLayer("relu"); -} - -TEST_P(Test_Darknet_layers, sam) -{ - testDarknetLayer("sam", true); -} - -INSTANTIATE_TEST_CASE_P(/**/, Test_Darknet_layers, dnnBackendsAndTargets()); +INSTANTIATE_TEST_CASE_P(/**/, Test_YOLO_nets, dnnBackendsAndTargets()); }} // namespace diff --git a/modules/dnn/test/test_int8_layers.cpp b/modules/dnn/test/test_int8_layers.cpp index acb1c87d33..2b266cda92 100644 --- a/modules/dnn/test/test_int8_layers.cpp +++ b/modules/dnn/test/test_int8_layers.cpp @@ -648,9 +648,9 @@ public: normAssert(ref, out, "", l1, lInf); } - void testDarknetModel(const std::string& cfg, const std::string& weights, - const cv::Mat& ref, double scoreDiff, double iouDiff, - float confThreshold = 0.24, float nmsThreshold = 0.4, bool perChannel = true) + void testYOLOModel(const std::string& model, + const cv::Mat& ref, double scoreDiff, double iouDiff, + float confThreshold = 0.24, float nmsThreshold = 0.4, bool perChannel = true) { CV_Assert(ref.cols == 7); std::vector > refClassIds; @@ -689,7 +689,7 @@ public: Mat inp = blobFromImages(samples, 1.0/255, Size(416, 416), Scalar(), true, false); - Net baseNet = readNetFromDarknet(findDataFile("dnn/" + cfg), findDataFile("dnn/" + weights, false)); + Net baseNet = readNet(findDataFile("dnn/" + model, false)); Net qnet = baseNet.quantize(inp, CV_32F, CV_32F, perChannel); qnet.setPreferableBackend(backend); qnet.setPreferableTarget(target); @@ -1225,86 +1225,6 @@ TEST_P(Test_Int8_nets, RFCN) testFaster(net, ref, confThreshold, scoreDiff, iouDiff); } -TEST_P(Test_Int8_nets, YoloVoc) -{ - applyTestTag( -#if defined(OPENCV_32BIT_CONFIGURATION) && defined(HAVE_OPENCL) - CV_TEST_TAG_MEMORY_2GB, -#else - CV_TEST_TAG_MEMORY_1GB, -#endif - CV_TEST_TAG_LONG, - CV_TEST_TAG_DEBUG_VERYLONG - ); - - if (target == DNN_TARGET_OPENCL_FP16 && !ocl::Device::getDefault().isIntel()) - applyTestTag(CV_TEST_TAG_DNN_SKIP_OPENCL_FP16); - if (target == DNN_TARGET_OPENCL && !ocl::Device::getDefault().isIntel()) - applyTestTag(CV_TEST_TAG_DNN_SKIP_OPENCL); - - Mat ref = (Mat_(6, 7) << 0, 6, 0.750469f, 0.577374f, 0.127391f, 0.902949f, 0.300809f, - 0, 1, 0.780879f, 0.270762f, 0.264102f, 0.732475f, 0.745412f, - 0, 11, 0.901615f, 0.1386f, 0.338509f, 0.421337f, 0.938789f, - 1, 14, 0.623813f, 0.183179f, 0.381921f, 0.247726f, 0.625847f, - 1, 6, 0.667770f, 0.446555f, 0.453578f, 0.499986f, 0.519167f, - 1, 6, 0.844947f, 0.637058f, 0.460398f, 0.828508f, 0.66427f); - - std::string config_file = "yolo-voc.cfg"; - std::string weights_file = "yolo-voc.weights"; - - double scoreDiff = 0.12, iouDiff = 0.3; - { - SCOPED_TRACE("batch size 1"); - testDarknetModel(config_file, weights_file, ref.rowRange(0, 3), scoreDiff, iouDiff); - } - - { - SCOPED_TRACE("batch size 2"); - testDarknetModel(config_file, weights_file, ref, scoreDiff, iouDiff); - } -} - -TEST_P(Test_Int8_nets, TinyYoloVoc) -{ - applyTestTag( - CV_TEST_TAG_MEMORY_512MB, - CV_TEST_TAG_DEBUG_VERYLONG - ); - - if (target == DNN_TARGET_OPENCL_FP16 && !ocl::Device::getDefault().isIntel()) - applyTestTag(CV_TEST_TAG_DNN_SKIP_OPENCL_FP16); - if (target == DNN_TARGET_OPENCL && !ocl::Device::getDefault().isIntel()) - applyTestTag(CV_TEST_TAG_DNN_SKIP_OPENCL); - - Mat ref = (Mat_(4, 7) << 0, 6, 0.761967f, 0.579042f, 0.159161f, 0.894482f, 0.31994f, - 0, 11, 0.780595f, 0.129696f, 0.386467f, 0.445275f, 0.920994f, - 1, 6, 0.651450f, 0.460526f, 0.458019f, 0.522527f, 0.5341f, - 1, 6, 0.928758f, 0.651024f, 0.463539f, 0.823784f, 0.654998f); - - std::string config_file = "tiny-yolo-voc.cfg"; - std::string weights_file = "tiny-yolo-voc.weights"; - - double scoreDiff = 0.043, iouDiff = 0.12; - { - SCOPED_TRACE("batch size 1"); - testDarknetModel(config_file, weights_file, ref.rowRange(0, 2), scoreDiff, iouDiff); - { - SCOPED_TRACE("Per-tensor quantize"); - testDarknetModel(config_file, weights_file, ref.rowRange(0, 2), 0.1, 0.2, 0.24, 0.6, false); - } - } - - { - SCOPED_TRACE("batch size 2"); - testDarknetModel(config_file, weights_file, ref, scoreDiff, iouDiff); - - { - SCOPED_TRACE("Per-tensor quantize"); - testDarknetModel(config_file, weights_file, ref, 0.1, 0.2, 0.24, 0.6, false); - } - } -} - TEST_P(Test_Int8_nets, YOLOv3) { applyTestTag( @@ -1334,18 +1254,17 @@ TEST_P(Test_Int8_nets, YOLOv3) }; Mat ref(N0 + N1, 7, CV_32FC1, (void*)ref_); - std::string config_file = "yolov3.cfg"; - std::string weights_file = "yolov3.weights"; + std::string model_file = "yolov3.onnx"; double scoreDiff = 0.08, iouDiff = 0.21, confThreshold = 0.25; { SCOPED_TRACE("batch size 1"); - testDarknetModel(config_file, weights_file, ref.rowRange(0, N0), scoreDiff, iouDiff, confThreshold); + testYOLOModel(model_file, ref.rowRange(0, N0), scoreDiff, iouDiff, confThreshold); } { SCOPED_TRACE("batch size 2"); - testDarknetModel(config_file, weights_file, ref, scoreDiff, iouDiff, confThreshold); + testYOLOModel(model_file, ref, scoreDiff, iouDiff, confThreshold); } } @@ -1379,18 +1298,17 @@ TEST_P(Test_Int8_nets, YOLOv4) }; Mat ref(N0 + N1, 7, CV_32FC1, (void*)ref_); - std::string config_file = "yolov4.cfg"; - std::string weights_file = "yolov4.weights"; + std::string model_file = "yolov4.onnx"; double scoreDiff = 0.15, iouDiff = 0.2; { SCOPED_TRACE("batch size 1"); - testDarknetModel(config_file, weights_file, ref.rowRange(0, N0), scoreDiff, iouDiff); + testYOLOModel(model_file, ref.rowRange(0, N0), scoreDiff, iouDiff); } { SCOPED_TRACE("batch size 2"); - testDarknetModel(config_file, weights_file, ref, scoreDiff, iouDiff); + testYOLOModel(model_file, ref, scoreDiff, iouDiff); } } @@ -1421,18 +1339,17 @@ TEST_P(Test_Int8_nets, YOLOv4_tiny) }; Mat ref(N0 + N1, 7, CV_32FC1, (void*)ref_); - std::string config_file = "yolov4-tiny-2020-12.cfg"; - std::string weights_file = "yolov4-tiny-2020-12.weights"; + std::string model_file = "yolov4-tiny.onnx"; double scoreDiff = 0.12; double iouDiff = target == DNN_TARGET_OPENCL_FP16 ? 0.2 : 0.118; { SCOPED_TRACE("batch size 1"); - testDarknetModel(config_file, weights_file, ref.rowRange(0, N0), scoreDiff, iouDiff, confThreshold); + testYOLOModel(model_file, ref.rowRange(0, N0), scoreDiff, iouDiff, confThreshold); { SCOPED_TRACE("Per-tensor quantize"); - testDarknetModel(config_file, weights_file, ref.rowRange(0, N0), scoreDiff, 0.224, 0.7, 0.4, false); + testYOLOModel(model_file, ref.rowRange(0, N0), scoreDiff, 0.224, 0.7, 0.4, false); } } @@ -1440,7 +1357,7 @@ TEST_P(Test_Int8_nets, YOLOv4_tiny) /* bad accuracy on second image { SCOPED_TRACE("batch size 2"); - testDarknetModel(config_file, weights_file, ref, scoreDiff, iouDiff, confThreshold); + testYOLOModel(model_file, ref, scoreDiff, iouDiff, confThreshold); } */ } diff --git a/modules/dnn/test/test_misc.cpp b/modules/dnn/test/test_misc.cpp index 1b33aaa630..6bd817ca10 100644 --- a/modules/dnn/test/test_misc.cpp +++ b/modules/dnn/test/test_misc.cpp @@ -247,9 +247,6 @@ TEST(readNet, Regression) Net net = readNet(findDataFile("dnn/squeezenet_v1.1.prototxt"), findDataFile("dnn/squeezenet_v1.1.caffemodel", false)); EXPECT_FALSE(net.empty()); - net = readNet(findDataFile("dnn/tiny-yolo-voc.cfg"), - findDataFile("dnn/tiny-yolo-voc.weights", false)); - EXPECT_FALSE(net.empty()); net = readNet(findDataFile("dnn/ssd_mobilenet_v1_coco.pbtxt"), findDataFile("dnn/ssd_mobilenet_v1_coco.pb", false)); EXPECT_FALSE(net.empty()); diff --git a/modules/dnn/test/test_model.cpp b/modules/dnn/test/test_model.cpp index f5b429032c..7fba6e98f1 100644 --- a/modules/dnn/test/test_model.cpp +++ b/modules/dnn/test/test_model.cpp @@ -289,129 +289,6 @@ TEST_P(Test_Model, Classify) } -TEST_P(Test_Model, DetectRegion) -{ - applyTestTag( - CV_TEST_TAG_MEMORY_2GB, - CV_TEST_TAG_LONG, - CV_TEST_TAG_DEBUG_VERYLONG - ); - -#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2022010000) - // accuracy - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL_FP16) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#elif defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2021040000) - // accuracy - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL_FP16) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#elif defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2020040000) // nGraph compilation failure - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL, CV_TEST_TAG_DNN_SKIP_IE_VERSION); - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL_FP16) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#elif defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_GE(2019010000) - // FIXIT DNN_BACKEND_INFERENCE_ENGINE is misused - if (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_OPENCL_FP16) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16); -#endif - -#if defined(INF_ENGINE_RELEASE) - if (target == DNN_TARGET_MYRIAD - && getInferenceEngineVPUType() == CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_X) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD_X); -#endif - - std::vector refClassIds = {6, 1, 11}; - std::vector refConfidences = {0.750469f, 0.780879f, 0.901615f}; - std::vector refBoxes = {Rect2d(240, 53, 135, 72), - Rect2d(112, 109, 192, 200), - Rect2d(58, 141, 117, 249)}; - - std::string img_path = _tf("dog416.png"); - std::string weights_file = _tf("yolo-voc.weights", false); - std::string config_file = _tf("yolo-voc.cfg"); - - double scale = 1.0 / 255.0; - Size size{416, 416}; - bool swapRB = true; - - double confThreshold = 0.24; - double nmsThreshold = (target == DNN_TARGET_MYRIAD) ? 0.397 : 0.4; - double scoreDiff = 8e-5, iouDiff = 1e-5; - if (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD || target == DNN_TARGET_CUDA_FP16 || target == DNN_TARGET_CPU_FP16) - { - scoreDiff = 1e-2; - iouDiff = 1.6e-2; - } - - testDetectModel(weights_file, config_file, img_path, refClassIds, refConfidences, - refBoxes, scoreDiff, iouDiff, confThreshold, nmsThreshold, size, - Scalar(), scale, swapRB); -} - -TEST_P(Test_Model, DetectRegionWithNmsAcrossClasses) -{ - applyTestTag( - CV_TEST_TAG_MEMORY_2GB, - CV_TEST_TAG_LONG, - CV_TEST_TAG_DEBUG_VERYLONG - ); - -#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2022010000) - // accuracy - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL_FP16) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#elif defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2021040000) - // accuracy - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL_FP16) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#elif defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2020040000) // nGraph compilation failure - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL, CV_TEST_TAG_DNN_SKIP_IE_VERSION); - if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL_FP16) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_VERSION); -#elif defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_GE(2019010000) - if (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_OPENCL_FP16) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16); -#endif - -#if defined(INF_ENGINE_RELEASE) - if (target == DNN_TARGET_MYRIAD - && getInferenceEngineVPUType() == CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_X) - applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD_X); -#endif - - std::vector refClassIds = { 6, 11 }; - std::vector refConfidences = { 0.750469f, 0.901615f }; - std::vector refBoxes = { Rect2d(240, 53, 135, 72), - Rect2d(58, 141, 117, 249) }; - - std::string img_path = _tf("dog416.png"); - std::string weights_file = _tf("yolo-voc.weights", false); - std::string config_file = _tf("yolo-voc.cfg"); - - double scale = 1.0 / 255.0; - Size size{ 416, 416 }; - bool swapRB = true; - bool crop = false; - bool nmsAcrossClasses = true; - - double confThreshold = 0.24; - double nmsThreshold = (target == DNN_TARGET_MYRIAD) ? 0.15: 0.15; - double scoreDiff = 8e-5, iouDiff = 1e-5; - if (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD || target == DNN_TARGET_CUDA_FP16 || target == DNN_TARGET_CPU_FP16) - { - scoreDiff = 1e-2; - iouDiff = 1.6e-2; - } - - testDetectModel(weights_file, config_file, img_path, refClassIds, refConfidences, - refBoxes, scoreDiff, iouDiff, confThreshold, nmsThreshold, size, - Scalar(), scale, swapRB, crop, - nmsAcrossClasses); -} - TEST_P(Test_Model, DetectionOutput) { applyTestTag(CV_TEST_TAG_DEBUG_VERYLONG); diff --git a/platforms/js/opencv_js.config.py b/platforms/js/opencv_js.config.py index ac6e4007e0..5108d1ed5b 100644 --- a/platforms/js/opencv_js.config.py +++ b/platforms/js/opencv_js.config.py @@ -172,7 +172,7 @@ video = { } dnn = {'dnn_Net': ['setInput', 'forward', 'setPreferableBackend','getUnconnectedOutLayersNames'], - '': ['readNetFromCaffe', 'readNetFromTensorflow', 'readNetFromDarknet', + '': ['readNetFromCaffe', 'readNetFromTensorflow', 'readNetFromONNX', 'readNetFromTFLite', 'readNet', 'blobFromImage']} features = {'Feature2D': ['detect', 'compute', 'detectAndCompute', 'descriptorSize', 'descriptorType', 'defaultNorm', 'empty', 'getDefaultName'],