9fd06996f9382636917c2247189daf941b70a458
[platform/upstream/opencv.git] / modules / dnn / test / test_misc.cpp
1 // This file is part of OpenCV project.
2 // It is subject to the license terms in the LICENSE file found in the top-level directory
3 // of this distribution and at http://opencv.org/license.html.
4 //
5 // Copyright (C) 2017, Intel Corporation, all rights reserved.
6 // Third party copyrights are property of their respective owners.
7
8 #include "test_precomp.hpp"
9 #include <opencv2/core/ocl.hpp>
10 #include <opencv2/core/opencl/ocl_defs.hpp>
11 #include <opencv2/dnn/layer.details.hpp>  // CV_DNN_REGISTER_LAYER_CLASS
12
13 namespace opencv_test { namespace {
14
15 TEST(blobFromImage_4ch, Regression)
16 {
17     Mat ch[4];
18     for(int i = 0; i < 4; i++)
19         ch[i] = Mat::ones(10, 10, CV_8U)*i;
20
21     Mat img;
22     merge(ch, 4, img);
23     Mat blob = dnn::blobFromImage(img, 1., Size(), Scalar(), false, false);
24
25     for(int i = 0; i < 4; i++)
26     {
27         ch[i] = Mat(img.rows, img.cols, CV_32F, blob.ptr(0, i));
28         ASSERT_DOUBLE_EQ(cvtest::norm(ch[i], cv::NORM_INF), i);
29     }
30 }
31
32 TEST(blobFromImage, allocated)
33 {
34     int size[] = {1, 3, 4, 5};
35     Mat img(size[2], size[3], CV_32FC(size[1]));
36     Mat blob(4, size, CV_32F);
37     void* blobData = blob.data;
38     dnn::blobFromImage(img, blob, 1.0 / 255, Size(), Scalar(), false, false);
39     ASSERT_EQ(blobData, blob.data);
40 }
41
42 TEST(imagesFromBlob, Regression)
43 {
44     int nbOfImages = 8;
45
46     std::vector<cv::Mat> inputImgs(nbOfImages);
47     for (int i = 0; i < nbOfImages; i++)
48     {
49         inputImgs[i] = cv::Mat::ones(100, 100, CV_32FC3);
50         cv::randu(inputImgs[i], cv::Scalar::all(0), cv::Scalar::all(1));
51     }
52
53     cv::Mat blob = cv::dnn::blobFromImages(inputImgs, 1., cv::Size(), cv::Scalar(), false, false);
54     std::vector<cv::Mat> outputImgs;
55     cv::dnn::imagesFromBlob(blob, outputImgs);
56
57     for (int i = 0; i < nbOfImages; i++)
58     {
59         ASSERT_EQ(cv::countNonZero(inputImgs[i] != outputImgs[i]), 0);
60     }
61 }
62
63 TEST(readNet, Regression)
64 {
65     Net net = readNet(findDataFile("dnn/squeezenet_v1.1.prototxt"),
66                       findDataFile("dnn/squeezenet_v1.1.caffemodel", false));
67     EXPECT_FALSE(net.empty());
68     net = readNet(findDataFile("dnn/opencv_face_detector.caffemodel", false),
69                   findDataFile("dnn/opencv_face_detector.prototxt"));
70     EXPECT_FALSE(net.empty());
71     net = readNet(findDataFile("dnn/openface_nn4.small2.v1.t7", false));
72     EXPECT_FALSE(net.empty());
73     net = readNet(findDataFile("dnn/tiny-yolo-voc.cfg"),
74                   findDataFile("dnn/tiny-yolo-voc.weights", false));
75     EXPECT_FALSE(net.empty());
76     net = readNet(findDataFile("dnn/ssd_mobilenet_v1_coco.pbtxt"),
77                   findDataFile("dnn/ssd_mobilenet_v1_coco.pb", false));
78     EXPECT_FALSE(net.empty());
79 }
80
81 typedef testing::TestWithParam<tuple<Backend, Target> > dump;
82 TEST_P(dump, Regression)
83 {
84     const int backend  = get<0>(GetParam());
85     const int target   = get<1>(GetParam());
86     Net net = readNet(findDataFile("dnn/squeezenet_v1.1.prototxt"),
87                       findDataFile("dnn/squeezenet_v1.1.caffemodel", false));
88
89     int size[] = {1, 3, 227, 227};
90     Mat input = cv::Mat::ones(4, size, CV_32F);
91     net.setInput(input);
92     net.setPreferableBackend(backend);
93     net.setPreferableTarget(target);
94     EXPECT_FALSE(net.dump().empty());
95     net.forward();
96     EXPECT_FALSE(net.dump().empty());
97 }
98
99 INSTANTIATE_TEST_CASE_P(/**/, dump, dnnBackendsAndTargets());
100
101 class FirstCustomLayer CV_FINAL : public Layer
102 {
103 public:
104     FirstCustomLayer(const LayerParams &params) : Layer(params) {}
105
106     static Ptr<Layer> create(LayerParams& params)
107     {
108         return Ptr<Layer>(new FirstCustomLayer(params));
109     }
110
111     void forward(InputArrayOfArrays, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays) CV_OVERRIDE
112     {
113         CV_TRACE_FUNCTION();
114         CV_TRACE_ARG_VALUE(name, "name", name.c_str());
115
116         std::vector<Mat> outputs;
117         outputs_arr.getMatVector(outputs);
118         outputs[0].setTo(1);
119     }
120 };
121
122 class SecondCustomLayer CV_FINAL : public Layer
123 {
124 public:
125     SecondCustomLayer(const LayerParams &params) : Layer(params) {}
126
127     static Ptr<Layer> create(LayerParams& params)
128     {
129         return Ptr<Layer>(new SecondCustomLayer(params));
130     }
131
132     void forward(InputArrayOfArrays, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays) CV_OVERRIDE
133     {
134         CV_TRACE_FUNCTION();
135         CV_TRACE_ARG_VALUE(name, "name", name.c_str());
136
137         std::vector<Mat> outputs;
138         outputs_arr.getMatVector(outputs);
139         outputs[0].setTo(2);
140     }
141 };
142
143 TEST(LayerFactory, custom_layers)
144 {
145     LayerParams lp;
146     lp.name = "name";
147     lp.type = "CustomType";
148
149     Mat inp(1, 1, CV_32FC1);
150     for (int i = 0; i < 3; ++i)
151     {
152         if (i == 0)      { CV_DNN_REGISTER_LAYER_CLASS(CustomType, FirstCustomLayer); }
153         else if (i == 1) { CV_DNN_REGISTER_LAYER_CLASS(CustomType, SecondCustomLayer); }
154         else if (i == 2) { LayerFactory::unregisterLayer("CustomType"); }
155
156         Net net;
157         net.addLayerToPrev(lp.name, lp.type, lp);
158
159         net.setInput(inp);
160         net.setPreferableBackend(DNN_BACKEND_OPENCV);
161         Mat output = net.forward();
162
163         if (i == 0)      { EXPECT_EQ(output.at<float>(0), 1); }
164         else if (i == 1) { EXPECT_EQ(output.at<float>(0), 2); }
165         else if (i == 2) { EXPECT_EQ(output.at<float>(0), 1); }
166     }
167     LayerFactory::unregisterLayer("CustomType");
168 }
169
170 typedef testing::TestWithParam<tuple<float, Vec3f, int, tuple<Backend, Target> > > setInput;
171 TEST_P(setInput, normalization)
172 {
173     const float kScale = get<0>(GetParam());
174     const Scalar kMean = get<1>(GetParam());
175     const int dtype    = get<2>(GetParam());
176     const int backend  = get<0>(get<3>(GetParam()));
177     const int target   = get<1>(get<3>(GetParam()));
178     const bool kSwapRB = true;
179
180     if (backend == DNN_BACKEND_OPENCV && target == DNN_TARGET_OPENCL_FP16 && dtype != CV_32F)
181         applyTestTag(CV_TEST_TAG_DNN_SKIP_OPENCL_FP16);
182     if (backend == DNN_BACKEND_VKCOM && dtype != CV_32F)
183         throw SkipTestException(CV_TEST_TAG_DNN_SKIP_VULKAN);
184
185     Mat inp(5, 5, CV_8UC3);
186     randu(inp, 0, 255);
187     Mat ref = blobFromImage(inp, kScale, Size(), kMean, kSwapRB, /*crop*/false);
188
189     LayerParams lp;
190     Net net;
191     net.addLayerToPrev("testLayer", "Identity", lp);
192     net.setPreferableBackend(backend);
193     net.setPreferableTarget(target);
194
195     Mat blob = blobFromImage(inp, 1.0, Size(), Scalar(), kSwapRB, /*crop*/false, dtype);
196     ASSERT_EQ(blob.type(), dtype);
197     net.setInput(blob, "", kScale, kMean);
198     Mat out = net.forward();
199     ASSERT_EQ(out.type(), CV_32F);
200     normAssert(ref, out, "", 4e-4, 1e-3);
201 }
202
203 INSTANTIATE_TEST_CASE_P(/**/, setInput, Combine(
204   Values(1.0f, 1.0 / 127.5),
205   Values(Vec3f(), Vec3f(50, 50, 50), Vec3f(10, 50, 140)),
206   Values(CV_32F, CV_8U),
207   dnnBackendsAndTargets()
208 ));
209
210 class CustomLayerWithDeprecatedForward CV_FINAL : public Layer
211 {
212 public:
213     CustomLayerWithDeprecatedForward(const LayerParams &params) : Layer(params) {}
214
215     static Ptr<Layer> create(LayerParams& params)
216     {
217         return Ptr<Layer>(new CustomLayerWithDeprecatedForward(params));
218     }
219
220     virtual void forward(std::vector<Mat*> &inputs, std::vector<Mat> &outputs, std::vector<Mat> &internals) CV_OVERRIDE
221     {
222         CV_Assert_N(inputs[0]->depth() == CV_32F, outputs[0].depth() == CV_32F);
223         cv::add(*inputs[0], 0.5f, outputs[0]);
224     }
225 };
226
227 class CustomLayerWithDeprecatedForwardAndFallback CV_FINAL : public Layer
228 {
229 public:
230     CustomLayerWithDeprecatedForwardAndFallback(const LayerParams &params) : Layer(params) {}
231
232     static Ptr<Layer> create(LayerParams& params)
233     {
234         return Ptr<Layer>(new CustomLayerWithDeprecatedForwardAndFallback(params));
235     }
236
237     void forward(InputArrayOfArrays inputs, OutputArrayOfArrays outputs, OutputArrayOfArrays internals) CV_OVERRIDE
238     {
239         CV_TRACE_FUNCTION();
240         CV_TRACE_ARG_VALUE(name, "name", name.c_str());
241
242         CV_OCL_RUN(preferableTarget == DNN_TARGET_OPENCL || preferableTarget == DNN_TARGET_OPENCL_FP16,
243                    forward_ocl(inputs, outputs, internals));
244
245         Layer::forward_fallback(inputs, outputs, internals);
246     }
247
248     virtual void forward(std::vector<Mat*> &inputs, std::vector<Mat> &outputs, std::vector<Mat> &internals) CV_OVERRIDE
249     {
250         CV_Assert_N(inputs[0]->depth() == CV_32F, outputs[0].depth() == CV_32F);
251         cv::add(*inputs[0], 0.5f, outputs[0]);
252     }
253
254 #ifdef HAVE_OPENCL
255     bool forward_ocl(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays internals_arr)
256     {
257         if (inputs_arr.depth() != CV_32F)
258             return false;
259
260         std::vector<UMat> inputs;
261         std::vector<UMat> outputs;
262         inputs_arr.getUMatVector(inputs);
263         outputs_arr.getUMatVector(outputs);
264         cv::add(inputs[0], 0.5f, outputs[0]);
265         return true;
266     }
267 #endif
268 };
269
270 typedef testing::TestWithParam<tuple<Backend, Target> > DeprecatedForward;
271 TEST_P(DeprecatedForward, CustomLayer)
272 {
273     const int backend  = get<0>(GetParam());
274     const int target   = get<1>(GetParam());
275
276     Mat inp(5, 5, CV_32FC1);
277     randu(inp, -1.0f, 1.0f);
278     inp = blobFromImage(inp);
279
280     CV_DNN_REGISTER_LAYER_CLASS(CustomType, CustomLayerWithDeprecatedForward);
281     try
282     {
283         LayerParams lp;
284         Net net;
285         net.addLayerToPrev("testLayer", "CustomType", lp);
286         net.setPreferableBackend(backend);
287         net.setPreferableTarget(target);
288         net.setInput(inp);
289         Mat out = net.forward();
290         normAssert(out, inp + 0.5f, "", 2e-4, 7e-4);
291     }
292     catch (...)
293     {
294         LayerFactory::unregisterLayer("CustomType");
295         throw;
296     }
297     LayerFactory::unregisterLayer("CustomType");
298 }
299
300 TEST_P(DeprecatedForward, CustomLayerWithFallback)
301 {
302     const int backend  = get<0>(GetParam());
303     const int target   = get<1>(GetParam());
304
305     Mat inp(5, 5, CV_32FC1);
306     randu(inp, -1.0f, 1.0f);
307     inp = blobFromImage(inp);
308
309     CV_DNN_REGISTER_LAYER_CLASS(CustomType, CustomLayerWithDeprecatedForwardAndFallback);
310     try
311     {
312         LayerParams lp;
313         Net net;
314         net.addLayerToPrev("testLayer", "CustomType", lp);
315         net.setPreferableBackend(backend);
316         net.setPreferableTarget(target);
317         net.setInput(inp);
318         Mat out = net.forward();
319         normAssert(out, inp + 0.5f, "", 2e-4, 7e-4);
320     }
321     catch (...)
322     {
323         LayerFactory::unregisterLayer("CustomType");
324         throw;
325     }
326     LayerFactory::unregisterLayer("CustomType");
327 }
328
329 INSTANTIATE_TEST_CASE_P(/**/, DeprecatedForward, dnnBackendsAndTargets());
330
331 TEST(Net, forwardAndRetrieve)
332 {
333     std::string prototxt =
334         "input: \"data\"\n"
335         "layer {\n"
336         "  name: \"testLayer\"\n"
337         "  type: \"Slice\"\n"
338         "  bottom: \"data\"\n"
339         "  top: \"firstCopy\"\n"
340         "  top: \"secondCopy\"\n"
341         "  slice_param {\n"
342         "    axis: 0\n"
343         "    slice_point: 2\n"
344         "  }\n"
345         "}";
346     Net net = readNetFromCaffe(&prototxt[0], prototxt.size());
347     net.setPreferableBackend(DNN_BACKEND_OPENCV);
348
349     Mat inp(4, 5, CV_32F);
350     randu(inp, -1, 1);
351     net.setInput(inp);
352
353     std::vector<String> outNames;
354     outNames.push_back("testLayer");
355     std::vector<std::vector<Mat> > outBlobs;
356
357     net.forward(outBlobs, outNames);
358
359     EXPECT_EQ(outBlobs.size(), 1);
360     EXPECT_EQ(outBlobs[0].size(), 2);
361     normAssert(outBlobs[0][0], inp.rowRange(0, 2), "first part");
362     normAssert(outBlobs[0][1], inp.rowRange(2, 4), "second part");
363 }
364
365 #ifdef HAVE_INF_ENGINE
366 static const std::chrono::milliseconds async_timeout(10000);
367
368 // This test runs network in synchronous mode for different inputs and then
369 // runs the same model asynchronously for the same inputs.
370 typedef testing::TestWithParam<tuple<int, Target> > Async;
371 TEST_P(Async, set_and_forward_single)
372 {
373     const int dtype = get<0>(GetParam());
374     const int target = get<1>(GetParam());
375
376     const std::string suffix = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? "_fp16" : "";
377     const std::string& model = findDataFile("dnn/layers/layer_convolution" + suffix + ".bin");
378     const std::string& proto = findDataFile("dnn/layers/layer_convolution" + suffix + ".xml");
379
380     Net netSync = readNet(model, proto);
381     netSync.setPreferableTarget(target);
382
383     Net netAsync = readNet(model, proto);
384     netAsync.setPreferableTarget(target);
385
386     // Generate inputs.
387     const int numInputs = 10;
388     std::vector<Mat> inputs(numInputs);
389     int blobSize[] = {2, 6, 75, 113};
390     for (int i = 0; i < numInputs; ++i)
391     {
392         inputs[i].create(4, &blobSize[0], dtype);
393         randu(inputs[i], 0, 255);
394     }
395
396     // Run synchronously.
397     std::vector<Mat> refs(numInputs);
398     for (int i = 0; i < numInputs; ++i)
399     {
400         netSync.setInput(inputs[i]);
401         refs[i] = netSync.forward().clone();
402     }
403
404     // Run asynchronously. To make test more robust, process inputs in the reversed order.
405     for (int i = numInputs - 1; i >= 0; --i)
406     {
407         netAsync.setInput(inputs[i]);
408
409         AsyncArray out = netAsync.forwardAsync();
410         ASSERT_TRUE(out.valid());
411         Mat result;
412         EXPECT_TRUE(out.get(result, async_timeout));
413         normAssert(refs[i], result, format("Index: %d", i).c_str(), 0, 0);
414     }
415 }
416
417 TEST_P(Async, set_and_forward_all)
418 {
419     const int dtype = get<0>(GetParam());
420     const int target = get<1>(GetParam());
421
422     const std::string suffix = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? "_fp16" : "";
423     const std::string& model = findDataFile("dnn/layers/layer_convolution" + suffix + ".bin");
424     const std::string& proto = findDataFile("dnn/layers/layer_convolution" + suffix + ".xml");
425
426
427     Net netSync = readNet(model, proto);
428     netSync.setPreferableTarget(target);
429
430     Net netAsync = readNet(model, proto);
431     netAsync.setPreferableTarget(target);
432
433     // Generate inputs.
434     const int numInputs = 10;
435     std::vector<Mat> inputs(numInputs);
436     int blobSize[] = {2, 6, 75, 113};
437     for (int i = 0; i < numInputs; ++i)
438     {
439         inputs[i].create(4, &blobSize[0], dtype);
440         randu(inputs[i], 0, 255);
441     }
442
443     // Run synchronously.
444     std::vector<Mat> refs(numInputs);
445     for (int i = 0; i < numInputs; ++i)
446     {
447         netSync.setInput(inputs[i]);
448         refs[i] = netSync.forward().clone();
449     }
450
451     // Run asynchronously. To make test more robust, process inputs in the reversed order.
452     std::vector<AsyncArray> outs(numInputs);
453     for (int i = numInputs - 1; i >= 0; --i)
454     {
455         netAsync.setInput(inputs[i]);
456         outs[i] = netAsync.forwardAsync();
457     }
458
459     for (int i = numInputs - 1; i >= 0; --i)
460     {
461         ASSERT_TRUE(outs[i].valid());
462         Mat result;
463         EXPECT_TRUE(outs[i].get(result, async_timeout));
464         normAssert(refs[i], result, format("Index: %d", i).c_str(), 0, 0);
465     }
466 }
467
468 INSTANTIATE_TEST_CASE_P(/**/, Async, Combine(
469   Values(CV_32F, CV_8U),
470   testing::ValuesIn(getAvailableTargets(DNN_BACKEND_INFERENCE_ENGINE))
471 ));
472
473 typedef testing::TestWithParam<Target>  Test_Model_Optimizer;
474 TEST_P(Test_Model_Optimizer, forward_two_nets)
475 {
476     const int target = GetParam();
477
478     const std::string suffix = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? "_fp16" : "";
479     const std::string& model = findDataFile("dnn/layers/layer_convolution" + suffix + ".bin");
480     const std::string& proto = findDataFile("dnn/layers/layer_convolution" + suffix + ".xml");
481
482     Net net0 = readNet(model, proto);
483     net0.setPreferableTarget(target);
484
485     Net net1 = readNet(model, proto);
486     net1.setPreferableTarget(target);
487
488     // Generate inputs.
489     int blobSize[] = {2, 6, 75, 113};
490     Mat input(4, &blobSize[0], CV_32F);
491     randu(input, 0, 255);
492
493     net0.setInput(input);
494     Mat ref0 = net0.forward().clone();
495
496     net1.setInput(input);
497     Mat ref1 = net1.forward();
498
499     net0.setInput(input);
500     Mat ref2 = net0.forward();
501
502     normAssert(ref0, ref2, 0, 0);
503 }
504 INSTANTIATE_TEST_CASE_P(/**/, Test_Model_Optimizer,
505   testing::ValuesIn(getAvailableTargets(DNN_BACKEND_INFERENCE_ENGINE))
506 );
507
508 #endif  // HAVE_INF_ENGINE
509
510 }} // namespace