Path: blob/master/modules/dnn/test/test_darknet_importer.cpp
16339 views
/*M///////////////////////////////////////////////////////////////////////////////////////1//2// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.3//4// By downloading, copying, installing or using the software you agree to this license.5// If you do not agree to this license, do not download, install,6// copy or use the software.7//8//9// License Agreement10// For Open Source Computer Vision Library11// (3-clause BSD License)12//13// Copyright (C) 2017, Intel Corporation, all rights reserved.14// Third party copyrights are property of their respective owners.15//16// Redistribution and use in source and binary forms, with or without modification,17// are permitted provided that the following conditions are met:18//19// * Redistributions of source code must retain the above copyright notice,20// this list of conditions and the following disclaimer.21//22// * Redistributions in binary form must reproduce the above copyright notice,23// this list of conditions and the following disclaimer in the documentation24// and/or other materials provided with the distribution.25//26// * Neither the names of the copyright holders nor the names of the contributors27// may be used to endorse or promote products derived from this software28// without specific prior written permission.29//30// This software is provided by the copyright holders and contributors "as is" and31// any express or implied warranties, including, but not limited to, the implied32// warranties of merchantability and fitness for a particular purpose are disclaimed.33// In no event shall copyright holders or contributors be liable for any direct,34// indirect, incidental, special, exemplary, or consequential damages35// (including, but not limited to, procurement of substitute goods or services;36// loss of use, data, or profits; or business interruption) however caused37// and on any theory of liability, whether in contract, strict liability,38// or tort (including negligence or otherwise) arising in any way out of39// the use of this software, even if advised of the possibility of such damage.40//41//M*/4243#include "test_precomp.hpp"44#include "npy_blob.hpp"45#include <opencv2/dnn/shape_utils.hpp>4647namespace opencv_test { namespace {4849template<typename TString>50static std::string _tf(TString filename)51{52return (getOpenCVExtraDir() + "/dnn/") + filename;53}5455static std::vector<String> getOutputsNames(const Net& net)56{57std::vector<String> names;58std::vector<int> outLayers = net.getUnconnectedOutLayers();59std::vector<String> layersNames = net.getLayerNames();60names.resize(outLayers.size());61for (size_t i = 0; i < outLayers.size(); ++i)62names[i] = layersNames[outLayers[i] - 1];63return names;64}6566TEST(Test_Darknet, read_tiny_yolo_voc)67{68Net net = readNetFromDarknet(_tf("tiny-yolo-voc.cfg"));69ASSERT_FALSE(net.empty());70}7172TEST(Test_Darknet, read_yolo_voc)73{74Net net = readNetFromDarknet(_tf("yolo-voc.cfg"));75ASSERT_FALSE(net.empty());76}7778TEST(Test_Darknet, read_yolo_voc_stream)79{80Mat ref;81Mat sample = imread(_tf("dog416.png"));82Mat inp = blobFromImage(sample, 1.0/255, Size(416, 416), Scalar(), true, false);83const std::string cfgFile = findDataFile("dnn/yolo-voc.cfg", false);84const std::string weightsFile = findDataFile("dnn/yolo-voc.weights", false);85// Import by paths.86{87Net net = readNetFromDarknet(cfgFile, weightsFile);88net.setInput(inp);89net.setPreferableBackend(DNN_BACKEND_OPENCV);90ref = net.forward();91}92// Import from bytes array.93{94std::string cfg, weights;95readFileInMemory(cfgFile, cfg);96readFileInMemory(weightsFile, weights);9798Net net = readNetFromDarknet(&cfg[0], cfg.size(), &weights[0], weights.size());99net.setInput(inp);100net.setPreferableBackend(DNN_BACKEND_OPENCV);101Mat out = net.forward();102normAssert(ref, out);103}104}105106class Test_Darknet_layers : public DNNTestLayer107{108public:109void testDarknetLayer(const std::string& name, bool hasWeights = false)110{111std::string cfg = findDataFile("dnn/darknet/" + name + ".cfg", false);112std::string model = "";113if (hasWeights)114model = findDataFile("dnn/darknet/" + name + ".weights", false);115Mat inp = blobFromNPY(findDataFile("dnn/darknet/" + name + "_in.npy", false));116Mat ref = blobFromNPY(findDataFile("dnn/darknet/" + name + "_out.npy", false));117118checkBackend(&inp, &ref);119120Net net = readNet(cfg, model);121net.setPreferableBackend(backend);122net.setPreferableTarget(target);123net.setInput(inp);124Mat out = net.forward();125normAssert(out, ref, "", default_l1, default_lInf);126}127};128129class Test_Darknet_nets : public DNNTestLayer130{131public:132// Test object detection network from Darknet framework.133void testDarknetModel(const std::string& cfg, const std::string& weights,134const std::vector<std::vector<int> >& refClassIds,135const std::vector<std::vector<float> >& refConfidences,136const std::vector<std::vector<Rect2d> >& refBoxes,137double scoreDiff, double iouDiff, float confThreshold = 0.24, float nmsThreshold = 0.4)138{139checkBackend();140141Mat img1 = imread(_tf("dog416.png"));142Mat img2 = imread(_tf("street.png"));143std::vector<Mat> samples(2);144samples[0] = img1; samples[1] = img2;145146// determine test type, whether batch or single img147int batch_size = refClassIds.size();148CV_Assert(batch_size == 1 || batch_size == 2);149samples.resize(batch_size);150151Mat inp = blobFromImages(samples, 1.0/255, Size(416, 416), Scalar(), true, false);152153Net net = readNet(findDataFile("dnn/" + cfg, false),154findDataFile("dnn/" + weights, false));155net.setPreferableBackend(backend);156net.setPreferableTarget(target);157net.setInput(inp);158std::vector<Mat> outs;159net.forward(outs, getOutputsNames(net));160161for (int b = 0; b < batch_size; ++b)162{163std::vector<int> classIds;164std::vector<float> confidences;165std::vector<Rect2d> boxes;166for (int i = 0; i < outs.size(); ++i)167{168Mat out;169if (batch_size > 1){170// get the sample slice from 3D matrix (batch, box, classes+5)171Range ranges[3] = {Range(b, b+1), Range::all(), Range::all()};172out = outs[i](ranges).reshape(1, outs[i].size[1]);173}else{174out = outs[i];175}176for (int j = 0; j < out.rows; ++j)177{178Mat scores = out.row(j).colRange(5, out.cols);179double confidence;180Point maxLoc;181minMaxLoc(scores, 0, &confidence, 0, &maxLoc);182183if (confidence > confThreshold) {184float* detection = out.ptr<float>(j);185double centerX = detection[0];186double centerY = detection[1];187double width = detection[2];188double height = detection[3];189boxes.push_back(Rect2d(centerX - 0.5 * width, centerY - 0.5 * height,190width, height));191confidences.push_back(confidence);192classIds.push_back(maxLoc.x);193}194}195}196197// here we need NMS of boxes198std::vector<int> indices;199NMSBoxes(boxes, confidences, confThreshold, nmsThreshold, indices);200201std::vector<int> nms_classIds;202std::vector<float> nms_confidences;203std::vector<Rect2d> nms_boxes;204205for (size_t i = 0; i < indices.size(); ++i)206{207int idx = indices[i];208Rect2d box = boxes[idx];209float conf = confidences[idx];210int class_id = classIds[idx];211nms_boxes.push_back(box);212nms_confidences.push_back(conf);213nms_classIds.push_back(class_id);214}215216normAssertDetections(refClassIds[b], refConfidences[b], refBoxes[b], nms_classIds,217nms_confidences, nms_boxes, format("batch size %d, sample %d\n", batch_size, b).c_str(), confThreshold, scoreDiff, iouDiff);218}219}220221void testDarknetModel(const std::string& cfg, const std::string& weights,222const std::vector<int>& refClassIds,223const std::vector<float>& refConfidences,224const std::vector<Rect2d>& refBoxes,225double scoreDiff, double iouDiff, float confThreshold = 0.24, float nmsThreshold = 0.4)226{227testDarknetModel(cfg, weights,228std::vector<std::vector<int> >(1, refClassIds),229std::vector<std::vector<float> >(1, refConfidences),230std::vector<std::vector<Rect2d> >(1, refBoxes),231scoreDiff, iouDiff, confThreshold, nmsThreshold);232}233234void testDarknetModel(const std::string& cfg, const std::string& weights,235const cv::Mat& ref, double scoreDiff, double iouDiff,236float confThreshold = 0.24, float nmsThreshold = 0.4)237{238CV_Assert(ref.cols == 7);239std::vector<std::vector<int> > refClassIds;240std::vector<std::vector<float> > refScores;241std::vector<std::vector<Rect2d> > refBoxes;242for (int i = 0; i < ref.rows; ++i)243{244int batchId = static_cast<int>(ref.at<float>(i, 0));245int classId = static_cast<int>(ref.at<float>(i, 1));246float score = ref.at<float>(i, 2);247float left = ref.at<float>(i, 3);248float top = ref.at<float>(i, 4);249float right = ref.at<float>(i, 5);250float bottom = ref.at<float>(i, 6);251Rect2d box(left, top, right - left, bottom - top);252if (batchId >= refClassIds.size())253{254refClassIds.resize(batchId + 1);255refScores.resize(batchId + 1);256refBoxes.resize(batchId + 1);257}258refClassIds[batchId].push_back(classId);259refScores[batchId].push_back(score);260refBoxes[batchId].push_back(box);261}262testDarknetModel(cfg, weights, refClassIds, refScores, refBoxes,263scoreDiff, iouDiff, confThreshold, nmsThreshold);264}265};266267TEST_P(Test_Darknet_nets, YoloVoc)268{269// batchId, classId, confidence, left, top, right, bottom270Mat ref = (Mat_<float>(6, 7) << 0, 6, 0.750469f, 0.577374f, 0.127391f, 0.902949f, 0.300809f, // a car2710, 1, 0.780879f, 0.270762f, 0.264102f, 0.732475f, 0.745412f, // a bicycle2720, 11, 0.901615f, 0.1386f, 0.338509f, 0.421337f, 0.938789f, // a dog2731, 14, 0.623813f, 0.183179f, 0.381921f, 0.247726f, 0.625847f, // a person2741, 6, 0.667770f, 0.446555f, 0.453578f, 0.499986f, 0.519167f, // a car2751, 6, 0.844947f, 0.637058f, 0.460398f, 0.828508f, 0.66427f); // a car276277double scoreDiff = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 1e-2 : 8e-5;278double iouDiff = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 0.018 : 3e-4;279double nmsThreshold = (target == DNN_TARGET_MYRIAD) ? 0.397 : 0.4;280281std::string config_file = "yolo-voc.cfg";282std::string weights_file = "yolo-voc.weights";283284// batch size 1285testDarknetModel(config_file, weights_file, ref.rowRange(0, 3), scoreDiff, iouDiff);286287// batch size 2288testDarknetModel(config_file, weights_file, ref, scoreDiff, iouDiff, 0.24, nmsThreshold);289}290291TEST_P(Test_Darknet_nets, TinyYoloVoc)292{293// batchId, classId, confidence, left, top, right, bottom294Mat ref = (Mat_<float>(4, 7) << 0, 6, 0.761967f, 0.579042f, 0.159161f, 0.894482f, 0.31994f, // a car2950, 11, 0.780595f, 0.129696f, 0.386467f, 0.445275f, 0.920994f, // a dog2961, 6, 0.651450f, 0.460526f, 0.458019f, 0.522527f, 0.5341f, // a car2971, 6, 0.928758f, 0.651024f, 0.463539f, 0.823784f, 0.654998f); // a car298299double scoreDiff = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 8e-3 : 8e-5;300double iouDiff = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 0.018 : 3e-4;301302std::string config_file = "tiny-yolo-voc.cfg";303std::string weights_file = "tiny-yolo-voc.weights";304305// batch size 1306testDarknetModel(config_file, weights_file, ref.rowRange(0, 2), scoreDiff, iouDiff);307308// batch size 2309testDarknetModel(config_file, weights_file, ref, scoreDiff, iouDiff);310}311312TEST_P(Test_Darknet_nets, YOLOv3)313{314// batchId, classId, confidence, left, top, right, bottom315Mat ref = (Mat_<float>(9, 7) << 0, 7, 0.952983f, 0.614622f, 0.150257f, 0.901369f, 0.289251f, // a truck3160, 1, 0.987908f, 0.150913f, 0.221933f, 0.742255f, 0.74626f, // a bicycle3170, 16, 0.998836f, 0.160024f, 0.389964f, 0.417885f, 0.943716f, // a dog (COCO)3181, 9, 0.384801f, 0.659824f, 0.372389f, 0.673926f, 0.429412f, // a traffic light3191, 9, 0.733283f, 0.376029f, 0.315694f, 0.401776f, 0.395165f, // a traffic light3201, 9, 0.785352f, 0.665503f, 0.373543f, 0.688893f, 0.439245f, // a traffic light3211, 0, 0.980052f, 0.195856f, 0.378454f, 0.258626f, 0.629258f, // a person3221, 2, 0.989633f, 0.450719f, 0.463353f, 0.496305f, 0.522258f, // a car3231, 2, 0.997412f, 0.647584f, 0.459939f, 0.821038f, 0.663947f); // a car324325double scoreDiff = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 0.0047 : 8e-5;326double iouDiff = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 0.018 : 3e-4;327328std::string config_file = "yolov3.cfg";329std::string weights_file = "yolov3.weights";330331// batch size 1332testDarknetModel(config_file, weights_file, ref.rowRange(0, 3), scoreDiff, iouDiff);333334if ((backend != DNN_BACKEND_INFERENCE_ENGINE || target != DNN_TARGET_MYRIAD) &&335(backend != DNN_BACKEND_INFERENCE_ENGINE || target != DNN_TARGET_OPENCL))336{337// batch size 2338testDarknetModel(config_file, weights_file, ref, scoreDiff, iouDiff);339}340}341342INSTANTIATE_TEST_CASE_P(/**/, Test_Darknet_nets, dnnBackendsAndTargets());343344TEST_P(Test_Darknet_layers, shortcut)345{346if (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_CPU)347throw SkipTestException("");348testDarknetLayer("shortcut");349}350351TEST_P(Test_Darknet_layers, upsample)352{353testDarknetLayer("upsample");354}355356TEST_P(Test_Darknet_layers, avgpool_softmax)357{358testDarknetLayer("avgpool_softmax");359}360361TEST_P(Test_Darknet_layers, region)362{363testDarknetLayer("region");364}365366TEST_P(Test_Darknet_layers, reorg)367{368testDarknetLayer("reorg");369}370371INSTANTIATE_TEST_CASE_P(/**/, Test_Darknet_layers, dnnBackendsAndTargets());372373}} // namespace374375376