Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/dnn/test/test_torch_importer.cpp
16339 views
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) 2013, OpenCV Foundation, 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 "npy_blob.hpp"
44
#include <opencv2/dnn/shape_utils.hpp>
45
#include <opencv2/dnn/layer.details.hpp> // CV_DNN_REGISTER_LAYER_CLASS
46
47
namespace opencv_test
48
{
49
50
using namespace std;
51
using namespace testing;
52
using namespace cv;
53
using namespace cv::dnn;
54
55
template<typename TStr>
56
static std::string _tf(TStr filename, bool inTorchDir = true)
57
{
58
String path = "dnn/";
59
if (inTorchDir)
60
path += "torch/";
61
path += filename;
62
return findDataFile(path, false);
63
}
64
65
TEST(Torch_Importer, simple_read)
66
{
67
Net net;
68
ASSERT_NO_THROW(net = readNetFromTorch(_tf("net_simple_net.txt"), false));
69
ASSERT_FALSE(net.empty());
70
}
71
72
class Test_Torch_layers : public DNNTestLayer
73
{
74
public:
75
void runTorchNet(const String& prefix, String outLayerName = "",
76
bool check2ndBlob = false, bool isBinary = false,
77
double l1 = 0.0, double lInf = 0.0)
78
{
79
String suffix = (isBinary) ? ".dat" : ".txt";
80
81
Mat inp, outRef;
82
ASSERT_NO_THROW( inp = readTorchBlob(_tf(prefix + "_input" + suffix), isBinary) );
83
ASSERT_NO_THROW( outRef = readTorchBlob(_tf(prefix + "_output" + suffix), isBinary) );
84
85
checkBackend(backend, target, &inp, &outRef);
86
87
Net net = readNetFromTorch(_tf(prefix + "_net" + suffix), isBinary);
88
ASSERT_FALSE(net.empty());
89
90
net.setPreferableBackend(backend);
91
net.setPreferableTarget(target);
92
93
if (outLayerName.empty())
94
outLayerName = net.getLayerNames().back();
95
96
net.setInput(inp);
97
std::vector<Mat> outBlobs;
98
net.forward(outBlobs, outLayerName);
99
l1 = l1 ? l1 : default_l1;
100
lInf = lInf ? lInf : default_lInf;
101
normAssert(outRef, outBlobs[0], "", l1, lInf);
102
103
if (check2ndBlob && backend != DNN_BACKEND_INFERENCE_ENGINE)
104
{
105
Mat out2 = outBlobs[1];
106
Mat ref2 = readTorchBlob(_tf(prefix + "_output_2" + suffix), isBinary);
107
normAssert(out2, ref2, "", l1, lInf);
108
}
109
}
110
};
111
112
TEST_P(Test_Torch_layers, run_convolution)
113
{
114
// Output reference values are in range [23.4018, 72.0181]
115
double l1 = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 0.08 : default_l1;
116
double lInf = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 0.42 : default_lInf;
117
runTorchNet("net_conv", "", false, true, l1, lInf);
118
}
119
120
TEST_P(Test_Torch_layers, run_pool_max)
121
{
122
if (backend == DNN_BACKEND_OPENCV && target == DNN_TARGET_OPENCL_FP16)
123
throw SkipTestException("");
124
runTorchNet("net_pool_max", "", true);
125
}
126
127
TEST_P(Test_Torch_layers, run_pool_ave)
128
{
129
runTorchNet("net_pool_ave");
130
}
131
132
TEST_P(Test_Torch_layers, run_reshape_change_batch_size)
133
{
134
runTorchNet("net_reshape");
135
}
136
137
TEST_P(Test_Torch_layers, run_reshape)
138
{
139
runTorchNet("net_reshape_batch");
140
runTorchNet("net_reshape_channels", "", false, true);
141
}
142
143
TEST_P(Test_Torch_layers, run_reshape_single_sample)
144
{
145
// Reference output values in range [14.4586, 18.4492].
146
runTorchNet("net_reshape_single_sample", "", false, false,
147
(target == DNN_TARGET_MYRIAD || target == DNN_TARGET_OPENCL_FP16) ? 0.0073 : default_l1,
148
(target == DNN_TARGET_MYRIAD || target == DNN_TARGET_OPENCL_FP16) ? 0.025 : default_lInf);
149
}
150
151
TEST_P(Test_Torch_layers, run_linear)
152
{
153
if (backend == DNN_BACKEND_OPENCV && target == DNN_TARGET_OPENCL_FP16)
154
throw SkipTestException("");
155
runTorchNet("net_linear_2d");
156
}
157
158
TEST_P(Test_Torch_layers, run_concat)
159
{
160
runTorchNet("net_concat", "l5_torchMerge");
161
}
162
163
TEST_P(Test_Torch_layers, run_depth_concat)
164
{
165
runTorchNet("net_depth_concat", "", false, true, 0.0,
166
target == DNN_TARGET_OPENCL_FP16 ? 0.021 : 0.0);
167
}
168
169
TEST_P(Test_Torch_layers, run_deconv)
170
{
171
runTorchNet("net_deconv");
172
}
173
174
TEST_P(Test_Torch_layers, run_batch_norm)
175
{
176
runTorchNet("net_batch_norm", "", false, true);
177
}
178
179
TEST_P(Test_Torch_layers, net_prelu)
180
{
181
runTorchNet("net_prelu");
182
}
183
184
TEST_P(Test_Torch_layers, net_cadd_table)
185
{
186
runTorchNet("net_cadd_table");
187
}
188
189
TEST_P(Test_Torch_layers, net_softmax)
190
{
191
runTorchNet("net_softmax");
192
runTorchNet("net_softmax_spatial");
193
}
194
195
TEST_P(Test_Torch_layers, net_logsoftmax)
196
{
197
runTorchNet("net_logsoftmax");
198
runTorchNet("net_logsoftmax_spatial");
199
}
200
201
TEST_P(Test_Torch_layers, net_lp_pooling)
202
{
203
runTorchNet("net_lp_pooling_square", "", false, true);
204
runTorchNet("net_lp_pooling_power", "", false, true);
205
}
206
207
TEST_P(Test_Torch_layers, net_conv_gemm_lrn)
208
{
209
if (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD)
210
throw SkipTestException("");
211
runTorchNet("net_conv_gemm_lrn", "", false, true,
212
target == DNN_TARGET_OPENCL_FP16 ? 0.046 : 0.0,
213
target == DNN_TARGET_OPENCL_FP16 ? 0.023 : 0.0);
214
}
215
216
TEST_P(Test_Torch_layers, net_inception_block)
217
{
218
#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_RELEASE == 2018030000
219
if (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD)
220
throw SkipTestException("");
221
#endif
222
runTorchNet("net_inception_block", "", false, true);
223
}
224
225
TEST_P(Test_Torch_layers, net_normalize)
226
{
227
runTorchNet("net_normalize", "", false, true);
228
}
229
230
TEST_P(Test_Torch_layers, net_padding)
231
{
232
runTorchNet("net_padding", "", false, true);
233
runTorchNet("net_spatial_zero_padding", "", false, true);
234
runTorchNet("net_spatial_reflection_padding", "", false, true);
235
}
236
237
TEST_P(Test_Torch_layers, net_non_spatial)
238
{
239
if (backend == DNN_BACKEND_INFERENCE_ENGINE &&
240
(target == DNN_TARGET_OPENCL || target == DNN_TARGET_OPENCL_FP16))
241
throw SkipTestException("");
242
runTorchNet("net_non_spatial", "", false, true);
243
}
244
245
TEST_P(Test_Torch_layers, run_paralel)
246
{
247
if (backend != DNN_BACKEND_OPENCV || target != DNN_TARGET_CPU)
248
throw SkipTestException("");
249
runTorchNet("net_parallel", "l5_torchMerge");
250
}
251
252
TEST_P(Test_Torch_layers, net_residual)
253
{
254
runTorchNet("net_residual", "", false, true);
255
}
256
257
class Test_Torch_nets : public DNNTestLayer {};
258
259
TEST_P(Test_Torch_nets, OpenFace_accuracy)
260
{
261
#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_RELEASE < 2018030000
262
if (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD)
263
throw SkipTestException("Test is enabled starts from OpenVINO 2018R3");
264
#endif
265
checkBackend();
266
if (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_OPENCL_FP16)
267
throw SkipTestException("");
268
269
const string model = findDataFile("dnn/openface_nn4.small2.v1.t7", false);
270
Net net = readNetFromTorch(model);
271
272
net.setPreferableBackend(backend);
273
net.setPreferableTarget(target);
274
275
Mat sample = imread(findDataFile("cv/shared/lena.png", false));
276
Mat sampleF32(sample.size(), CV_32FC3);
277
sample.convertTo(sampleF32, sampleF32.type());
278
sampleF32 /= 255;
279
resize(sampleF32, sampleF32, Size(96, 96), 0, 0, INTER_NEAREST);
280
281
Mat inputBlob = blobFromImage(sampleF32, 1.0, Size(), Scalar(), /*swapRB*/true);
282
283
net.setInput(inputBlob);
284
Mat out = net.forward();
285
286
Mat outRef = readTorchBlob(_tf("net_openface_output.dat"), true);
287
normAssert(out, outRef, "", default_l1, default_lInf);
288
}
289
290
static Mat getSegmMask(const Mat& scores)
291
{
292
const int rows = scores.size[2];
293
const int cols = scores.size[3];
294
const int numClasses = scores.size[1];
295
296
Mat maxCl = Mat::zeros(rows, cols, CV_8UC1);
297
Mat maxVal(rows, cols, CV_32FC1, Scalar(0));
298
for (int ch = 0; ch < numClasses; ch++)
299
{
300
for (int row = 0; row < rows; row++)
301
{
302
const float *ptrScore = scores.ptr<float>(0, ch, row);
303
uint8_t *ptrMaxCl = maxCl.ptr<uint8_t>(row);
304
float *ptrMaxVal = maxVal.ptr<float>(row);
305
for (int col = 0; col < cols; col++)
306
{
307
if (ptrScore[col] > ptrMaxVal[col])
308
{
309
ptrMaxVal[col] = ptrScore[col];
310
ptrMaxCl[col] = (uchar)ch;
311
}
312
}
313
}
314
}
315
return maxCl;
316
}
317
318
// Computer per-class intersection over union metric.
319
static void normAssertSegmentation(const Mat& ref, const Mat& test)
320
{
321
CV_Assert_N(ref.dims == 4, test.dims == 4);
322
const int numClasses = ref.size[1];
323
CV_Assert(numClasses == test.size[1]);
324
325
Mat refMask = getSegmMask(ref);
326
Mat testMask = getSegmMask(test);
327
EXPECT_EQ(countNonZero(refMask != testMask), 0);
328
}
329
330
TEST_P(Test_Torch_nets, ENet_accuracy)
331
{
332
checkBackend();
333
if (backend == DNN_BACKEND_INFERENCE_ENGINE ||
334
(backend == DNN_BACKEND_OPENCV && target == DNN_TARGET_OPENCL_FP16))
335
throw SkipTestException("");
336
337
Net net;
338
{
339
const string model = findDataFile("dnn/Enet-model-best.net", false);
340
net = readNetFromTorch(model, true);
341
ASSERT_TRUE(!net.empty());
342
}
343
344
net.setPreferableBackend(backend);
345
net.setPreferableTarget(target);
346
347
Mat sample = imread(_tf("street.png", false));
348
Mat inputBlob = blobFromImage(sample, 1./255, Size(), Scalar(), /*swapRB*/true);
349
350
net.setInput(inputBlob, "");
351
Mat out = net.forward();
352
Mat ref = blobFromNPY(_tf("torch_enet_prob.npy", false));
353
// Due to numerical instability in Pooling-Unpooling layers (indexes jittering)
354
// thresholds for ENet must be changed. Accuracy of results was checked on
355
// Cityscapes dataset and difference in mIOU with Torch is 10E-4%
356
normAssert(ref, out, "", 0.00044, /*target == DNN_TARGET_CPU ? 0.453 : */0.552);
357
normAssertSegmentation(ref, out);
358
359
const int N = 3;
360
for (int i = 0; i < N; i++)
361
{
362
net.setInput(inputBlob, "");
363
Mat out = net.forward();
364
normAssert(ref, out, "", 0.00044, /*target == DNN_TARGET_CPU ? 0.453 : */0.552);
365
normAssertSegmentation(ref, out);
366
}
367
}
368
369
// Check accuracy of style transfer models from https://github.com/jcjohnson/fast-neural-style
370
// th fast_neural_style.lua \
371
// -input_image ~/opencv_extra/testdata/dnn/googlenet_1.png \
372
// -output_image lena.png \
373
// -median_filter 0 \
374
// -image_size 0 \
375
// -model models/eccv16/starry_night.t7
376
// th fast_neural_style.lua \
377
// -input_image ~/opencv_extra/testdata/dnn/googlenet_1.png \
378
// -output_image lena.png \
379
// -median_filter 0 \
380
// -image_size 0 \
381
// -model models/instance_norm/feathers.t7
382
TEST_P(Test_Torch_nets, FastNeuralStyle_accuracy)
383
{
384
checkBackend();
385
std::string models[] = {"dnn/fast_neural_style_eccv16_starry_night.t7",
386
"dnn/fast_neural_style_instance_norm_feathers.t7"};
387
std::string targets[] = {"dnn/lena_starry_night.png", "dnn/lena_feathers.png"};
388
389
for (int i = 0; i < 2; ++i)
390
{
391
const string model = findDataFile(models[i], false);
392
Net net = readNetFromTorch(model);
393
394
net.setPreferableBackend(backend);
395
net.setPreferableTarget(target);
396
397
Mat img = imread(findDataFile("dnn/googlenet_1.png", false));
398
Mat inputBlob = blobFromImage(img, 1.0, Size(), Scalar(103.939, 116.779, 123.68), false);
399
400
net.setInput(inputBlob);
401
Mat out = net.forward();
402
403
// Deprocessing.
404
getPlane(out, 0, 0) += 103.939;
405
getPlane(out, 0, 1) += 116.779;
406
getPlane(out, 0, 2) += 123.68;
407
out = cv::min(cv::max(0, out), 255);
408
409
Mat ref = imread(findDataFile(targets[i]));
410
Mat refBlob = blobFromImage(ref, 1.0, Size(), Scalar(), false);
411
412
if (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD)
413
{
414
double normL1 = cvtest::norm(refBlob, out, cv::NORM_L1) / refBlob.total();
415
if (target == DNN_TARGET_MYRIAD)
416
EXPECT_LE(normL1, 4.0f);
417
else
418
EXPECT_LE(normL1, 0.6f);
419
}
420
else
421
normAssert(out, refBlob, "", 0.5, 1.1);
422
}
423
}
424
425
INSTANTIATE_TEST_CASE_P(/**/, Test_Torch_nets, dnnBackendsAndTargets());
426
427
// Test a custom layer
428
// https://github.com/torch/nn/blob/master/doc/convolution.md#nn.SpatialUpSamplingNearest
429
class SpatialUpSamplingNearestLayer CV_FINAL : public Layer
430
{
431
public:
432
SpatialUpSamplingNearestLayer(const LayerParams &params) : Layer(params)
433
{
434
scale = params.get<int>("scale_factor");
435
}
436
437
static Ptr<Layer> create(LayerParams& params)
438
{
439
return Ptr<Layer>(new SpatialUpSamplingNearestLayer(params));
440
}
441
442
virtual bool getMemoryShapes(const std::vector<std::vector<int> > &inputs,
443
const int requiredOutputs,
444
std::vector<std::vector<int> > &outputs,
445
std::vector<std::vector<int> > &internals) const CV_OVERRIDE
446
{
447
std::vector<int> outShape(4);
448
outShape[0] = inputs[0][0]; // batch size
449
outShape[1] = inputs[0][1]; // number of channels
450
outShape[2] = scale * inputs[0][2];
451
outShape[3] = scale * inputs[0][3];
452
outputs.assign(1, outShape);
453
return false;
454
}
455
456
void forward(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays) CV_OVERRIDE
457
{
458
CV_TRACE_FUNCTION();
459
CV_TRACE_ARG_VALUE(name, "name", name.c_str());
460
461
std::vector<Mat> inputs, outputs;
462
inputs_arr.getMatVector(inputs);
463
outputs_arr.getMatVector(outputs);
464
465
Mat& inp = inputs[0];
466
Mat& out = outputs[0];
467
const int outHeight = out.size[2];
468
const int outWidth = out.size[3];
469
for (size_t n = 0; n < inp.size[0]; ++n)
470
{
471
for (size_t ch = 0; ch < inp.size[1]; ++ch)
472
{
473
resize(getPlane(inp, n, ch), getPlane(out, n, ch),
474
Size(outWidth, outHeight), 0, 0, INTER_NEAREST);
475
}
476
}
477
}
478
479
private:
480
int scale;
481
};
482
483
TEST_P(Test_Torch_layers, upsampling_nearest)
484
{
485
// Test a custom layer.
486
CV_DNN_REGISTER_LAYER_CLASS(SpatialUpSamplingNearest, SpatialUpSamplingNearestLayer);
487
try
488
{
489
runTorchNet("net_spatial_upsampling_nearest", "", false, true);
490
}
491
catch (...)
492
{
493
LayerFactory::unregisterLayer("SpatialUpSamplingNearest");
494
throw;
495
}
496
LayerFactory::unregisterLayer("SpatialUpSamplingNearest");
497
498
// Test an implemented layer.
499
runTorchNet("net_spatial_upsampling_nearest", "", false, true);
500
}
501
502
INSTANTIATE_TEST_CASE_P(/**/, Test_Torch_layers, dnnBackendsAndTargets());
503
504
}
505
506