Merge pull request #9705 from AlexeyAB:dnn_darknet_yolo_v2
[platform/upstream/opencv.git] / modules / dnn / test / test_layers.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                           License Agreement
11 //                For Open Source Computer Vision Library
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 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of the copyright holders may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 #include "test_precomp.hpp"
43 #include <opencv2/core/ocl.hpp>
44 #include <iostream>
45 #include "npy_blob.hpp"
46 #include <opencv2/dnn/shape_utils.hpp>
47 #include <opencv2/dnn/all_layers.hpp>
48 #include <opencv2/ts/ocl_test.hpp>
49
50 namespace cvtest
51 {
52
53 using namespace cv;
54 using namespace cv::dnn;
55
56 template<typename TString>
57 static String _tf(TString filename)
58 {
59     String basetestdir = getOpenCVExtraDir();
60     size_t len = basetestdir.size();
61     if(len > 0 && basetestdir[len-1] != '/' && basetestdir[len-1] != '\\')
62         return (basetestdir + "/dnn/layers") + filename;
63     return (basetestdir + "dnn/layers/") + filename;
64 }
65
66 void runLayer(Ptr<Layer> layer, std::vector<Mat> &inpBlobs, std::vector<Mat> &outBlobs)
67 {
68     size_t i, ninputs = inpBlobs.size();
69     std::vector<Mat> inp_(ninputs);
70     std::vector<Mat*> inp(ninputs);
71     std::vector<Mat> outp, intp;
72     std::vector<MatShape> inputs, outputs, internals;
73
74     for( i = 0; i < ninputs; i++ )
75     {
76         inp_[i] = inpBlobs[i].clone();
77         inp[i] = &inp_[i];
78         inputs.push_back(shape(inp_[i]));
79     }
80
81     layer->getMemoryShapes(inputs, 0, outputs, internals);
82     for(int i = 0; i < outputs.size(); i++)
83     {
84         outp.push_back(Mat(outputs[i], CV_32F));
85     }
86     for(int i = 0; i < internals.size(); i++)
87     {
88         intp.push_back(Mat(internals[i], CV_32F));
89     }
90
91     layer->finalize(inp, outp);
92     layer->forward(inp, outp, intp);
93
94     size_t noutputs = outp.size();
95     outBlobs.resize(noutputs);
96     for( i = 0; i < noutputs; i++ )
97         outBlobs[i] = outp[i];
98 }
99
100
101 void testLayerUsingCaffeModels(String basename, int targetId = DNN_TARGET_CPU,
102                                bool useCaffeModel = false, bool useCommonInputBlob = true)
103 {
104     String prototxt = _tf(basename + ".prototxt");
105     String caffemodel = _tf(basename + ".caffemodel");
106
107     String inpfile = (useCommonInputBlob) ? _tf("blob.npy") : _tf(basename + ".input.npy");
108     String outfile = _tf(basename + ".npy");
109
110     cv::setNumThreads(cv::getNumberOfCPUs());
111
112     Net net = readNetFromCaffe(prototxt, (useCaffeModel) ? caffemodel : String());
113     ASSERT_FALSE(net.empty());
114
115     net.setPreferableBackend(DNN_BACKEND_DEFAULT);
116     net.setPreferableTarget(targetId);
117
118     Mat inp = blobFromNPY(inpfile);
119     Mat ref = blobFromNPY(outfile);
120
121     net.setInput(inp, "input");
122     Mat out = net.forward("output");
123
124     normAssert(ref, out);
125 }
126
127 TEST(Layer_Test_Softmax, Accuracy)
128 {
129     testLayerUsingCaffeModels("layer_softmax");
130 }
131
132 OCL_TEST(Layer_Test_Softmax, Accuracy)
133 {
134     testLayerUsingCaffeModels("layer_softmax", DNN_TARGET_OPENCL);
135 }
136
137 TEST(Layer_Test_LRN_spatial, Accuracy)
138 {
139     testLayerUsingCaffeModels("layer_lrn_spatial");
140 }
141
142 OCL_TEST(Layer_Test_LRN_spatial, Accuracy)
143 {
144     testLayerUsingCaffeModels("layer_lrn_spatial", DNN_TARGET_OPENCL);
145 }
146
147 TEST(Layer_Test_LRN_channels, Accuracy)
148 {
149     testLayerUsingCaffeModels("layer_lrn_channels");
150 }
151
152 OCL_TEST(Layer_Test_LRN_channels, Accuracy)
153 {
154     testLayerUsingCaffeModels("layer_lrn_channels", DNN_TARGET_OPENCL);
155 }
156
157 TEST(Layer_Test_Convolution, Accuracy)
158 {
159     testLayerUsingCaffeModels("layer_convolution", DNN_TARGET_CPU, true);
160 }
161
162 OCL_TEST(Layer_Test_Convolution, Accuracy)
163 {
164     testLayerUsingCaffeModels("layer_convolution", DNN_TARGET_OPENCL, true);
165 }
166
167 TEST(Layer_Test_DeConvolution, Accuracy)
168 {
169     testLayerUsingCaffeModels("layer_deconvolution", DNN_TARGET_CPU, true, false);
170 }
171
172 TEST(Layer_Test_InnerProduct, Accuracy)
173 {
174     testLayerUsingCaffeModels("layer_inner_product", DNN_TARGET_CPU, true);
175 }
176
177 OCL_TEST(Layer_Test_InnerProduct, Accuracy)
178 {
179     testLayerUsingCaffeModels("layer_inner_product", DNN_TARGET_OPENCL, true);
180 }
181
182 TEST(Layer_Test_Pooling_max, Accuracy)
183 {
184     testLayerUsingCaffeModels("layer_pooling_max");
185 }
186
187 OCL_TEST(Layer_Test_Pooling_max, Accuracy)
188 {
189     testLayerUsingCaffeModels("layer_pooling_max", DNN_TARGET_OPENCL);
190 }
191
192 TEST(Layer_Test_Pooling_ave, Accuracy)
193 {
194     testLayerUsingCaffeModels("layer_pooling_ave");
195 }
196
197 OCL_TEST(Layer_Test_Pooling_ave, Accuracy)
198 {
199     testLayerUsingCaffeModels("layer_pooling_ave", DNN_TARGET_OPENCL);
200 }
201
202 TEST(Layer_Test_MVN, Accuracy)
203 {
204     testLayerUsingCaffeModels("layer_mvn");
205 }
206
207 void testReshape(const MatShape& inputShape, const MatShape& targetShape,
208                  int axis = 0, int num_axes = -1,
209                  MatShape mask = MatShape())
210 {
211     LayerParams params;
212     params.set("axis", axis);
213     params.set("num_axes", num_axes);
214     if (!mask.empty())
215     {
216         params.set("dim", DictValue::arrayInt<int*>(&mask[0], mask.size()));
217     }
218
219     Mat inp(inputShape.size(), &inputShape[0], CV_32F);
220     std::vector<Mat> inpVec(1, inp);
221     std::vector<Mat> outVec, intVec;
222
223     Ptr<Layer> rl = LayerFactory::createLayerInstance("Reshape", params);
224     runLayer(rl, inpVec, outVec);
225
226     Mat& out = outVec[0];
227     MatShape shape(out.size.p, out.size.p + out.dims);
228     EXPECT_EQ(shape, targetShape);
229 }
230
231 TEST(Layer_Test_Reshape, Accuracy)
232 {
233     {
234         int inp[] = {4, 3, 1, 2};
235         int out[] = {4, 3, 2};
236         testReshape(MatShape(inp, inp + 4), MatShape(out, out + 3), 2, 1);
237     }
238     {
239         int inp[] = {1, 128, 4, 4};
240         int out[] = {1, 2048};
241         int mask[] = {-1, 2048};
242         testReshape(MatShape(inp, inp + 4), MatShape(out, out + 2), 0, -1,
243                     MatShape(mask, mask + 2));
244     }
245 }
246
247 TEST(Layer_Test_BatchNorm, Accuracy)
248 {
249     testLayerUsingCaffeModels("layer_batch_norm", DNN_TARGET_CPU, true);
250 }
251
252 TEST(Layer_Test_ReLU, Accuracy)
253 {
254     testLayerUsingCaffeModels("layer_relu");
255 }
256
257 OCL_TEST(Layer_Test_ReLU, Accuracy)
258 {
259     testLayerUsingCaffeModels("layer_relu", DNN_TARGET_OPENCL);
260 }
261
262 TEST(Layer_Test_Dropout, Accuracy)
263 {
264     testLayerUsingCaffeModels("layer_dropout");
265 }
266
267 TEST(Layer_Test_Concat, Accuracy)
268 {
269     testLayerUsingCaffeModels("layer_concat");
270 }
271
272 OCL_TEST(Layer_Test_Concat, Accuracy)
273 {
274     testLayerUsingCaffeModels("layer_concat", DNN_TARGET_OPENCL);
275 }
276
277 TEST(Layer_Test_Eltwise, Accuracy)
278 {
279     testLayerUsingCaffeModels("layer_eltwise");
280 }
281
282 TEST(Layer_Test_PReLU, Accuracy)
283 {
284     testLayerUsingCaffeModels("layer_prelu", DNN_TARGET_CPU, true);
285 }
286
287 //template<typename XMat>
288 //static void test_Layer_Concat()
289 //{
290 //    Matx21f a(1.f, 1.f), b(2.f, 2.f), c(3.f, 3.f);
291 //    std::vector<Blob> res(1), src = { Blob(XMat(a)), Blob(XMat(b)), Blob(XMat(c)) };
292 //    Blob ref(XMat(Matx23f(1.f, 2.f, 3.f, 1.f, 2.f, 3.f)));
293 //
294 //    runLayer(ConcatLayer::create(1), src, res);
295 //    normAssert(ref, res[0]);
296 //}
297 //TEST(Layer_Concat, Accuracy)
298 //{
299 //    test_Layer_Concat<Mat>());
300 //}
301 //OCL_TEST(Layer_Concat, Accuracy)
302 //{
303 //    OCL_ON(test_Layer_Concat<Mat>());
304 //    );
305 //}
306
307 static void test_Reshape_Split_Slice_layers()
308 {
309     Net net = readNetFromCaffe(_tf("reshape_and_slice_routines.prototxt"));
310     ASSERT_FALSE(net.empty());
311
312     Mat input(6, 12, CV_32F);
313     RNG rng(0);
314     rng.fill(input, RNG::UNIFORM, -1, 1);
315
316     net.setInput(input, "input");
317     Mat output = net.forward("output");
318
319     normAssert(input, output);
320 }
321
322 TEST(Layer_Test_Reshape_Split_Slice, Accuracy)
323 {
324     test_Reshape_Split_Slice_layers();
325 }
326
327 TEST(Layer_Conv_Elu, Accuracy)
328 {
329     Net net = readNetFromTensorflow(_tf("layer_elu_model.pb"));
330     ASSERT_FALSE(net.empty());
331
332     Mat inp = blobFromNPY(_tf("layer_elu_in.npy"));
333     Mat ref = blobFromNPY(_tf("layer_elu_out.npy"));
334
335     net.setInput(inp, "input");
336     Mat out = net.forward();
337
338     normAssert(ref, out);
339 }
340
341 class Layer_LSTM_Test : public ::testing::Test
342 {
343 public:
344     int numInp, numOut;
345     Mat Wh, Wx, b;
346     Ptr<LSTMLayer> layer;
347     std::vector<Mat> inputs, outputs;
348
349     Layer_LSTM_Test() {}
350
351     void init(const MatShape &inpShape_, const MatShape &outShape_,
352               bool produceCellOutput, bool useTimestampDim)
353     {
354         numInp = total(inpShape_);
355         numOut = total(outShape_);
356
357         Wh = Mat::ones(4 * numOut, numOut, CV_32F);
358         Wx = Mat::ones(4 * numOut, numInp, CV_32F);
359         b  = Mat::ones(4 * numOut, 1, CV_32F);
360
361         LayerParams lp;
362         lp.blobs.resize(3);
363         lp.blobs[0] = Wh;
364         lp.blobs[1] = Wx;
365         lp.blobs[2] = b;
366         lp.set<bool>("produce_cell_output", produceCellOutput);
367         lp.set<bool>("use_timestamp_dim", useTimestampDim);
368
369         layer = LSTMLayer::create(lp);
370         layer->setOutShape(outShape_);
371     }
372 };
373
374 TEST_F(Layer_LSTM_Test, get_set_test)
375 {
376     const int TN = 4;
377     MatShape inpShape = shape(5, 3, 2);
378     MatShape outShape = shape(3, 1, 2);
379     MatShape inpResShape = concat(shape(TN), inpShape);
380     MatShape outResShape = concat(shape(TN), outShape);
381
382     init(inpShape, outShape, true, false);
383     layer->setOutShape(outShape);
384
385     Mat C((int)outResShape.size(), &outResShape[0], CV_32F);
386     randu(C, -1., 1.);
387     Mat H = C.clone();
388     randu(H, -1., 1.);
389
390     Mat inp((int)inpResShape.size(), &inpResShape[0], CV_32F);
391     randu(inp, -1., 1.);
392
393     inputs.push_back(inp);
394     runLayer(layer, inputs, outputs);
395
396     EXPECT_EQ(2u, outputs.size());
397
398     print(outResShape, "outResShape");
399     print(shape(outputs[0]), "out0");
400     print(shape(outputs[0]), "out1");
401
402     EXPECT_EQ(outResShape, shape(outputs[0]));
403     EXPECT_EQ(outResShape, shape(outputs[1]));
404
405     EXPECT_EQ(0, layer->inputNameToIndex("x"));
406     EXPECT_EQ(0, layer->outputNameToIndex("h"));
407     EXPECT_EQ(1, layer->outputNameToIndex("c"));
408 }
409
410 TEST(Layer_LSTM_Test_Accuracy_with_, CaffeRecurrent)
411 {
412     LayerParams lp;
413     lp.blobs.resize(3);
414     lp.blobs[0] = blobFromNPY(_tf("lstm.prototxt.w_2.npy"));  // Wh
415     lp.blobs[1] = blobFromNPY(_tf("lstm.prototxt.w_0.npy"));  // Wx
416     lp.blobs[2] = blobFromNPY(_tf("lstm.prototxt.w_1.npy"));  // bias
417     Ptr<LSTMLayer> layer = LSTMLayer::create(lp);
418
419     Mat inp = blobFromNPY(_tf("recurrent.input.npy"));
420     std::vector<Mat> inputs(1, inp), outputs;
421     runLayer(layer, inputs, outputs);
422
423     Mat h_t_reference = blobFromNPY(_tf("lstm.prototxt.h_1.npy"));
424     normAssert(h_t_reference, outputs[0]);
425 }
426
427 TEST(Layer_RNN_Test_Accuracy_with_, CaffeRecurrent)
428 {
429     Ptr<RNNLayer> layer = RNNLayer::create(LayerParams());
430
431     layer->setWeights(
432                 blobFromNPY(_tf("rnn.prototxt.w_0.npy")),
433                 blobFromNPY(_tf("rnn.prototxt.w_1.npy")),
434                 blobFromNPY(_tf("rnn.prototxt.w_2.npy")),
435                 blobFromNPY(_tf("rnn.prototxt.w_3.npy")),
436                 blobFromNPY(_tf("rnn.prototxt.w_4.npy")) );
437
438     std::vector<Mat> output, input(1, blobFromNPY(_tf("recurrent.input.npy")));
439     runLayer(layer, input, output);
440
441     Mat h_ref = blobFromNPY(_tf("rnn.prototxt.h_1.npy"));
442     normAssert(h_ref, output[0]);
443 }
444
445
446 class Layer_RNN_Test : public ::testing::Test
447 {
448 public:
449     int nX, nH, nO, nT, nS;
450     Mat Whh, Wxh, bh, Who, bo;
451     Ptr<RNNLayer> layer;
452
453     std::vector<Mat> inputs, outputs;
454
455     Layer_RNN_Test()
456     {
457         nT = 3;
458         nS = 5;
459         nX = 31;
460         nH = 64;
461         nO = 100;
462
463         Whh = Mat::ones(nH, nH, CV_32F);
464         Wxh = Mat::ones(nH, nX, CV_32F);
465         bh  = Mat::ones(nH, 1, CV_32F);
466         Who = Mat::ones(nO, nH, CV_32F);
467         bo  = Mat::ones(nO, 1, CV_32F);
468
469         layer = RNNLayer::create(LayerParams());
470         layer->setProduceHiddenOutput(true);
471         layer->setWeights(Wxh, bh, Whh, Who, bo);
472     }
473 };
474
475 TEST_F(Layer_RNN_Test, get_set_test)
476 {
477     int sz[] = { nT, nS, 1, nX };
478     Mat inp(4, sz, CV_32F);
479     randu(inp, -1., 1.);
480     inputs.push_back(inp);
481     runLayer(layer, inputs, outputs);
482
483     EXPECT_EQ(outputs.size(), 2u);
484     EXPECT_EQ(shape(outputs[0]), shape(nT, nS, nO));
485     EXPECT_EQ(shape(outputs[1]), shape(nT, nS, nH));
486 }
487
488 void testLayerUsingDarknetModels(String basename, bool useDarknetModel = false, bool useCommonInputBlob = true)
489 {
490     String cfg = _tf(basename + ".cfg");
491     String weights = _tf(basename + ".weights");
492
493     String inpfile = (useCommonInputBlob) ? _tf("blob.npy") : _tf(basename + ".input.npy");
494     String outfile = _tf(basename + ".npy");
495
496     cv::setNumThreads(cv::getNumberOfCPUs());
497
498     Net net = readNetFromDarknet(cfg, (useDarknetModel) ? weights : String());
499     ASSERT_FALSE(net.empty());
500
501     Mat inp = blobFromNPY(inpfile);
502     Mat ref = blobFromNPY(outfile);
503
504     net.setInput(inp, "data");
505     Mat out = net.forward();
506
507     normAssert(ref, out);
508 }
509
510 TEST(Layer_Test_Region, Accuracy)
511 {
512     testLayerUsingDarknetModels("region", false, false);
513 }
514
515 TEST(Layer_Test_Reorg, Accuracy)
516 {
517     testLayerUsingDarknetModels("reorg", false, false);
518 }
519
520 }