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 | |
40 | using namespace glow; |
41 | |
42 | class ImageLoaderTest : public ::testing::TestWithParam<bool> { |
43 | protected: |
44 | void SetUp() override {} |
45 | void TearDown() override {} |
46 | }; |
47 | |
48 | template <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). |
57 | TEST_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). |
86 | TEST_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. |
142 | TEST_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. |
202 | TEST_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. |
261 | TEST_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. |
316 | TEST_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. |
371 | TEST_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. |
425 | TEST_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. |
482 | TEST_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 | |
537 | TEST_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 | |
590 | TEST_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 | |
646 | INSTANTIATE_TEST_SUITE_P(BN, ImageLoaderTest, ::testing::Values(true)); |
647 | |