blob: 87cade7dca37c13ecc63541d1f2b2ed95d59afb5 [file] [log] [blame]
Mike Kelly386ff1a2021-03-29 15:04:50 +01001//
2// Copyright © 2021 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#pragma once
7
8#include <ResolveType.hpp>
9
10#include <armnn/IWorkingMemHandle.hpp>
11#include <armnn/INetwork.hpp>
Keith Davise813d672021-04-22 10:10:34 +010012#include <armnn/IAsyncExecutionCallback.hpp>
Mike Kelly386ff1a2021-03-29 15:04:50 +010013
Keith Davise813d672021-04-22 10:10:34 +010014#include <AsyncExecutionCallback.hpp>
Mike Kelly386ff1a2021-03-29 15:04:50 +010015#include <backendsCommon/test/CommonTestUtils.hpp>
16
17#include <boost/test/unit_test.hpp>
18
19#include <vector>
20
21namespace armnn
22{
23
24namespace experimental
25{
26
27template<DataType ArmnnIType, DataType ArmnnOType,
28 typename TInput = ResolveType <ArmnnIType>, typename TOutput = ResolveType <ArmnnOType>>
Finn Williamsb8181f72021-04-07 10:23:21 +010029void AsyncThreadedEndToEndTestImpl(INetworkPtr network,
30 const std::vector<std::map<int, std::vector<TInput>>>& inputTensorData,
31 const std::vector<std::map<int, std::vector<TOutput>>>& expectedOutputData,
32 std::vector<BackendId> backends,
33 const size_t numberOfInferences,
34 float tolerance = 0.000001f)
35{
36 // Create Runtime in which test will run
37 IRuntime::CreationOptions options;
38 IRuntimePtr runtime(IRuntime::Create(options));
39
40 // Optimize the Network
41 IOptimizedNetworkPtr optNet = Optimize(*network, backends, runtime->GetDeviceSpec());
42
43
44 // Creates AsyncNetwork
45 NetworkId networkId = 0;
46 std::string errorMessage;
Francis Murtagh73d3e2e2021-04-29 14:23:04 +010047 const INetworkProperties networkProperties(true, MemorySource::Undefined, MemorySource::Undefined);
Finn Williamsb8181f72021-04-07 10:23:21 +010048 runtime->LoadNetwork(networkId, std::move(optNet), errorMessage, networkProperties);
49
50 std::vector<InputTensors> inputTensorsVec;
51 std::vector<OutputTensors> outputTensorsVec;
52 std::vector<std::map<int, std::vector<TOutput>>> outputStorageVec;
53 std::vector<std::unique_ptr<IWorkingMemHandle>> workingMemHandles;
54
55 for (unsigned int i = 0; i < numberOfInferences; ++i)
56 {
57 InputTensors inputTensors;
58 OutputTensors outputTensors;
59 outputStorageVec.emplace_back(std::map<int, std::vector<TOutput>>());
60
61 inputTensors.reserve(inputTensorData.size());
62 for (auto&& it : inputTensorData[i])
63 {
64 inputTensors.push_back({it.first,
65 ConstTensor(runtime->GetInputTensorInfo(networkId, it.first), it.second.data())});
66 }
67
68 outputTensors.reserve(expectedOutputData.size());
69 for (auto&& it : expectedOutputData[i])
70 {
71 std::vector<TOutput> out(it.second.size());
72 outputStorageVec[i].emplace(it.first, out);
73 outputTensors.push_back({it.first,
74 Tensor(runtime->GetOutputTensorInfo(networkId, it.first),
75 outputStorageVec[i].at(it.first).data())});
76 }
77
78 inputTensorsVec.push_back(inputTensors);
79 outputTensorsVec.push_back(outputTensors);
80
81 workingMemHandles.push_back(runtime->CreateWorkingMemHandle(networkId));
82 }
83
84 std::vector<std::thread> threads;
85 for (unsigned int i = 0; i < numberOfInferences; ++i)
86 {
87 // Access the vectors before we do anything multi-threaded
88 InputTensors& inputTensors = inputTensorsVec[i];
89 OutputTensors& outputTensors = outputTensorsVec[i];
90 IWorkingMemHandle& workingMemHandle = *workingMemHandles[i].get();
91
92 threads.emplace_back([&]()
93 {
94 // Run the async network
95 runtime->Execute(workingMemHandle, inputTensors, outputTensors);
96 });
97 }
98
99 for (unsigned int i = 0; i < numberOfInferences; ++i)
100 {
101 threads[i].join();
102 }
103
104 // Checks the results.
105 for (unsigned int i = 0; i < numberOfInferences; ++i)
106 {
107 for (auto &&it : expectedOutputData[i])
108 {
109 std::vector<TOutput> out = outputStorageVec[i].at(it.first);
110 for (unsigned int j = 0; j < out.size(); ++j)
111 {
112 BOOST_CHECK(Compare<ArmnnOType>(it.second[j], out[j], tolerance) == true);
113 }
114 }
115 }
116
117}
118
Finn Williamsb8181f72021-04-07 10:23:21 +0100119template<DataType ArmnnIType, DataType ArmnnOType,
Keith Davise813d672021-04-22 10:10:34 +0100120 typename TInput = ResolveType<ArmnnIType>, typename TOutput = ResolveType<ArmnnOType>>
Mike Kelly386ff1a2021-03-29 15:04:50 +0100121void AsyncEndToEndTestImpl(INetworkPtr network,
122 const std::map<int, std::vector<TInput>>& inputTensorData,
123 const std::map<int, std::vector<TOutput>>& expectedOutputData,
124 std::vector<BackendId> backends,
Keith Davise813d672021-04-22 10:10:34 +0100125 float tolerance = 0.000001f,
126 size_t numThreads = 0)
Mike Kelly386ff1a2021-03-29 15:04:50 +0100127{
128 // Create Runtime in which test will run
129 IRuntime::CreationOptions options;
Keith Davise813d672021-04-22 10:10:34 +0100130 IRuntimePtr runtime(IRuntime::Create(options));
Mike Kelly386ff1a2021-03-29 15:04:50 +0100131
132 // Optimize the Network
133 IOptimizedNetworkPtr optNet = Optimize(*network, backends, runtime->GetDeviceSpec());
134
135 // Creates AsyncNetwork
136 NetworkId networkId = 0;
Keith Davise813d672021-04-22 10:10:34 +0100137
Mike Kelly386ff1a2021-03-29 15:04:50 +0100138 std::string errorMessage;
Keith Davise813d672021-04-22 10:10:34 +0100139
140 const INetworkProperties networkProperties(true, MemorySource::Undefined, MemorySource::Undefined, numThreads);
141
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100142 runtime->LoadNetwork(networkId, std::move(optNet), errorMessage, networkProperties);
Mike Kelly386ff1a2021-03-29 15:04:50 +0100143
144 InputTensors inputTensors;
145 inputTensors.reserve(inputTensorData.size());
146 for (auto&& it : inputTensorData)
147 {
148 inputTensors.push_back({it.first,
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100149 ConstTensor(runtime->GetInputTensorInfo(networkId, it.first), it.second.data())});
Mike Kelly386ff1a2021-03-29 15:04:50 +0100150 }
151
152 OutputTensors outputTensors;
153 outputTensors.reserve(expectedOutputData.size());
154 std::map<int, std::vector<TOutput>> outputStorage;
155 for (auto&& it : expectedOutputData)
156 {
157 std::vector<TOutput> out(it.second.size());
158 outputStorage.emplace(it.first, out);
159 outputTensors.push_back({it.first,
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100160 Tensor(runtime->GetOutputTensorInfo(networkId, it.first),
Mike Kelly386ff1a2021-03-29 15:04:50 +0100161 outputStorage.at(it.first).data())});
162 }
163
Keith Davise813d672021-04-22 10:10:34 +0100164 if (numThreads == 0)
165 {
166 // Create WorkingMemHandle for this async network
167 std::unique_ptr<IWorkingMemHandle> workingMemHandle = runtime->CreateWorkingMemHandle(networkId);
168 IWorkingMemHandle& workingMemHandleRef = *workingMemHandle.get();
Mike Kelly386ff1a2021-03-29 15:04:50 +0100169
Keith Davise813d672021-04-22 10:10:34 +0100170 // Run the async network
171 runtime->Execute(workingMemHandleRef, inputTensors, outputTensors);
172 }
173 else
174 {
175 std::vector<IAsyncExecutionCallbackPtr> callbacks;
Mike Kelly386ff1a2021-03-29 15:04:50 +0100176
Keith Davise813d672021-04-22 10:10:34 +0100177 // Create 1000 callbacks that will be checked post scheduling
178 for (size_t i = 0; i < 1000; ++i)
179 {
180 callbacks.emplace_back(std::make_shared<AsyncExecutionCallback>());
181 }
182
183 // For the asyncronous execution, we are adding a pool of working memory handles (1 per thread) in the
184 // LoadedNetwork with a each scheduled inference having a spefic priority
185 for (IAsyncExecutionCallbackPtr cb : callbacks)
186 {
187 runtime->Schedule(networkId,
188 inputTensors,
189 outputTensors,
190 static_cast<QosExecPriority>(rand()%3),
191 cb);
192 }
193
194 // Wait until the execution signals a notify
195 for (IAsyncExecutionCallbackPtr cb : callbacks)
196 {
197 cb->Wait();
198
199 // Checks the results.
200 BOOST_CHECK(cb->GetStatus() == Status::Success);
201 }
202 }
203
Mike Kelly386ff1a2021-03-29 15:04:50 +0100204 for (auto&& it : expectedOutputData)
205 {
206 std::vector<TOutput> out = outputStorage.at(it.first);
Keith Davise813d672021-04-22 10:10:34 +0100207
Mike Kelly386ff1a2021-03-29 15:04:50 +0100208 for (unsigned int i = 0; i < out.size(); ++i)
209 {
210 BOOST_CHECK(Compare<ArmnnOType>(it.second[i], out[i], tolerance) == true);
211 }
212 }
213}
214
215template<typename armnn::DataType DataType>
216INetworkPtr CreateStridedSliceNetwork(const TensorShape& inputShape,
217 const TensorShape& outputShape,
218 const std::vector<int>& beginData,
219 const std::vector<int>& endData,
220 const std::vector<int>& stridesData,
221 int beginMask = 0,
222 int endMask = 0,
223 int shrinkAxisMask = 0,
224 int ellipsisMask = 0,
225 int newAxisMask = 0,
226 const float qScale = 1.0f,
227 const int32_t qOffset = 0)
228{
229 using namespace armnn;
230 // Builds up the structure of the network.
231 INetworkPtr net(INetwork::Create());
232
233 TensorInfo inputTensorInfo(inputShape, DataType, qScale, qOffset);
234 TensorInfo outputTensorInfo(outputShape, DataType, qScale, qOffset);
235
236 armnn::StridedSliceDescriptor stridedSliceDescriptor;
237 stridedSliceDescriptor.m_Begin = beginData;
238 stridedSliceDescriptor.m_End = endData;
239 stridedSliceDescriptor.m_Stride = stridesData;
240 stridedSliceDescriptor.m_BeginMask = beginMask;
241 stridedSliceDescriptor.m_EndMask = endMask;
242 stridedSliceDescriptor.m_ShrinkAxisMask = shrinkAxisMask;
243 stridedSliceDescriptor.m_EllipsisMask = ellipsisMask;
244 stridedSliceDescriptor.m_NewAxisMask = newAxisMask;
245
246 IConnectableLayer* input = net->AddInputLayer(0, "Input_Layer");
247 IConnectableLayer* stridedSlice = net->AddStridedSliceLayer(stridedSliceDescriptor, "splitter");
248 IConnectableLayer* output = net->AddOutputLayer(0);
249
250 Connect(input, stridedSlice, inputTensorInfo, 0, 0);
251 Connect(stridedSlice, output, outputTensorInfo, 0, 0);
252
253 return net;
254}
255
256template<armnn::DataType ArmnnType>
257void StridedSlicedEndToEndTest(const std::vector<BackendId>& backends)
258{
259 using namespace armnn;
260 using T = ResolveType<ArmnnType>;
261
262 const TensorShape& inputShape = {3, 2, 3, 1};
263 const TensorShape& outputShape = {1, 2, 3, 1};
264 const std::vector<int>& beginData = {1, 0, 0, 0};
265 const std::vector<int>& endData = {2, 2, 3, 1};
266 const std::vector<int>& stridesData = {1, 1, 1, 1};
267 int beginMask = 0;
268 int endMask = 0;
269 int shrinkAxisMask = 0;
270 int ellipsisMask = 0;
271 int newAxisMask = 0;
272
273 // Builds up the structure of the network
274 INetworkPtr net = CreateStridedSliceNetwork<ArmnnType>(inputShape,
275 outputShape,
276 beginData,
277 endData,
278 stridesData,
279 beginMask,
280 endMask,
281 shrinkAxisMask,
282 ellipsisMask,
283 newAxisMask);
284
285 BOOST_TEST_CHECKPOINT("create a network");
286
287 // Creates structures for input & output.
288 std::vector<T> inputData{
289 1.0f, 1.0f, 1.0f, 2.0f, 2.0f, 2.0f,
290
291 3.0f, 3.0f, 3.0f, 4.0f, 4.0f, 4.0f,
292
293 5.0f, 5.0f, 5.0f, 6.0f, 6.0f, 6.0f
294 };
295
296 std::vector<T> outputExpected{
297 3.0f, 3.0f, 3.0f, 4.0f, 4.0f, 4.0f
298 };
299
300 std::map<int, std::vector<T>> inputTensorData = {{0, inputData}};
301 std::map<int, std::vector<T>> expectedOutputData = {{0, outputExpected}};
302
Keith Davise813d672021-04-22 10:10:34 +0100303 AsyncEndToEndTestImpl<ArmnnType, ArmnnType>(move(net), inputTensorData, expectedOutputData, backends, 0.000001f);
304}
305
306template<armnn::DataType ArmnnType>
307void AsyncScheduledStridedSlicedEndToEndTest(const std::vector<BackendId>& backends)
308{
309 using namespace armnn;
310 using T = ResolveType<ArmnnType>;
311
312 const TensorShape& inputShape = {3, 2, 3, 1};
313 const TensorShape& outputShape = {1, 2, 3, 1};
314 const std::vector<int>& beginData = {1, 0, 0, 0};
315 const std::vector<int>& endData = {2, 2, 3, 1};
316 const std::vector<int>& stridesData = {1, 1, 1, 1};
317 int beginMask = 0;
318 int endMask = 0;
319 int shrinkAxisMask = 0;
320 int ellipsisMask = 0;
321 int newAxisMask = 0;
322
323 // Builds up the structure of the network
324 INetworkPtr net = CreateStridedSliceNetwork<ArmnnType>(inputShape,
325 outputShape,
326 beginData,
327 endData,
328 stridesData,
329 beginMask,
330 endMask,
331 shrinkAxisMask,
332 ellipsisMask,
333 newAxisMask);
334
335 // Creates structures for input & output.
336 std::vector<T> inputData{
337 1.0f, 1.0f, 1.0f, 2.0f, 2.0f, 2.0f,
338
339 3.0f, 3.0f, 3.0f, 4.0f, 4.0f, 4.0f,
340
341 5.0f, 5.0f, 5.0f, 6.0f, 6.0f, 6.0f
342 };
343
344 std::vector<T> outputExpected{
345 3.0f, 3.0f, 3.0f, 4.0f, 4.0f, 4.0f
346 };
347
348 std::map<int, std::vector<T>> inputTensorData = {{0, inputData}};
349 std::map<int, std::vector<T>> expectedOutputData = {{0, outputExpected}};
350
351 AsyncEndToEndTestImpl<ArmnnType, ArmnnType>(move(net), inputTensorData, expectedOutputData, backends, 0.000001f, 1);
352}
353
354template<armnn::DataType ArmnnType>
355void AsyncScheduledStridedSlicedMultiThreadedEndToEndTest(const std::vector<BackendId>& backends)
356{
357 using namespace armnn;
358 using T = ResolveType<ArmnnType>;
359
360 const TensorShape& inputShape = {3, 2, 3, 1};
361 const TensorShape& outputShape = {1, 2, 3, 1};
362 const std::vector<int>& beginData = {1, 0, 0, 0};
363 const std::vector<int>& endData = {2, 2, 3, 1};
364 const std::vector<int>& stridesData = {1, 1, 1, 1};
365 int beginMask = 0;
366 int endMask = 0;
367 int shrinkAxisMask = 0;
368 int ellipsisMask = 0;
369 int newAxisMask = 0;
370
371 // Builds up the structure of the network
372 INetworkPtr net = CreateStridedSliceNetwork<ArmnnType>(inputShape,
373 outputShape,
374 beginData,
375 endData,
376 stridesData,
377 beginMask,
378 endMask,
379 shrinkAxisMask,
380 ellipsisMask,
381 newAxisMask);
382
383 // Creates structures for input & output.
384 std::vector<T> inputData{
385 1.0f, 1.0f, 1.0f, 2.0f, 2.0f, 2.0f,
386
387 3.0f, 3.0f, 3.0f, 4.0f, 4.0f, 4.0f,
388
389 5.0f, 5.0f, 5.0f, 6.0f, 6.0f, 6.0f
390 };
391
392 std::vector<T> outputExpected{
393 3.0f, 3.0f, 3.0f, 4.0f, 4.0f, 4.0f
394 };
395
396 std::map<int, std::vector<T>> inputTensorData = {{0, inputData}};
397 std::map<int, std::vector<T>> expectedOutputData = {{0, outputExpected}};
398
399 AsyncEndToEndTestImpl<ArmnnType, ArmnnType>(move(net), inputTensorData, expectedOutputData, backends, 0.000001f, 3);
Finn Williamsb8181f72021-04-07 10:23:21 +0100400}
401
402template<armnn::DataType ArmnnType>
403void StridedSlicedMultiThreadedEndToEndTest(const std::vector<BackendId>& backends)
404{
405 using namespace armnn;
406 using T = ResolveType<ArmnnType>;
407
408 const TensorShape& inputShape = {3, 2, 3, 1};
409 const TensorShape& outputShape = {1, 2, 3, 1};
410 const std::vector<int>& beginData = {1, 0, 0, 0};
411 const std::vector<int>& endData = {2, 2, 3, 1};
412 const std::vector<int>& stridesData = {1, 1, 1, 1};
413 int beginMask = 0;
414 int endMask = 0;
415 int shrinkAxisMask = 0;
416 int ellipsisMask = 0;
417 int newAxisMask = 0;
418
419 // Builds up the structure of the network
420 INetworkPtr net = CreateStridedSliceNetwork<ArmnnType>(inputShape,
421 outputShape,
422 beginData,
423 endData,
424 stridesData,
425 beginMask,
426 endMask,
427 shrinkAxisMask,
428 ellipsisMask,
429 newAxisMask);
430
431 BOOST_TEST_CHECKPOINT("create a network");
432
433 // Creates structures for input & output.
434 std::vector<T> inputData1{
435 1.0f, 1.0f, 1.0f, 2.0f, 2.0f, 2.0f,
436
437 3.0f, 3.0f, 3.0f, 4.0f, 4.0f, 4.0f,
438
439 5.0f, 5.0f, 5.0f, 6.0f, 6.0f, 6.0f
440 };
441
442 std::vector<T> outputExpected1{ 3.0f, 3.0f, 3.0f, 4.0f, 4.0f, 4.0f };
443
444 // Creates structures for input & output.
445 std::vector<T> inputData2{
446 1.0f, 1.0f, 1.0f, 2.0f, 2.0f, 2.0f,
447
448 8.0f, 8.0f, 8.0f, 7.0f, 7.0f, 7.0f,
449
450 5.0f, 5.0f, 5.0f, 6.0f, 6.0f, 6.0f
451 };
452
453 std::vector<T> outputExpected2{ 8.0f, 8.0f, 8.0f, 7.0f, 7.0f, 7.0f };
454
455 std::vector<std::map<int, std::vector<T>>> inputTensors;
456 std::vector<std::map<int, std::vector<T>>> outputTensors;
457
458 inputTensors.push_back(std::map<int, std::vector<T>> {{0, inputData1}});
459 inputTensors.push_back(std::map<int, std::vector<T>> {{0, inputData2}});
460 outputTensors.push_back(std::map<int, std::vector<T>> {{0, outputExpected1}});
461 outputTensors.push_back(std::map<int, std::vector<T>> {{0, outputExpected2}});
462
463 AsyncThreadedEndToEndTestImpl<ArmnnType, ArmnnType>(move(net), inputTensors, outputTensors, backends, 2);
Mike Kelly386ff1a2021-03-29 15:04:50 +0100464}
465
466} // experimental namespace
467
468} // armnn namespace
469