blob: efaffb9b67f490fafea9b93377fbca52a2054a43 [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
Aron Virginas-Tard4f0fea2019-04-09 14:08:06 +01007#include <ResolveType.hpp>
Nattapat Chaimanowong1fcb4ff2019-01-24 15:25:26 +00008
Aron Virginas-Tar70104002018-10-24 15:33:28 +01009#include <armnn/ArmNN.hpp>
narpra01b9546cf2018-11-20 15:21:28 +000010#include <armnn/INetwork.hpp>
Ferran Balaguerdcaa6102019-08-21 13:28:38 +010011#include <Profiling.hpp>
Aron Virginas-Tar70104002018-10-24 15:33:28 +010012
Aron Virginas-Tarc9cc8042018-11-01 16:15:57 +000013#include <backendsCommon/test/QuantizeHelper.hpp>
Aron Virginas-Tar70104002018-10-24 15:33:28 +010014
narpra01b9546cf2018-11-20 15:21:28 +000015#include <boost/test/unit_test.hpp>
16
Aron Virginas-Tar70104002018-10-24 15:33:28 +010017#include <vector>
18
19namespace
20{
21
22using namespace armnn;
23
24template<typename T>
25bool ConstantUsageTest(const std::vector<BackendId>& computeDevice,
26 const TensorInfo& commonTensorInfo,
27 const std::vector<T>& inputData,
28 const std::vector<T>& constantData,
29 const std::vector<T>& expectedOutputData)
30{
31 // Create runtime in which test will run
32 IRuntime::CreationOptions options;
33 IRuntimePtr runtime(IRuntime::Create(options));
34
35 // Builds up the structure of the network.
36 INetworkPtr net(INetwork::Create());
37
38 IConnectableLayer* input = net->AddInputLayer(0);
39 IConnectableLayer* constant = net->AddConstantLayer(ConstTensor(commonTensorInfo, constantData));
40 IConnectableLayer* add = net->AddAdditionLayer();
41 IConnectableLayer* output = net->AddOutputLayer(0);
42
43 input->GetOutputSlot(0).Connect(add->GetInputSlot(0));
44 constant->GetOutputSlot(0).Connect(add->GetInputSlot(1));
45 add->GetOutputSlot(0).Connect(output->GetInputSlot(0));
46
47 // Sets the tensors in the network.
48 input->GetOutputSlot(0).SetTensorInfo(commonTensorInfo);
49 constant->GetOutputSlot(0).SetTensorInfo(commonTensorInfo);
50 add->GetOutputSlot(0).SetTensorInfo(commonTensorInfo);
51
52 // optimize the network
53 IOptimizedNetworkPtr optNet = Optimize(*net, computeDevice, runtime->GetDeviceSpec());
54
55 // Loads it into the runtime.
56 NetworkId netId;
57 runtime->LoadNetwork(netId, std::move(optNet));
58
59 // Creates structures for input & output.
60 std::vector<T> outputData(inputData.size());
61
62 InputTensors inputTensors
63 {
64 {0, ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())}
65 };
66 OutputTensors outputTensors
67 {
68 {0, Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
69 };
70
71 // Does the inference.
72 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
73
74 // Checks the results.
75 return outputData == expectedOutputData;
76}
77
78inline bool ConstantUsageFloat32Test(const std::vector<BackendId>& backends)
79{
80 const TensorInfo commonTensorInfo({ 2, 3 }, DataType::Float32);
81
82 return ConstantUsageTest(backends,
83 commonTensorInfo,
84 std::vector<float>{ 1.f, 2.f, 3.f, 4.f, 5.f, 6.f }, // Input.
85 std::vector<float>{ 6.f, 5.f, 4.f, 3.f, 2.f, 1.f }, // Const input.
86 std::vector<float>{ 7.f, 7.f, 7.f, 7.f, 7.f, 7.f } // Expected output.
87 );
88}
89
90inline bool ConstantUsageUint8Test(const std::vector<BackendId>& backends)
91{
92 TensorInfo commonTensorInfo({ 2, 3 }, DataType::QuantisedAsymm8);
93
94 const float scale = 0.023529f;
95 const int8_t offset = -43;
96
97 commonTensorInfo.SetQuantizationScale(scale);
98 commonTensorInfo.SetQuantizationOffset(offset);
99
100 return ConstantUsageTest(backends,
101 commonTensorInfo,
102 QuantizedVector<uint8_t>(scale, offset, { 1.f, 2.f, 3.f, 4.f, 5.f, 6.f }), // Input.
103 QuantizedVector<uint8_t>(scale, offset, { 6.f, 5.f, 4.f, 3.f, 2.f, 1.f }), // Const input.
104 QuantizedVector<uint8_t>(scale, offset, { 7.f, 7.f, 7.f, 7.f, 7.f, 7.f }) // Expected output.
105 );
106}
107
Aron Virginas-Tarf97f6da2019-10-01 18:35:44 +0100108// Utility template for comparing tensor elements
109template<DataType ArmnnType, typename T = ResolveType<ArmnnType>>
110bool Compare(T a, T b)
Nattapat Chaimanowong1fcb4ff2019-01-24 15:25:26 +0000111{
Aron Virginas-Tarf97f6da2019-10-01 18:35:44 +0100112 if (ArmnnType == DataType::Boolean)
113 {
114 // NOTE: Boolean is represented as uint8_t (with zero equals
115 // false and everything else equals true), therefore values
116 // need to be casted to bool before comparing them
117 return static_cast<bool>(a) == static_cast<bool>(b);
118 }
119
120 // NOTE: All other types can be cast to float and compared with
121 // a certain level of tolerance
122 constexpr float tolerance = 0.000001f;
123 return std::fabs(static_cast<float>(a) - static_cast<float>(b)) <= tolerance;
124}
Nattapat Chaimanowong1fcb4ff2019-01-24 15:25:26 +0000125
Ferran Balaguer83239f92019-09-19 11:49:25 +0100126// Utility function to find the number of instances of a substring within a string.
127int SubStringCounter(std::string& string, std::string&& substring)
128{
129 std::size_t found = 0;
130 int count = 0;
131 // Look for the substring starting from where we last found the substring
132 while((found = string.find(substring, found)) != std::string::npos)
133 {
134 count++;
135 // Offset by substring length to avoid finding the same substring twice
136 found += substring.length();
137 }
138 return count;
139}
140
Nattapat Chaimanowong1fcb4ff2019-01-24 15:25:26 +0000141template<DataType ArmnnIType, DataType ArmnnOType,
142 typename TInput = ResolveType<ArmnnIType>, typename TOutput = ResolveType<ArmnnOType>>
narpra01b9546cf2018-11-20 15:21:28 +0000143void EndToEndLayerTestImpl(INetworkPtr network,
kevmay012b4d88e2019-01-24 14:05:09 +0000144 const std::map<int, std::vector<TInput>>& inputTensorData,
145 const std::map<int, std::vector<TOutput>>& expectedOutputData,
narpra01b9546cf2018-11-20 15:21:28 +0000146 std::vector<BackendId> backends)
147{
148 // Create runtime in which test will run
149 IRuntime::CreationOptions options;
150 IRuntimePtr runtime(IRuntime::Create(options));
151
152 // optimize the network
153 IOptimizedNetworkPtr optNet = Optimize(*network, backends, runtime->GetDeviceSpec());
154
155 // Loads it into the runtime.
156 NetworkId netId;
157 runtime->LoadNetwork(netId, std::move(optNet));
158
159 InputTensors inputTensors;
160 inputTensors.reserve(inputTensorData.size());
161 for (auto&& it : inputTensorData)
162 {
163 inputTensors.push_back({it.first,
164 ConstTensor(runtime->GetInputTensorInfo(netId, it.first), it.second.data())});
165 }
166 OutputTensors outputTensors;
167 outputTensors.reserve(expectedOutputData.size());
kevmay012b4d88e2019-01-24 14:05:09 +0000168 std::map<int, std::vector<TOutput>> outputStorage;
narpra01b9546cf2018-11-20 15:21:28 +0000169 for (auto&& it : expectedOutputData)
170 {
kevmay012b4d88e2019-01-24 14:05:09 +0000171 std::vector<TOutput> out(it.second.size());
narpra01b9546cf2018-11-20 15:21:28 +0000172 outputStorage.emplace(it.first, out);
173 outputTensors.push_back({it.first,
174 Tensor(runtime->GetOutputTensorInfo(netId, it.first),
175 outputStorage.at(it.first).data())});
176 }
177
178 // Does the inference.
179 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
180
181 // Checks the results.
182 for (auto&& it : expectedOutputData)
183 {
kevmay012b4d88e2019-01-24 14:05:09 +0000184 std::vector<TOutput> out = outputStorage.at(it.first);
Aron Virginas-Tarf97f6da2019-10-01 18:35:44 +0100185 for (unsigned int i = 0; i < out.size(); ++i)
Nattapat Chaimanowong1fcb4ff2019-01-24 15:25:26 +0000186 {
Aron Virginas-Tarf97f6da2019-10-01 18:35:44 +0100187 BOOST_CHECK(Compare<ArmnnOType>(it.second[i], out[i]) == true);
Nattapat Chaimanowong1fcb4ff2019-01-24 15:25:26 +0000188 }
narpra01b9546cf2018-11-20 15:21:28 +0000189 }
190}
191
David Monahan4f1e8e42019-09-04 09:22:10 +0100192inline void ImportNonAlignedInputPointerTest(std::vector<BackendId> backends)
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100193{
194 using namespace armnn;
195
196 // Create runtime in which test will run
197 IRuntime::CreationOptions options;
198 IRuntimePtr runtime(armnn::IRuntime::Create(options));
199
200 // build up the structure of the network
201 INetworkPtr net(INetwork::Create());
202
203 IConnectableLayer* input = net->AddInputLayer(0);
204
David Monahan3fb7e102019-08-20 11:25:29 +0100205 ActivationDescriptor descriptor;
206 descriptor.m_Function = ActivationFunction::Square;
207 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100208
209 IConnectableLayer* output = net->AddOutputLayer(0);
210
David Monahan3fb7e102019-08-20 11:25:29 +0100211 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
212 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100213
David Monahan3fb7e102019-08-20 11:25:29 +0100214 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
215 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100216
217 // Optimize the network
218 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
David Monahan3fb7e102019-08-20 11:25:29 +0100219 BOOST_CHECK(optNet);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100220
221 // Loads it into the runtime.
222 NetworkId netId;
David Monahan4f1e8e42019-09-04 09:22:10 +0100223 std::string ignoredErrorMessage;
224 // Enable Importing
David Monahan3fb7e102019-08-20 11:25:29 +0100225 INetworkProperties networkProperties(true, false);
David Monahan4f1e8e42019-09-04 09:22:10 +0100226 runtime->LoadNetwork(netId, std::move(optNet), ignoredErrorMessage, networkProperties);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100227
228 // Creates structures for input & output
229 std::vector<float> inputData
230 {
David Monahan3fb7e102019-08-20 11:25:29 +0100231 1.0f, 2.0f, 3.0f, 4.0f
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100232 };
233
234 // Misaligned input
Aron Virginas-Tard9f7c8b2019-09-13 13:37:03 +0100235 float* misalignedInputData = reinterpret_cast<float*>(reinterpret_cast<char*>(inputData.data()) + 1);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100236
David Monahan3fb7e102019-08-20 11:25:29 +0100237 std::vector<float> outputData(4);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100238
David Monahan4f1e8e42019-09-04 09:22:10 +0100239 // Aligned output
David Monahan3fb7e102019-08-20 11:25:29 +0100240 float* alignedOutputData = outputData.data();
David Monahan4f1e8e42019-09-04 09:22:10 +0100241
242 InputTensors inputTensors
243 {
244 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), misalignedInputData)},
245 };
246 OutputTensors outputTensors
247 {
248 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), alignedOutputData)}
249 };
250
David Monahan4f1e8e42019-09-04 09:22:10 +0100251 runtime->GetProfiler(netId)->EnableProfiling(true);
252
253 // Do the inference and expect it to fail with a ImportMemoryException
254 BOOST_CHECK_THROW(runtime->EnqueueWorkload(netId, inputTensors, outputTensors), MemoryImportException);
255}
256
Ferran Balaguer83239f92019-09-19 11:49:25 +0100257inline void ExportNonAlignedOutputPointerTest(std::vector<BackendId> backends)
David Monahan4f1e8e42019-09-04 09:22:10 +0100258{
259 using namespace armnn;
260
261 // Create runtime in which test will run
262 IRuntime::CreationOptions options;
263 IRuntimePtr runtime(armnn::IRuntime::Create(options));
264
265 // build up the structure of the network
266 INetworkPtr net(INetwork::Create());
267
268 IConnectableLayer* input = net->AddInputLayer(0);
269
David Monahan3fb7e102019-08-20 11:25:29 +0100270 ActivationDescriptor descriptor;
271 descriptor.m_Function = ActivationFunction::Square;
272 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
David Monahan4f1e8e42019-09-04 09:22:10 +0100273
274 IConnectableLayer* output = net->AddOutputLayer(0);
275
David Monahan3fb7e102019-08-20 11:25:29 +0100276 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
277 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
David Monahan4f1e8e42019-09-04 09:22:10 +0100278
David Monahan3fb7e102019-08-20 11:25:29 +0100279 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
280 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
David Monahan4f1e8e42019-09-04 09:22:10 +0100281
282 // Optimize the network
283 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
David Monahan3fb7e102019-08-20 11:25:29 +0100284 BOOST_CHECK(optNet);
David Monahan4f1e8e42019-09-04 09:22:10 +0100285
286 // Loads it into the runtime.
287 NetworkId netId;
288 std::string ignoredErrorMessage;
David Monahan3fb7e102019-08-20 11:25:29 +0100289 // Enable Importing and Exporting
David Monahan4f1e8e42019-09-04 09:22:10 +0100290 INetworkProperties networkProperties(true, true);
291 runtime->LoadNetwork(netId, std::move(optNet), ignoredErrorMessage, networkProperties);
292
293 // Creates structures for input & output
294 std::vector<float> inputData
295 {
296 1.0f, 2.0f, 3.0f, 4.0f, 5.0f
297 };
298
299 // Aligned input
David Monahan3fb7e102019-08-20 11:25:29 +0100300 float* alignedInputData = inputData.data();
David Monahan4f1e8e42019-09-04 09:22:10 +0100301
302 std::vector<float> outputData(5);
303
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100304 // Misaligned output
Aron Virginas-Tard9f7c8b2019-09-13 13:37:03 +0100305 float* misalignedOutputData = reinterpret_cast<float*>(reinterpret_cast<char*>(outputData.data()) + 1);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100306
307 InputTensors inputTensors
308 {
David Monahan4f1e8e42019-09-04 09:22:10 +0100309 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), alignedInputData)},
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100310 };
311 OutputTensors outputTensors
312 {
313 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), misalignedOutputData)}
314 };
315
Ferran Balaguer83239f92019-09-19 11:49:25 +0100316 // Do the inference and expect it to fail with a ExportMemoryException
317 if (backends[0] == Compute::CpuAcc)
318 {
319 // For CpuAcc the NeonTensorHandle will throw its own exception on misaligned memory
320 BOOST_CHECK_THROW(runtime->EnqueueWorkload(netId, inputTensors, outputTensors), MemoryImportException);
321 }
322 else
323 {
324 BOOST_CHECK_THROW(runtime->EnqueueWorkload(netId, inputTensors, outputTensors), MemoryExportException);
325 }
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100326}
327
328inline void ImportAlignedPointerTest(std::vector<BackendId> backends)
329{
330 using namespace armnn;
331
332 // Create runtime in which test will run
333 IRuntime::CreationOptions options;
334 IRuntimePtr runtime(armnn::IRuntime::Create(options));
335
336 // build up the structure of the network
337 INetworkPtr net(INetwork::Create());
338
339 IConnectableLayer* input = net->AddInputLayer(0);
340
David Monahan3fb7e102019-08-20 11:25:29 +0100341 ActivationDescriptor descriptor;
342 descriptor.m_Function = ActivationFunction::Square;
343 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100344
345 IConnectableLayer* output = net->AddOutputLayer(0);
346
David Monahan3fb7e102019-08-20 11:25:29 +0100347 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
348 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100349
David Monahan3fb7e102019-08-20 11:25:29 +0100350 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
351 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100352
353 // Optimize the network
354 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
David Monahan3fb7e102019-08-20 11:25:29 +0100355 BOOST_CHECK(optNet);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100356
357 // Loads it into the runtime.
358 NetworkId netId;
David Monahan4f1e8e42019-09-04 09:22:10 +0100359 std::string ignoredErrorMessage;
360 // Enable Importing
361 INetworkProperties networkProperties(true, true);
362 runtime->LoadNetwork(netId, std::move(optNet), ignoredErrorMessage, networkProperties);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100363
364 // Creates structures for input & output
365 std::vector<float> inputData
366 {
367 1.0f, 2.0f, 3.0f, 4.0f
368 };
369
370 std::vector<float> outputData(4);
371
372 InputTensors inputTensors
373 {
374 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())},
375 };
376 OutputTensors outputTensors
377 {
378 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
379 };
380
381 // The result of the inference is not important, just the fact that there
382 // should not be CopyMemGeneric workloads.
383 runtime->GetProfiler(netId)->EnableProfiling(true);
384
385 // Do the inference
386 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
387
388 // Retrieve the Profiler.Print() output to get the workload execution
389 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
390 std::stringstream ss;
391 profilerManager.GetProfiler()->Print(ss);;
392 std::string dump = ss.str();
393
David Monahan3fb7e102019-08-20 11:25:29 +0100394 // Contains ActivationWorkload
395 std::size_t found = dump.find("ActivationWorkload");
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100396 BOOST_TEST(found != std::string::npos);
397 // Contains SyncMemGeneric
398 found = dump.find("SyncMemGeneric");
399 BOOST_TEST(found != std::string::npos);
Ferran Balaguer83239f92019-09-19 11:49:25 +0100400 // Does not contain CopyMemGeneric
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100401 found = dump.find("CopyMemGeneric");
402 BOOST_TEST(found == std::string::npos);
403}
404
Ferran Balaguer83239f92019-09-19 11:49:25 +0100405inline void ImportOnlyWorkload(std::vector<BackendId> backends)
406{
407 using namespace armnn;
408
409 IRuntime::CreationOptions options;
410 IRuntimePtr runtime(IRuntime::Create(options));
411
412 // Builds up the structure of the network.
413 INetworkPtr net(INetwork::Create());
414
415 IConnectableLayer* input = net->AddInputLayer(0);
416
417 ActivationDescriptor descriptor;
418 descriptor.m_Function = ActivationFunction::Square;
419 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
420
421 IConnectableLayer* output = net->AddOutputLayer(0);
422
423 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
424 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
425
426 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
427 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
428
429 // optimize the network
430 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
431
432 BOOST_TEST_CHECKPOINT("Load Network");
433 // Load it into the runtime. It should pass.
434 NetworkId netId;
435 std::string ignoredErrorMessage;
436 INetworkProperties networkProperties(true, false);
437 BOOST_TEST(runtime->LoadNetwork(netId, std::move(optNet),ignoredErrorMessage, networkProperties)
438 == Status::Success);
439
440 BOOST_TEST_CHECKPOINT("Generate Data");
441 // Creates structures for input & output
442 std::vector<float> inputData
443 {
444 1.0f, 2.0f, 3.0f, 4.0f
445 };
446
447 std::vector<float> outputData(4);
448
449 std::vector<float> expectedOutput
450 {
451 1.0f, 4.0f, 9.0f, 16.0f
452 };
453
454 BOOST_TEST_CHECKPOINT("Create Network");
455 InputTensors inputTensors
456 {
457 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())},
458 };
459 OutputTensors outputTensors
460 {
461 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
462 };
463
464 BOOST_TEST_CHECKPOINT("Get Profiler");
465
466 runtime->GetProfiler(netId)->EnableProfiling(true);
467
468 BOOST_TEST_CHECKPOINT("Run Inference");
469 // Do the inference
470 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
471
472 BOOST_TEST_CHECKPOINT("Print Profiler");
473 // Retrieve the Profiler.Print() output to get the workload execution
474 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
475 std::stringstream ss;
476 profilerManager.GetProfiler()->Print(ss);;
477 std::string dump = ss.str();
478
479 // Check there are no SyncMemGeneric workloads as we didn't export
480 BOOST_TEST_CHECKPOINT("Find SyncMemGeneric");
481 int count = SubStringCounter(dump, "SyncMemGeneric");
482 BOOST_TEST(count == 0);
483
484 // Should only be 1 CopyMemGeneric for the output as we imported
485 BOOST_TEST_CHECKPOINT("Find CopyMemGeneric");
486 count = SubStringCounter(dump, "CopyMemGeneric");
487 BOOST_TEST(count == 1);
488
489 // Check the output is correct
490 BOOST_CHECK_EQUAL_COLLECTIONS(outputData.begin(), outputData.end(), expectedOutput.begin(), expectedOutput.end());
491}
492
493inline void ExportOnlyWorkload(std::vector<BackendId> backends)
494{
495 using namespace armnn;
496
497 IRuntime::CreationOptions options;
498 IRuntimePtr runtime(IRuntime::Create(options));
499
500 // Builds up the structure of the network.
501 INetworkPtr net(INetwork::Create());
502
503 IConnectableLayer* input = net->AddInputLayer(0);
504
505 ActivationDescriptor descriptor;
506 descriptor.m_Function = ActivationFunction::Square;
507 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
508
509 IConnectableLayer* output = net->AddOutputLayer(0);
510
511 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
512 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
513
514 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
515 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
516
517 // optimize the network
518 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
519
520 BOOST_TEST_CHECKPOINT("Load Network");
521 // Load it into the runtime. It should pass.
522 NetworkId netId;
523 std::string ignoredErrorMessage;
524 INetworkProperties networkProperties(false, true);
525 BOOST_TEST(runtime->LoadNetwork(netId, std::move(optNet),ignoredErrorMessage, networkProperties)
526 == Status::Success);
527
528 BOOST_TEST_CHECKPOINT("Generate Data");
529 // Creates structures for input & output
530 std::vector<float> inputData
531 {
532 1.0f, 2.0f, 3.0f, 4.0f
533 };
534
535 std::vector<float> outputData(4);
536
537 std::vector<float> expectedOutput
538 {
539 1.0f, 4.0f, 9.0f, 16.0f
540 };
541
542 BOOST_TEST_CHECKPOINT("Create Network");
543 InputTensors inputTensors
544 {
545 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())},
546 };
547 OutputTensors outputTensors
548 {
549 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
550 };
551
552 BOOST_TEST_CHECKPOINT("Get Profiler");
553
554 runtime->GetProfiler(netId)->EnableProfiling(true);
555
556 BOOST_TEST_CHECKPOINT("Run Inference");
557 // Do the inference
558 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
559
560 BOOST_TEST_CHECKPOINT("Print Profiler");
561 // Retrieve the Profiler.Print() output to get the workload execution
562 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
563 std::stringstream ss;
564 profilerManager.GetProfiler()->Print(ss);;
565 std::string dump = ss.str();
566
567 // Check there is a SyncMemGeneric workload as we exported
568 BOOST_TEST_CHECKPOINT("Find SyncMemGeneric");
569 int count = SubStringCounter(dump, "SyncMemGeneric");
570 BOOST_TEST(count == 1);
571
572 // Should be 1 CopyMemGeneric for the output as we did not import
573 BOOST_TEST_CHECKPOINT("Find CopyMemGeneric");
574 count = SubStringCounter(dump, "CopyMemGeneric");
575 BOOST_TEST(count == 1);
576
577 // Check the output is correct
578 BOOST_CHECK_EQUAL_COLLECTIONS(outputData.begin(), outputData.end(), expectedOutput.begin(), expectedOutput.end());
579}
580
581inline void ImportAndExportWorkload(std::vector<BackendId> backends)
582{
583 using namespace armnn;
584
585 IRuntime::CreationOptions options;
586 IRuntimePtr runtime(IRuntime::Create(options));
587
588 // Builds up the structure of the network.
589 INetworkPtr net(INetwork::Create());
590
591 IConnectableLayer* input = net->AddInputLayer(0);
592
593 ActivationDescriptor descriptor;
594 descriptor.m_Function = ActivationFunction::Square;
595 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
596
597 IConnectableLayer* output = net->AddOutputLayer(0);
598
599 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
600 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
601
602 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
603 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
604
605 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
606
607 BOOST_TEST_CHECKPOINT("Load Network");
608 // Load it into the runtime. It should pass.
609 NetworkId netId;
610 std::string ignoredErrorMessage;
611 INetworkProperties networkProperties(true, true);
612 BOOST_TEST(runtime->LoadNetwork(netId, std::move(optNet),ignoredErrorMessage, networkProperties)
613 == Status::Success);
614
615 BOOST_TEST_CHECKPOINT("Generate Data");
616 // Creates structures for input & output
617 std::vector<float> inputData
618 {
619 1.0f, 2.0f, 3.0f, 4.0f
620 };
621
622 std::vector<float> outputData(4);
623
624 std::vector<float> expectedOutput
625 {
626 1.0f, 4.0f, 9.0f, 16.0f
627 };
628
629 BOOST_TEST_CHECKPOINT("Create Network");
630 InputTensors inputTensors
631 {
632 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())},
633 };
634 OutputTensors outputTensors
635 {
636 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
637 };
638
639 BOOST_TEST_CHECKPOINT("Get Profiler");
640
641 runtime->GetProfiler(netId)->EnableProfiling(true);
642
643 BOOST_TEST_CHECKPOINT("Run Inference");
644 // Do the inference
645 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
646
647 BOOST_TEST_CHECKPOINT("Print Profiler");
648 // Retrieve the Profiler.Print() output to get the workload execution
649 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
650 std::stringstream ss;
651 profilerManager.GetProfiler()->Print(ss);;
652 std::string dump = ss.str();
653
654 // Check there is a SyncMemGeneric workload as we exported
655 BOOST_TEST_CHECKPOINT("Find SyncMemGeneric");
656 int count = SubStringCounter(dump, "SyncMemGeneric");
657 BOOST_TEST(count == 1);
658
659 // Shouldn't be any CopyMemGeneric workloads
660 BOOST_TEST_CHECKPOINT("Find CopyMemGeneric");
661 count = SubStringCounter(dump, "CopyMemGeneric");
662 BOOST_TEST(count == 0);
663
664 // Check the output is correct
665 BOOST_CHECK_EQUAL_COLLECTIONS(outputData.begin(), outputData.end(), expectedOutput.begin(), expectedOutput.end());
666}
667
668inline void ExportOutputWithSeveralOutputSlotConnectionsTest(std::vector<BackendId> backends)
669{
670 using namespace armnn;
671
672 // Create runtime in which test will run
673 IRuntime::CreationOptions options;
674 IRuntimePtr runtime(armnn::IRuntime::Create(options));
675
676 // build up the structure of the network
677 INetworkPtr net(INetwork::Create());
678
679 IConnectableLayer* input = net->AddInputLayer(0);
680
681 ActivationDescriptor descriptor;
682 descriptor.m_Function = ActivationFunction::Square;
683 IConnectableLayer* activation = net->AddActivationLayer(descriptor);
684
685 IConnectableLayer* output0 = net->AddOutputLayer(0);
686 IConnectableLayer* output1 = net->AddOutputLayer(1);
687
688 input->GetOutputSlot(0).Connect(activation->GetInputSlot(0));
689 activation->GetOutputSlot(0).Connect(output0->GetInputSlot(0));
690 activation->GetOutputSlot(0).Connect(output1->GetInputSlot(0));
691
692 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 1 }, DataType::Float32));
693 activation->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 1 }, DataType::Float32));
694
695 // Optimize the network
696 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
697
698 // Loads it into the runtime.
699 NetworkId netId;
700 std::string ignoredErrorMessage;
701 // Enable Importing
702 INetworkProperties networkProperties(true, true);
703 runtime->LoadNetwork(netId, std::move(optNet), ignoredErrorMessage, networkProperties);
704
705 // Creates structures for input & output
706 std::vector<float> inputData
707 {
708 1.0f, 2.0f, 3.0f, 4.0f
709 };
710
711 std::vector<float> outputData0(4);
712 std::vector<float> outputData1(4);
713
714 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);
759}
760
Nattapat Chaimanowong1fcb4ff2019-01-24 15:25:26 +0000761} // anonymous namespace