029e24103cfba8036641d9312c0068d8cc81cb57
[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_Fused_Concat, Accuracy)
278 {
279     // Test case
280     // input
281     //   |
282     //   v
283     // some_layer
284     // |   |
285     // v   v
286     // concat
287     Net net;
288     int interLayer;
289     {
290         LayerParams lp;
291         lp.type = "AbsVal";
292         lp.name = "someLayer";
293         interLayer = net.addLayerToPrev(lp.name, lp.type, lp);
294     }
295     {
296         LayerParams lp;
297         lp.set("axis", 1);
298         lp.type = "Concat";
299         lp.name = "testConcat";
300         int id = net.addLayer(lp.name, lp.type, lp);
301         net.connect(interLayer, 0, id, 0);
302         net.connect(interLayer, 0, id, 1);
303     }
304     int shape[] = {1, 2, 3, 4};
305     Mat input(4, shape, CV_32F);
306     randu(input, 0.0f, 1.0f);  // [0, 1] to make AbsVal an identity transformation.
307
308     net.setInput(input);
309     Mat out = net.forward();
310
311     normAssert(slice(out, Range::all(), Range(0, 2), Range::all(), Range::all()), input);
312     normAssert(slice(out, Range::all(), Range(2, 4), Range::all(), Range::all()), input);
313
314     //
315
316     testLayerUsingCaffeModels("layer_concat_optim", DNN_TARGET_CPU, true, false);
317 }
318
319 TEST(Layer_Test_Eltwise, Accuracy)
320 {
321     testLayerUsingCaffeModels("layer_eltwise");
322 }
323
324 TEST(Layer_Test_PReLU, Accuracy)
325 {
326     testLayerUsingCaffeModels("layer_prelu", DNN_TARGET_CPU, true);
327     testLayerUsingCaffeModels("layer_prelu_fc", DNN_TARGET_CPU, true, false);
328 }
329
330 //template<typename XMat>
331 //static void test_Layer_Concat()
332 //{
333 //    Matx21f a(1.f, 1.f), b(2.f, 2.f), c(3.f, 3.f);
334 //    std::vector<Blob> res(1), src = { Blob(XMat(a)), Blob(XMat(b)), Blob(XMat(c)) };
335 //    Blob ref(XMat(Matx23f(1.f, 2.f, 3.f, 1.f, 2.f, 3.f)));
336 //
337 //    runLayer(ConcatLayer::create(1), src, res);
338 //    normAssert(ref, res[0]);
339 //}
340 //TEST(Layer_Concat, Accuracy)
341 //{
342 //    test_Layer_Concat<Mat>());
343 //}
344 //OCL_TEST(Layer_Concat, Accuracy)
345 //{
346 //    OCL_ON(test_Layer_Concat<Mat>());
347 //    );
348 //}
349
350 static void test_Reshape_Split_Slice_layers()
351 {
352     Net net = readNetFromCaffe(_tf("reshape_and_slice_routines.prototxt"));
353     ASSERT_FALSE(net.empty());
354
355     Mat input(6, 12, CV_32F);
356     RNG rng(0);
357     rng.fill(input, RNG::UNIFORM, -1, 1);
358
359     net.setInput(input, "input");
360     Mat output = net.forward("output");
361
362     normAssert(input, output);
363 }
364
365 TEST(Layer_Test_Reshape_Split_Slice, Accuracy)
366 {
367     test_Reshape_Split_Slice_layers();
368 }
369
370 TEST(Layer_Conv_Elu, Accuracy)
371 {
372     Net net = readNetFromTensorflow(_tf("layer_elu_model.pb"));
373     ASSERT_FALSE(net.empty());
374
375     Mat inp = blobFromNPY(_tf("layer_elu_in.npy"));
376     Mat ref = blobFromNPY(_tf("layer_elu_out.npy"));
377
378     net.setInput(inp, "input");
379     Mat out = net.forward();
380
381     normAssert(ref, out);
382 }
383
384 class Layer_LSTM_Test : public ::testing::Test
385 {
386 public:
387     int numInp, numOut;
388     Mat Wh, Wx, b;
389     Ptr<LSTMLayer> layer;
390     std::vector<Mat> inputs, outputs;
391
392     Layer_LSTM_Test() {}
393
394     void init(const MatShape &inpShape_, const MatShape &outShape_,
395               bool produceCellOutput, bool useTimestampDim)
396     {
397         numInp = total(inpShape_);
398         numOut = total(outShape_);
399
400         Wh = Mat::ones(4 * numOut, numOut, CV_32F);
401         Wx = Mat::ones(4 * numOut, numInp, CV_32F);
402         b  = Mat::ones(4 * numOut, 1, CV_32F);
403
404         LayerParams lp;
405         lp.blobs.resize(3);
406         lp.blobs[0] = Wh;
407         lp.blobs[1] = Wx;
408         lp.blobs[2] = b;
409         lp.set<bool>("produce_cell_output", produceCellOutput);
410         lp.set<bool>("use_timestamp_dim", useTimestampDim);
411
412         layer = LSTMLayer::create(lp);
413         layer->setOutShape(outShape_);
414     }
415 };
416
417 TEST_F(Layer_LSTM_Test, get_set_test)
418 {
419     const int TN = 4;
420     MatShape inpShape = shape(5, 3, 2);
421     MatShape outShape = shape(3, 1, 2);
422     MatShape inpResShape = concat(shape(TN), inpShape);
423     MatShape outResShape = concat(shape(TN), outShape);
424
425     init(inpShape, outShape, true, false);
426     layer->setOutShape(outShape);
427
428     Mat C((int)outResShape.size(), &outResShape[0], CV_32F);
429     randu(C, -1., 1.);
430     Mat H = C.clone();
431     randu(H, -1., 1.);
432
433     Mat inp((int)inpResShape.size(), &inpResShape[0], CV_32F);
434     randu(inp, -1., 1.);
435
436     inputs.push_back(inp);
437     runLayer(layer, inputs, outputs);
438
439     EXPECT_EQ(2u, outputs.size());
440
441     print(outResShape, "outResShape");
442     print(shape(outputs[0]), "out0");
443     print(shape(outputs[0]), "out1");
444
445     EXPECT_EQ(outResShape, shape(outputs[0]));
446     EXPECT_EQ(outResShape, shape(outputs[1]));
447
448     EXPECT_EQ(0, layer->inputNameToIndex("x"));
449     EXPECT_EQ(0, layer->outputNameToIndex("h"));
450     EXPECT_EQ(1, layer->outputNameToIndex("c"));
451 }
452
453 TEST(Layer_LSTM_Test_Accuracy_with_, CaffeRecurrent)
454 {
455     LayerParams lp;
456     lp.blobs.resize(3);
457     lp.blobs[0] = blobFromNPY(_tf("lstm.prototxt.w_2.npy"));  // Wh
458     lp.blobs[1] = blobFromNPY(_tf("lstm.prototxt.w_0.npy"));  // Wx
459     lp.blobs[2] = blobFromNPY(_tf("lstm.prototxt.w_1.npy"));  // bias
460     Ptr<LSTMLayer> layer = LSTMLayer::create(lp);
461
462     Mat inp = blobFromNPY(_tf("recurrent.input.npy"));
463     std::vector<Mat> inputs(1, inp), outputs;
464     runLayer(layer, inputs, outputs);
465
466     Mat h_t_reference = blobFromNPY(_tf("lstm.prototxt.h_1.npy"));
467     normAssert(h_t_reference, outputs[0]);
468 }
469
470 TEST(Layer_RNN_Test_Accuracy_with_, CaffeRecurrent)
471 {
472     Ptr<RNNLayer> layer = RNNLayer::create(LayerParams());
473
474     layer->setWeights(
475                 blobFromNPY(_tf("rnn.prototxt.w_0.npy")),
476                 blobFromNPY(_tf("rnn.prototxt.w_1.npy")),
477                 blobFromNPY(_tf("rnn.prototxt.w_2.npy")),
478                 blobFromNPY(_tf("rnn.prototxt.w_3.npy")),
479                 blobFromNPY(_tf("rnn.prototxt.w_4.npy")) );
480
481     std::vector<Mat> output, input(1, blobFromNPY(_tf("recurrent.input.npy")));
482     runLayer(layer, input, output);
483
484     Mat h_ref = blobFromNPY(_tf("rnn.prototxt.h_1.npy"));
485     normAssert(h_ref, output[0]);
486 }
487
488
489 class Layer_RNN_Test : public ::testing::Test
490 {
491 public:
492     int nX, nH, nO, nT, nS;
493     Mat Whh, Wxh, bh, Who, bo;
494     Ptr<RNNLayer> layer;
495
496     std::vector<Mat> inputs, outputs;
497
498     Layer_RNN_Test()
499     {
500         nT = 3;
501         nS = 5;
502         nX = 31;
503         nH = 64;
504         nO = 100;
505
506         Whh = Mat::ones(nH, nH, CV_32F);
507         Wxh = Mat::ones(nH, nX, CV_32F);
508         bh  = Mat::ones(nH, 1, CV_32F);
509         Who = Mat::ones(nO, nH, CV_32F);
510         bo  = Mat::ones(nO, 1, CV_32F);
511
512         layer = RNNLayer::create(LayerParams());
513         layer->setProduceHiddenOutput(true);
514         layer->setWeights(Wxh, bh, Whh, Who, bo);
515     }
516 };
517
518 TEST_F(Layer_RNN_Test, get_set_test)
519 {
520     int sz[] = { nT, nS, 1, nX };
521     Mat inp(4, sz, CV_32F);
522     randu(inp, -1., 1.);
523     inputs.push_back(inp);
524     runLayer(layer, inputs, outputs);
525
526     EXPECT_EQ(outputs.size(), 2u);
527     EXPECT_EQ(shape(outputs[0]), shape(nT, nS, nO));
528     EXPECT_EQ(shape(outputs[1]), shape(nT, nS, nH));
529 }
530
531 void testLayerUsingDarknetModels(String basename, bool useDarknetModel = false, bool useCommonInputBlob = true)
532 {
533     String cfg = _tf(basename + ".cfg");
534     String weights = _tf(basename + ".weights");
535
536     String inpfile = (useCommonInputBlob) ? _tf("blob.npy") : _tf(basename + ".input.npy");
537     String outfile = _tf(basename + ".npy");
538
539     cv::setNumThreads(cv::getNumberOfCPUs());
540
541     Net net = readNetFromDarknet(cfg, (useDarknetModel) ? weights : String());
542     ASSERT_FALSE(net.empty());
543
544     Mat inp = blobFromNPY(inpfile);
545     Mat ref = blobFromNPY(outfile);
546
547     net.setInput(inp, "data");
548     Mat out = net.forward();
549
550     normAssert(ref, out);
551 }
552
553 TEST(Layer_Test_Region, Accuracy)
554 {
555     testLayerUsingDarknetModels("region", false, false);
556 }
557
558 TEST(Layer_Test_Reorg, Accuracy)
559 {
560     testLayerUsingDarknetModels("reorg", false, false);
561 }
562
563 TEST(Layer_Test_ROIPooling, Accuracy)
564 {
565     Net net = readNetFromCaffe(_tf("net_roi_pooling.prototxt"));
566
567     Mat inp = blobFromNPY(_tf("net_roi_pooling.input.npy"));
568     Mat rois = blobFromNPY(_tf("net_roi_pooling.rois.npy"));
569     Mat ref = blobFromNPY(_tf("net_roi_pooling.npy"));
570
571     net.setInput(inp, "input");
572     net.setInput(rois, "rois");
573
574     Mat out = net.forward();
575
576     normAssert(out, ref);
577 }
578
579 }