1 //
2 // Copyright © 2017,2023 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5
6 #include "DebugTestImpl.hpp"
7
8 #include <armnnUtils/QuantizeHelper.hpp>
9 #include <armnnUtils/Filesystem.hpp>
10 #include <ResolveType.hpp>
11
12 #include <armnnTestUtils/TensorCopyUtils.hpp>
13 #include <armnnTestUtils/WorkloadTestUtils.hpp>
14
15 #include <armnnTestUtils/TensorHelpers.hpp>
16
17 #include <doctest/doctest.h>
18 #include <armnnUtils/Filesystem.hpp>
19
20 namespace
21 {
22
23 template<typename T, std::size_t Dim>
DebugTestImpl(armnn::IWorkloadFactory & workloadFactory,const armnn::IBackendInternal::IMemoryManagerSharedPtr & memoryManager,armnn::TensorInfo & inputTensorInfo,armnn::TensorInfo & outputTensorInfo,std::vector<float> & inputData,std::vector<float> & outputExpectedData,armnn::DebugQueueDescriptor descriptor,const std::string expectedStringOutput,const std::string & layerName,bool toFile,const float qScale=1.0f,const int32_t qOffset=0)24 LayerTestResult<T, Dim> DebugTestImpl(
25 armnn::IWorkloadFactory& workloadFactory,
26 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
27 armnn::TensorInfo& inputTensorInfo,
28 armnn::TensorInfo& outputTensorInfo,
29 std::vector<float>& inputData,
30 std::vector<float>& outputExpectedData,
31 armnn::DebugQueueDescriptor descriptor,
32 const std::string expectedStringOutput,
33 const std::string& layerName,
34 bool toFile,
35 const float qScale = 1.0f,
36 const int32_t qOffset = 0)
37 {
38 IgnoreUnused(memoryManager);
39 if(armnn::IsQuantizedType<T>())
40 {
41 inputTensorInfo.SetQuantizationScale(qScale);
42 inputTensorInfo.SetQuantizationOffset(qOffset);
43
44 outputTensorInfo.SetQuantizationScale(qScale);
45 outputTensorInfo.SetQuantizationOffset(qOffset);
46 }
47
48 std::vector<T> input = armnnUtils::QuantizedVector<T>(inputData, qScale, qOffset);
49
50 std::vector<T> actualOutput(outputTensorInfo.GetNumElements());
51 std::vector<T> expectedOutput = armnnUtils::QuantizedVector<T>(outputExpectedData, qScale, qOffset);
52
53 ARMNN_NO_DEPRECATE_WARN_BEGIN
54 std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfo);
55 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
56 ARMNN_NO_DEPRECATE_WARN_END
57
58 armnn::WorkloadInfo info;
59 AddInputToWorkload(descriptor, info, inputTensorInfo, inputHandle.get());
60 AddOutputToWorkload(descriptor, info, outputTensorInfo, outputHandle.get());
61
62 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateWorkload(armnn::LayerType::Debug,
63 descriptor,
64 info);
65
66 inputHandle->Allocate();
67 outputHandle->Allocate();
68
69 CopyDataToITensorHandle(inputHandle.get(), input.data());
70
71 if (toFile)
72 {
73 // Given that this is dependent on an ExNet switch, we need to explicitly set the directory that the
74 // files are stored in as this happens within the ExNet flow
75 auto tmpDir = armnnUtils::Filesystem::CreateDirectory("/ArmNNIntermediateLayerOutputs");
76 std::string full_path = tmpDir + layerName + ".numpy";
77
78 ExecuteWorkload(*workload, memoryManager);
79
80 armnnUtils::Filesystem::FileContents output = armnnUtils::Filesystem::ReadFileContentsIntoString(full_path);
81 CHECK((output == expectedStringOutput));
82
83 // Clean up afterwards.
84 armnnUtils::Filesystem::RemoveDirectoryAndContents(tmpDir);
85 }
86 else
87 {
88 std::ostringstream oss;
89 std::streambuf* coutStreambuf = std::cout.rdbuf();
90 std::cout.rdbuf(oss.rdbuf());
91
92 ExecuteWorkload(*workload, memoryManager);
93
94 std::cout.rdbuf(coutStreambuf);
95 CHECK(oss.str() == expectedStringOutput);
96 }
97
98 CopyDataFromITensorHandle(actualOutput.data(), outputHandle.get());
99
100 return LayerTestResult<T, Dim>(actualOutput,
101 expectedOutput,
102 outputHandle->GetShape(),
103 outputTensorInfo.GetShape());
104 }
105
106 template <armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
Debug4dTest(armnn::IWorkloadFactory & workloadFactory,const armnn::IBackendInternal::IMemoryManagerSharedPtr & memoryManager,bool toFile=false)107 LayerTestResult<T, 4> Debug4dTest(
108 armnn::IWorkloadFactory& workloadFactory,
109 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
110 bool toFile = false)
111 {
112 armnn::TensorInfo inputTensorInfo;
113 armnn::TensorInfo outputTensorInfo;
114
115 unsigned int inputShape[] = {1, 2, 2, 3};
116 unsigned int outputShape[] = {1, 2, 2, 3};
117
118 armnn::DebugQueueDescriptor desc;
119 desc.m_Guid = 1;
120 desc.m_LayerName = "TestOutput";
121 desc.m_SlotIndex = 0;
122 desc.m_LayerOutputToFile = toFile;
123
124 inputTensorInfo = armnn::TensorInfo(4, inputShape, ArmnnType);
125 outputTensorInfo = armnn::TensorInfo(4, outputShape, ArmnnType);
126
127 std::vector<float> input = std::vector<float>(
128 {
129 1.0f, 2.0f, 3.0f,
130 4.0f, 5.0f, 6.0f,
131 7.0f, 8.0f, 9.0f,
132 10.0f, 11.0f, 12.0f,
133 });
134
135 std::vector<float> outputExpected = std::vector<float>(
136 {
137 1.0f, 2.0f, 3.0f,
138 4.0f, 5.0f, 6.0f,
139 7.0f, 8.0f, 9.0f,
140 10.0f, 11.0f, 12.0f,
141 });
142
143 const std::string expectedStringOutput =
144 "{ \"layerGuid\": 1,"
145 " \"layerName\": \"TestOutput\","
146 " \"outputSlot\": 0,"
147 " \"shape\": [1, 2, 2, 3],"
148 " \"min\": 1, \"max\": 12,"
149 " \"data\": [[[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]] }\n";
150
151 return DebugTestImpl<T, 4>(workloadFactory,
152 memoryManager,
153 inputTensorInfo,
154 outputTensorInfo,
155 input,
156 outputExpected,
157 desc,
158 expectedStringOutput,
159 desc.m_LayerName,
160 toFile);
161 }
162
163 template <armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
Debug3dTest(armnn::IWorkloadFactory & workloadFactory,const armnn::IBackendInternal::IMemoryManagerSharedPtr & memoryManager,bool toFile=false)164 LayerTestResult<T, 3> Debug3dTest(
165 armnn::IWorkloadFactory& workloadFactory,
166 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
167 bool toFile = false)
168 {
169 armnn::TensorInfo inputTensorInfo;
170 armnn::TensorInfo outputTensorInfo;
171
172 unsigned int inputShape[] = {3, 3, 1};
173 unsigned int outputShape[] = {3, 3, 1};
174
175 armnn::DebugQueueDescriptor desc;
176 desc.m_Guid = 1;
177 desc.m_LayerName = "TestOutput";
178 desc.m_SlotIndex = 0;
179 desc.m_LayerOutputToFile = toFile;
180
181 inputTensorInfo = armnn::TensorInfo(3, inputShape, ArmnnType);
182 outputTensorInfo = armnn::TensorInfo(3, outputShape, ArmnnType);
183
184 std::vector<float> input = std::vector<float>(
185 {
186 1.0f, 2.0f, 3.0f,
187 4.0f, 5.0f, 6.0f,
188 7.0f, 8.0f, 9.0f,
189 });
190
191 std::vector<float> outputExpected = std::vector<float>(
192 {
193 1.0f, 2.0f, 3.0f,
194 4.0f, 5.0f, 6.0f,
195 7.0f, 8.0f, 9.0f,
196 });
197
198 const std::string expectedStringOutput =
199 "{ \"layerGuid\": 1,"
200 " \"layerName\": \"TestOutput\","
201 " \"outputSlot\": 0,"
202 " \"shape\": [3, 3, 1],"
203 " \"min\": 1, \"max\": 9,"
204 " \"data\": [[[1], [2], [3]], [[4], [5], [6]], [[7], [8], [9]]] }\n";
205
206 return DebugTestImpl<T, 3>(workloadFactory,
207 memoryManager,
208 inputTensorInfo,
209 outputTensorInfo,
210 input,
211 outputExpected,
212 desc,
213 expectedStringOutput,
214 desc.m_LayerName,
215 toFile);
216 }
217
218 template <armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
Debug2dTest(armnn::IWorkloadFactory & workloadFactory,const armnn::IBackendInternal::IMemoryManagerSharedPtr & memoryManager,bool toFile=false)219 LayerTestResult<T, 2> Debug2dTest(
220 armnn::IWorkloadFactory& workloadFactory,
221 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
222 bool toFile = false)
223 {
224 armnn::TensorInfo inputTensorInfo;
225 armnn::TensorInfo outputTensorInfo;
226
227 unsigned int inputShape[] = {2, 2};
228 unsigned int outputShape[] = {2, 2};
229
230 armnn::DebugQueueDescriptor desc;
231 desc.m_Guid = 1;
232 desc.m_LayerName = "TestOutput";
233 desc.m_SlotIndex = 0;
234 desc.m_LayerOutputToFile = toFile;
235
236 inputTensorInfo = armnn::TensorInfo(2, inputShape, ArmnnType);
237 outputTensorInfo = armnn::TensorInfo(2, outputShape, ArmnnType);
238
239 std::vector<float> input = std::vector<float>(
240 {
241 1.0f, 2.0f,
242 3.0f, 4.0f,
243 });
244
245 std::vector<float> outputExpected = std::vector<float>(
246 {
247 1.0f, 2.0f,
248 3.0f, 4.0f,
249 });
250
251 const std::string expectedStringOutput =
252 "{ \"layerGuid\": 1,"
253 " \"layerName\": \"TestOutput\","
254 " \"outputSlot\": 0,"
255 " \"shape\": [2, 2],"
256 " \"min\": 1, \"max\": 4,"
257 " \"data\": [[1, 2], [3, 4]] }\n";
258
259 return DebugTestImpl<T, 2>(workloadFactory,
260 memoryManager,
261 inputTensorInfo,
262 outputTensorInfo,
263 input,
264 outputExpected,
265 desc,
266 expectedStringOutput,
267 desc.m_LayerName,
268 toFile);
269 }
270
271 template <armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
Debug1dTest(armnn::IWorkloadFactory & workloadFactory,const armnn::IBackendInternal::IMemoryManagerSharedPtr & memoryManager,bool toFile=false)272 LayerTestResult<T, 1> Debug1dTest(
273 armnn::IWorkloadFactory& workloadFactory,
274 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
275 bool toFile = false)
276 {
277 armnn::TensorInfo inputTensorInfo;
278 armnn::TensorInfo outputTensorInfo;
279
280 unsigned int inputShape[] = {4};
281 unsigned int outputShape[] = {4};
282
283 armnn::DebugQueueDescriptor desc;
284 desc.m_Guid = 1;
285 desc.m_LayerName = "TestOutput";
286 desc.m_SlotIndex = 0;
287 desc.m_LayerOutputToFile = toFile;
288
289 inputTensorInfo = armnn::TensorInfo(1, inputShape, ArmnnType);
290 outputTensorInfo = armnn::TensorInfo(1, outputShape, ArmnnType);
291
292 std::vector<float> input = std::vector<float>(
293 {
294 1.0f, 2.0f, 3.0f, 4.0f,
295 });
296
297 std::vector<float> outputExpected = std::vector<float>(
298 {
299 1.0f, 2.0f, 3.0f, 4.0f,
300 });
301
302 const std::string expectedStringOutput =
303 "{ \"layerGuid\": 1,"
304 " \"layerName\": \"TestOutput\","
305 " \"outputSlot\": 0,"
306 " \"shape\": [4],"
307 " \"min\": 1, \"max\": 4,"
308 " \"data\": [1, 2, 3, 4] }\n";
309
310 return DebugTestImpl<T, 1>(workloadFactory,
311 memoryManager,
312 inputTensorInfo,
313 outputTensorInfo,
314 input,
315 outputExpected,
316 desc,
317 expectedStringOutput,
318 desc.m_LayerName,
319 toFile);
320 }
321
322 } // anonymous namespace
323
Debug4dFloat32Test(armnn::IWorkloadFactory & workloadFactory,const armnn::IBackendInternal::IMemoryManagerSharedPtr & memoryManager,bool toFile=false)324 LayerTestResult<float, 4> Debug4dFloat32Test(
325 armnn::IWorkloadFactory& workloadFactory,
326 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
327 bool toFile = false)
328 {
329 return Debug4dTest<armnn::DataType::Float32>(workloadFactory, memoryManager, toFile);
330 }
331
Debug3dFloat32Test(armnn::IWorkloadFactory & workloadFactory,const armnn::IBackendInternal::IMemoryManagerSharedPtr & memoryManager,bool toFile=false)332 LayerTestResult<float, 3> Debug3dFloat32Test(
333 armnn::IWorkloadFactory& workloadFactory,
334 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
335 bool toFile = false)
336 {
337 return Debug3dTest<armnn::DataType::Float32>(workloadFactory, memoryManager, toFile);
338 }
339
Debug2dFloat32Test(armnn::IWorkloadFactory & workloadFactory,const armnn::IBackendInternal::IMemoryManagerSharedPtr & memoryManager,bool toFile=false)340 LayerTestResult<float, 2> Debug2dFloat32Test(
341 armnn::IWorkloadFactory& workloadFactory,
342 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
343 bool toFile = false)
344 {
345 return Debug2dTest<armnn::DataType::Float32>(workloadFactory, memoryManager, toFile);
346 }
347
Debug1dFloat32Test(armnn::IWorkloadFactory & workloadFactory,const armnn::IBackendInternal::IMemoryManagerSharedPtr & memoryManager,bool toFile=false)348 LayerTestResult<float, 1> Debug1dFloat32Test(
349 armnn::IWorkloadFactory& workloadFactory,
350 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
351 bool toFile = false)
352 {
353 return Debug1dTest<armnn::DataType::Float32>(workloadFactory, memoryManager, toFile);
354 }
355
Debug4dBFloat16Test(armnn::IWorkloadFactory & workloadFactory,const armnn::IBackendInternal::IMemoryManagerSharedPtr & memoryManager,bool toFile=false)356 LayerTestResult<armnn::BFloat16, 4> Debug4dBFloat16Test(
357 armnn::IWorkloadFactory& workloadFactory,
358 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
359 bool toFile = false)
360 {
361 return Debug4dTest<armnn::DataType::BFloat16>(workloadFactory, memoryManager, toFile);
362 }
363
Debug3dBFloat16Test(armnn::IWorkloadFactory & workloadFactory,const armnn::IBackendInternal::IMemoryManagerSharedPtr & memoryManager,bool toFile=false)364 LayerTestResult<armnn::BFloat16, 3> Debug3dBFloat16Test(
365 armnn::IWorkloadFactory& workloadFactory,
366 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
367 bool toFile = false)
368 {
369 return Debug3dTest<armnn::DataType::BFloat16>(workloadFactory, memoryManager, toFile);
370 }
371
Debug2dBFloat16Test(armnn::IWorkloadFactory & workloadFactory,const armnn::IBackendInternal::IMemoryManagerSharedPtr & memoryManager,bool toFile=false)372 LayerTestResult<armnn::BFloat16, 2> Debug2dBFloat16Test(
373 armnn::IWorkloadFactory& workloadFactory,
374 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
375 bool toFile = false)
376 {
377 return Debug2dTest<armnn::DataType::BFloat16>(workloadFactory, memoryManager, toFile);
378 }
379
Debug1dBFloat16Test(armnn::IWorkloadFactory & workloadFactory,const armnn::IBackendInternal::IMemoryManagerSharedPtr & memoryManager,bool toFile=false)380 LayerTestResult<armnn::BFloat16, 1> Debug1dBFloat16Test(
381 armnn::IWorkloadFactory& workloadFactory,
382 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
383 bool toFile = false)
384 {
385 return Debug1dTest<armnn::DataType::BFloat16>(workloadFactory, memoryManager, toFile);
386 }
387
Debug4dUint8Test(armnn::IWorkloadFactory & workloadFactory,const armnn::IBackendInternal::IMemoryManagerSharedPtr & memoryManager,bool toFile=false)388 LayerTestResult<uint8_t, 4> Debug4dUint8Test(
389 armnn::IWorkloadFactory& workloadFactory,
390 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
391 bool toFile = false)
392 {
393 return Debug4dTest<armnn::DataType::QAsymmU8>(workloadFactory, memoryManager, toFile);
394 }
395
Debug3dUint8Test(armnn::IWorkloadFactory & workloadFactory,const armnn::IBackendInternal::IMemoryManagerSharedPtr & memoryManager,bool toFile=false)396 LayerTestResult<uint8_t, 3> Debug3dUint8Test(
397 armnn::IWorkloadFactory& workloadFactory,
398 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
399 bool toFile = false)
400 {
401 return Debug3dTest<armnn::DataType::QAsymmU8>(workloadFactory, memoryManager, toFile);
402 }
403
Debug2dUint8Test(armnn::IWorkloadFactory & workloadFactory,const armnn::IBackendInternal::IMemoryManagerSharedPtr & memoryManager,bool toFile=false)404 LayerTestResult<uint8_t, 2> Debug2dUint8Test(
405 armnn::IWorkloadFactory& workloadFactory,
406 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
407 bool toFile = false)
408 {
409 return Debug2dTest<armnn::DataType::QAsymmU8>(workloadFactory, memoryManager, toFile);
410 }
411
Debug1dUint8Test(armnn::IWorkloadFactory & workloadFactory,const armnn::IBackendInternal::IMemoryManagerSharedPtr & memoryManager,bool toFile=false)412 LayerTestResult<uint8_t, 1> Debug1dUint8Test(
413 armnn::IWorkloadFactory& workloadFactory,
414 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
415 bool toFile = false)
416 {
417 return Debug1dTest<armnn::DataType::QAsymmU8>(workloadFactory, memoryManager, toFile);
418 }
419
Debug4dInt16Test(armnn::IWorkloadFactory & workloadFactory,const armnn::IBackendInternal::IMemoryManagerSharedPtr & memoryManager,bool toFile=false)420 LayerTestResult<int16_t, 4> Debug4dInt16Test(
421 armnn::IWorkloadFactory& workloadFactory,
422 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
423 bool toFile = false)
424 {
425 return Debug4dTest<armnn::DataType::QSymmS16>(workloadFactory, memoryManager, toFile);
426 }
427
Debug3dInt16Test(armnn::IWorkloadFactory & workloadFactory,const armnn::IBackendInternal::IMemoryManagerSharedPtr & memoryManager,bool toFile=false)428 LayerTestResult<int16_t, 3> Debug3dInt16Test(
429 armnn::IWorkloadFactory& workloadFactory,
430 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
431 bool toFile = false)
432 {
433 return Debug3dTest<armnn::DataType::QSymmS16>(workloadFactory, memoryManager, toFile);
434 }
435
Debug2dInt16Test(armnn::IWorkloadFactory & workloadFactory,const armnn::IBackendInternal::IMemoryManagerSharedPtr & memoryManager,bool toFile=false)436 LayerTestResult<int16_t, 2> Debug2dInt16Test(
437 armnn::IWorkloadFactory& workloadFactory,
438 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
439 bool toFile = false)
440 {
441 return Debug2dTest<armnn::DataType::QSymmS16>(workloadFactory, memoryManager, toFile);
442 }
443
Debug1dInt16Test(armnn::IWorkloadFactory & workloadFactory,const armnn::IBackendInternal::IMemoryManagerSharedPtr & memoryManager,bool toFile=false)444 LayerTestResult<int16_t, 1> Debug1dInt16Test(
445 armnn::IWorkloadFactory& workloadFactory,
446 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
447 bool toFile = false)
448 {
449 return Debug1dTest<armnn::DataType::QSymmS16>(workloadFactory, memoryManager, toFile);
450 }
451