ff2122856b2bd75b4cae28b7ef58cc7dc68f19d7
[platform/upstream/opencv.git] / modules / dnn / test / test_tf_importer.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 /*
9 Test for Tensorflow models loading
10 */
11
12 #include "test_precomp.hpp"
13 #include "npy_blob.hpp"
14
15 namespace opencv_test
16 {
17
18 using namespace cv;
19 using namespace cv::dnn;
20
21 template<typename TString>
22 static std::string _tf(TString filename)
23 {
24     return (getOpenCVExtraDir() + "/dnn/") + filename;
25 }
26
27 TEST(Test_TensorFlow, read_inception)
28 {
29     Net net;
30     {
31         const string model = findDataFile("dnn/tensorflow_inception_graph.pb", false);
32         net = readNetFromTensorflow(model);
33         ASSERT_FALSE(net.empty());
34     }
35
36     Mat sample = imread(_tf("grace_hopper_227.png"));
37     ASSERT_TRUE(!sample.empty());
38     Mat input;
39     resize(sample, input, Size(224, 224));
40     input -= 128; // mean sub
41
42     Mat inputBlob = blobFromImage(input);
43
44     net.setInput(inputBlob, "input");
45     Mat out = net.forward("softmax2");
46
47     std::cout << out.dims << std::endl;
48 }
49
50 TEST(Test_TensorFlow, inception_accuracy)
51 {
52     Net net;
53     {
54         const string model = findDataFile("dnn/tensorflow_inception_graph.pb", false);
55         net = readNetFromTensorflow(model);
56         ASSERT_FALSE(net.empty());
57     }
58
59     Mat sample = imread(_tf("grace_hopper_227.png"));
60     ASSERT_TRUE(!sample.empty());
61     resize(sample, sample, Size(224, 224));
62     Mat inputBlob = blobFromImage(sample);
63
64     net.setInput(inputBlob, "input");
65     Mat out = net.forward("softmax2");
66
67     Mat ref = blobFromNPY(_tf("tf_inception_prob.npy"));
68
69     normAssert(ref, out);
70 }
71
72 static std::string path(const std::string& file)
73 {
74     return findDataFile("dnn/tensorflow/" + file, false);
75 }
76
77 static void runTensorFlowNet(const std::string& prefix, int targetId = DNN_TARGET_CPU, bool hasText = false,
78                              double l1 = 1e-5, double lInf = 1e-4,
79                              bool memoryLoad = false)
80 {
81     std::string netPath = path(prefix + "_net.pb");
82     std::string netConfig = (hasText ? path(prefix + "_net.pbtxt") : "");
83     std::string inpPath = path(prefix + "_in.npy");
84     std::string outPath = path(prefix + "_out.npy");
85
86     Net net;
87     if (memoryLoad)
88     {
89         // Load files into a memory buffers
90         string dataModel;
91         ASSERT_TRUE(readFileInMemory(netPath, dataModel));
92
93         string dataConfig;
94         if (hasText)
95             ASSERT_TRUE(readFileInMemory(netConfig, dataConfig));
96
97         net = readNetFromTensorflow(dataModel.c_str(), dataModel.size(),
98                                     dataConfig.c_str(), dataConfig.size());
99     }
100     else
101         net = readNetFromTensorflow(netPath, netConfig);
102
103     ASSERT_FALSE(net.empty());
104
105     net.setPreferableBackend(DNN_BACKEND_DEFAULT);
106     net.setPreferableTarget(targetId);
107
108     cv::Mat input = blobFromNPY(inpPath);
109     cv::Mat target = blobFromNPY(outPath);
110
111     net.setInput(input);
112     cv::Mat output = net.forward();
113     normAssert(target, output, "", l1, lInf);
114 }
115
116 typedef testing::TestWithParam<DNNTarget> Test_TensorFlow_layers;
117
118 TEST_P(Test_TensorFlow_layers, conv)
119 {
120     int targetId = GetParam();
121     runTensorFlowNet("single_conv", targetId);
122     runTensorFlowNet("atrous_conv2d_valid", targetId);
123     runTensorFlowNet("atrous_conv2d_same", targetId);
124     runTensorFlowNet("depthwise_conv2d", targetId);
125 }
126
127 TEST_P(Test_TensorFlow_layers, padding)
128 {
129     int targetId = GetParam();
130     runTensorFlowNet("padding_same", targetId);
131     runTensorFlowNet("padding_valid", targetId);
132     runTensorFlowNet("spatial_padding", targetId);
133 }
134
135 TEST_P(Test_TensorFlow_layers, eltwise_add_mul)
136 {
137     runTensorFlowNet("eltwise_add_mul", GetParam());
138 }
139
140 TEST_P(Test_TensorFlow_layers, pad_and_concat)
141 {
142     runTensorFlowNet("pad_and_concat", GetParam());
143 }
144
145 TEST_P(Test_TensorFlow_layers, batch_norm)
146 {
147     int targetId = GetParam();
148     runTensorFlowNet("batch_norm", targetId);
149     runTensorFlowNet("fused_batch_norm", targetId);
150     runTensorFlowNet("batch_norm_text", targetId, true);
151     runTensorFlowNet("mvn_batch_norm", targetId);
152     runTensorFlowNet("mvn_batch_norm_1x1", targetId);
153     runTensorFlowNet("unfused_batch_norm", targetId);
154     runTensorFlowNet("fused_batch_norm_no_gamma", targetId);
155     runTensorFlowNet("unfused_batch_norm_no_gamma", targetId);
156 }
157
158 TEST_P(Test_TensorFlow_layers, pooling)
159 {
160     int targetId = GetParam();
161     runTensorFlowNet("max_pool_even", targetId);
162     runTensorFlowNet("max_pool_odd_valid", targetId);
163     runTensorFlowNet("ave_pool_same", targetId);
164     runTensorFlowNet("max_pool_odd_same", targetId);
165     runTensorFlowNet("reduce_mean", targetId);  // an average pooling over all spatial dimensions.
166 }
167
168 TEST_P(Test_TensorFlow_layers, deconvolution)
169 {
170     int targetId = GetParam();
171     runTensorFlowNet("deconvolution", targetId);
172     runTensorFlowNet("deconvolution_same", targetId);
173     runTensorFlowNet("deconvolution_stride_2_same", targetId);
174     runTensorFlowNet("deconvolution_adj_pad_valid", targetId);
175     runTensorFlowNet("deconvolution_adj_pad_same", targetId);
176 }
177
178 TEST_P(Test_TensorFlow_layers, matmul)
179 {
180     int targetId = GetParam();
181     runTensorFlowNet("matmul", targetId);
182     runTensorFlowNet("nhwc_reshape_matmul", targetId);
183     runTensorFlowNet("nhwc_transpose_reshape_matmul", targetId);
184 }
185
186 TEST_P(Test_TensorFlow_layers, reshape)
187 {
188     int targetId = GetParam();
189     runTensorFlowNet("shift_reshape_no_reorder", targetId);
190     runTensorFlowNet("reshape_reduce", targetId);
191     runTensorFlowNet("flatten", targetId, true);
192     runTensorFlowNet("unfused_flatten", targetId);
193     runTensorFlowNet("unfused_flatten_unknown_batch", targetId);
194 }
195
196 INSTANTIATE_TEST_CASE_P(/**/, Test_TensorFlow_layers, availableDnnTargets());
197
198 typedef testing::TestWithParam<DNNTarget> Test_TensorFlow_nets;
199
200 TEST_P(Test_TensorFlow_nets, MobileNet_SSD)
201 {
202     std::string netPath = findDataFile("dnn/ssd_mobilenet_v1_coco.pb", false);
203     std::string netConfig = findDataFile("dnn/ssd_mobilenet_v1_coco.pbtxt", false);
204     std::string imgPath = findDataFile("dnn/street.png", false);
205
206     Mat inp;
207     resize(imread(imgPath), inp, Size(300, 300));
208     inp = blobFromImage(inp, 1.0f / 127.5, Size(), Scalar(127.5, 127.5, 127.5), true);
209
210     std::vector<String> outNames(3);
211     outNames[0] = "concat";
212     outNames[1] = "concat_1";
213     outNames[2] = "detection_out";
214
215     std::vector<Mat> target(outNames.size());
216     for (int i = 0; i < outNames.size(); ++i)
217     {
218         std::string path = findDataFile("dnn/tensorflow/ssd_mobilenet_v1_coco." + outNames[i] + ".npy", false);
219         target[i] = blobFromNPY(path);
220     }
221
222     Net net = readNetFromTensorflow(netPath, netConfig);
223
224     net.setPreferableTarget(GetParam());
225
226     net.setInput(inp);
227
228     std::vector<Mat> output;
229     net.forward(output, outNames);
230
231     normAssert(target[0].reshape(1, 1), output[0].reshape(1, 1), "", 1e-5, 1.5e-4);
232     normAssert(target[1].reshape(1, 1), output[1].reshape(1, 1), "", 1e-5, 3e-4);
233     normAssert(target[2].reshape(1, 1), output[2].reshape(1, 1), "", 4e-5, 1e-2);
234 }
235
236 TEST_P(Test_TensorFlow_nets, Inception_v2_SSD)
237 {
238     std::string proto = findDataFile("dnn/ssd_inception_v2_coco_2017_11_17.pbtxt", false);
239     std::string model = findDataFile("dnn/ssd_inception_v2_coco_2017_11_17.pb", false);
240
241     Net net = readNetFromTensorflow(model, proto);
242     Mat img = imread(findDataFile("dnn/street.png", false));
243     Mat blob = blobFromImage(img, 1.0f / 127.5, Size(300, 300), Scalar(127.5, 127.5, 127.5), true, false);
244
245     net.setPreferableTarget(GetParam());
246
247     net.setInput(blob);
248     // Output has shape 1x1xNx7 where N - number of detections.
249     // An every detection is a vector of values [id, classId, confidence, left, top, right, bottom]
250     Mat out = net.forward();
251     out = out.reshape(1, out.total() / 7);
252
253     Mat detections;
254     for (int i = 0; i < out.rows; ++i)
255     {
256         if (out.at<float>(i, 2) > 0.5)
257           detections.push_back(out.row(i).colRange(1, 7));
258     }
259
260     Mat ref = (Mat_<float>(5, 6) << 1, 0.90176028, 0.19872092, 0.36311883, 0.26461923, 0.63498729,
261                                     3, 0.93569964, 0.64865261, 0.45906419, 0.80675775, 0.65708131,
262                                     3, 0.75838411, 0.44668293, 0.45907149, 0.49459291, 0.52197015,
263                                     10, 0.95932811, 0.38349164, 0.32528657, 0.40387636, 0.39165527,
264                                     10, 0.93973452, 0.66561931, 0.37841269, 0.68074018, 0.42907384);
265     normAssert(detections, ref);
266 }
267
268 TEST_P(Test_TensorFlow_nets, opencv_face_detector_uint8)
269 {
270     std::string proto = findDataFile("dnn/opencv_face_detector.pbtxt", false);
271     std::string model = findDataFile("dnn/opencv_face_detector_uint8.pb", false);
272
273     Net net = readNetFromTensorflow(model, proto);
274     Mat img = imread(findDataFile("gpu/lbpcascade/er.png", false));
275     Mat blob = blobFromImage(img, 1.0, Size(), Scalar(104.0, 177.0, 123.0), false, false);
276
277     net.setPreferableTarget(GetParam());
278
279     net.setInput(blob);
280     // Output has shape 1x1xNx7 where N - number of detections.
281     // An every detection is a vector of values [id, classId, confidence, left, top, right, bottom]
282     Mat out = net.forward();
283
284     // References are from test for Caffe model.
285     Mat ref = (Mat_<float>(6, 5) << 0.99520785, 0.80997437, 0.16379407, 0.87996572, 0.26685631,
286                                     0.9934696, 0.2831718, 0.50738752, 0.345781, 0.5985168,
287                                     0.99096733, 0.13629119, 0.24892329, 0.19756334, 0.3310290,
288                                     0.98977017, 0.23901358, 0.09084064, 0.29902688, 0.1769477,
289                                     0.97203469, 0.67965847, 0.06876482, 0.73999709, 0.1513494,
290                                     0.95097077, 0.51901293, 0.45863652, 0.5777427, 0.5347801);
291     normAssert(out.reshape(1, out.total() / 7).rowRange(0, 6).colRange(2, 7), ref, "", 2.8e-4, 3.4e-3);
292 }
293
294 INSTANTIATE_TEST_CASE_P(/**/, Test_TensorFlow_nets, availableDnnTargets());
295
296 TEST(Test_TensorFlow, defun)
297 {
298     runTensorFlowNet("defun_dropout");
299 }
300
301 TEST(Test_TensorFlow, fp16)
302 {
303     const float l1 = 1e-3;
304     const float lInf = 1e-2;
305     runTensorFlowNet("fp16_single_conv", DNN_TARGET_CPU, false, l1, lInf);
306     runTensorFlowNet("fp16_deconvolution", DNN_TARGET_CPU, false, l1, lInf);
307     runTensorFlowNet("fp16_max_pool_odd_same", DNN_TARGET_CPU, false, l1, lInf);
308     runTensorFlowNet("fp16_padding_valid", DNN_TARGET_CPU, false, l1, lInf);
309     runTensorFlowNet("fp16_eltwise_add_mul", DNN_TARGET_CPU, false, l1, lInf);
310     runTensorFlowNet("fp16_max_pool_odd_valid", DNN_TARGET_CPU, false, l1, lInf);
311     runTensorFlowNet("fp16_pad_and_concat", DNN_TARGET_CPU, false, l1, lInf);
312     runTensorFlowNet("fp16_max_pool_even", DNN_TARGET_CPU, false, l1, lInf);
313     runTensorFlowNet("fp16_padding_same", DNN_TARGET_CPU, false, l1, lInf);
314 }
315
316 TEST(Test_TensorFlow, quantized)
317 {
318     runTensorFlowNet("uint8_single_conv");
319 }
320
321 TEST(Test_TensorFlow, lstm)
322 {
323     runTensorFlowNet("lstm", DNN_TARGET_CPU, true);
324 }
325
326 TEST(Test_TensorFlow, split)
327 {
328     runTensorFlowNet("split_equals");
329 }
330
331 TEST(Test_TensorFlow, resize_nearest_neighbor)
332 {
333     runTensorFlowNet("resize_nearest_neighbor");
334 }
335
336 TEST(Test_TensorFlow, slice)
337 {
338     runTensorFlowNet("slice_4d");
339 }
340
341 TEST(Test_TensorFlow, softmax)
342 {
343     runTensorFlowNet("keras_softmax");
344 }
345
346 TEST(Test_TensorFlow, relu6)
347 {
348     runTensorFlowNet("keras_relu6");
349 }
350
351 TEST(Test_TensorFlow, keras_mobilenet_head)
352 {
353     runTensorFlowNet("keras_mobilenet_head");
354 }
355
356 TEST(Test_TensorFlow, memory_read)
357 {
358     double l1 = 1e-5;
359     double lInf = 1e-4;
360     runTensorFlowNet("lstm", DNN_TARGET_CPU, true, l1, lInf, true);
361
362     runTensorFlowNet("batch_norm", DNN_TARGET_CPU, false, l1, lInf, true);
363     runTensorFlowNet("fused_batch_norm", DNN_TARGET_CPU, false, l1, lInf, true);
364     runTensorFlowNet("batch_norm_text", DNN_TARGET_CPU, true, l1, lInf, true);
365 }
366
367 }