blob: 1577e1323c7786c4e73401d7d1850bbf7db1e7b0 [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
Nattapat Chaimanowong1fcb4ff2019-01-24 15:25:26 +0000108template<typename T>
109bool CompareBoolean(T a, T b)
110{
111 return (a == 0 && b == 0) ||(a != 0 && b != 0);
112};
113
Ferran Balaguer83239f92019-09-19 11:49:25 +0100114// Utility function to find the number of instances of a substring within a string.
115int SubStringCounter(std::string& string, std::string&& substring)
116{
117 std::size_t found = 0;
118 int count = 0;
119 // Look for the substring starting from where we last found the substring
120 while((found = string.find(substring, found)) != std::string::npos)
121 {
122 count++;
123 // Offset by substring length to avoid finding the same substring twice
124 found += substring.length();
125 }
126 return count;
127}
128
Nattapat Chaimanowong1fcb4ff2019-01-24 15:25:26 +0000129template<DataType ArmnnIType, DataType ArmnnOType,
130 typename TInput = ResolveType<ArmnnIType>, typename TOutput = ResolveType<ArmnnOType>>
narpra01b9546cf2018-11-20 15:21:28 +0000131void EndToEndLayerTestImpl(INetworkPtr network,
kevmay012b4d88e2019-01-24 14:05:09 +0000132 const std::map<int, std::vector<TInput>>& inputTensorData,
133 const std::map<int, std::vector<TOutput>>& expectedOutputData,
narpra01b9546cf2018-11-20 15:21:28 +0000134 std::vector<BackendId> backends)
135{
136 // Create runtime in which test will run
137 IRuntime::CreationOptions options;
138 IRuntimePtr runtime(IRuntime::Create(options));
139
140 // optimize the network
141 IOptimizedNetworkPtr optNet = Optimize(*network, backends, runtime->GetDeviceSpec());
142
143 // Loads it into the runtime.
144 NetworkId netId;
145 runtime->LoadNetwork(netId, std::move(optNet));
146
147 InputTensors inputTensors;
148 inputTensors.reserve(inputTensorData.size());
149 for (auto&& it : inputTensorData)
150 {
151 inputTensors.push_back({it.first,
152 ConstTensor(runtime->GetInputTensorInfo(netId, it.first), it.second.data())});
153 }
154 OutputTensors outputTensors;
155 outputTensors.reserve(expectedOutputData.size());
kevmay012b4d88e2019-01-24 14:05:09 +0000156 std::map<int, std::vector<TOutput>> outputStorage;
narpra01b9546cf2018-11-20 15:21:28 +0000157 for (auto&& it : expectedOutputData)
158 {
kevmay012b4d88e2019-01-24 14:05:09 +0000159 std::vector<TOutput> out(it.second.size());
narpra01b9546cf2018-11-20 15:21:28 +0000160 outputStorage.emplace(it.first, out);
161 outputTensors.push_back({it.first,
162 Tensor(runtime->GetOutputTensorInfo(netId, it.first),
163 outputStorage.at(it.first).data())});
164 }
165
166 // Does the inference.
167 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
168
169 // Checks the results.
170 for (auto&& it : expectedOutputData)
171 {
kevmay012b4d88e2019-01-24 14:05:09 +0000172 std::vector<TOutput> out = outputStorage.at(it.first);
Nattapat Chaimanowong1fcb4ff2019-01-24 15:25:26 +0000173 if (ArmnnOType == DataType::Boolean)
174 {
175 for (unsigned int i = 0; i < out.size(); ++i)
176 {
177 BOOST_TEST(CompareBoolean<TOutput>(it.second[i], out[i]));
178 }
179 }
180 else
181 {
Narumol Prangnawarat6d302bf2019-02-04 11:46:26 +0000182 for (unsigned int i = 0; i < out.size(); ++i)
183 {
184 BOOST_TEST(it.second[i] == out[i], boost::test_tools::tolerance(0.000001f));
185 }
Nattapat Chaimanowong1fcb4ff2019-01-24 15:25:26 +0000186 }
narpra01b9546cf2018-11-20 15:21:28 +0000187 }
188}
189
David Monahan4f1e8e42019-09-04 09:22:10 +0100190inline void ImportNonAlignedInputPointerTest(std::vector<BackendId> backends)
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100191{
192 using namespace armnn;
193
194 // Create runtime in which test will run
195 IRuntime::CreationOptions options;
196 IRuntimePtr runtime(armnn::IRuntime::Create(options));
197
198 // build up the structure of the network
199 INetworkPtr net(INetwork::Create());
200
201 IConnectableLayer* input = net->AddInputLayer(0);
202
David Monahan3fb7e102019-08-20 11:25:29 +0100203 ActivationDescriptor descriptor;
204 descriptor.m_Function = ActivationFunction::Square;
205 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100206
207 IConnectableLayer* output = net->AddOutputLayer(0);
208
David Monahan3fb7e102019-08-20 11:25:29 +0100209 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
210 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100211
David Monahan3fb7e102019-08-20 11:25:29 +0100212 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
213 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100214
215 // Optimize the network
216 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
David Monahan3fb7e102019-08-20 11:25:29 +0100217 BOOST_CHECK(optNet);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100218
219 // Loads it into the runtime.
220 NetworkId netId;
David Monahan4f1e8e42019-09-04 09:22:10 +0100221 std::string ignoredErrorMessage;
222 // Enable Importing
David Monahan3fb7e102019-08-20 11:25:29 +0100223 INetworkProperties networkProperties(true, false);
David Monahan4f1e8e42019-09-04 09:22:10 +0100224 runtime->LoadNetwork(netId, std::move(optNet), ignoredErrorMessage, networkProperties);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100225
226 // Creates structures for input & output
227 std::vector<float> inputData
228 {
David Monahan3fb7e102019-08-20 11:25:29 +0100229 1.0f, 2.0f, 3.0f, 4.0f
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100230 };
231
232 // Misaligned input
Aron Virginas-Tard9f7c8b2019-09-13 13:37:03 +0100233 float* misalignedInputData = reinterpret_cast<float*>(reinterpret_cast<char*>(inputData.data()) + 1);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100234
David Monahan3fb7e102019-08-20 11:25:29 +0100235 std::vector<float> outputData(4);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100236
David Monahan4f1e8e42019-09-04 09:22:10 +0100237 // Aligned output
David Monahan3fb7e102019-08-20 11:25:29 +0100238 float* alignedOutputData = outputData.data();
David Monahan4f1e8e42019-09-04 09:22:10 +0100239
240 InputTensors inputTensors
241 {
242 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), misalignedInputData)},
243 };
244 OutputTensors outputTensors
245 {
246 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), alignedOutputData)}
247 };
248
David Monahan4f1e8e42019-09-04 09:22:10 +0100249 runtime->GetProfiler(netId)->EnableProfiling(true);
250
251 // Do the inference and expect it to fail with a ImportMemoryException
252 BOOST_CHECK_THROW(runtime->EnqueueWorkload(netId, inputTensors, outputTensors), MemoryImportException);
253}
254
Ferran Balaguer83239f92019-09-19 11:49:25 +0100255inline void ExportNonAlignedOutputPointerTest(std::vector<BackendId> backends)
David Monahan4f1e8e42019-09-04 09:22:10 +0100256{
257 using namespace armnn;
258
259 // Create runtime in which test will run
260 IRuntime::CreationOptions options;
261 IRuntimePtr runtime(armnn::IRuntime::Create(options));
262
263 // build up the structure of the network
264 INetworkPtr net(INetwork::Create());
265
266 IConnectableLayer* input = net->AddInputLayer(0);
267
David Monahan3fb7e102019-08-20 11:25:29 +0100268 ActivationDescriptor descriptor;
269 descriptor.m_Function = ActivationFunction::Square;
270 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
David Monahan4f1e8e42019-09-04 09:22:10 +0100271
272 IConnectableLayer* output = net->AddOutputLayer(0);
273
David Monahan3fb7e102019-08-20 11:25:29 +0100274 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
275 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
David Monahan4f1e8e42019-09-04 09:22:10 +0100276
David Monahan3fb7e102019-08-20 11:25:29 +0100277 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
278 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
David Monahan4f1e8e42019-09-04 09:22:10 +0100279
280 // Optimize the network
281 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
David Monahan3fb7e102019-08-20 11:25:29 +0100282 BOOST_CHECK(optNet);
David Monahan4f1e8e42019-09-04 09:22:10 +0100283
284 // Loads it into the runtime.
285 NetworkId netId;
286 std::string ignoredErrorMessage;
David Monahan3fb7e102019-08-20 11:25:29 +0100287 // Enable Importing and Exporting
David Monahan4f1e8e42019-09-04 09:22:10 +0100288 INetworkProperties networkProperties(true, true);
289 runtime->LoadNetwork(netId, std::move(optNet), ignoredErrorMessage, networkProperties);
290
291 // Creates structures for input & output
292 std::vector<float> inputData
293 {
294 1.0f, 2.0f, 3.0f, 4.0f, 5.0f
295 };
296
297 // Aligned input
David Monahan3fb7e102019-08-20 11:25:29 +0100298 float* alignedInputData = inputData.data();
David Monahan4f1e8e42019-09-04 09:22:10 +0100299
300 std::vector<float> outputData(5);
301
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100302 // Misaligned output
Aron Virginas-Tard9f7c8b2019-09-13 13:37:03 +0100303 float* misalignedOutputData = reinterpret_cast<float*>(reinterpret_cast<char*>(outputData.data()) + 1);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100304
305 InputTensors inputTensors
306 {
David Monahan4f1e8e42019-09-04 09:22:10 +0100307 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), alignedInputData)},
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100308 };
309 OutputTensors outputTensors
310 {
311 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), misalignedOutputData)}
312 };
313
Ferran Balaguer83239f92019-09-19 11:49:25 +0100314 // Do the inference and expect it to fail with a ExportMemoryException
315 if (backends[0] == Compute::CpuAcc)
316 {
317 // For CpuAcc the NeonTensorHandle will throw its own exception on misaligned memory
318 BOOST_CHECK_THROW(runtime->EnqueueWorkload(netId, inputTensors, outputTensors), MemoryImportException);
319 }
320 else
321 {
322 BOOST_CHECK_THROW(runtime->EnqueueWorkload(netId, inputTensors, outputTensors), MemoryExportException);
323 }
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100324}
325
326inline void ImportAlignedPointerTest(std::vector<BackendId> backends)
327{
328 using namespace armnn;
329
330 // Create runtime in which test will run
331 IRuntime::CreationOptions options;
332 IRuntimePtr runtime(armnn::IRuntime::Create(options));
333
334 // build up the structure of the network
335 INetworkPtr net(INetwork::Create());
336
337 IConnectableLayer* input = net->AddInputLayer(0);
338
David Monahan3fb7e102019-08-20 11:25:29 +0100339 ActivationDescriptor descriptor;
340 descriptor.m_Function = ActivationFunction::Square;
341 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100342
343 IConnectableLayer* output = net->AddOutputLayer(0);
344
David Monahan3fb7e102019-08-20 11:25:29 +0100345 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
346 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100347
David Monahan3fb7e102019-08-20 11:25:29 +0100348 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
349 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100350
351 // Optimize the network
352 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
David Monahan3fb7e102019-08-20 11:25:29 +0100353 BOOST_CHECK(optNet);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100354
355 // Loads it into the runtime.
356 NetworkId netId;
David Monahan4f1e8e42019-09-04 09:22:10 +0100357 std::string ignoredErrorMessage;
358 // Enable Importing
359 INetworkProperties networkProperties(true, true);
360 runtime->LoadNetwork(netId, std::move(optNet), ignoredErrorMessage, networkProperties);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100361
362 // Creates structures for input & output
363 std::vector<float> inputData
364 {
365 1.0f, 2.0f, 3.0f, 4.0f
366 };
367
368 std::vector<float> outputData(4);
369
370 InputTensors inputTensors
371 {
372 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())},
373 };
374 OutputTensors outputTensors
375 {
376 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
377 };
378
379 // The result of the inference is not important, just the fact that there
380 // should not be CopyMemGeneric workloads.
381 runtime->GetProfiler(netId)->EnableProfiling(true);
382
383 // Do the inference
384 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
385
386 // Retrieve the Profiler.Print() output to get the workload execution
387 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
388 std::stringstream ss;
389 profilerManager.GetProfiler()->Print(ss);;
390 std::string dump = ss.str();
391
David Monahan3fb7e102019-08-20 11:25:29 +0100392 // Contains ActivationWorkload
393 std::size_t found = dump.find("ActivationWorkload");
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100394 BOOST_TEST(found != std::string::npos);
395 // Contains SyncMemGeneric
396 found = dump.find("SyncMemGeneric");
397 BOOST_TEST(found != std::string::npos);
Ferran Balaguer83239f92019-09-19 11:49:25 +0100398 // Does not contain CopyMemGeneric
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100399 found = dump.find("CopyMemGeneric");
400 BOOST_TEST(found == std::string::npos);
401}
402
Ferran Balaguer83239f92019-09-19 11:49:25 +0100403inline void ImportOnlyWorkload(std::vector<BackendId> backends)
404{
405 using namespace armnn;
406
407 IRuntime::CreationOptions options;
408 IRuntimePtr runtime(IRuntime::Create(options));
409
410 // Builds up the structure of the network.
411 INetworkPtr net(INetwork::Create());
412
413 IConnectableLayer* input = net->AddInputLayer(0);
414
415 ActivationDescriptor descriptor;
416 descriptor.m_Function = ActivationFunction::Square;
417 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
418
419 IConnectableLayer* output = net->AddOutputLayer(0);
420
421 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
422 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
423
424 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
425 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
426
427 // optimize the network
428 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
429
430 BOOST_TEST_CHECKPOINT("Load Network");
431 // Load it into the runtime. It should pass.
432 NetworkId netId;
433 std::string ignoredErrorMessage;
434 INetworkProperties networkProperties(true, false);
435 BOOST_TEST(runtime->LoadNetwork(netId, std::move(optNet),ignoredErrorMessage, networkProperties)
436 == Status::Success);
437
438 BOOST_TEST_CHECKPOINT("Generate Data");
439 // Creates structures for input & output
440 std::vector<float> inputData
441 {
442 1.0f, 2.0f, 3.0f, 4.0f
443 };
444
445 std::vector<float> outputData(4);
446
447 std::vector<float> expectedOutput
448 {
449 1.0f, 4.0f, 9.0f, 16.0f
450 };
451
452 BOOST_TEST_CHECKPOINT("Create Network");
453 InputTensors inputTensors
454 {
455 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())},
456 };
457 OutputTensors outputTensors
458 {
459 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
460 };
461
462 BOOST_TEST_CHECKPOINT("Get Profiler");
463
464 runtime->GetProfiler(netId)->EnableProfiling(true);
465
466 BOOST_TEST_CHECKPOINT("Run Inference");
467 // Do the inference
468 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
469
470 BOOST_TEST_CHECKPOINT("Print Profiler");
471 // Retrieve the Profiler.Print() output to get the workload execution
472 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
473 std::stringstream ss;
474 profilerManager.GetProfiler()->Print(ss);;
475 std::string dump = ss.str();
476
477 // Check there are no SyncMemGeneric workloads as we didn't export
478 BOOST_TEST_CHECKPOINT("Find SyncMemGeneric");
479 int count = SubStringCounter(dump, "SyncMemGeneric");
480 BOOST_TEST(count == 0);
481
482 // Should only be 1 CopyMemGeneric for the output as we imported
483 BOOST_TEST_CHECKPOINT("Find CopyMemGeneric");
484 count = SubStringCounter(dump, "CopyMemGeneric");
485 BOOST_TEST(count == 1);
486
487 // Check the output is correct
488 BOOST_CHECK_EQUAL_COLLECTIONS(outputData.begin(), outputData.end(), expectedOutput.begin(), expectedOutput.end());
489}
490
491inline void ExportOnlyWorkload(std::vector<BackendId> backends)
492{
493 using namespace armnn;
494
495 IRuntime::CreationOptions options;
496 IRuntimePtr runtime(IRuntime::Create(options));
497
498 // Builds up the structure of the network.
499 INetworkPtr net(INetwork::Create());
500
501 IConnectableLayer* input = net->AddInputLayer(0);
502
503 ActivationDescriptor descriptor;
504 descriptor.m_Function = ActivationFunction::Square;
505 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
506
507 IConnectableLayer* output = net->AddOutputLayer(0);
508
509 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
510 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
511
512 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
513 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
514
515 // optimize the network
516 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
517
518 BOOST_TEST_CHECKPOINT("Load Network");
519 // Load it into the runtime. It should pass.
520 NetworkId netId;
521 std::string ignoredErrorMessage;
522 INetworkProperties networkProperties(false, true);
523 BOOST_TEST(runtime->LoadNetwork(netId, std::move(optNet),ignoredErrorMessage, networkProperties)
524 == Status::Success);
525
526 BOOST_TEST_CHECKPOINT("Generate Data");
527 // Creates structures for input & output
528 std::vector<float> inputData
529 {
530 1.0f, 2.0f, 3.0f, 4.0f
531 };
532
533 std::vector<float> outputData(4);
534
535 std::vector<float> expectedOutput
536 {
537 1.0f, 4.0f, 9.0f, 16.0f
538 };
539
540 BOOST_TEST_CHECKPOINT("Create Network");
541 InputTensors inputTensors
542 {
543 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())},
544 };
545 OutputTensors outputTensors
546 {
547 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
548 };
549
550 BOOST_TEST_CHECKPOINT("Get Profiler");
551
552 runtime->GetProfiler(netId)->EnableProfiling(true);
553
554 BOOST_TEST_CHECKPOINT("Run Inference");
555 // Do the inference
556 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
557
558 BOOST_TEST_CHECKPOINT("Print Profiler");
559 // Retrieve the Profiler.Print() output to get the workload execution
560 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
561 std::stringstream ss;
562 profilerManager.GetProfiler()->Print(ss);;
563 std::string dump = ss.str();
564
565 // Check there is a SyncMemGeneric workload as we exported
566 BOOST_TEST_CHECKPOINT("Find SyncMemGeneric");
567 int count = SubStringCounter(dump, "SyncMemGeneric");
568 BOOST_TEST(count == 1);
569
570 // Should be 1 CopyMemGeneric for the output as we did not import
571 BOOST_TEST_CHECKPOINT("Find CopyMemGeneric");
572 count = SubStringCounter(dump, "CopyMemGeneric");
573 BOOST_TEST(count == 1);
574
575 // Check the output is correct
576 BOOST_CHECK_EQUAL_COLLECTIONS(outputData.begin(), outputData.end(), expectedOutput.begin(), expectedOutput.end());
577}
578
579inline void ImportAndExportWorkload(std::vector<BackendId> backends)
580{
581 using namespace armnn;
582
583 IRuntime::CreationOptions options;
584 IRuntimePtr runtime(IRuntime::Create(options));
585
586 // Builds up the structure of the network.
587 INetworkPtr net(INetwork::Create());
588
589 IConnectableLayer* input = net->AddInputLayer(0);
590
591 ActivationDescriptor descriptor;
592 descriptor.m_Function = ActivationFunction::Square;
593 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
594
595 IConnectableLayer* output = net->AddOutputLayer(0);
596
597 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
598 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
599
600 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
601 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
602
603 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
604
605 BOOST_TEST_CHECKPOINT("Load Network");
606 // Load it into the runtime. It should pass.
607 NetworkId netId;
608 std::string ignoredErrorMessage;
609 INetworkProperties networkProperties(true, true);
610 BOOST_TEST(runtime->LoadNetwork(netId, std::move(optNet),ignoredErrorMessage, networkProperties)
611 == Status::Success);
612
613 BOOST_TEST_CHECKPOINT("Generate Data");
614 // Creates structures for input & output
615 std::vector<float> inputData
616 {
617 1.0f, 2.0f, 3.0f, 4.0f
618 };
619
620 std::vector<float> outputData(4);
621
622 std::vector<float> expectedOutput
623 {
624 1.0f, 4.0f, 9.0f, 16.0f
625 };
626
627 BOOST_TEST_CHECKPOINT("Create Network");
628 InputTensors inputTensors
629 {
630 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())},
631 };
632 OutputTensors outputTensors
633 {
634 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
635 };
636
637 BOOST_TEST_CHECKPOINT("Get Profiler");
638
639 runtime->GetProfiler(netId)->EnableProfiling(true);
640
641 BOOST_TEST_CHECKPOINT("Run Inference");
642 // Do the inference
643 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
644
645 BOOST_TEST_CHECKPOINT("Print Profiler");
646 // Retrieve the Profiler.Print() output to get the workload execution
647 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
648 std::stringstream ss;
649 profilerManager.GetProfiler()->Print(ss);;
650 std::string dump = ss.str();
651
652 // Check there is a SyncMemGeneric workload as we exported
653 BOOST_TEST_CHECKPOINT("Find SyncMemGeneric");
654 int count = SubStringCounter(dump, "SyncMemGeneric");
655 BOOST_TEST(count == 1);
656
657 // Shouldn't be any CopyMemGeneric workloads
658 BOOST_TEST_CHECKPOINT("Find CopyMemGeneric");
659 count = SubStringCounter(dump, "CopyMemGeneric");
660 BOOST_TEST(count == 0);
661
662 // Check the output is correct
663 BOOST_CHECK_EQUAL_COLLECTIONS(outputData.begin(), outputData.end(), expectedOutput.begin(), expectedOutput.end());
664}
665
666inline void ExportOutputWithSeveralOutputSlotConnectionsTest(std::vector<BackendId> backends)
667{
668 using namespace armnn;
669
670 // Create runtime in which test will run
671 IRuntime::CreationOptions options;
672 IRuntimePtr runtime(armnn::IRuntime::Create(options));
673
674 // build up the structure of the network
675 INetworkPtr net(INetwork::Create());
676
677 IConnectableLayer* input = net->AddInputLayer(0);
678
679 ActivationDescriptor descriptor;
680 descriptor.m_Function = ActivationFunction::Square;
681 IConnectableLayer* activation = net->AddActivationLayer(descriptor);
682
683 IConnectableLayer* output0 = net->AddOutputLayer(0);
684 IConnectableLayer* output1 = net->AddOutputLayer(1);
685
686 input->GetOutputSlot(0).Connect(activation->GetInputSlot(0));
687 activation->GetOutputSlot(0).Connect(output0->GetInputSlot(0));
688 activation->GetOutputSlot(0).Connect(output1->GetInputSlot(0));
689
690 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 1 }, DataType::Float32));
691 activation->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 1 }, DataType::Float32));
692
693 // Optimize the network
694 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
695
696 // Loads it into the runtime.
697 NetworkId netId;
698 std::string ignoredErrorMessage;
699 // Enable Importing
700 INetworkProperties networkProperties(true, true);
701 runtime->LoadNetwork(netId, std::move(optNet), ignoredErrorMessage, networkProperties);
702
703 // Creates structures for input & output
704 std::vector<float> inputData
705 {
706 1.0f, 2.0f, 3.0f, 4.0f
707 };
708
709 std::vector<float> outputData0(4);
710 std::vector<float> outputData1(4);
711
712 InputTensors inputTensors
713 {
714 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())},
715 };
716 OutputTensors outputTensors
717 {
718 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData0.data())},
719 {1,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 1), outputData1.data())}
720 };
721
722 // The result of the inference is not important, just the fact that there
723 // should not be CopyMemGeneric workloads.
724 runtime->GetProfiler(netId)->EnableProfiling(true);
725
726 // Do the inference
727 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
728
729 // Retrieve the Profiler.Print() output to get the workload execution
730 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
731 std::stringstream ss;
732 profilerManager.GetProfiler()->Print(ss);
733 std::string dump = ss.str();
734
735 std::size_t found = std::string::npos;
736
737 if (backends[0] == Compute::CpuRef)
738 {
739 found = dump.find("RefActivationWorkload");
740 }
741 else if (backends[0] == Compute::CpuAcc)
742 {
743 found = dump.find("NeonActivationWorkload");
744 }
745 else if (backends[0] == Compute::GpuAcc)
746 {
747 found = dump.find("ClActivationWorkload");
748 }
749
750 BOOST_TEST(found != std::string::npos);
751 // No contains SyncMemGeneric
752 found = dump.find("SyncMemGeneric");
753 BOOST_TEST(found == std::string::npos);
754 // Contains CopyMemGeneric
755 found = dump.find("CopyMemGeneric");
756 BOOST_TEST(found != std::string::npos);
757}
758
Nattapat Chaimanowong1fcb4ff2019-01-24 15:25:26 +0000759} // anonymous namespace