blob: d6f589fa0008289b1abab22979e880281d5356b6 [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
7#include <armnn/ArmNN.hpp>
narpra01b9546cf2018-11-20 15:21:28 +00008#include <armnn/INetwork.hpp>
Aron Virginas-Tar70104002018-10-24 15:33:28 +01009
Aron Virginas-Tar48623a02019-10-22 10:00:28 +010010#include <Profiling.hpp>
11#include <QuantizeHelper.hpp>
12#include <ResolveType.hpp>
Aron Virginas-Tar70104002018-10-24 15:33:28 +010013
narpra01b9546cf2018-11-20 15:21:28 +000014#include <boost/test/unit_test.hpp>
15
Aron Virginas-Tar70104002018-10-24 15:33:28 +010016#include <vector>
17
18namespace
19{
20
21using namespace armnn;
22
23template<typename T>
24bool ConstantUsageTest(const std::vector<BackendId>& computeDevice,
25 const TensorInfo& commonTensorInfo,
26 const std::vector<T>& inputData,
27 const std::vector<T>& constantData,
28 const std::vector<T>& expectedOutputData)
29{
30 // Create runtime in which test will run
31 IRuntime::CreationOptions options;
32 IRuntimePtr runtime(IRuntime::Create(options));
33
34 // Builds up the structure of the network.
35 INetworkPtr net(INetwork::Create());
36
37 IConnectableLayer* input = net->AddInputLayer(0);
38 IConnectableLayer* constant = net->AddConstantLayer(ConstTensor(commonTensorInfo, constantData));
39 IConnectableLayer* add = net->AddAdditionLayer();
40 IConnectableLayer* output = net->AddOutputLayer(0);
41
42 input->GetOutputSlot(0).Connect(add->GetInputSlot(0));
43 constant->GetOutputSlot(0).Connect(add->GetInputSlot(1));
44 add->GetOutputSlot(0).Connect(output->GetInputSlot(0));
45
46 // Sets the tensors in the network.
47 input->GetOutputSlot(0).SetTensorInfo(commonTensorInfo);
48 constant->GetOutputSlot(0).SetTensorInfo(commonTensorInfo);
49 add->GetOutputSlot(0).SetTensorInfo(commonTensorInfo);
50
51 // optimize the network
52 IOptimizedNetworkPtr optNet = Optimize(*net, computeDevice, runtime->GetDeviceSpec());
53
54 // Loads it into the runtime.
55 NetworkId netId;
56 runtime->LoadNetwork(netId, std::move(optNet));
57
58 // Creates structures for input & output.
59 std::vector<T> outputData(inputData.size());
60
61 InputTensors inputTensors
62 {
63 {0, ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())}
64 };
65 OutputTensors outputTensors
66 {
67 {0, Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
68 };
69
70 // Does the inference.
71 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
72
73 // Checks the results.
74 return outputData == expectedOutputData;
75}
76
77inline bool ConstantUsageFloat32Test(const std::vector<BackendId>& backends)
78{
79 const TensorInfo commonTensorInfo({ 2, 3 }, DataType::Float32);
80
81 return ConstantUsageTest(backends,
82 commonTensorInfo,
83 std::vector<float>{ 1.f, 2.f, 3.f, 4.f, 5.f, 6.f }, // Input.
84 std::vector<float>{ 6.f, 5.f, 4.f, 3.f, 2.f, 1.f }, // Const input.
85 std::vector<float>{ 7.f, 7.f, 7.f, 7.f, 7.f, 7.f } // Expected output.
86 );
87}
88
89inline bool ConstantUsageUint8Test(const std::vector<BackendId>& backends)
90{
91 TensorInfo commonTensorInfo({ 2, 3 }, DataType::QuantisedAsymm8);
92
93 const float scale = 0.023529f;
94 const int8_t offset = -43;
95
96 commonTensorInfo.SetQuantizationScale(scale);
97 commonTensorInfo.SetQuantizationOffset(offset);
98
99 return ConstantUsageTest(backends,
100 commonTensorInfo,
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100101 armnnUtils::QuantizedVector<uint8_t>({ 1.f, 2.f, 3.f, 4.f, 5.f, 6.f }, scale, offset), // Input.
102 armnnUtils::QuantizedVector<uint8_t>({ 6.f, 5.f, 4.f, 3.f, 2.f, 1.f }, scale, offset), // Const input.
103 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 +0100104 );
105}
106
Aron Virginas-Tarf97f6da2019-10-01 18:35:44 +0100107// Utility template for comparing tensor elements
108template<DataType ArmnnType, typename T = ResolveType<ArmnnType>>
109bool Compare(T a, T b)
Nattapat Chaimanowong1fcb4ff2019-01-24 15:25:26 +0000110{
Aron Virginas-Tarf97f6da2019-10-01 18:35:44 +0100111 if (ArmnnType == DataType::Boolean)
112 {
113 // NOTE: Boolean is represented as uint8_t (with zero equals
114 // false and everything else equals true), therefore values
115 // need to be casted to bool before comparing them
116 return static_cast<bool>(a) == static_cast<bool>(b);
117 }
118
119 // NOTE: All other types can be cast to float and compared with
120 // a certain level of tolerance
121 constexpr float tolerance = 0.000001f;
122 return std::fabs(static_cast<float>(a) - static_cast<float>(b)) <= tolerance;
123}
Nattapat Chaimanowong1fcb4ff2019-01-24 15:25:26 +0000124
Ferran Balaguer83239f92019-09-19 11:49:25 +0100125// Utility function to find the number of instances of a substring within a string.
126int SubStringCounter(std::string& string, std::string&& substring)
127{
128 std::size_t found = 0;
129 int count = 0;
130 // Look for the substring starting from where we last found the substring
131 while((found = string.find(substring, found)) != std::string::npos)
132 {
133 count++;
134 // Offset by substring length to avoid finding the same substring twice
135 found += substring.length();
136 }
137 return count;
138}
139
Nattapat Chaimanowong1fcb4ff2019-01-24 15:25:26 +0000140template<DataType ArmnnIType, DataType ArmnnOType,
141 typename TInput = ResolveType<ArmnnIType>, typename TOutput = ResolveType<ArmnnOType>>
narpra01b9546cf2018-11-20 15:21:28 +0000142void EndToEndLayerTestImpl(INetworkPtr network,
kevmay012b4d88e2019-01-24 14:05:09 +0000143 const std::map<int, std::vector<TInput>>& inputTensorData,
144 const std::map<int, std::vector<TOutput>>& expectedOutputData,
narpra01b9546cf2018-11-20 15:21:28 +0000145 std::vector<BackendId> backends)
146{
147 // Create runtime in which test will run
148 IRuntime::CreationOptions options;
149 IRuntimePtr runtime(IRuntime::Create(options));
150
151 // optimize the network
152 IOptimizedNetworkPtr optNet = Optimize(*network, backends, runtime->GetDeviceSpec());
153
154 // Loads it into the runtime.
155 NetworkId netId;
156 runtime->LoadNetwork(netId, std::move(optNet));
157
158 InputTensors inputTensors;
159 inputTensors.reserve(inputTensorData.size());
160 for (auto&& it : inputTensorData)
161 {
162 inputTensors.push_back({it.first,
163 ConstTensor(runtime->GetInputTensorInfo(netId, it.first), it.second.data())});
164 }
165 OutputTensors outputTensors;
166 outputTensors.reserve(expectedOutputData.size());
kevmay012b4d88e2019-01-24 14:05:09 +0000167 std::map<int, std::vector<TOutput>> outputStorage;
narpra01b9546cf2018-11-20 15:21:28 +0000168 for (auto&& it : expectedOutputData)
169 {
kevmay012b4d88e2019-01-24 14:05:09 +0000170 std::vector<TOutput> out(it.second.size());
narpra01b9546cf2018-11-20 15:21:28 +0000171 outputStorage.emplace(it.first, out);
172 outputTensors.push_back({it.first,
173 Tensor(runtime->GetOutputTensorInfo(netId, it.first),
174 outputStorage.at(it.first).data())});
175 }
176
177 // Does the inference.
178 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
179
180 // Checks the results.
181 for (auto&& it : expectedOutputData)
182 {
kevmay012b4d88e2019-01-24 14:05:09 +0000183 std::vector<TOutput> out = outputStorage.at(it.first);
Aron Virginas-Tarf97f6da2019-10-01 18:35:44 +0100184 for (unsigned int i = 0; i < out.size(); ++i)
Nattapat Chaimanowong1fcb4ff2019-01-24 15:25:26 +0000185 {
Aron Virginas-Tarf97f6da2019-10-01 18:35:44 +0100186 BOOST_CHECK(Compare<ArmnnOType>(it.second[i], out[i]) == true);
Nattapat Chaimanowong1fcb4ff2019-01-24 15:25:26 +0000187 }
narpra01b9546cf2018-11-20 15:21:28 +0000188 }
189}
190
David Monahan4f1e8e42019-09-04 09:22:10 +0100191inline void ImportNonAlignedInputPointerTest(std::vector<BackendId> backends)
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100192{
193 using namespace armnn;
194
195 // Create runtime in which test will run
196 IRuntime::CreationOptions options;
197 IRuntimePtr runtime(armnn::IRuntime::Create(options));
198
199 // build up the structure of the network
200 INetworkPtr net(INetwork::Create());
201
202 IConnectableLayer* input = net->AddInputLayer(0);
203
David Monahan3fb7e102019-08-20 11:25:29 +0100204 ActivationDescriptor descriptor;
205 descriptor.m_Function = ActivationFunction::Square;
206 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100207
208 IConnectableLayer* output = net->AddOutputLayer(0);
209
David Monahan3fb7e102019-08-20 11:25:29 +0100210 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
211 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100212
David Monahan3fb7e102019-08-20 11:25:29 +0100213 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
214 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100215
216 // Optimize the network
217 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
David Monahan3fb7e102019-08-20 11:25:29 +0100218 BOOST_CHECK(optNet);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100219
220 // Loads it into the runtime.
221 NetworkId netId;
David Monahan4f1e8e42019-09-04 09:22:10 +0100222 std::string ignoredErrorMessage;
223 // Enable Importing
David Monahan3fb7e102019-08-20 11:25:29 +0100224 INetworkProperties networkProperties(true, false);
David Monahan4f1e8e42019-09-04 09:22:10 +0100225 runtime->LoadNetwork(netId, std::move(optNet), ignoredErrorMessage, networkProperties);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100226
227 // Creates structures for input & output
228 std::vector<float> inputData
229 {
David Monahan3fb7e102019-08-20 11:25:29 +0100230 1.0f, 2.0f, 3.0f, 4.0f
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100231 };
232
233 // Misaligned input
Aron Virginas-Tard9f7c8b2019-09-13 13:37:03 +0100234 float* misalignedInputData = reinterpret_cast<float*>(reinterpret_cast<char*>(inputData.data()) + 1);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100235
David Monahan3fb7e102019-08-20 11:25:29 +0100236 std::vector<float> outputData(4);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100237
David Monahan4f1e8e42019-09-04 09:22:10 +0100238 // Aligned output
David Monahan3fb7e102019-08-20 11:25:29 +0100239 float* alignedOutputData = outputData.data();
David Monahan4f1e8e42019-09-04 09:22:10 +0100240
241 InputTensors inputTensors
242 {
243 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), misalignedInputData)},
244 };
245 OutputTensors outputTensors
246 {
247 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), alignedOutputData)}
248 };
249
David Monahan4f1e8e42019-09-04 09:22:10 +0100250 runtime->GetProfiler(netId)->EnableProfiling(true);
251
252 // Do the inference and expect it to fail with a ImportMemoryException
253 BOOST_CHECK_THROW(runtime->EnqueueWorkload(netId, inputTensors, outputTensors), MemoryImportException);
254}
255
Ferran Balaguer83239f92019-09-19 11:49:25 +0100256inline void ExportNonAlignedOutputPointerTest(std::vector<BackendId> backends)
David Monahan4f1e8e42019-09-04 09:22:10 +0100257{
258 using namespace armnn;
259
260 // Create runtime in which test will run
261 IRuntime::CreationOptions options;
262 IRuntimePtr runtime(armnn::IRuntime::Create(options));
263
264 // build up the structure of the network
265 INetworkPtr net(INetwork::Create());
266
267 IConnectableLayer* input = net->AddInputLayer(0);
268
David Monahan3fb7e102019-08-20 11:25:29 +0100269 ActivationDescriptor descriptor;
270 descriptor.m_Function = ActivationFunction::Square;
271 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
David Monahan4f1e8e42019-09-04 09:22:10 +0100272
273 IConnectableLayer* output = net->AddOutputLayer(0);
274
David Monahan3fb7e102019-08-20 11:25:29 +0100275 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
276 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
David Monahan4f1e8e42019-09-04 09:22:10 +0100277
David Monahan3fb7e102019-08-20 11:25:29 +0100278 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
279 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
David Monahan4f1e8e42019-09-04 09:22:10 +0100280
281 // Optimize the network
282 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
David Monahan3fb7e102019-08-20 11:25:29 +0100283 BOOST_CHECK(optNet);
David Monahan4f1e8e42019-09-04 09:22:10 +0100284
285 // Loads it into the runtime.
286 NetworkId netId;
287 std::string ignoredErrorMessage;
David Monahan3fb7e102019-08-20 11:25:29 +0100288 // Enable Importing and Exporting
David Monahan4f1e8e42019-09-04 09:22:10 +0100289 INetworkProperties networkProperties(true, true);
290 runtime->LoadNetwork(netId, std::move(optNet), ignoredErrorMessage, networkProperties);
291
292 // Creates structures for input & output
293 std::vector<float> inputData
294 {
295 1.0f, 2.0f, 3.0f, 4.0f, 5.0f
296 };
297
298 // Aligned input
David Monahan3fb7e102019-08-20 11:25:29 +0100299 float* alignedInputData = inputData.data();
David Monahan4f1e8e42019-09-04 09:22:10 +0100300
301 std::vector<float> outputData(5);
302
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100303 // Misaligned output
Aron Virginas-Tard9f7c8b2019-09-13 13:37:03 +0100304 float* misalignedOutputData = reinterpret_cast<float*>(reinterpret_cast<char*>(outputData.data()) + 1);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100305
306 InputTensors inputTensors
307 {
David Monahan4f1e8e42019-09-04 09:22:10 +0100308 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), alignedInputData)},
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100309 };
310 OutputTensors outputTensors
311 {
312 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), misalignedOutputData)}
313 };
314
Ferran Balaguer83239f92019-09-19 11:49:25 +0100315 // Do the inference and expect it to fail with a ExportMemoryException
316 if (backends[0] == Compute::CpuAcc)
317 {
318 // For CpuAcc the NeonTensorHandle will throw its own exception on misaligned memory
319 BOOST_CHECK_THROW(runtime->EnqueueWorkload(netId, inputTensors, outputTensors), MemoryImportException);
320 }
321 else
322 {
323 BOOST_CHECK_THROW(runtime->EnqueueWorkload(netId, inputTensors, outputTensors), MemoryExportException);
324 }
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100325}
326
327inline void ImportAlignedPointerTest(std::vector<BackendId> backends)
328{
329 using namespace armnn;
330
331 // Create runtime in which test will run
332 IRuntime::CreationOptions options;
333 IRuntimePtr runtime(armnn::IRuntime::Create(options));
334
335 // build up the structure of the network
336 INetworkPtr net(INetwork::Create());
337
338 IConnectableLayer* input = net->AddInputLayer(0);
339
David Monahan3fb7e102019-08-20 11:25:29 +0100340 ActivationDescriptor descriptor;
341 descriptor.m_Function = ActivationFunction::Square;
342 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100343
344 IConnectableLayer* output = net->AddOutputLayer(0);
345
David Monahan3fb7e102019-08-20 11:25:29 +0100346 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
347 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100348
David Monahan3fb7e102019-08-20 11:25:29 +0100349 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
350 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100351
352 // Optimize the network
353 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
David Monahan3fb7e102019-08-20 11:25:29 +0100354 BOOST_CHECK(optNet);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100355
356 // Loads it into the runtime.
357 NetworkId netId;
David Monahan4f1e8e42019-09-04 09:22:10 +0100358 std::string ignoredErrorMessage;
359 // Enable Importing
360 INetworkProperties networkProperties(true, true);
361 runtime->LoadNetwork(netId, std::move(optNet), ignoredErrorMessage, networkProperties);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100362
363 // Creates structures for input & output
364 std::vector<float> inputData
365 {
366 1.0f, 2.0f, 3.0f, 4.0f
367 };
368
369 std::vector<float> outputData(4);
370
James Conroy57d10b72019-10-25 09:44:14 +0100371 std::vector<float> expectedOutput
372 {
373 1.0f, 4.0f, 9.0f, 16.0f
374 };
375
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100376 InputTensors inputTensors
377 {
378 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())},
379 };
380 OutputTensors outputTensors
381 {
382 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
383 };
384
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100385 runtime->GetProfiler(netId)->EnableProfiling(true);
386
387 // Do the inference
388 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
389
390 // Retrieve the Profiler.Print() output to get the workload execution
391 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
392 std::stringstream ss;
393 profilerManager.GetProfiler()->Print(ss);;
394 std::string dump = ss.str();
395
David Monahan3fb7e102019-08-20 11:25:29 +0100396 // Contains ActivationWorkload
397 std::size_t found = dump.find("ActivationWorkload");
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100398 BOOST_TEST(found != std::string::npos);
James Conroy57d10b72019-10-25 09:44:14 +0100399
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100400 // Contains SyncMemGeneric
401 found = dump.find("SyncMemGeneric");
402 BOOST_TEST(found != std::string::npos);
James Conroy57d10b72019-10-25 09:44:14 +0100403
Ferran Balaguer83239f92019-09-19 11:49:25 +0100404 // Does not contain CopyMemGeneric
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100405 found = dump.find("CopyMemGeneric");
406 BOOST_TEST(found == std::string::npos);
James Conroy57d10b72019-10-25 09:44:14 +0100407
408 // Check output is as expected
409 BOOST_TEST(outputData == expectedOutput);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100410}
411
Ferran Balaguer83239f92019-09-19 11:49:25 +0100412inline void ImportOnlyWorkload(std::vector<BackendId> backends)
413{
414 using namespace armnn;
415
416 IRuntime::CreationOptions options;
417 IRuntimePtr runtime(IRuntime::Create(options));
418
419 // Builds up the structure of the network.
420 INetworkPtr net(INetwork::Create());
421
422 IConnectableLayer* input = net->AddInputLayer(0);
423
424 ActivationDescriptor descriptor;
425 descriptor.m_Function = ActivationFunction::Square;
426 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
427
428 IConnectableLayer* output = net->AddOutputLayer(0);
429
430 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
431 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
432
433 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
434 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
435
436 // optimize the network
437 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
438
439 BOOST_TEST_CHECKPOINT("Load Network");
440 // Load it into the runtime. It should pass.
441 NetworkId netId;
442 std::string ignoredErrorMessage;
443 INetworkProperties networkProperties(true, false);
444 BOOST_TEST(runtime->LoadNetwork(netId, std::move(optNet),ignoredErrorMessage, networkProperties)
445 == Status::Success);
446
447 BOOST_TEST_CHECKPOINT("Generate Data");
448 // Creates structures for input & output
449 std::vector<float> inputData
450 {
451 1.0f, 2.0f, 3.0f, 4.0f
452 };
453
454 std::vector<float> outputData(4);
455
456 std::vector<float> expectedOutput
457 {
458 1.0f, 4.0f, 9.0f, 16.0f
459 };
460
461 BOOST_TEST_CHECKPOINT("Create Network");
462 InputTensors inputTensors
463 {
464 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())},
465 };
466 OutputTensors outputTensors
467 {
468 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
469 };
470
471 BOOST_TEST_CHECKPOINT("Get Profiler");
472
473 runtime->GetProfiler(netId)->EnableProfiling(true);
474
475 BOOST_TEST_CHECKPOINT("Run Inference");
476 // Do the inference
477 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
478
479 BOOST_TEST_CHECKPOINT("Print Profiler");
480 // Retrieve the Profiler.Print() output to get the workload execution
481 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
482 std::stringstream ss;
483 profilerManager.GetProfiler()->Print(ss);;
484 std::string dump = ss.str();
485
486 // Check there are no SyncMemGeneric workloads as we didn't export
487 BOOST_TEST_CHECKPOINT("Find SyncMemGeneric");
488 int count = SubStringCounter(dump, "SyncMemGeneric");
489 BOOST_TEST(count == 0);
490
491 // Should only be 1 CopyMemGeneric for the output as we imported
492 BOOST_TEST_CHECKPOINT("Find CopyMemGeneric");
493 count = SubStringCounter(dump, "CopyMemGeneric");
494 BOOST_TEST(count == 1);
495
496 // Check the output is correct
497 BOOST_CHECK_EQUAL_COLLECTIONS(outputData.begin(), outputData.end(), expectedOutput.begin(), expectedOutput.end());
498}
499
500inline void ExportOnlyWorkload(std::vector<BackendId> backends)
501{
502 using namespace armnn;
503
504 IRuntime::CreationOptions options;
505 IRuntimePtr runtime(IRuntime::Create(options));
506
507 // Builds up the structure of the network.
508 INetworkPtr net(INetwork::Create());
509
510 IConnectableLayer* input = net->AddInputLayer(0);
511
512 ActivationDescriptor descriptor;
513 descriptor.m_Function = ActivationFunction::Square;
514 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
515
516 IConnectableLayer* output = net->AddOutputLayer(0);
517
518 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
519 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
520
521 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
522 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
523
524 // optimize the network
525 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
526
527 BOOST_TEST_CHECKPOINT("Load Network");
528 // Load it into the runtime. It should pass.
529 NetworkId netId;
530 std::string ignoredErrorMessage;
531 INetworkProperties networkProperties(false, true);
532 BOOST_TEST(runtime->LoadNetwork(netId, std::move(optNet),ignoredErrorMessage, networkProperties)
533 == Status::Success);
534
535 BOOST_TEST_CHECKPOINT("Generate Data");
536 // Creates structures for input & output
537 std::vector<float> inputData
538 {
539 1.0f, 2.0f, 3.0f, 4.0f
540 };
541
542 std::vector<float> outputData(4);
543
544 std::vector<float> expectedOutput
545 {
546 1.0f, 4.0f, 9.0f, 16.0f
547 };
548
549 BOOST_TEST_CHECKPOINT("Create Network");
550 InputTensors inputTensors
551 {
552 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())},
553 };
554 OutputTensors outputTensors
555 {
556 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
557 };
558
559 BOOST_TEST_CHECKPOINT("Get Profiler");
560
561 runtime->GetProfiler(netId)->EnableProfiling(true);
562
563 BOOST_TEST_CHECKPOINT("Run Inference");
564 // Do the inference
565 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
566
567 BOOST_TEST_CHECKPOINT("Print Profiler");
568 // Retrieve the Profiler.Print() output to get the workload execution
569 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
570 std::stringstream ss;
571 profilerManager.GetProfiler()->Print(ss);;
572 std::string dump = ss.str();
573
574 // Check there is a SyncMemGeneric workload as we exported
575 BOOST_TEST_CHECKPOINT("Find SyncMemGeneric");
576 int count = SubStringCounter(dump, "SyncMemGeneric");
577 BOOST_TEST(count == 1);
578
579 // Should be 1 CopyMemGeneric for the output as we did not import
580 BOOST_TEST_CHECKPOINT("Find CopyMemGeneric");
581 count = SubStringCounter(dump, "CopyMemGeneric");
582 BOOST_TEST(count == 1);
583
584 // Check the output is correct
585 BOOST_CHECK_EQUAL_COLLECTIONS(outputData.begin(), outputData.end(), expectedOutput.begin(), expectedOutput.end());
586}
587
588inline void ImportAndExportWorkload(std::vector<BackendId> backends)
589{
590 using namespace armnn;
591
592 IRuntime::CreationOptions options;
593 IRuntimePtr runtime(IRuntime::Create(options));
594
595 // Builds up the structure of the network.
596 INetworkPtr net(INetwork::Create());
597
598 IConnectableLayer* input = net->AddInputLayer(0);
599
600 ActivationDescriptor descriptor;
601 descriptor.m_Function = ActivationFunction::Square;
602 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
603
604 IConnectableLayer* output = net->AddOutputLayer(0);
605
606 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
607 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
608
609 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
610 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
611
612 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
613
614 BOOST_TEST_CHECKPOINT("Load Network");
615 // Load it into the runtime. It should pass.
616 NetworkId netId;
617 std::string ignoredErrorMessage;
618 INetworkProperties networkProperties(true, true);
619 BOOST_TEST(runtime->LoadNetwork(netId, std::move(optNet),ignoredErrorMessage, networkProperties)
620 == Status::Success);
621
622 BOOST_TEST_CHECKPOINT("Generate Data");
623 // Creates structures for input & output
624 std::vector<float> inputData
625 {
626 1.0f, 2.0f, 3.0f, 4.0f
627 };
628
629 std::vector<float> outputData(4);
630
631 std::vector<float> expectedOutput
632 {
633 1.0f, 4.0f, 9.0f, 16.0f
634 };
635
636 BOOST_TEST_CHECKPOINT("Create Network");
637 InputTensors inputTensors
638 {
639 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())},
640 };
641 OutputTensors outputTensors
642 {
643 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
644 };
645
646 BOOST_TEST_CHECKPOINT("Get Profiler");
647
648 runtime->GetProfiler(netId)->EnableProfiling(true);
649
650 BOOST_TEST_CHECKPOINT("Run Inference");
651 // Do the inference
652 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
653
654 BOOST_TEST_CHECKPOINT("Print Profiler");
655 // Retrieve the Profiler.Print() output to get the workload execution
656 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
657 std::stringstream ss;
658 profilerManager.GetProfiler()->Print(ss);;
659 std::string dump = ss.str();
660
661 // Check there is a SyncMemGeneric workload as we exported
662 BOOST_TEST_CHECKPOINT("Find SyncMemGeneric");
663 int count = SubStringCounter(dump, "SyncMemGeneric");
664 BOOST_TEST(count == 1);
665
666 // Shouldn't be any CopyMemGeneric workloads
667 BOOST_TEST_CHECKPOINT("Find CopyMemGeneric");
668 count = SubStringCounter(dump, "CopyMemGeneric");
669 BOOST_TEST(count == 0);
670
671 // Check the output is correct
672 BOOST_CHECK_EQUAL_COLLECTIONS(outputData.begin(), outputData.end(), expectedOutput.begin(), expectedOutput.end());
673}
674
675inline void ExportOutputWithSeveralOutputSlotConnectionsTest(std::vector<BackendId> backends)
676{
677 using namespace armnn;
678
679 // Create runtime in which test will run
680 IRuntime::CreationOptions options;
681 IRuntimePtr runtime(armnn::IRuntime::Create(options));
682
683 // build up the structure of the network
684 INetworkPtr net(INetwork::Create());
685
686 IConnectableLayer* input = net->AddInputLayer(0);
687
688 ActivationDescriptor descriptor;
689 descriptor.m_Function = ActivationFunction::Square;
690 IConnectableLayer* activation = net->AddActivationLayer(descriptor);
691
692 IConnectableLayer* output0 = net->AddOutputLayer(0);
693 IConnectableLayer* output1 = net->AddOutputLayer(1);
694
695 input->GetOutputSlot(0).Connect(activation->GetInputSlot(0));
696 activation->GetOutputSlot(0).Connect(output0->GetInputSlot(0));
697 activation->GetOutputSlot(0).Connect(output1->GetInputSlot(0));
698
699 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 1 }, DataType::Float32));
700 activation->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 1 }, DataType::Float32));
701
702 // Optimize the network
703 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
704
705 // Loads it into the runtime.
706 NetworkId netId;
707 std::string ignoredErrorMessage;
708 // Enable Importing
709 INetworkProperties networkProperties(true, true);
710 runtime->LoadNetwork(netId, std::move(optNet), ignoredErrorMessage, networkProperties);
711
712 // Creates structures for input & output
713 std::vector<float> inputData
714 {
715 1.0f, 2.0f, 3.0f, 4.0f
716 };
717
718 std::vector<float> outputData0(4);
719 std::vector<float> outputData1(4);
720
721 InputTensors inputTensors
722 {
723 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())},
724 };
725 OutputTensors outputTensors
726 {
727 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData0.data())},
728 {1,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 1), outputData1.data())}
729 };
730
731 // The result of the inference is not important, just the fact that there
732 // should not be CopyMemGeneric workloads.
733 runtime->GetProfiler(netId)->EnableProfiling(true);
734
735 // Do the inference
736 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
737
738 // Retrieve the Profiler.Print() output to get the workload execution
739 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
740 std::stringstream ss;
741 profilerManager.GetProfiler()->Print(ss);
742 std::string dump = ss.str();
743
744 std::size_t found = std::string::npos;
745
746 if (backends[0] == Compute::CpuRef)
747 {
748 found = dump.find("RefActivationWorkload");
749 }
750 else if (backends[0] == Compute::CpuAcc)
751 {
752 found = dump.find("NeonActivationWorkload");
753 }
754 else if (backends[0] == Compute::GpuAcc)
755 {
756 found = dump.find("ClActivationWorkload");
757 }
758
759 BOOST_TEST(found != std::string::npos);
760 // No contains SyncMemGeneric
761 found = dump.find("SyncMemGeneric");
762 BOOST_TEST(found == std::string::npos);
763 // Contains CopyMemGeneric
764 found = dump.find("CopyMemGeneric");
765 BOOST_TEST(found != std::string::npos);
766}
767
Nattapat Chaimanowong1fcb4ff2019-01-24 15:25:26 +0000768} // anonymous namespace