blob: 764983f3b9ff60c16fd39e319248d121c88f3825 [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>
Finn Williamsf364d532021-06-09 17:07:33 +010012#include <armnn/Threadpool.hpp>
Keith Davise813d672021-04-22 10:10:34 +010013#include <armnn/IAsyncExecutionCallback.hpp>
Mike Kelly386ff1a2021-03-29 15:04:50 +010014
Keith Davise813d672021-04-22 10:10:34 +010015#include <AsyncExecutionCallback.hpp>
Mike Kelly386ff1a2021-03-29 15:04:50 +010016#include <backendsCommon/test/CommonTestUtils.hpp>
17
Sadik Armagan1625efc2021-06-10 18:24:34 +010018#include <doctest/doctest.h>
Mike Kelly386ff1a2021-03-29 15:04:50 +010019
20#include <vector>
21
22namespace armnn
23{
24
25namespace experimental
26{
27
28template<DataType ArmnnIType, DataType ArmnnOType,
29 typename TInput = ResolveType <ArmnnIType>, typename TOutput = ResolveType <ArmnnOType>>
Finn Williamsb8181f72021-04-07 10:23:21 +010030void AsyncThreadedEndToEndTestImpl(INetworkPtr network,
31 const std::vector<std::map<int, std::vector<TInput>>>& inputTensorData,
32 const std::vector<std::map<int, std::vector<TOutput>>>& expectedOutputData,
33 std::vector<BackendId> backends,
34 const size_t numberOfInferences,
35 float tolerance = 0.000001f)
36{
37 // Create Runtime in which test will run
38 IRuntime::CreationOptions options;
39 IRuntimePtr runtime(IRuntime::Create(options));
40
41 // Optimize the Network
42 IOptimizedNetworkPtr optNet = Optimize(*network, backends, runtime->GetDeviceSpec());
43
44
45 // Creates AsyncNetwork
46 NetworkId networkId = 0;
47 std::string errorMessage;
Francis Murtagh73d3e2e2021-04-29 14:23:04 +010048 const INetworkProperties networkProperties(true, MemorySource::Undefined, MemorySource::Undefined);
Finn Williamsb8181f72021-04-07 10:23:21 +010049 runtime->LoadNetwork(networkId, std::move(optNet), errorMessage, networkProperties);
50
51 std::vector<InputTensors> inputTensorsVec;
52 std::vector<OutputTensors> outputTensorsVec;
53 std::vector<std::map<int, std::vector<TOutput>>> outputStorageVec;
54 std::vector<std::unique_ptr<IWorkingMemHandle>> workingMemHandles;
55
56 for (unsigned int i = 0; i < numberOfInferences; ++i)
57 {
58 InputTensors inputTensors;
59 OutputTensors outputTensors;
60 outputStorageVec.emplace_back(std::map<int, std::vector<TOutput>>());
61
62 inputTensors.reserve(inputTensorData.size());
63 for (auto&& it : inputTensorData[i])
64 {
65 inputTensors.push_back({it.first,
66 ConstTensor(runtime->GetInputTensorInfo(networkId, it.first), it.second.data())});
67 }
68
69 outputTensors.reserve(expectedOutputData.size());
70 for (auto&& it : expectedOutputData[i])
71 {
72 std::vector<TOutput> out(it.second.size());
73 outputStorageVec[i].emplace(it.first, out);
74 outputTensors.push_back({it.first,
75 Tensor(runtime->GetOutputTensorInfo(networkId, it.first),
76 outputStorageVec[i].at(it.first).data())});
77 }
78
79 inputTensorsVec.push_back(inputTensors);
80 outputTensorsVec.push_back(outputTensors);
81
82 workingMemHandles.push_back(runtime->CreateWorkingMemHandle(networkId));
83 }
84
85 std::vector<std::thread> threads;
86 for (unsigned int i = 0; i < numberOfInferences; ++i)
87 {
88 // Access the vectors before we do anything multi-threaded
89 InputTensors& inputTensors = inputTensorsVec[i];
90 OutputTensors& outputTensors = outputTensorsVec[i];
91 IWorkingMemHandle& workingMemHandle = *workingMemHandles[i].get();
92
93 threads.emplace_back([&]()
94 {
95 // Run the async network
96 runtime->Execute(workingMemHandle, inputTensors, outputTensors);
97 });
98 }
99
100 for (unsigned int i = 0; i < numberOfInferences; ++i)
101 {
102 threads[i].join();
103 }
104
105 // Checks the results.
106 for (unsigned int i = 0; i < numberOfInferences; ++i)
107 {
108 for (auto &&it : expectedOutputData[i])
109 {
110 std::vector<TOutput> out = outputStorageVec[i].at(it.first);
111 for (unsigned int j = 0; j < out.size(); ++j)
112 {
Sadik Armagan1625efc2021-06-10 18:24:34 +0100113 CHECK(Compare<ArmnnOType>(it.second[j], out[j], tolerance) == true);
Finn Williamsb8181f72021-04-07 10:23:21 +0100114 }
115 }
116 }
117
118}
119
Finn Williamsb8181f72021-04-07 10:23:21 +0100120template<DataType ArmnnIType, DataType ArmnnOType,
Keith Davise813d672021-04-22 10:10:34 +0100121 typename TInput = ResolveType<ArmnnIType>, typename TOutput = ResolveType<ArmnnOType>>
Mike Kelly386ff1a2021-03-29 15:04:50 +0100122void AsyncEndToEndTestImpl(INetworkPtr network,
123 const std::map<int, std::vector<TInput>>& inputTensorData,
124 const std::map<int, std::vector<TOutput>>& expectedOutputData,
125 std::vector<BackendId> backends,
Keith Davise813d672021-04-22 10:10:34 +0100126 float tolerance = 0.000001f,
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100127 size_t numThreads = 1)
Mike Kelly386ff1a2021-03-29 15:04:50 +0100128{
129 // Create Runtime in which test will run
130 IRuntime::CreationOptions options;
Keith Davise813d672021-04-22 10:10:34 +0100131 IRuntimePtr runtime(IRuntime::Create(options));
Mike Kelly386ff1a2021-03-29 15:04:50 +0100132
133 // Optimize the Network
134 IOptimizedNetworkPtr optNet = Optimize(*network, backends, runtime->GetDeviceSpec());
135
136 // Creates AsyncNetwork
137 NetworkId networkId = 0;
Keith Davise813d672021-04-22 10:10:34 +0100138
Mike Kelly386ff1a2021-03-29 15:04:50 +0100139 std::string errorMessage;
Keith Davise813d672021-04-22 10:10:34 +0100140
Finn Williamsf364d532021-06-09 17:07:33 +0100141 const INetworkProperties networkProperties(true, MemorySource::Undefined, MemorySource::Undefined);
Keith Davise813d672021-04-22 10:10:34 +0100142
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100143 runtime->LoadNetwork(networkId, std::move(optNet), errorMessage, networkProperties);
Mike Kelly386ff1a2021-03-29 15:04:50 +0100144
145 InputTensors inputTensors;
146 inputTensors.reserve(inputTensorData.size());
147 for (auto&& it : inputTensorData)
148 {
149 inputTensors.push_back({it.first,
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100150 ConstTensor(runtime->GetInputTensorInfo(networkId, it.first), it.second.data())});
Mike Kelly386ff1a2021-03-29 15:04:50 +0100151 }
152
153 OutputTensors outputTensors;
154 outputTensors.reserve(expectedOutputData.size());
155 std::map<int, std::vector<TOutput>> outputStorage;
156 for (auto&& it : expectedOutputData)
157 {
158 std::vector<TOutput> out(it.second.size());
159 outputStorage.emplace(it.first, out);
160 outputTensors.push_back({it.first,
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100161 Tensor(runtime->GetOutputTensorInfo(networkId, it.first),
Mike Kelly386ff1a2021-03-29 15:04:50 +0100162 outputStorage.at(it.first).data())});
163 }
164
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100165 if (numThreads <= 1)
Keith Davise813d672021-04-22 10:10:34 +0100166 {
167 // Create WorkingMemHandle for this async network
168 std::unique_ptr<IWorkingMemHandle> workingMemHandle = runtime->CreateWorkingMemHandle(networkId);
169 IWorkingMemHandle& workingMemHandleRef = *workingMemHandle.get();
Mike Kelly386ff1a2021-03-29 15:04:50 +0100170
Keith Davise813d672021-04-22 10:10:34 +0100171 // Run the async network
172 runtime->Execute(workingMemHandleRef, inputTensors, outputTensors);
173 }
174 else
175 {
Finn Williamsf364d532021-06-09 17:07:33 +0100176 std::vector<std::shared_ptr<IWorkingMemHandle>> memHandles;
Mike Kelly386ff1a2021-03-29 15:04:50 +0100177
Finn Williamsf364d532021-06-09 17:07:33 +0100178 for (size_t i = 0; i < numThreads; ++i)
Keith Davise813d672021-04-22 10:10:34 +0100179 {
Finn Williamsf364d532021-06-09 17:07:33 +0100180 memHandles.emplace_back(runtime->CreateWorkingMemHandle(networkId));
Keith Davise813d672021-04-22 10:10:34 +0100181 }
182
Finn Williamsf364d532021-06-09 17:07:33 +0100183 Threadpool threadpool(numThreads, runtime.get(), memHandles);
184 AsyncCallbackManager callbackManager;
185
Keith Davise813d672021-04-22 10:10:34 +0100186 // For the asyncronous execution, we are adding a pool of working memory handles (1 per thread) in the
187 // LoadedNetwork with a each scheduled inference having a spefic priority
Finn Williamsf364d532021-06-09 17:07:33 +0100188 for (size_t i = 0; i < 1000; ++i)
Keith Davise813d672021-04-22 10:10:34 +0100189 {
Finn Williamsf364d532021-06-09 17:07:33 +0100190 threadpool.Schedule(networkId,
191 inputTensors,
192 outputTensors,
193 static_cast<QosExecPriority>(rand()%3),
194 callbackManager.GetNewCallback());
Keith Davise813d672021-04-22 10:10:34 +0100195 }
196
197 // Wait until the execution signals a notify
Finn Williamsf364d532021-06-09 17:07:33 +0100198 for (size_t i = 0; i < 1000; ++i)
Keith Davise813d672021-04-22 10:10:34 +0100199 {
Finn Williamsf364d532021-06-09 17:07:33 +0100200 auto cb = callbackManager.GetNotifiedCallback();
201
Keith Davise813d672021-04-22 10:10:34 +0100202 // Checks the results.
Sadik Armagan1625efc2021-06-10 18:24:34 +0100203 CHECK(cb->GetStatus() == Status::Success);
Keith Davise813d672021-04-22 10:10:34 +0100204 }
205 }
206
Mike Kelly386ff1a2021-03-29 15:04:50 +0100207 for (auto&& it : expectedOutputData)
208 {
209 std::vector<TOutput> out = outputStorage.at(it.first);
Keith Davise813d672021-04-22 10:10:34 +0100210
Mike Kelly386ff1a2021-03-29 15:04:50 +0100211 for (unsigned int i = 0; i < out.size(); ++i)
212 {
Sadik Armagan1625efc2021-06-10 18:24:34 +0100213 CHECK(Compare<ArmnnOType>(it.second[i], out[i], tolerance) == true);
Mike Kelly386ff1a2021-03-29 15:04:50 +0100214 }
215 }
216}
217
218template<typename armnn::DataType DataType>
219INetworkPtr CreateStridedSliceNetwork(const TensorShape& inputShape,
220 const TensorShape& outputShape,
221 const std::vector<int>& beginData,
222 const std::vector<int>& endData,
223 const std::vector<int>& stridesData,
224 int beginMask = 0,
225 int endMask = 0,
226 int shrinkAxisMask = 0,
227 int ellipsisMask = 0,
228 int newAxisMask = 0,
229 const float qScale = 1.0f,
230 const int32_t qOffset = 0)
231{
232 using namespace armnn;
233 // Builds up the structure of the network.
234 INetworkPtr net(INetwork::Create());
235
236 TensorInfo inputTensorInfo(inputShape, DataType, qScale, qOffset);
237 TensorInfo outputTensorInfo(outputShape, DataType, qScale, qOffset);
238
239 armnn::StridedSliceDescriptor stridedSliceDescriptor;
240 stridedSliceDescriptor.m_Begin = beginData;
241 stridedSliceDescriptor.m_End = endData;
242 stridedSliceDescriptor.m_Stride = stridesData;
243 stridedSliceDescriptor.m_BeginMask = beginMask;
244 stridedSliceDescriptor.m_EndMask = endMask;
245 stridedSliceDescriptor.m_ShrinkAxisMask = shrinkAxisMask;
246 stridedSliceDescriptor.m_EllipsisMask = ellipsisMask;
247 stridedSliceDescriptor.m_NewAxisMask = newAxisMask;
248
249 IConnectableLayer* input = net->AddInputLayer(0, "Input_Layer");
250 IConnectableLayer* stridedSlice = net->AddStridedSliceLayer(stridedSliceDescriptor, "splitter");
251 IConnectableLayer* output = net->AddOutputLayer(0);
252
253 Connect(input, stridedSlice, inputTensorInfo, 0, 0);
254 Connect(stridedSlice, output, outputTensorInfo, 0, 0);
255
256 return net;
257}
258
259template<armnn::DataType ArmnnType>
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100260void StridedSlicedEndToEndTest(const std::vector<BackendId>& backends, size_t numThreads)
Mike Kelly386ff1a2021-03-29 15:04:50 +0100261{
262 using namespace armnn;
263 using T = ResolveType<ArmnnType>;
264
265 const TensorShape& inputShape = {3, 2, 3, 1};
266 const TensorShape& outputShape = {1, 2, 3, 1};
267 const std::vector<int>& beginData = {1, 0, 0, 0};
268 const std::vector<int>& endData = {2, 2, 3, 1};
269 const std::vector<int>& stridesData = {1, 1, 1, 1};
270 int beginMask = 0;
271 int endMask = 0;
272 int shrinkAxisMask = 0;
273 int ellipsisMask = 0;
274 int newAxisMask = 0;
275
276 // Builds up the structure of the network
277 INetworkPtr net = CreateStridedSliceNetwork<ArmnnType>(inputShape,
278 outputShape,
279 beginData,
280 endData,
281 stridesData,
282 beginMask,
283 endMask,
284 shrinkAxisMask,
285 ellipsisMask,
286 newAxisMask);
287
Sadik Armagan1625efc2021-06-10 18:24:34 +0100288 CHECK(net);
Mike Kelly386ff1a2021-03-29 15:04:50 +0100289 // Creates structures for input & output.
290 std::vector<T> inputData{
291 1.0f, 1.0f, 1.0f, 2.0f, 2.0f, 2.0f,
292
293 3.0f, 3.0f, 3.0f, 4.0f, 4.0f, 4.0f,
294
295 5.0f, 5.0f, 5.0f, 6.0f, 6.0f, 6.0f
296 };
297
298 std::vector<T> outputExpected{
299 3.0f, 3.0f, 3.0f, 4.0f, 4.0f, 4.0f
300 };
301
302 std::map<int, std::vector<T>> inputTensorData = {{0, inputData}};
303 std::map<int, std::vector<T>> expectedOutputData = {{0, outputExpected}};
304
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100305 AsyncEndToEndTestImpl<ArmnnType, ArmnnType>(move(net),
306 inputTensorData,
307 expectedOutputData,
308 backends,
309 0.000001f,
310 numThreads);
Finn Williamsb8181f72021-04-07 10:23:21 +0100311}
312
313template<armnn::DataType ArmnnType>
314void StridedSlicedMultiThreadedEndToEndTest(const std::vector<BackendId>& backends)
315{
316 using namespace armnn;
317 using T = ResolveType<ArmnnType>;
318
319 const TensorShape& inputShape = {3, 2, 3, 1};
320 const TensorShape& outputShape = {1, 2, 3, 1};
321 const std::vector<int>& beginData = {1, 0, 0, 0};
322 const std::vector<int>& endData = {2, 2, 3, 1};
323 const std::vector<int>& stridesData = {1, 1, 1, 1};
324 int beginMask = 0;
325 int endMask = 0;
326 int shrinkAxisMask = 0;
327 int ellipsisMask = 0;
328 int newAxisMask = 0;
329
330 // Builds up the structure of the network
331 INetworkPtr net = CreateStridedSliceNetwork<ArmnnType>(inputShape,
332 outputShape,
333 beginData,
334 endData,
335 stridesData,
336 beginMask,
337 endMask,
338 shrinkAxisMask,
339 ellipsisMask,
340 newAxisMask);
341
Sadik Armagan1625efc2021-06-10 18:24:34 +0100342 CHECK(net);
Finn Williamsb8181f72021-04-07 10:23:21 +0100343
344 // Creates structures for input & output.
345 std::vector<T> inputData1{
346 1.0f, 1.0f, 1.0f, 2.0f, 2.0f, 2.0f,
347
348 3.0f, 3.0f, 3.0f, 4.0f, 4.0f, 4.0f,
349
350 5.0f, 5.0f, 5.0f, 6.0f, 6.0f, 6.0f
351 };
352
353 std::vector<T> outputExpected1{ 3.0f, 3.0f, 3.0f, 4.0f, 4.0f, 4.0f };
354
355 // Creates structures for input & output.
356 std::vector<T> inputData2{
357 1.0f, 1.0f, 1.0f, 2.0f, 2.0f, 2.0f,
358
359 8.0f, 8.0f, 8.0f, 7.0f, 7.0f, 7.0f,
360
361 5.0f, 5.0f, 5.0f, 6.0f, 6.0f, 6.0f
362 };
363
364 std::vector<T> outputExpected2{ 8.0f, 8.0f, 8.0f, 7.0f, 7.0f, 7.0f };
365
366 std::vector<std::map<int, std::vector<T>>> inputTensors;
367 std::vector<std::map<int, std::vector<T>>> outputTensors;
368
369 inputTensors.push_back(std::map<int, std::vector<T>> {{0, inputData1}});
370 inputTensors.push_back(std::map<int, std::vector<T>> {{0, inputData2}});
371 outputTensors.push_back(std::map<int, std::vector<T>> {{0, outputExpected1}});
372 outputTensors.push_back(std::map<int, std::vector<T>> {{0, outputExpected2}});
373
374 AsyncThreadedEndToEndTestImpl<ArmnnType, ArmnnType>(move(net), inputTensors, outputTensors, backends, 2);
Mike Kelly386ff1a2021-03-29 15:04:50 +0100375}
376
377} // experimental namespace
378
379} // armnn namespace
380