1/**
2 * Copyright (c) Glow Contributors. See CONTRIBUTORS file.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "glow/Importer/Caffe2ModelLoader.h"
18#include "glow/Importer/ONNXModelLoader.h"
19
20#include "ImporterTestUtils.h"
21#include "glow/Base/Image.h"
22#include "glow/Converter/TypeAToTypeBFunctionConverter.h"
23#include "glow/ExecutionEngine/ExecutionEngine.h"
24#include "glow/Graph/Graph.h"
25#include "glow/Graph/Nodes.h"
26#include "glow/Importer/Caffe2ModelLoader.h"
27#include "tools/loader/Loader.h"
28
29#include "gtest/gtest.h"
30
31#include "llvm/ADT/StringMap.h"
32
33#include "tools/loader/ExecutorCore.h"
34#include "tools/loader/ExecutorCoreHelperFunctions.h"
35
36#ifndef GLOW_DATA_PATH
37#define GLOW_DATA_PATH
38#endif
39
40using namespace glow;
41
42class ImageLoaderTest : public ::testing::TestWithParam<bool> {
43protected:
44 void SetUp() override {}
45 void TearDown() override {}
46};
47
48template <class PP> static void registerPP(glow::Executor &core) {
49 auto pp = []() -> std::unique_ptr<PostProcessOutputDataExtension> {
50 return std::make_unique<PP>();
51 };
52 core.registerPostProcessOutputExtension(pp);
53}
54
55/// Load an ONNX model w/ two inputs. Provide two input lists, each
56/// with a single 4D numpy file, inputs normalized to (0,1), (-1,1).
57TEST_P(ImageLoaderTest, Numpy2InputsNormModeS1U1tTest) {
58 const char *argv[6];
59 size_t idx = 0;
60 argv[idx++] = "test";
61 argv[idx++] =
62 "-m=" GLOW_DATA_PATH "tests/models/onnxModels/add_2inputs_4D.onnx";
63 argv[idx++] =
64 "-input-image-list-file=" GLOW_DATA_PATH
65 "tests/images/npy/input1List_4D.txt,tests/images/npy/input2List_4D.txt";
66 argv[idx++] = "-model-input-name=X";
67 argv[idx++] = "-model-input-name=Y";
68 argv[idx++] = "-image-mode=neg1to1,0to1";
69
70 glow::Executor core("test", idx, (char **)argv);
71
72 class PP : public PostProcessOutputDataExtension {
73 public:
74 int processOutputs(const llvm::StringMap<glow::Placeholder *> &PHM,
75 PlaceholderBindings &b,
76 VecVecRef<std::string> inputImageBatchFilenames) {
77 return 0;
78 }
79 };
80 registerPP<PP>(core);
81 core.executeNetwork();
82}
83
84/// Load an ONNX model w/ two inputs. Provide two input lists, each
85/// with a single 4D numpy file, inputs normalized to (-128,127), (0,255).
86TEST_P(ImageLoaderTest, Numpy2InputsNormModeS8U8Test) {
87 const char *argv[6];
88 size_t idx = 0;
89 argv[idx++] = "test";
90 argv[idx++] =
91 "-m=" GLOW_DATA_PATH "tests/models/onnxModels/add_2inputs_4D.onnx";
92 argv[idx++] =
93 "-input-image-list-file=" GLOW_DATA_PATH
94 "tests/images/npy/input1List_4D.txt,tests/images/npy/input2List_4D.txt";
95 argv[idx++] = "-model-input-name=X";
96 argv[idx++] = "-model-input-name=Y";
97 argv[idx++] = "-image-mode=neg128to127,0to255";
98
99 glow::Executor core("test", idx, (char **)argv);
100
101 class PP : public PostProcessOutputDataExtension {
102 public:
103 int processOutputs(const llvm::StringMap<glow::Placeholder *> &PHM,
104 PlaceholderBindings &b,
105 VecVecRef<std::string> inputImageBatchFilenames) {
106 doChecks(PHM, b, inputImageBatchFilenames);
107 return 0;
108 }
109 void doChecks(const llvm::StringMap<glow::Placeholder *> &PHM,
110 PlaceholderBindings &b,
111 VecVecRef<std::string> inputImageBatchFilenames) {
112 Placeholder *outPH = getOutputForPostProcessing(PHM);
113 CHECK(outPH) << "Missing placeholder";
114
115 auto *S = getSaveNodeFromDest(outPH);
116 ASSERT_TRUE(S);
117 auto *add = llvm::dyn_cast<AddNode>(S->getInput().getNode());
118 ASSERT_TRUE(add);
119
120 std::vector<float> exp = {-108, -106, -104, -102, -100, -98, -96, -94,
121 -92, -90, -88, -86, -84, -82, -80, -78,
122 -76, -74, -72, -70, -68, -66, -64, -62,
123 -60, -58, -56, -54, -52, -50, -48, -46};
124 Tensor *outT = b.get(outPH);
125 CHECK(outT) << "Missing output tensor";
126 auto H = outT->getHandle();
127 for (size_t i = 0; i < H.size(); i++) {
128 float expected = exp[i];
129 float value = H.raw(i);
130 EXPECT_NEAR(expected, value, 0.001);
131 }
132 }
133 };
134
135 registerPP<PP>(core);
136 core.executeNetwork();
137}
138
139/// Load an ONNX model w/ two inputs. Provide two input lists, each
140/// with a single 4D numpy file, Each channel within each input has it's
141/// own mean/stddev value.
142TEST_P(ImageLoaderTest, Numpy2InputsMeanStddevTest) {
143 const char *argv[8];
144 size_t idx = 0;
145 argv[idx++] = "test";
146 argv[idx++] =
147 "-m=" GLOW_DATA_PATH "tests/models/onnxModels/add_2inputs_4D.onnx";
148 argv[idx++] =
149 "-input-image-list-file=" GLOW_DATA_PATH
150 "tests/images/npy/input1List_4D.txt,tests/images/npy/input2List_4D.txt";
151 argv[idx++] = "-model-input=X";
152 argv[idx++] = "-model-input=Y";
153 argv[idx++] = "-mean=0,1:2,3";
154 argv[idx++] = "-stddev=4,5:6,7";
155
156 glow::Executor core("test", idx, (char **)argv);
157
158 class PP : public PostProcessOutputDataExtension {
159 public:
160 int processOutputs(const llvm::StringMap<glow::Placeholder *> &PHM,
161 PlaceholderBindings &b,
162 VecVecRef<std::string> inputImageBatchFilenames) {
163 doChecks(PHM, b, inputImageBatchFilenames);
164 return 0;
165 }
166 void doChecks(const llvm::StringMap<glow::Placeholder *> &PHM,
167 PlaceholderBindings &b,
168 VecVecRef<std::string> inputImageBatchFilenames) {
169 Placeholder *outPH = getOutputForPostProcessing(PHM);
170 CHECK(outPH) << "Missing placeholder";
171
172 auto *S = getSaveNodeFromDest(outPH);
173 ASSERT_TRUE(S);
174 auto *add = llvm::dyn_cast<AddNode>(S->getInput().getNode());
175 ASSERT_TRUE(add);
176
177 std::vector<float> exp = {
178 3.833, 4.250, 4.667, 5.083, 5.500, 5.917, 6.333, 6.750,
179 7.167, 7.583, 8.000, 8.417, 8.833, 9.250, 9.667, 10.083,
180 8.286, 8.629, 8.971, 9.314, 9.657, 10.000, 10.343, 10.686,
181 11.029, 11.371, 11.714, 12.057, 12.400, 12.743, 13.086, 13.429};
182
183 Tensor *outT = b.get(outPH);
184 CHECK(outT) << "Missing output tensor";
185 auto H = outT->getHandle();
186 for (size_t i = 0; i < H.size(); i++) {
187 float expected = exp[i];
188 float value = H.raw(i);
189 EXPECT_NEAR(expected, value, 0.001);
190 }
191 }
192 };
193
194 registerPP<PP>(core);
195 core.executeNetwork();
196}
197
198/// Load an ONNX model w/ two inputs. Provide two input lists, one with
199/// a single 4D numpy file other with a single 3D file (which gets expanded to
200/// 4D) both with NCHW layout. Each channel within each input has it's own
201/// mean/stddev value.
202TEST_P(ImageLoaderTest, Numpy2InputsMeanStddev4D3DTest) {
203 const char *argv[7];
204 size_t idx = 0;
205 argv[idx++] = "test";
206 argv[idx++] =
207 "-m=" GLOW_DATA_PATH "tests/models/onnxModels/add_2inputs_4D.onnx";
208 argv[idx++] =
209 "-input-image-list-file=" GLOW_DATA_PATH
210 "tests/images/npy/input1List_4D.txt,tests/images/npy/input2List_3D_2.txt";
211 argv[idx++] = "-model-input=X";
212 argv[idx++] = "-model-input=Y";
213 argv[idx++] = "-mean=0,1:2,3";
214 argv[idx++] = "-stddev=4,5:6,7";
215
216 glow::Executor core("test", idx, (char **)argv);
217
218 class PP : public PostProcessOutputDataExtension {
219 public:
220 int processOutputs(const llvm::StringMap<glow::Placeholder *> &PHM,
221 PlaceholderBindings &b,
222 VecVecRef<std::string> inputImageBatchFilenames) {
223 doChecks(PHM, b, inputImageBatchFilenames);
224 return 0;
225 }
226 void doChecks(const llvm::StringMap<glow::Placeholder *> &PHM,
227 PlaceholderBindings &b,
228 VecVecRef<std::string> inputImageBatchFilenames) {
229 Placeholder *outPH = getOutputForPostProcessing(PHM);
230 CHECK(outPH) << "Missing placeholder";
231
232 auto *S = getSaveNodeFromDest(outPH);
233 ASSERT_TRUE(S);
234 auto *add = llvm::dyn_cast<AddNode>(S->getInput().getNode());
235 ASSERT_TRUE(add);
236
237 std::vector<float> exp = {
238 3.833, 4.250, 4.667, 5.083, 5.500, 5.917, 6.333, 6.750,
239 7.167, 7.583, 8.000, 8.417, 8.833, 9.250, 9.667, 10.083,
240 8.286, 8.629, 8.971, 9.314, 9.657, 10.000, 10.343, 10.686,
241 11.029, 11.371, 11.714, 12.057, 12.400, 12.743, 13.086, 13.429};
242
243 Tensor *outT = b.get(outPH);
244 CHECK(outT) << "Missing output tensor";
245 auto H = outT->getHandle();
246 for (size_t i = 0; i < H.size(); i++) {
247 float expected = exp[i];
248 float value = H.raw(i);
249 EXPECT_NEAR(expected, value, 0.001);
250 }
251 }
252 };
253
254 registerPP<PP>(core);
255 core.executeNetwork();
256}
257
258/// Load an ONNX model w/ two inputs. Provide two input lists, each
259/// with a single 3D numpy file w/ no layout, Each input has it's
260/// own mean/stddev value.
261TEST_P(ImageLoaderTest, Numpy2InputsMeanStddev3DNoLayoutTest) {
262 const char *argv[8];
263 size_t idx = 0;
264 argv[idx++] = "test";
265 argv[idx++] =
266 "-m=" GLOW_DATA_PATH "tests/models/onnxModels/add_2inputs_3D.onnx";
267 argv[idx++] =
268 "-input-image-list-file=" GLOW_DATA_PATH
269 "tests/images/npy/input1List_3D.txt,tests/images/npy/input2List_3D.txt";
270 argv[idx++] = "-model-input-name=X";
271 argv[idx++] = "-model-input-name=Y";
272 argv[idx++] = "-mean=1:2";
273 argv[idx++] = "-stddev=4:5";
274 argv[idx++] = "-image-layout=NonImage,NonImage";
275
276 glow::Executor core("test", idx, (char **)argv);
277
278 class PP : public PostProcessOutputDataExtension {
279 public:
280 int processOutputs(const llvm::StringMap<glow::Placeholder *> &PHM,
281 PlaceholderBindings &b,
282 VecVecRef<std::string> inputImageBatchFilenames) {
283 doChecks(PHM, b, inputImageBatchFilenames);
284 return 0;
285 }
286
287 void doChecks(const llvm::StringMap<glow::Placeholder *> &PHM,
288 PlaceholderBindings &b,
289 VecVecRef<std::string> inputImageBatchFilenames) {
290 Placeholder *outPH = getOutputForPostProcessing(PHM);
291 CHECK(outPH) << "Missing placeholder";
292
293 auto *S = getSaveNodeFromDest(outPH);
294 ASSERT_TRUE(S);
295 auto *add = llvm::dyn_cast<AddNode>(S->getInput().getNode());
296 ASSERT_TRUE(add);
297
298 std::vector<float> exp = {3.85, 4.3, 4.75, 5.2, 5.65, 6.1, 6.55, 7.};
299
300 Tensor *outT = b.get(outPH);
301 CHECK(outT) << "Missing output tensor";
302 auto H = outT->getHandle();
303 for (size_t i = 0; i < H.size(); i++) {
304 float expected = exp[i];
305 float value = H.raw(i);
306 EXPECT_NEAR(expected, value, 0.001);
307 }
308 }
309 };
310
311 registerPP<PP>(core);
312 core.executeNetwork();
313}
314
315/// Test loading Float NUMPY tensors - converted to U8.
316TEST_P(ImageLoaderTest, Numpy2TestFloatToDefault) {
317 const char *argv[8];
318 size_t idx = 0;
319 argv[idx++] = "test";
320 argv[idx++] =
321 "-m=" GLOW_DATA_PATH "tests/models/onnxModels/add_2inputs_3D.onnx";
322 argv[idx++] = "-input-image-list-file=" GLOW_DATA_PATH
323 "tests/images/npy/input1List_3D_f32_2.txt,tests/images/npy/"
324 "input2List_3D_f32_2.txt";
325 argv[idx++] = "-model-input=X";
326 argv[idx++] = "-model-input=Y";
327 argv[idx++] = "-image-layout=NonImage,NonImage";
328
329 glow::Executor core("test", idx, (char **)argv);
330
331 class PP : public PostProcessOutputDataExtension {
332 public:
333 int processOutputs(const llvm::StringMap<glow::Placeholder *> &PHM,
334 PlaceholderBindings &b,
335 VecVecRef<std::string> inputImageBatchFilenames) {
336 doChecks(PHM, b, inputImageBatchFilenames);
337 return 0;
338 }
339
340 void doChecks(const llvm::StringMap<glow::Placeholder *> &PHM,
341 PlaceholderBindings &b,
342 VecVecRef<std::string> inputImageBatchFilenames) {
343 Placeholder *outPH = getOutputForPostProcessing(PHM);
344 CHECK(outPH) << "Missing placeholder";
345
346 auto *S = getSaveNodeFromDest(outPH);
347 ASSERT_TRUE(S);
348 auto *add = llvm::dyn_cast<AddNode>(S->getInput().getNode());
349 ASSERT_TRUE(add);
350
351 std::vector<float> exp = {20, 22, 24, 26, 28, 30, 32, 34};
352
353 Tensor *outT = b.get(outPH);
354 CHECK(outT) << "Missing output tensor";
355 auto H = outT->getHandle();
356 for (size_t i = 0; i < H.size(); i++) {
357 float expected = exp[i];
358 float value = H.raw(i);
359 EXPECT_NEAR(expected, value, 0.01);
360 }
361 }
362 };
363
364 registerPP<PP>(core);
365 core.executeNetwork();
366}
367
368/// Load an ONNX model w/ two inputs. Provide two input lists, each
369/// with a single 3D numpy file with I16 and U16 data w/ no layout.
370/// No normalization.
371TEST_P(ImageLoaderTest, Numpy2TestS16U16PassThrough) {
372 const char *argv[8];
373 size_t idx = 0;
374 argv[idx++] = "test";
375 argv[idx++] =
376 "-m=" GLOW_DATA_PATH "tests/models/onnxModels/add_2inputs_3D.onnx";
377 argv[idx++] = "-input-image-list-file=" GLOW_DATA_PATH
378 "tests/images/npy/input1List_3D_i16.txt,tests/images/npy/"
379 "input2List_3D_u16.txt";
380 argv[idx++] = "-model-input=X";
381 argv[idx++] = "-model-input=Y";
382 argv[idx++] = "-image-layout=NonImage,NonImage";
383 glow::Executor core("test", idx, (char **)argv);
384
385 class PP : public PostProcessOutputDataExtension {
386 public:
387 int processOutputs(const llvm::StringMap<glow::Placeholder *> &PHM,
388 PlaceholderBindings &b,
389 VecVecRef<std::string> inputImageBatchFilenames) {
390 doChecks(PHM, b, inputImageBatchFilenames);
391 return 0;
392 }
393
394 void doChecks(const llvm::StringMap<glow::Placeholder *> &PHM,
395 PlaceholderBindings &b,
396 VecVecRef<std::string> inputImageBatchFilenames) {
397 Placeholder *outPH = getOutputForPostProcessing(PHM);
398 CHECK(outPH) << "Missing placeholder";
399
400 auto *S = getSaveNodeFromDest(outPH);
401 ASSERT_TRUE(S);
402 auto *add = llvm::dyn_cast<AddNode>(S->getInput().getNode());
403 ASSERT_TRUE(add);
404
405 std::vector<float> exp = {2000, 2002, 2004, 2006, 2008, 2010, 2012, 2014};
406
407 Tensor *outT = b.get(outPH);
408 CHECK(outT) << "Missing output tensor";
409 auto H = outT->getHandle();
410 for (size_t i = 0; i < H.size(); i++) {
411 float expected = exp[i];
412 float value = H.raw(i);
413 EXPECT_NEAR(expected, value, 0.1);
414 }
415 }
416 };
417
418 registerPP<PP>(core);
419 core.executeNetwork();
420}
421
422/// Load an ONNX model w/ two inputs. Provide two input lists, each
423/// with a single 3D numpy file with I16 and U16 data w/ no layout.
424/// With mean/stddev.
425TEST_P(ImageLoaderTest, Numpy2TestS16U16MeanStddev) {
426 const char *argv[8];
427 size_t idx = 0;
428 argv[idx++] = "test";
429 argv[idx++] =
430 "-m=" GLOW_DATA_PATH "tests/models/onnxModels/add_2inputs_3D.onnx";
431 argv[idx++] = "-input-image-list-file=" GLOW_DATA_PATH
432 "tests/images/npy/input1List_3D_i16.txt,tests/images/npy/"
433 "input2List_3D_u16.txt";
434 argv[idx++] = "-model-input=X";
435 argv[idx++] = "-model-input=Y";
436 argv[idx++] = "-mean=100:200";
437 argv[idx++] = "-stddev=4:5";
438 argv[idx++] = "-image-layout=NonImage,NonImage";
439 glow::Executor core("test", idx, (char **)argv);
440
441 class PP : public PostProcessOutputDataExtension {
442 public:
443 int processOutputs(const llvm::StringMap<glow::Placeholder *> &PHM,
444 PlaceholderBindings &b,
445 VecVecRef<std::string> inputImageBatchFilenames) {
446 doChecks(PHM, b, inputImageBatchFilenames);
447 return 0;
448 }
449
450 void doChecks(const llvm::StringMap<glow::Placeholder *> &PHM,
451 PlaceholderBindings &b,
452 VecVecRef<std::string> inputImageBatchFilenames) {
453 Placeholder *outPH = getOutputForPostProcessing(PHM);
454 CHECK(outPH) << "Missing placeholder";
455
456 auto *S = getSaveNodeFromDest(outPH);
457 ASSERT_TRUE(S);
458 auto *add = llvm::dyn_cast<AddNode>(S->getInput().getNode());
459 ASSERT_TRUE(add);
460
461 std::vector<float> exp = {385, 385.45, 385.90, 386.35,
462 386.80, 387.25, 387.70, 388.15};
463
464 Tensor *outT = b.get(outPH);
465 CHECK(outT) << "Missing output tensor";
466 auto H = outT->getHandle();
467 for (size_t i = 0; i < H.size(); i++) {
468 float expected = exp[i];
469 float value = H.raw(i);
470 EXPECT_NEAR(expected, value, 0.001);
471 }
472 }
473 };
474
475 registerPP<PP>(core);
476 core.executeNetwork();
477}
478
479/// Load an ONNX model w/ two inputs. Provide two input lists, each
480/// with a single 3D numpy file with I16 and U16 data w/ no layout.
481/// With normalization.
482TEST_P(ImageLoaderTest, Numpy2TestU16S16NormalizeS1U1) {
483 const char *argv[8];
484 size_t idx = 0;
485 argv[idx++] = "test";
486 argv[idx++] =
487 "-m=" GLOW_DATA_PATH "tests/models/onnxModels/add_2inputs_3D.onnx";
488 argv[idx++] = "-input-image-list-file=" GLOW_DATA_PATH
489 "tests/images/npy/input1List_3D_u16.txt,tests/images/npy/"
490 "input2List_3D_i16.txt";
491 argv[idx++] = "-model-input=X";
492 argv[idx++] = "-model-input=Y";
493 argv[idx++] = "-image-mode=neg1to1,0to1";
494 argv[idx++] = "-image-layout=NonImage,NonImage";
495
496 glow::Executor core("test", idx, (char **)argv);
497
498 class PP : public PostProcessOutputDataExtension {
499 public:
500 int processOutputs(const llvm::StringMap<glow::Placeholder *> &PHM,
501 PlaceholderBindings &b,
502 VecVecRef<std::string> inputImageBatchFilenames) {
503 doChecks(PHM, b, inputImageBatchFilenames);
504 return 0;
505 }
506
507 void doChecks(const llvm::StringMap<glow::Placeholder *> &PHM,
508 PlaceholderBindings &b,
509 VecVecRef<std::string> inputImageBatchFilenames) {
510 Placeholder *outPH = getOutputForPostProcessing(PHM);
511 CHECK(outPH) << "Missing placeholder";
512
513 auto *S = getSaveNodeFromDest(outPH);
514 ASSERT_TRUE(S);
515 auto *add = llvm::dyn_cast<AddNode>(S->getInput().getNode());
516 ASSERT_TRUE(add);
517
518 std::vector<float> exp = {-0.469627, -0.469749, -0.469871,
519 -0.469993, -0.470115, -0.47023726,
520 -0.4703596, -0.47048143};
521
522 Tensor *outT = b.get(outPH);
523 CHECK(outT) << "Missing output tensor";
524 auto H = outT->getHandle();
525 for (size_t i = 0; i < H.size(); i++) {
526 float expected = exp[i];
527 float value = H.raw(i);
528 EXPECT_NEAR(expected, value, 0.000001);
529 }
530 }
531 };
532
533 registerPP<PP>(core);
534 core.executeNetwork();
535}
536
537TEST_P(ImageLoaderTest, Numpy2TestFloatToU16) {
538 const char *argv[8];
539 size_t idx = 0;
540 argv[idx++] = "test";
541 argv[idx++] =
542 "-m=" GLOW_DATA_PATH "tests/models/onnxModels/add_2inputs_3D.onnx";
543 argv[idx++] = "-input-image-list-file=" GLOW_DATA_PATH
544 "tests/images/npy/input1List_3D_f32.txt,tests/images/npy/"
545 "input2List_3D_f32.txt";
546 argv[idx++] = "-model-input=X";
547 argv[idx++] = "-model-input=Y";
548 argv[idx++] = "-image-layout=NonImage,NonImage";
549 argv[idx++] = "-input-values-range=U16,S16";
550
551 glow::Executor core("test", idx, (char **)argv);
552
553 class PP : public PostProcessOutputDataExtension {
554 public:
555 int processOutputs(const llvm::StringMap<glow::Placeholder *> &PHM,
556 PlaceholderBindings &b,
557 VecVecRef<std::string> inputImageBatchFilenames) {
558 doChecks(PHM, b, inputImageBatchFilenames);
559 return 0;
560 }
561
562 void doChecks(const llvm::StringMap<glow::Placeholder *> &PHM,
563 PlaceholderBindings &b,
564 VecVecRef<std::string> inputImageBatchFilenames) {
565 Placeholder *outPH = getOutputForPostProcessing(PHM);
566 CHECK(outPH) << "Missing placeholder";
567
568 auto *S = getSaveNodeFromDest(outPH);
569 ASSERT_TRUE(S);
570 auto *add = llvm::dyn_cast<AddNode>(S->getInput().getNode());
571 ASSERT_TRUE(add);
572
573 std::vector<float> exp = {2000, 2002, 2004, 2006, 2008, 2010, 2012, 2014};
574
575 Tensor *outT = b.get(outPH);
576 CHECK(outT) << "Missing output tensor";
577 auto H = outT->getHandle();
578 for (size_t i = 0; i < H.size(); i++) {
579 float expected = exp[i];
580 float value = H.raw(i);
581 EXPECT_NEAR(expected, value, 0.1);
582 }
583 }
584 };
585
586 registerPP<PP>(core);
587 core.executeNetwork();
588}
589
590TEST_P(ImageLoaderTest, Numpy2TestFloatToU16Norm) {
591 const char *argv[8];
592 size_t idx = 0;
593 argv[idx++] = "test";
594 argv[idx++] =
595 "-m=" GLOW_DATA_PATH "tests/models/onnxModels/add_2inputs_3D.onnx";
596 argv[idx++] = "-input-image-list-file=" GLOW_DATA_PATH
597 "tests/images/npy/input1List_3D_f32.txt,tests/images/npy/"
598 "input2List_3D_f32.txt";
599 argv[idx++] = "-model-input=X";
600 argv[idx++] = "-model-input=Y";
601 argv[idx++] = "-image-mode=neg1to1,0to1";
602 argv[idx++] = "-image-layout=NonImage,NonImage";
603 argv[idx++] = "-input-values-range=U16,S16";
604
605 glow::Executor core("test", idx, (char **)argv);
606
607 class PP : public PostProcessOutputDataExtension {
608 public:
609 int processOutputs(const llvm::StringMap<glow::Placeholder *> &PHM,
610 PlaceholderBindings &b,
611 VecVecRef<std::string> inputImageBatchFilenames) {
612 doChecks(PHM, b, inputImageBatchFilenames);
613 return 0;
614 }
615
616 void doChecks(const llvm::StringMap<glow::Placeholder *> &PHM,
617 PlaceholderBindings &b,
618 VecVecRef<std::string> inputImageBatchFilenames) {
619 Placeholder *outPH = getOutputForPostProcessing(PHM);
620 CHECK(outPH) << "Missing placeholder";
621
622 auto *S = getSaveNodeFromDest(outPH);
623 ASSERT_TRUE(S);
624 auto *add = llvm::dyn_cast<AddNode>(S->getInput().getNode());
625 ASSERT_TRUE(add);
626
627 std::vector<float> exp = {-0.4542152, -0.4541695, -0.4541237,
628 -0.45407796, -0.4540322, -0.45398641,
629 -0.45394063, -0.4538949};
630
631 Tensor *outT = b.get(outPH);
632 CHECK(outT) << "Missing output tensor";
633 auto H = outT->getHandle();
634 for (size_t i = 0; i < H.size(); i++) {
635 float expected = exp[i];
636 float value = H.raw(i);
637 EXPECT_NEAR(expected, value, 0.000001);
638 }
639 }
640 };
641
642 registerPP<PP>(core);
643 core.executeNetwork();
644}
645
646INSTANTIATE_TEST_SUITE_P(BN, ImageLoaderTest, ::testing::Values(true));
647