blob: 4221f626da6cfcf7afb6b2cad18876229b9670b4 [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
Matthew Bentham246bd462020-01-20 16:16:06 +00007#include <armnn/Descriptors.hpp>
narpra01b9546cf2018-11-20 15:21:28 +00008#include <armnn/INetwork.hpp>
Matthew Bentham246bd462020-01-20 16:16:06 +00009#include <armnn/IRuntime.hpp>
Aron Virginas-Tar70104002018-10-24 15:33:28 +010010
Aron Virginas-Tar48623a02019-10-22 10:00:28 +010011#include <Profiling.hpp>
12#include <QuantizeHelper.hpp>
13#include <ResolveType.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{
Derek Lambertif90c56d2020-01-10 17:14:08 +000092 TensorInfo commonTensorInfo({ 2, 3 }, DataType::QAsymmU8);
Aron Virginas-Tar70104002018-10-24 15:33:28 +010093
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,
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100102 armnnUtils::QuantizedVector<uint8_t>({ 1.f, 2.f, 3.f, 4.f, 5.f, 6.f }, scale, offset), // Input.
103 armnnUtils::QuantizedVector<uint8_t>({ 6.f, 5.f, 4.f, 3.f, 2.f, 1.f }, scale, offset), // Const input.
104 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 +0100105 );
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
James Conroy57d10b72019-10-25 09:44:14 +0100372 std::vector<float> expectedOutput
373 {
374 1.0f, 4.0f, 9.0f, 16.0f
375 };
376
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100377 InputTensors inputTensors
378 {
379 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())},
380 };
381 OutputTensors outputTensors
382 {
383 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
384 };
385
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100386 runtime->GetProfiler(netId)->EnableProfiling(true);
387
388 // Do the inference
389 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
390
391 // Retrieve the Profiler.Print() output to get the workload execution
392 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
393 std::stringstream ss;
394 profilerManager.GetProfiler()->Print(ss);;
395 std::string dump = ss.str();
396
David Monahan3fb7e102019-08-20 11:25:29 +0100397 // Contains ActivationWorkload
398 std::size_t found = dump.find("ActivationWorkload");
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100399 BOOST_TEST(found != std::string::npos);
James Conroy57d10b72019-10-25 09:44:14 +0100400
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100401 // Contains SyncMemGeneric
402 found = dump.find("SyncMemGeneric");
403 BOOST_TEST(found != std::string::npos);
James Conroy57d10b72019-10-25 09:44:14 +0100404
Ferran Balaguer83239f92019-09-19 11:49:25 +0100405 // Does not contain CopyMemGeneric
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100406 found = dump.find("CopyMemGeneric");
407 BOOST_TEST(found == std::string::npos);
James Conroy57d10b72019-10-25 09:44:14 +0100408
409 // Check output is as expected
410 BOOST_TEST(outputData == expectedOutput);
Ferran Balaguerdcaa6102019-08-21 13:28:38 +0100411}
412
Ferran Balaguer83239f92019-09-19 11:49:25 +0100413inline void ImportOnlyWorkload(std::vector<BackendId> backends)
414{
415 using namespace armnn;
416
417 IRuntime::CreationOptions options;
418 IRuntimePtr runtime(IRuntime::Create(options));
419
420 // Builds up the structure of the network.
421 INetworkPtr net(INetwork::Create());
422
423 IConnectableLayer* input = net->AddInputLayer(0);
424
425 ActivationDescriptor descriptor;
426 descriptor.m_Function = ActivationFunction::Square;
427 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
428
429 IConnectableLayer* output = net->AddOutputLayer(0);
430
431 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
432 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
433
434 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
435 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
436
437 // optimize the network
438 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
439
440 BOOST_TEST_CHECKPOINT("Load Network");
441 // Load it into the runtime. It should pass.
442 NetworkId netId;
443 std::string ignoredErrorMessage;
444 INetworkProperties networkProperties(true, false);
445 BOOST_TEST(runtime->LoadNetwork(netId, std::move(optNet),ignoredErrorMessage, networkProperties)
446 == Status::Success);
447
448 BOOST_TEST_CHECKPOINT("Generate Data");
449 // Creates structures for input & output
450 std::vector<float> inputData
451 {
452 1.0f, 2.0f, 3.0f, 4.0f
453 };
454
455 std::vector<float> outputData(4);
456
457 std::vector<float> expectedOutput
458 {
459 1.0f, 4.0f, 9.0f, 16.0f
460 };
461
462 BOOST_TEST_CHECKPOINT("Create Network");
463 InputTensors inputTensors
464 {
465 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())},
466 };
467 OutputTensors outputTensors
468 {
469 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
470 };
471
472 BOOST_TEST_CHECKPOINT("Get Profiler");
473
474 runtime->GetProfiler(netId)->EnableProfiling(true);
475
476 BOOST_TEST_CHECKPOINT("Run Inference");
477 // Do the inference
478 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
479
480 BOOST_TEST_CHECKPOINT("Print Profiler");
481 // Retrieve the Profiler.Print() output to get the workload execution
482 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
483 std::stringstream ss;
484 profilerManager.GetProfiler()->Print(ss);;
485 std::string dump = ss.str();
486
487 // Check there are no SyncMemGeneric workloads as we didn't export
488 BOOST_TEST_CHECKPOINT("Find SyncMemGeneric");
489 int count = SubStringCounter(dump, "SyncMemGeneric");
490 BOOST_TEST(count == 0);
491
492 // Should only be 1 CopyMemGeneric for the output as we imported
493 BOOST_TEST_CHECKPOINT("Find CopyMemGeneric");
494 count = SubStringCounter(dump, "CopyMemGeneric");
495 BOOST_TEST(count == 1);
496
497 // Check the output is correct
498 BOOST_CHECK_EQUAL_COLLECTIONS(outputData.begin(), outputData.end(), expectedOutput.begin(), expectedOutput.end());
499}
500
501inline void ExportOnlyWorkload(std::vector<BackendId> backends)
502{
503 using namespace armnn;
504
505 IRuntime::CreationOptions options;
506 IRuntimePtr runtime(IRuntime::Create(options));
507
508 // Builds up the structure of the network.
509 INetworkPtr net(INetwork::Create());
510
511 IConnectableLayer* input = net->AddInputLayer(0);
512
513 ActivationDescriptor descriptor;
514 descriptor.m_Function = ActivationFunction::Square;
515 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
516
517 IConnectableLayer* output = net->AddOutputLayer(0);
518
519 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
520 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
521
522 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
523 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
524
525 // optimize the network
526 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
527
528 BOOST_TEST_CHECKPOINT("Load Network");
529 // Load it into the runtime. It should pass.
530 NetworkId netId;
531 std::string ignoredErrorMessage;
532 INetworkProperties networkProperties(false, true);
533 BOOST_TEST(runtime->LoadNetwork(netId, std::move(optNet),ignoredErrorMessage, networkProperties)
534 == Status::Success);
535
536 BOOST_TEST_CHECKPOINT("Generate Data");
537 // Creates structures for input & output
538 std::vector<float> inputData
539 {
540 1.0f, 2.0f, 3.0f, 4.0f
541 };
542
543 std::vector<float> outputData(4);
544
545 std::vector<float> expectedOutput
546 {
547 1.0f, 4.0f, 9.0f, 16.0f
548 };
549
550 BOOST_TEST_CHECKPOINT("Create Network");
551 InputTensors inputTensors
552 {
553 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())},
554 };
555 OutputTensors outputTensors
556 {
557 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
558 };
559
560 BOOST_TEST_CHECKPOINT("Get Profiler");
561
562 runtime->GetProfiler(netId)->EnableProfiling(true);
563
564 BOOST_TEST_CHECKPOINT("Run Inference");
565 // Do the inference
566 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
567
568 BOOST_TEST_CHECKPOINT("Print Profiler");
569 // Retrieve the Profiler.Print() output to get the workload execution
570 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
571 std::stringstream ss;
572 profilerManager.GetProfiler()->Print(ss);;
573 std::string dump = ss.str();
574
575 // Check there is a SyncMemGeneric workload as we exported
576 BOOST_TEST_CHECKPOINT("Find SyncMemGeneric");
577 int count = SubStringCounter(dump, "SyncMemGeneric");
578 BOOST_TEST(count == 1);
579
580 // Should be 1 CopyMemGeneric for the output as we did not import
581 BOOST_TEST_CHECKPOINT("Find CopyMemGeneric");
582 count = SubStringCounter(dump, "CopyMemGeneric");
583 BOOST_TEST(count == 1);
584
585 // Check the output is correct
586 BOOST_CHECK_EQUAL_COLLECTIONS(outputData.begin(), outputData.end(), expectedOutput.begin(), expectedOutput.end());
587}
588
589inline void ImportAndExportWorkload(std::vector<BackendId> backends)
590{
591 using namespace armnn;
592
593 IRuntime::CreationOptions options;
594 IRuntimePtr runtime(IRuntime::Create(options));
595
596 // Builds up the structure of the network.
597 INetworkPtr net(INetwork::Create());
598
599 IConnectableLayer* input = net->AddInputLayer(0);
600
601 ActivationDescriptor descriptor;
602 descriptor.m_Function = ActivationFunction::Square;
603 IConnectableLayer* pooling = net->AddActivationLayer(descriptor);
604
605 IConnectableLayer* output = net->AddOutputLayer(0);
606
607 input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
608 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
609
610 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
611 pooling->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 1, 4 }, DataType::Float32));
612
613 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
614
615 BOOST_TEST_CHECKPOINT("Load Network");
616 // Load it into the runtime. It should pass.
617 NetworkId netId;
618 std::string ignoredErrorMessage;
619 INetworkProperties networkProperties(true, true);
620 BOOST_TEST(runtime->LoadNetwork(netId, std::move(optNet),ignoredErrorMessage, networkProperties)
621 == Status::Success);
622
623 BOOST_TEST_CHECKPOINT("Generate Data");
624 // Creates structures for input & output
625 std::vector<float> inputData
626 {
627 1.0f, 2.0f, 3.0f, 4.0f
628 };
629
630 std::vector<float> outputData(4);
631
632 std::vector<float> expectedOutput
633 {
634 1.0f, 4.0f, 9.0f, 16.0f
635 };
636
637 BOOST_TEST_CHECKPOINT("Create Network");
638 InputTensors inputTensors
639 {
640 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())},
641 };
642 OutputTensors outputTensors
643 {
644 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
645 };
646
647 BOOST_TEST_CHECKPOINT("Get Profiler");
648
649 runtime->GetProfiler(netId)->EnableProfiling(true);
650
651 BOOST_TEST_CHECKPOINT("Run Inference");
652 // Do the inference
653 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
654
655 BOOST_TEST_CHECKPOINT("Print Profiler");
656 // Retrieve the Profiler.Print() output to get the workload execution
657 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
658 std::stringstream ss;
659 profilerManager.GetProfiler()->Print(ss);;
660 std::string dump = ss.str();
661
662 // Check there is a SyncMemGeneric workload as we exported
663 BOOST_TEST_CHECKPOINT("Find SyncMemGeneric");
664 int count = SubStringCounter(dump, "SyncMemGeneric");
665 BOOST_TEST(count == 1);
666
667 // Shouldn't be any CopyMemGeneric workloads
668 BOOST_TEST_CHECKPOINT("Find CopyMemGeneric");
669 count = SubStringCounter(dump, "CopyMemGeneric");
670 BOOST_TEST(count == 0);
671
672 // Check the output is correct
673 BOOST_CHECK_EQUAL_COLLECTIONS(outputData.begin(), outputData.end(), expectedOutput.begin(), expectedOutput.end());
674}
675
676inline void ExportOutputWithSeveralOutputSlotConnectionsTest(std::vector<BackendId> backends)
677{
678 using namespace armnn;
679
680 // Create runtime in which test will run
681 IRuntime::CreationOptions options;
682 IRuntimePtr runtime(armnn::IRuntime::Create(options));
683
684 // build up the structure of the network
685 INetworkPtr net(INetwork::Create());
686
687 IConnectableLayer* input = net->AddInputLayer(0);
688
689 ActivationDescriptor descriptor;
690 descriptor.m_Function = ActivationFunction::Square;
691 IConnectableLayer* activation = net->AddActivationLayer(descriptor);
692
693 IConnectableLayer* output0 = net->AddOutputLayer(0);
694 IConnectableLayer* output1 = net->AddOutputLayer(1);
695
696 input->GetOutputSlot(0).Connect(activation->GetInputSlot(0));
697 activation->GetOutputSlot(0).Connect(output0->GetInputSlot(0));
698 activation->GetOutputSlot(0).Connect(output1->GetInputSlot(0));
699
700 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 1 }, DataType::Float32));
701 activation->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 1 }, DataType::Float32));
702
703 // Optimize the network
704 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
705
706 // Loads it into the runtime.
707 NetworkId netId;
708 std::string ignoredErrorMessage;
709 // Enable Importing
710 INetworkProperties networkProperties(true, true);
711 runtime->LoadNetwork(netId, std::move(optNet), ignoredErrorMessage, networkProperties);
712
713 // Creates structures for input & output
714 std::vector<float> inputData
715 {
716 1.0f, 2.0f, 3.0f, 4.0f
717 };
718
719 std::vector<float> outputData0(4);
720 std::vector<float> outputData1(4);
721
722 InputTensors inputTensors
723 {
724 {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData.data())},
725 };
726 OutputTensors outputTensors
727 {
728 {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData0.data())},
729 {1,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 1), outputData1.data())}
730 };
731
732 // The result of the inference is not important, just the fact that there
733 // should not be CopyMemGeneric workloads.
734 runtime->GetProfiler(netId)->EnableProfiling(true);
735
736 // Do the inference
737 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
738
739 // Retrieve the Profiler.Print() output to get the workload execution
740 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
741 std::stringstream ss;
742 profilerManager.GetProfiler()->Print(ss);
743 std::string dump = ss.str();
744
745 std::size_t found = std::string::npos;
746
747 if (backends[0] == Compute::CpuRef)
748 {
749 found = dump.find("RefActivationWorkload");
750 }
751 else if (backends[0] == Compute::CpuAcc)
752 {
753 found = dump.find("NeonActivationWorkload");
754 }
755 else if (backends[0] == Compute::GpuAcc)
756 {
757 found = dump.find("ClActivationWorkload");
758 }
759
760 BOOST_TEST(found != std::string::npos);
761 // No contains SyncMemGeneric
762 found = dump.find("SyncMemGeneric");
763 BOOST_TEST(found == std::string::npos);
764 // Contains CopyMemGeneric
765 found = dump.find("CopyMemGeneric");
766 BOOST_TEST(found != std::string::npos);
767}
768
David Monahan0a99a142020-03-13 07:52:54 +0000769inline void StridedSliceInvalidSliceEndToEndTest(std::vector<BackendId> backends)
770{
771 using namespace armnn;
772
773 // Create runtime in which test will run
774 IRuntime::CreationOptions options;
775 IRuntimePtr runtime(armnn::IRuntime::Create(options));
776
777 // build up the structure of the network
778 INetworkPtr net(INetwork::Create());
779
780 IConnectableLayer* input = net->AddInputLayer(0);
781
782 // Configure a strided slice with a stride the same size as the input but with a ShrinkAxisMask on the first
783 // dim of the output to make it too small to hold the specified slice.
784 StridedSliceDescriptor descriptor;
785 descriptor.m_Begin = {0, 0};
786 descriptor.m_End = {2, 3};
787 descriptor.m_Stride = {1, 1};
788 descriptor.m_BeginMask = 0;
789 descriptor.m_EndMask = 0;
790 descriptor.m_ShrinkAxisMask = 1;
791 IConnectableLayer* stridedSlice = net->AddStridedSliceLayer(descriptor);
792
793 IConnectableLayer* output0 = net->AddOutputLayer(0);
794
795 input->GetOutputSlot(0).Connect(stridedSlice->GetInputSlot(0));
796 stridedSlice->GetOutputSlot(0).Connect(output0->GetInputSlot(0));
797
798 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 2, 3 }, DataType::Float32));
799 stridedSlice->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 3 }, DataType::Float32));
800
801 // Attempt to optimize the network and check that the correct exception is thrown
802 BOOST_CHECK_THROW(Optimize(*net, backends, runtime->GetDeviceSpec()), armnn::LayerValidationException);
803}
804
Nattapat Chaimanowong1fcb4ff2019-01-24 15:25:26 +0000805} // anonymous namespace