blob: 3a757d0c59fbb2daf6fd16e455ca0b0707210ad2 [file] [log] [blame]
Aron Virginas-Tar70104002018-10-24 15:33:28 +01001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5#pragma once
6
Mike Kelly386ff1a2021-03-29 15:04:50 +01007#include "CommonTestUtils.hpp"
8
Matthew Bentham246bd462020-01-20 16:16:06 +00009#include <armnn/Descriptors.hpp>
narpra01b9546cf2018-11-20 15:21:28 +000010#include <armnn/INetwork.hpp>
Matthew Bentham246bd462020-01-20 16:16:06 +000011#include <armnn/IRuntime.hpp>
Aron Virginas-Tar70104002018-10-24 15:33:28 +010012
Aron Virginas-Tar48623a02019-10-22 10:00:28 +010013#include <Profiling.hpp>
14#include <QuantizeHelper.hpp>
15#include <ResolveType.hpp>
Aron Virginas-Tar70104002018-10-24 15:33:28 +010016
narpra01b9546cf2018-11-20 15:21:28 +000017#include <boost/test/unit_test.hpp>
18
Aron Virginas-Tar70104002018-10-24 15:33:28 +010019#include <vector>
20
21namespace
22{
23
24using namespace armnn;
25
26template<typename T>
27bool ConstantUsageTest(const std::vector<BackendId>& computeDevice,
28 const TensorInfo& commonTensorInfo,
29 const std::vector<T>& inputData,
30 const std::vector<T>& constantData,
31 const std::vector<T>& expectedOutputData)
32{
33 // Create runtime in which test will run
34 IRuntime::CreationOptions options;
35 IRuntimePtr runtime(IRuntime::Create(options));
36
37 // Builds up the structure of the network.
38 INetworkPtr net(INetwork::Create());
39
40 IConnectableLayer* input = net->AddInputLayer(0);
41 IConnectableLayer* constant = net->AddConstantLayer(ConstTensor(commonTensorInfo, constantData));
42 IConnectableLayer* add = net->AddAdditionLayer();
43 IConnectableLayer* output = net->AddOutputLayer(0);
44
45 input->GetOutputSlot(0).Connect(add->GetInputSlot(0));
46 constant->GetOutputSlot(0).Connect(add->GetInputSlot(1));
47 add->GetOutputSlot(0).Connect(output->GetInputSlot(0));
48
49 // Sets the tensors in the network.
50 input->GetOutputSlot(0).SetTensorInfo(commonTensorInfo);
51 constant->GetOutputSlot(0).SetTensorInfo(commonTensorInfo);
52 add->GetOutputSlot(0).SetTensorInfo(commonTensorInfo);
53
54 // optimize the network
55 IOptimizedNetworkPtr optNet = Optimize(*net, computeDevice, runtime->GetDeviceSpec());
56
57 // Loads it into the runtime.
58 NetworkId netId;
59 runtime->LoadNetwork(netId, std::move(optNet));
60
61 // Creates structures for input & output.
62 std::vector<T> outputData(inputData.size());
63
64 InputTensors inputTensors
65 {
66 {0, ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())}
67 };
68 OutputTensors outputTensors
69 {
70 {0, Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
71 };
72
73 // Does the inference.
74 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
75
76 // Checks the results.
77 return outputData == expectedOutputData;
78}
79
80inline bool ConstantUsageFloat32Test(const std::vector<BackendId>& backends)
81{
82 const TensorInfo commonTensorInfo({ 2, 3 }, DataType::Float32);
83
84 return ConstantUsageTest(backends,
85 commonTensorInfo,
86 std::vector<float>{ 1.f, 2.f, 3.f, 4.f, 5.f, 6.f }, // Input.
87 std::vector<float>{ 6.f, 5.f, 4.f, 3.f, 2.f, 1.f }, // Const input.
88 std::vector<float>{ 7.f, 7.f, 7.f, 7.f, 7.f, 7.f } // Expected output.
89 );
90}
91
92inline bool ConstantUsageUint8Test(const std::vector<BackendId>& backends)
93{
Derek Lambertif90c56d2020-01-10 17:14:08 +000094 TensorInfo commonTensorInfo({ 2, 3 }, DataType::QAsymmU8);
Aron Virginas-Tar70104002018-10-24 15:33:28 +010095
96 const float scale = 0.023529f;
97 const int8_t offset = -43;
98
99 commonTensorInfo.SetQuantizationScale(scale);
100 commonTensorInfo.SetQuantizationOffset(offset);
101
102 return ConstantUsageTest(backends,
103 commonTensorInfo,
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100104 armnnUtils::QuantizedVector<uint8_t>({ 1.f, 2.f, 3.f, 4.f, 5.f, 6.f }, scale, offset), // Input.
105 armnnUtils::QuantizedVector<uint8_t>({ 6.f, 5.f, 4.f, 3.f, 2.f, 1.f }, scale, offset), // Const input.
106 armnnUtils::QuantizedVector<uint8_t>({ 7.f, 7.f, 7.f, 7.f, 7.f, 7.f }, scale, offset) // Expected output.
Aron Virginas-Tar70104002018-10-24 15:33:28 +0100107 );
108}
109
Ferran Balaguer83239f92019-09-19 11:49:25 +0100110// Utility function to find the number of instances of a substring within a string.
111int SubStringCounter(std::string& string, std::string&& substring)
112{
113 std::size_t found = 0;
114 int count = 0;
115 // Look for the substring starting from where we last found the substring
116 while((found = string.find(substring, found)) != std::string::npos)
117 {
118 count++;
119 // Offset by substring length to avoid finding the same substring twice
120 found += substring.length();
121 }
122 return count;
123}
124
Nattapat Chaimanowong1fcb4ff2019-01-24 15:25:26 +0000125template<DataType ArmnnIType, DataType ArmnnOType,
126 typename TInput = ResolveType<ArmnnIType>, typename TOutput = ResolveType<ArmnnOType>>
narpra01b9546cf2018-11-20 15:21:28 +0000127void EndToEndLayerTestImpl(INetworkPtr network,
kevmay012b4d88e2019-01-24 14:05:09 +0000128 const std::map<int, std::vector<TInput>>& inputTensorData,
129 const std::map<int, std::vector<TOutput>>& expectedOutputData,
Jan Eilersbca73e12020-03-11 12:52:46 +0000130 std::vector<BackendId> backends,
131 float tolerance = 0.000001f)
narpra01b9546cf2018-11-20 15:21:28 +0000132{
133 // Create runtime in which test will run
134 IRuntime::CreationOptions options;
135 IRuntimePtr runtime(IRuntime::Create(options));
136
137 // optimize the network
138 IOptimizedNetworkPtr optNet = Optimize(*network, backends, runtime->GetDeviceSpec());
139
140 // Loads it into the runtime.
141 NetworkId netId;
142 runtime->LoadNetwork(netId, std::move(optNet));
143
144 InputTensors inputTensors;
145 inputTensors.reserve(inputTensorData.size());
146 for (auto&& it : inputTensorData)
147 {
148 inputTensors.push_back({it.first,
149 ConstTensor(runtime->GetInputTensorInfo(netId, it.first), it.second.data())});
150 }
151 OutputTensors outputTensors;
152 outputTensors.reserve(expectedOutputData.size());
kevmay012b4d88e2019-01-24 14:05:09 +0000153 std::map<int, std::vector<TOutput>> outputStorage;
narpra01b9546cf2018-11-20 15:21:28 +0000154 for (auto&& it : expectedOutputData)
155 {
kevmay012b4d88e2019-01-24 14:05:09 +0000156 std::vector<TOutput> out(it.second.size());
narpra01b9546cf2018-11-20 15:21:28 +0000157 outputStorage.emplace(it.first, out);
158 outputTensors.push_back({it.first,
159 Tensor(runtime->GetOutputTensorInfo(netId, it.first),
160 outputStorage.at(it.first).data())});
161 }
162
163 // Does the inference.
164 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
165
166 // Checks the results.
167 for (auto&& it : expectedOutputData)
168 {
kevmay012b4d88e2019-01-24 14:05:09 +0000169 std::vector<TOutput> out = outputStorage.at(it.first);
Aron Virginas-Tarf97f6da2019-10-01 18:35:44 +0100170 for (unsigned int i = 0; i < out.size(); ++i)
Nattapat Chaimanowong1fcb4ff2019-01-24 15:25:26 +0000171 {
Teresa Charlin2e3f4d22020-07-29 14:29:20 +0100172 BOOST_CHECK_MESSAGE(Compare<ArmnnOType>(it.second[i], out[i], tolerance) == true,
173 "Actual output: " << out[i] << ". Expected output:" << it.second[i]);
174
Nattapat Chaimanowong1fcb4ff2019-01-24 15:25:26 +0000175 }
narpra01b9546cf2018-11-20 15:21:28 +0000176 }
177}
178
David Monahan4f1e8e42019-09-04 09:22:10 +0100179inline void ImportNonAlignedInputPointerTest(std::vector<BackendId> backends)
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100180{
181 using namespace armnn;
182
183 // Create runtime in which test will run
184 IRuntime::CreationOptions options;
185 IRuntimePtr runtime(armnn::IRuntime::Create(options));
186
187 // build up the structure of the network
188 INetworkPtr net(INetwork::Create());
189
190 IConnectableLayer* input = net->AddInputLayer(0);
191
David Monahan3fb7e102019-08-20 11:25:29 +0100192 ActivationDescriptor descriptor;
193 descriptor.m_Function = ActivationFunction::Square;
194 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100195
196 IConnectableLayer* output = net->AddOutputLayer(0);
197
David Monahan3fb7e102019-08-20 11:25:29 +0100198 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
199 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100200
David Monahan3fb7e102019-08-20 11:25:29 +0100201 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
202 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100203
204 // Optimize the network
205 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
David Monahan3fb7e102019-08-20 11:25:29 +0100206 BOOST_CHECK(optNet);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100207
208 // Loads it into the runtime.
209 NetworkId netId;
David Monahan4f1e8e42019-09-04 09:22:10 +0100210 std::string ignoredErrorMessage;
211 // Enable Importing
David Monahan3fb7e102019-08-20 11:25:29 +0100212 INetworkProperties networkProperties(true, false);
David Monahan4f1e8e42019-09-04 09:22:10 +0100213 runtime->LoadNetwork(netId, std::move(optNet), ignoredErrorMessage, networkProperties);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100214
215 // Creates structures for input & output
216 std::vector<float> inputData
217 {
David Monahan3fb7e102019-08-20 11:25:29 +0100218 1.0f, 2.0f, 3.0f, 4.0f
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100219 };
220
221 // Misaligned input
Aron Virginas-Tard9f7c8b2019-09-13 13:37:03 +0100222 float* misalignedInputData = reinterpret_cast<float*>(reinterpret_cast<char*>(inputData.data()) + 1);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100223
David Monahan3fb7e102019-08-20 11:25:29 +0100224 std::vector<float> outputData(4);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100225
David Monahan4f1e8e42019-09-04 09:22:10 +0100226 // Aligned output
David Monahan3fb7e102019-08-20 11:25:29 +0100227 float* alignedOutputData = outputData.data();
David Monahan4f1e8e42019-09-04 09:22:10 +0100228
229 InputTensors inputTensors
230 {
231 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), misalignedInputData)},
232 };
233 OutputTensors outputTensors
234 {
235 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), alignedOutputData)}
236 };
237
David Monahan4f1e8e42019-09-04 09:22:10 +0100238 runtime->GetProfiler(netId)->EnableProfiling(true);
239
240 // Do the inference and expect it to fail with a ImportMemoryException
241 BOOST_CHECK_THROW(runtime->EnqueueWorkload(netId, inputTensors, outputTensors), MemoryImportException);
242}
243
Ferran Balaguer83239f92019-09-19 11:49:25 +0100244inline void ExportNonAlignedOutputPointerTest(std::vector<BackendId> backends)
David Monahan4f1e8e42019-09-04 09:22:10 +0100245{
246 using namespace armnn;
247
248 // Create runtime in which test will run
249 IRuntime::CreationOptions options;
250 IRuntimePtr runtime(armnn::IRuntime::Create(options));
251
252 // build up the structure of the network
253 INetworkPtr net(INetwork::Create());
254
255 IConnectableLayer* input = net->AddInputLayer(0);
256
David Monahan3fb7e102019-08-20 11:25:29 +0100257 ActivationDescriptor descriptor;
258 descriptor.m_Function = ActivationFunction::Square;
259 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
David Monahan4f1e8e42019-09-04 09:22:10 +0100260
261 IConnectableLayer* output = net->AddOutputLayer(0);
262
David Monahan3fb7e102019-08-20 11:25:29 +0100263 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
264 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
David Monahan4f1e8e42019-09-04 09:22:10 +0100265
David Monahan3fb7e102019-08-20 11:25:29 +0100266 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
267 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
David Monahan4f1e8e42019-09-04 09:22:10 +0100268
269 // Optimize the network
270 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
David Monahan3fb7e102019-08-20 11:25:29 +0100271 BOOST_CHECK(optNet);
David Monahan4f1e8e42019-09-04 09:22:10 +0100272
273 // Loads it into the runtime.
274 NetworkId netId;
275 std::string ignoredErrorMessage;
David Monahan3fb7e102019-08-20 11:25:29 +0100276 // Enable Importing and Exporting
David Monahan4f1e8e42019-09-04 09:22:10 +0100277 INetworkProperties networkProperties(true, true);
278 runtime->LoadNetwork(netId, std::move(optNet), ignoredErrorMessage, networkProperties);
279
280 // Creates structures for input & output
281 std::vector<float> inputData
282 {
283 1.0f, 2.0f, 3.0f, 4.0f, 5.0f
284 };
285
286 // Aligned input
David Monahan3fb7e102019-08-20 11:25:29 +0100287 float* alignedInputData = inputData.data();
David Monahan4f1e8e42019-09-04 09:22:10 +0100288
289 std::vector<float> outputData(5);
290
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100291 // Misaligned output
Aron Virginas-Tard9f7c8b2019-09-13 13:37:03 +0100292 float* misalignedOutputData = reinterpret_cast<float*>(reinterpret_cast<char*>(outputData.data()) + 1);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100293
294 InputTensors inputTensors
295 {
David Monahan4f1e8e42019-09-04 09:22:10 +0100296 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), alignedInputData)},
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100297 };
298 OutputTensors outputTensors
299 {
300 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), misalignedOutputData)}
301 };
302
Ferran Balaguer83239f92019-09-19 11:49:25 +0100303 // Do the inference and expect it to fail with a ExportMemoryException
304 if (backends[0] == Compute::CpuAcc)
305 {
306 // For CpuAcc the NeonTensorHandle will throw its own exception on misaligned memory
307 BOOST_CHECK_THROW(runtime->EnqueueWorkload(netId, inputTensors, outputTensors), MemoryImportException);
308 }
309 else
310 {
311 BOOST_CHECK_THROW(runtime->EnqueueWorkload(netId, inputTensors, outputTensors), MemoryExportException);
312 }
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100313}
314
315inline void ImportAlignedPointerTest(std::vector<BackendId> backends)
316{
317 using namespace armnn;
318
319 // Create runtime in which test will run
320 IRuntime::CreationOptions options;
321 IRuntimePtr runtime(armnn::IRuntime::Create(options));
322
323 // build up the structure of the network
324 INetworkPtr net(INetwork::Create());
325
326 IConnectableLayer* input = net->AddInputLayer(0);
327
David Monahan3fb7e102019-08-20 11:25:29 +0100328 ActivationDescriptor descriptor;
329 descriptor.m_Function = ActivationFunction::Square;
330 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100331
332 IConnectableLayer* output = net->AddOutputLayer(0);
333
David Monahan3fb7e102019-08-20 11:25:29 +0100334 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
335 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100336
David Monahan3fb7e102019-08-20 11:25:29 +0100337 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
338 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100339
340 // Optimize the network
341 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
David Monahan3fb7e102019-08-20 11:25:29 +0100342 BOOST_CHECK(optNet);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100343
344 // Loads it into the runtime.
345 NetworkId netId;
David Monahan4f1e8e42019-09-04 09:22:10 +0100346 std::string ignoredErrorMessage;
347 // Enable Importing
348 INetworkProperties networkProperties(true, true);
349 runtime->LoadNetwork(netId, std::move(optNet), ignoredErrorMessage, networkProperties);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100350
351 // Creates structures for input & output
352 std::vector<float> inputData
353 {
354 1.0f, 2.0f, 3.0f, 4.0f
355 };
356
357 std::vector<float> outputData(4);
358
James Conroy57d10b72019-10-25 09:44:14 +0100359 std::vector<float> expectedOutput
360 {
361 1.0f, 4.0f, 9.0f, 16.0f
362 };
363
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100364 InputTensors inputTensors
365 {
366 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())},
367 };
368 OutputTensors outputTensors
369 {
370 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
371 };
372
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100373 runtime->GetProfiler(netId)->EnableProfiling(true);
374
375 // Do the inference
376 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
377
378 // Retrieve the Profiler.Print() output to get the workload execution
379 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
380 std::stringstream ss;
381 profilerManager.GetProfiler()->Print(ss);;
382 std::string dump = ss.str();
383
David Monahan3fb7e102019-08-20 11:25:29 +0100384 // Contains ActivationWorkload
385 std::size_t found = dump.find("ActivationWorkload");
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100386 BOOST_TEST(found != std::string::npos);
James Conroy57d10b72019-10-25 09:44:14 +0100387
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100388 // Contains SyncMemGeneric
389 found = dump.find("SyncMemGeneric");
390 BOOST_TEST(found != std::string::npos);
James Conroy57d10b72019-10-25 09:44:14 +0100391
Ferran Balaguer83239f92019-09-19 11:49:25 +0100392 // Does not contain CopyMemGeneric
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100393 found = dump.find("CopyMemGeneric");
394 BOOST_TEST(found == std::string::npos);
James Conroy57d10b72019-10-25 09:44:14 +0100395
396 // Check output is as expected
397 BOOST_TEST(outputData == expectedOutput);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100398}
399
Ferran Balaguer83239f92019-09-19 11:49:25 +0100400inline void ImportOnlyWorkload(std::vector<BackendId> backends)
401{
402 using namespace armnn;
403
404 IRuntime::CreationOptions options;
405 IRuntimePtr runtime(IRuntime::Create(options));
406
407 // Builds up the structure of the network.
408 INetworkPtr net(INetwork::Create());
409
410 IConnectableLayer* input = net->AddInputLayer(0);
411
412 ActivationDescriptor descriptor;
413 descriptor.m_Function = ActivationFunction::Square;
414 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
415
416 IConnectableLayer* output = net->AddOutputLayer(0);
417
418 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
419 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
420
421 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
422 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
423
424 // optimize the network
425 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
426
427 BOOST_TEST_CHECKPOINT("Load Network");
428 // Load it into the runtime. It should pass.
429 NetworkId netId;
430 std::string ignoredErrorMessage;
431 INetworkProperties networkProperties(true, false);
432 BOOST_TEST(runtime->LoadNetwork(netId, std::move(optNet),ignoredErrorMessage, networkProperties)
433 == Status::Success);
434
435 BOOST_TEST_CHECKPOINT("Generate Data");
436 // Creates structures for input & output
437 std::vector<float> inputData
438 {
439 1.0f, 2.0f, 3.0f, 4.0f
440 };
441
442 std::vector<float> outputData(4);
443
444 std::vector<float> expectedOutput
445 {
446 1.0f, 4.0f, 9.0f, 16.0f
447 };
448
449 BOOST_TEST_CHECKPOINT("Create Network");
450 InputTensors inputTensors
451 {
452 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())},
453 };
454 OutputTensors outputTensors
455 {
456 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
457 };
458
459 BOOST_TEST_CHECKPOINT("Get Profiler");
460
461 runtime->GetProfiler(netId)->EnableProfiling(true);
462
463 BOOST_TEST_CHECKPOINT("Run Inference");
464 // Do the inference
465 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
466
467 BOOST_TEST_CHECKPOINT("Print Profiler");
468 // Retrieve the Profiler.Print() output to get the workload execution
469 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
470 std::stringstream ss;
471 profilerManager.GetProfiler()->Print(ss);;
472 std::string dump = ss.str();
473
474 // Check there are no SyncMemGeneric workloads as we didn't export
475 BOOST_TEST_CHECKPOINT("Find SyncMemGeneric");
476 int count = SubStringCounter(dump, "SyncMemGeneric");
477 BOOST_TEST(count == 0);
478
479 // Should only be 1 CopyMemGeneric for the output as we imported
480 BOOST_TEST_CHECKPOINT("Find CopyMemGeneric");
481 count = SubStringCounter(dump, "CopyMemGeneric");
482 BOOST_TEST(count == 1);
483
484 // Check the output is correct
485 BOOST_CHECK_EQUAL_COLLECTIONS(outputData.begin(), outputData.end(), expectedOutput.begin(), expectedOutput.end());
486}
487
488inline void ExportOnlyWorkload(std::vector<BackendId> backends)
489{
490 using namespace armnn;
491
492 IRuntime::CreationOptions options;
493 IRuntimePtr runtime(IRuntime::Create(options));
494
495 // Builds up the structure of the network.
496 INetworkPtr net(INetwork::Create());
497
498 IConnectableLayer* input = net->AddInputLayer(0);
499
500 ActivationDescriptor descriptor;
501 descriptor.m_Function = ActivationFunction::Square;
502 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
503
504 IConnectableLayer* output = net->AddOutputLayer(0);
505
506 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
507 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
508
509 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
510 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
511
512 // optimize the network
513 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
514
515 BOOST_TEST_CHECKPOINT("Load Network");
516 // Load it into the runtime. It should pass.
517 NetworkId netId;
518 std::string ignoredErrorMessage;
519 INetworkProperties networkProperties(false, true);
520 BOOST_TEST(runtime->LoadNetwork(netId, std::move(optNet),ignoredErrorMessage, networkProperties)
521 == Status::Success);
522
523 BOOST_TEST_CHECKPOINT("Generate Data");
524 // Creates structures for input & output
525 std::vector<float> inputData
526 {
527 1.0f, 2.0f, 3.0f, 4.0f
528 };
529
530 std::vector<float> outputData(4);
531
532 std::vector<float> expectedOutput
533 {
534 1.0f, 4.0f, 9.0f, 16.0f
535 };
536
537 BOOST_TEST_CHECKPOINT("Create Network");
538 InputTensors inputTensors
539 {
540 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())},
541 };
542 OutputTensors outputTensors
543 {
544 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
545 };
546
547 BOOST_TEST_CHECKPOINT("Get Profiler");
548
549 runtime->GetProfiler(netId)->EnableProfiling(true);
550
551 BOOST_TEST_CHECKPOINT("Run Inference");
552 // Do the inference
553 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
554
555 BOOST_TEST_CHECKPOINT("Print Profiler");
556 // Retrieve the Profiler.Print() output to get the workload execution
557 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
558 std::stringstream ss;
559 profilerManager.GetProfiler()->Print(ss);;
560 std::string dump = ss.str();
561
562 // Check there is a SyncMemGeneric workload as we exported
563 BOOST_TEST_CHECKPOINT("Find SyncMemGeneric");
564 int count = SubStringCounter(dump, "SyncMemGeneric");
565 BOOST_TEST(count == 1);
566
567 // Should be 1 CopyMemGeneric for the output as we did not import
568 BOOST_TEST_CHECKPOINT("Find CopyMemGeneric");
569 count = SubStringCounter(dump, "CopyMemGeneric");
570 BOOST_TEST(count == 1);
571
572 // Check the output is correct
573 BOOST_CHECK_EQUAL_COLLECTIONS(outputData.begin(), outputData.end(), expectedOutput.begin(), expectedOutput.end());
574}
575
576inline void ImportAndExportWorkload(std::vector<BackendId> backends)
577{
578 using namespace armnn;
579
580 IRuntime::CreationOptions options;
581 IRuntimePtr runtime(IRuntime::Create(options));
582
583 // Builds up the structure of the network.
584 INetworkPtr net(INetwork::Create());
585
586 IConnectableLayer* input = net->AddInputLayer(0);
587
588 ActivationDescriptor descriptor;
589 descriptor.m_Function = ActivationFunction::Square;
590 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
591
592 IConnectableLayer* output = net->AddOutputLayer(0);
593
594 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
595 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
596
597 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
598 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
599
600 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
601
602 BOOST_TEST_CHECKPOINT("Load Network");
603 // Load it into the runtime. It should pass.
604 NetworkId netId;
605 std::string ignoredErrorMessage;
606 INetworkProperties networkProperties(true, true);
607 BOOST_TEST(runtime->LoadNetwork(netId, std::move(optNet),ignoredErrorMessage, networkProperties)
608 == Status::Success);
609
610 BOOST_TEST_CHECKPOINT("Generate Data");
611 // Creates structures for input & output
612 std::vector<float> inputData
613 {
614 1.0f, 2.0f, 3.0f, 4.0f
615 };
616
617 std::vector<float> outputData(4);
618
619 std::vector<float> expectedOutput
620 {
621 1.0f, 4.0f, 9.0f, 16.0f
622 };
623
624 BOOST_TEST_CHECKPOINT("Create Network");
625 InputTensors inputTensors
626 {
627 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())},
628 };
629 OutputTensors outputTensors
630 {
631 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
632 };
633
634 BOOST_TEST_CHECKPOINT("Get Profiler");
635
636 runtime->GetProfiler(netId)->EnableProfiling(true);
637
638 BOOST_TEST_CHECKPOINT("Run Inference");
639 // Do the inference
640 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
641
642 BOOST_TEST_CHECKPOINT("Print Profiler");
643 // Retrieve the Profiler.Print() output to get the workload execution
644 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
645 std::stringstream ss;
646 profilerManager.GetProfiler()->Print(ss);;
647 std::string dump = ss.str();
648
649 // Check there is a SyncMemGeneric workload as we exported
650 BOOST_TEST_CHECKPOINT("Find SyncMemGeneric");
651 int count = SubStringCounter(dump, "SyncMemGeneric");
652 BOOST_TEST(count == 1);
653
654 // Shouldn't be any CopyMemGeneric workloads
655 BOOST_TEST_CHECKPOINT("Find CopyMemGeneric");
656 count = SubStringCounter(dump, "CopyMemGeneric");
657 BOOST_TEST(count == 0);
658
659 // Check the output is correct
660 BOOST_CHECK_EQUAL_COLLECTIONS(outputData.begin(), outputData.end(), expectedOutput.begin(), expectedOutput.end());
661}
662
663inline void ExportOutputWithSeveralOutputSlotConnectionsTest(std::vector<BackendId> backends)
664{
665 using namespace armnn;
666
667 // Create runtime in which test will run
668 IRuntime::CreationOptions options;
669 IRuntimePtr runtime(armnn::IRuntime::Create(options));
670
671 // build up the structure of the network
672 INetworkPtr net(INetwork::Create());
673
674 IConnectableLayer* input = net->AddInputLayer(0);
675
676 ActivationDescriptor descriptor;
677 descriptor.m_Function = ActivationFunction::Square;
678 IConnectableLayer* activation = net->AddActivationLayer(descriptor);
679
680 IConnectableLayer* output0 = net->AddOutputLayer(0);
681 IConnectableLayer* output1 = net->AddOutputLayer(1);
682
683 input->GetOutputSlot(0).Connect(activation->GetInputSlot(0));
684 activation->GetOutputSlot(0).Connect(output0->GetInputSlot(0));
685 activation->GetOutputSlot(0).Connect(output1->GetInputSlot(0));
686
687 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 1 }, DataType::Float32));
688 activation->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 1 }, DataType::Float32));
689
690 // Optimize the network
691 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
692
693 // Loads it into the runtime.
694 NetworkId netId;
695 std::string ignoredErrorMessage;
696 // Enable Importing
697 INetworkProperties networkProperties(true, true);
698 runtime->LoadNetwork(netId, std::move(optNet), ignoredErrorMessage, networkProperties);
699
700 // Creates structures for input & output
701 std::vector<float> inputData
702 {
703 1.0f, 2.0f, 3.0f, 4.0f
704 };
705
706 std::vector<float> outputData0(4);
707 std::vector<float> outputData1(4);
708
Narumol Prangnawarat3b90af62020-06-26 11:00:21 +0100709 std::vector<float> expectedOutput
710 {
711 1.0f, 4.0f, 9.0f, 16.0f
712 };
713
Ferran Balaguer83239f92019-09-19 11:49:25 +0100714 InputTensors inputTensors
715 {
716 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())},
717 };
718 OutputTensors outputTensors
719 {
720 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData0.data())},
721 {1,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 1), outputData1.data())}
722 };
723
724 // The result of the inference is not important, just the fact that there
725 // should not be CopyMemGeneric workloads.
726 runtime->GetProfiler(netId)->EnableProfiling(true);
727
728 // Do the inference
729 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
730
731 // Retrieve the Profiler.Print() output to get the workload execution
732 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
733 std::stringstream ss;
734 profilerManager.GetProfiler()->Print(ss);
735 std::string dump = ss.str();
736
737 std::size_t found = std::string::npos;
738
739 if (backends[0] == Compute::CpuRef)
740 {
741 found = dump.find("RefActivationWorkload");
742 }
743 else if (backends[0] == Compute::CpuAcc)
744 {
745 found = dump.find("NeonActivationWorkload");
746 }
747 else if (backends[0] == Compute::GpuAcc)
748 {
749 found = dump.find("ClActivationWorkload");
750 }
751
752 BOOST_TEST(found != std::string::npos);
753 // No contains SyncMemGeneric
754 found = dump.find("SyncMemGeneric");
755 BOOST_TEST(found == std::string::npos);
756 // Contains CopyMemGeneric
757 found = dump.find("CopyMemGeneric");
758 BOOST_TEST(found != std::string::npos);
Narumol Prangnawarat3b90af62020-06-26 11:00:21 +0100759
760 // Check that the outputs are correct
761 BOOST_CHECK_EQUAL_COLLECTIONS(outputData0.begin(), outputData0.end(),
762 expectedOutput.begin(), expectedOutput.end());
763 BOOST_CHECK_EQUAL_COLLECTIONS(outputData1.begin(), outputData1.end(),
764 expectedOutput.begin(), expectedOutput.end());
Ferran Balaguer83239f92019-09-19 11:49:25 +0100765}
766
David Monahan0a99a142020-03-13 07:52:54 +0000767inline void StridedSliceInvalidSliceEndToEndTest(std::vector<BackendId> backends)
768{
769 using namespace armnn;
770
771 // Create runtime in which test will run
772 IRuntime::CreationOptions options;
773 IRuntimePtr runtime(armnn::IRuntime::Create(options));
774
775 // build up the structure of the network
776 INetworkPtr net(INetwork::Create());
777
778 IConnectableLayer* input = net->AddInputLayer(0);
779
780 // Configure a strided slice with a stride the same size as the input but with a ShrinkAxisMask on the first
781 // dim of the output to make it too small to hold the specified slice.
782 StridedSliceDescriptor descriptor;
783 descriptor.m_Begin = {0, 0};
784 descriptor.m_End = {2, 3};
785 descriptor.m_Stride = {1, 1};
786 descriptor.m_BeginMask = 0;
787 descriptor.m_EndMask = 0;
788 descriptor.m_ShrinkAxisMask = 1;
789 IConnectableLayer* stridedSlice = net->AddStridedSliceLayer(descriptor);
790
791 IConnectableLayer* output0 = net->AddOutputLayer(0);
792
793 input->GetOutputSlot(0).Connect(stridedSlice->GetInputSlot(0));
794 stridedSlice->GetOutputSlot(0).Connect(output0->GetInputSlot(0));
795
796 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 2, 3 }, DataType::Float32));
797 stridedSlice->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 3 }, DataType::Float32));
798
799 // Attempt to optimize the network and check that the correct exception is thrown
800 BOOST_CHECK_THROW(Optimize(*net, backends, runtime->GetDeviceSpec()), armnn::LayerValidationException);
801}
802
Nattapat Chaimanowong1fcb4ff2019-01-24 15:25:26 +0000803} // anonymous namespace