blob: 48577c9990f2dd8ca4200641b54e7ce4e3617600 [file] [log] [blame]
Laurent Carlier749294b2020-06-01 09:03:17 +01001//
Sadik Armagana9c2ce12020-07-14 10:02:22 +01002// Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
David Beckecb56cd2018-09-05 12:52:57 +01003// SPDX-License-Identifier: MIT
telsoa014fcda012018-03-09 14:13:49 +00004//
telsoa01c577f2c2018-08-31 09:22:23 +01005
Jan Eilers45274902020-10-15 18:34:43 +01006#include "NetworkExecutionUtils/NetworkExecutionUtils.hpp"
7#include "ExecuteNetworkProgramOptions.hpp"
Kevin Mayb4b3ac92021-05-21 16:42:21 +01008#include <armnn/IAsyncExecutionCallback.hpp>
9#include <AsyncExecutionCallback.hpp>
Jan Eilers45274902020-10-15 18:34:43 +010010
11#include <armnn/Logging.hpp>
12#include <Filesystem.hpp>
13#include <InferenceTest.hpp>
14
15#if defined(ARMNN_SERIALIZER)
16#include "armnnDeserializer/IDeserializer.hpp"
17#endif
Jan Eilers45274902020-10-15 18:34:43 +010018#if defined(ARMNN_TF_LITE_PARSER)
19#include "armnnTfLiteParser/ITfLiteParser.hpp"
20#endif
21#if defined(ARMNN_ONNX_PARSER)
22#include "armnnOnnxParser/IOnnxParser.hpp"
23#endif
Sadik Armagan5d03e312020-11-17 16:43:56 +000024#if defined(ARMNN_TFLITE_DELEGATE)
25#include <armnn_delegate.hpp>
26#include <DelegateOptions.hpp>
27
28#include <tensorflow/lite/builtin_ops.h>
29#include <tensorflow/lite/c/builtin_op_data.h>
30#include <tensorflow/lite/c/common.h>
31#include <tensorflow/lite/optional_debug_tools.h>
32#include <tensorflow/lite/kernels/builtin_op_kernels.h>
33#include <tensorflow/lite/interpreter.h>
34#include <tensorflow/lite/kernels/register.h>
35#endif
Jan Eilers45274902020-10-15 18:34:43 +010036
37#include <future>
Sadik Armagan5d03e312020-11-17 16:43:56 +000038#if defined(ARMNN_TFLITE_DELEGATE)
39int TfLiteDelegateMainImpl(const ExecuteNetworkParams& params,
40 const std::shared_ptr<armnn::IRuntime>& runtime = nullptr)
41{
42 using namespace tflite;
Jan Eilers45274902020-10-15 18:34:43 +010043
Sadik Armagan5d03e312020-11-17 16:43:56 +000044 std::unique_ptr<tflite::FlatBufferModel> model = tflite::FlatBufferModel::BuildFromFile(params.m_ModelPath.c_str());
45
46 auto tfLiteInterpreter = std::make_unique<Interpreter>();
47 tflite::ops::builtin::BuiltinOpResolver resolver;
48
49 tflite::InterpreterBuilder builder(*model, resolver);
50 builder(&tfLiteInterpreter);
51 tfLiteInterpreter->AllocateTensors();
52
Finn Williamsf806c4d2021-02-22 15:13:12 +000053 int status = 0;
54 if (params.m_TfLiteExecutor == ExecuteNetworkParams::TfLiteExecutor::ArmNNTfLiteDelegate)
Sadik Armagan19a1c032021-01-20 12:17:00 +000055 {
Finn Williamsf806c4d2021-02-22 15:13:12 +000056 // Create the Armnn Delegate
57 armnnDelegate::DelegateOptions delegateOptions(params.m_ComputeDevices);
58 std::unique_ptr<TfLiteDelegate, decltype(&armnnDelegate::TfLiteArmnnDelegateDelete)>
59 theArmnnDelegate(armnnDelegate::TfLiteArmnnDelegateCreate(delegateOptions),
60 armnnDelegate::TfLiteArmnnDelegateDelete);
61 // Register armnn_delegate to TfLiteInterpreter
62 status = tfLiteInterpreter->ModifyGraphWithDelegate(std::move(theArmnnDelegate));
63 if (status == kTfLiteError)
64 {
65 ARMNN_LOG(fatal) << "Could not register ArmNN TfLite Delegate to TfLiteInterpreter!";
66 return EXIT_FAILURE;
67 }
Sadik Armagan19a1c032021-01-20 12:17:00 +000068 }
Finn Williamsf806c4d2021-02-22 15:13:12 +000069 else
70 {
71 std::cout << "Running on TfLite without ArmNN delegate\n";
72 }
73
Sadik Armagan5d03e312020-11-17 16:43:56 +000074
75 std::vector<std::string> inputBindings;
76 for (const std::string& inputName: params.m_InputNames)
77 {
78 inputBindings.push_back(inputName);
79 }
80
81 armnn::Optional<std::string> dataFile = params.m_GenerateTensorData
82 ? armnn::EmptyOptional()
83 : armnn::MakeOptional<std::string>(params.m_InputTensorDataFilePaths[0]);
84
85 const size_t numInputs = inputBindings.size();
86
87 for(unsigned int inputIndex = 0; inputIndex < numInputs; ++inputIndex)
88 {
89 int input = tfLiteInterpreter->inputs()[inputIndex];
Sadik Armagan15f7fae2020-11-18 09:37:03 +000090 TfLiteIntArray* inputDims = tfLiteInterpreter->tensor(input)->dims;
91
92 long inputSize = 1;
93 for (unsigned int dim = 0; dim < static_cast<unsigned int>(inputDims->size); ++dim)
94 {
95 inputSize *= inputDims->data[dim];
96 }
97
Sadik Armagan5d03e312020-11-17 16:43:56 +000098 if (params.m_InputTypes[inputIndex].compare("float") == 0)
99 {
100 auto inputData = tfLiteInterpreter->typed_tensor<float>(input);
Finn Williamsbbbefec2020-11-25 14:32:42 +0000101
Matthew Sloyanf00f6c22020-12-07 13:33:24 +0000102 if(inputData == NULL)
Finn Williamsbbbefec2020-11-25 14:32:42 +0000103 {
104 ARMNN_LOG(fatal) << "Input tensor is null, input type: "
105 "\"" << params.m_InputTypes[inputIndex] << "\" may be incorrect.";
106 return EXIT_FAILURE;
107 }
108
Finn Williams56870182020-11-20 13:57:53 +0000109 std::vector<float> tensorData;
110 PopulateTensorWithDataGeneric<float>(tensorData,
111 params.m_InputTensorShapes[inputIndex]->GetNumElements(),
112 dataFile,
113 [](const std::string& s)
114 { return std::stof(s); });
Sadik Armagan15f7fae2020-11-18 09:37:03 +0000115
Finn Williams56870182020-11-20 13:57:53 +0000116 std::copy(tensorData.begin(), tensorData.end(), inputData);
117 }
Finn Williamsf806c4d2021-02-22 15:13:12 +0000118 else if (params.m_InputTypes[inputIndex].compare("qsymms8") == 0)
Finn Williams56870182020-11-20 13:57:53 +0000119 {
120 auto inputData = tfLiteInterpreter->typed_tensor<int8_t>(input);
Finn Williamsbbbefec2020-11-25 14:32:42 +0000121
Matthew Sloyanf00f6c22020-12-07 13:33:24 +0000122 if(inputData == NULL)
Finn Williamsbbbefec2020-11-25 14:32:42 +0000123 {
124 ARMNN_LOG(fatal) << "Input tensor is null, input type: "
125 "\"" << params.m_InputTypes[inputIndex] << "\" may be incorrect.";
126 return EXIT_FAILURE;
127 }
128
Finn Williams56870182020-11-20 13:57:53 +0000129 std::vector<int8_t> tensorData;
130 PopulateTensorWithDataGeneric<int8_t>(tensorData,
131 params.m_InputTensorShapes[inputIndex]->GetNumElements(),
132 dataFile,
133 [](const std::string& s)
134 { return armnn::numeric_cast<int8_t>(std::stoi(s)); });
135
136 std::copy(tensorData.begin(), tensorData.end(), inputData);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000137 }
138 else if (params.m_InputTypes[inputIndex].compare("int") == 0)
139 {
140 auto inputData = tfLiteInterpreter->typed_tensor<int32_t>(input);
Finn Williamsbbbefec2020-11-25 14:32:42 +0000141
Matthew Sloyanf00f6c22020-12-07 13:33:24 +0000142 if(inputData == NULL)
Finn Williamsbbbefec2020-11-25 14:32:42 +0000143 {
144 ARMNN_LOG(fatal) << "Input tensor is null, input type: "
145 "\"" << params.m_InputTypes[inputIndex] << "\" may be incorrect.";
146 return EXIT_FAILURE;
147 }
148
Finn Williams56870182020-11-20 13:57:53 +0000149 std::vector<int32_t> tensorData;
150 PopulateTensorWithDataGeneric<int32_t>(tensorData,
151 params.m_InputTensorShapes[inputIndex]->GetNumElements(),
152 dataFile,
153 [](const std::string& s)
154 { return std::stoi(s); });
155
156 std::copy(tensorData.begin(), tensorData.end(), inputData);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000157 }
158 else if (params.m_InputTypes[inputIndex].compare("qasymm8") == 0)
159 {
160 auto inputData = tfLiteInterpreter->typed_tensor<uint8_t>(input);
Finn Williamsbbbefec2020-11-25 14:32:42 +0000161
Matthew Sloyanf00f6c22020-12-07 13:33:24 +0000162 if(inputData == NULL)
Finn Williamsbbbefec2020-11-25 14:32:42 +0000163 {
164 ARMNN_LOG(fatal) << "Input tensor is null, input type: "
165 "\"" << params.m_InputTypes[inputIndex] << "\" may be incorrect.";
166 return EXIT_FAILURE;
167 }
168
Finn Williams56870182020-11-20 13:57:53 +0000169 std::vector<uint8_t> tensorData;
170 PopulateTensorWithDataGeneric<uint8_t>(tensorData,
171 params.m_InputTensorShapes[inputIndex]->GetNumElements(),
172 dataFile,
173 [](const std::string& s)
174 { return armnn::numeric_cast<uint8_t>(std::stoi(s)); });
175
176 std::copy(tensorData.begin(), tensorData.end(), inputData);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000177 }
178 else
179 {
180 ARMNN_LOG(fatal) << "Unsupported input tensor data type \"" << params.m_InputTypes[inputIndex] << "\". ";
181 return EXIT_FAILURE;
182 }
183 }
184
185 for (size_t x = 0; x < params.m_Iterations; x++)
186 {
187 // Run the inference
Finn Williamsf806c4d2021-02-22 15:13:12 +0000188 status = tfLiteInterpreter->Invoke();
Sadik Armagan5d03e312020-11-17 16:43:56 +0000189
190 // Print out the output
191 for (unsigned int outputIndex = 0; outputIndex < params.m_OutputNames.size(); ++outputIndex)
192 {
Sadik Armagan5d03e312020-11-17 16:43:56 +0000193 auto tfLiteDelegateOutputId = tfLiteInterpreter->outputs()[outputIndex];
Sadik Armagan15f7fae2020-11-18 09:37:03 +0000194 TfLiteIntArray* outputDims = tfLiteInterpreter->tensor(tfLiteDelegateOutputId)->dims;
Sadik Armagan5d03e312020-11-17 16:43:56 +0000195
Sadik Armagan15f7fae2020-11-18 09:37:03 +0000196 long outputSize = 1;
Sadik Armagan5d03e312020-11-17 16:43:56 +0000197 for (unsigned int dim = 0; dim < static_cast<unsigned int>(outputDims->size); ++dim)
198 {
Sadik Armagan15f7fae2020-11-18 09:37:03 +0000199 outputSize *= outputDims->data[dim];
Sadik Armagan5d03e312020-11-17 16:43:56 +0000200 }
201
202 std::cout << params.m_OutputNames[outputIndex] << ": ";
203 if (params.m_OutputTypes[outputIndex].compare("float") == 0)
204 {
205 auto tfLiteDelageOutputData = tfLiteInterpreter->typed_tensor<float>(tfLiteDelegateOutputId);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000206 if(tfLiteDelageOutputData == NULL)
207 {
208 ARMNN_LOG(fatal) << "Output tensor is null, output type: "
209 "\"" << params.m_OutputTypes[outputIndex] << "\" may be incorrect.";
210 return EXIT_FAILURE;
211 }
212
213 for (int i = 0; i < outputSize; ++i)
214 {
Finn Williamsf806c4d2021-02-22 15:13:12 +0000215 printf("%f ", tfLiteDelageOutputData[i]);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000216 }
217 }
218 else if (params.m_OutputTypes[outputIndex].compare("int") == 0)
219 {
220 auto tfLiteDelageOutputData = tfLiteInterpreter->typed_tensor<int32_t>(tfLiteDelegateOutputId);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000221 if(tfLiteDelageOutputData == NULL)
222 {
223 ARMNN_LOG(fatal) << "Output tensor is null, output type: "
224 "\"" << params.m_OutputTypes[outputIndex] << "\" may be incorrect.";
225 return EXIT_FAILURE;
226 }
227
228 for (int i = 0; i < outputSize; ++i)
229 {
Finn Williamsf806c4d2021-02-22 15:13:12 +0000230 printf("%d ", tfLiteDelageOutputData[i]);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000231 }
232 }
Finn Williamsf806c4d2021-02-22 15:13:12 +0000233 else if (params.m_OutputTypes[outputIndex].compare("qsymms8") == 0)
Finn Williams56870182020-11-20 13:57:53 +0000234 {
235 auto tfLiteDelageOutputData = tfLiteInterpreter->typed_tensor<int8_t>(tfLiteDelegateOutputId);
236 if(tfLiteDelageOutputData == NULL)
237 {
238 ARMNN_LOG(fatal) << "Output tensor is null, output type: "
239 "\"" << params.m_OutputTypes[outputIndex] << "\" may be incorrect.";
240 return EXIT_FAILURE;
241 }
242
243 for (int i = 0; i < outputSize; ++i)
244 {
Finn Williamsf806c4d2021-02-22 15:13:12 +0000245 printf("%d ", tfLiteDelageOutputData[i]);
Finn Williams56870182020-11-20 13:57:53 +0000246 }
247 }
Sadik Armagan5d03e312020-11-17 16:43:56 +0000248 else if (params.m_OutputTypes[outputIndex].compare("qasymm8") == 0)
249 {
250 auto tfLiteDelageOutputData = tfLiteInterpreter->typed_tensor<uint8_t>(tfLiteDelegateOutputId);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000251 if(tfLiteDelageOutputData == NULL)
252 {
253 ARMNN_LOG(fatal) << "Output tensor is null, output type: "
254 "\"" << params.m_OutputTypes[outputIndex] << "\" may be incorrect.";
255 return EXIT_FAILURE;
256 }
257
258 for (int i = 0; i < outputSize; ++i)
259 {
Finn Williamsf806c4d2021-02-22 15:13:12 +0000260 printf("%u ", tfLiteDelageOutputData[i]);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000261 }
262 }
263 else
264 {
265 ARMNN_LOG(fatal) << "Output tensor is null, output type: "
266 "\"" << params.m_OutputTypes[outputIndex] <<
267 "\" may be incorrect. Output type can be specified with -z argument";
268 return EXIT_FAILURE;
269 }
270 std::cout << std::endl;
271 }
272 }
273
274 return status;
275}
276#endif
Jan Eilers45274902020-10-15 18:34:43 +0100277template<typename TParser, typename TDataType>
278int MainImpl(const ExecuteNetworkParams& params,
279 const std::shared_ptr<armnn::IRuntime>& runtime = nullptr)
280{
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100281 using namespace std::chrono;
Jan Eilers45274902020-10-15 18:34:43 +0100282
Sadik Armagana04a9d72021-04-27 10:02:10 +0100283 std::vector<std::vector<TContainer>> inputs;
284 std::vector<std::vector<TContainer>> outputs;
Jan Eilers45274902020-10-15 18:34:43 +0100285
286 try
287 {
288 // Creates an InferenceModel, which will parse the model and load it into an IRuntime.
289 typename InferenceModel<TParser, TDataType>::Params inferenceModelParams;
290 inferenceModelParams.m_ModelPath = params.m_ModelPath;
291 inferenceModelParams.m_IsModelBinary = params.m_IsModelBinary;
292 inferenceModelParams.m_ComputeDevices = params.m_ComputeDevices;
293 inferenceModelParams.m_DynamicBackendsPath = params.m_DynamicBackendsPath;
294 inferenceModelParams.m_PrintIntermediateLayers = params.m_PrintIntermediate;
295 inferenceModelParams.m_VisualizePostOptimizationModel = params.m_EnableLayerDetails;
296 inferenceModelParams.m_ParseUnsupported = params.m_ParseUnsupported;
297 inferenceModelParams.m_InferOutputShape = params.m_InferOutputShape;
298 inferenceModelParams.m_EnableFastMath = params.m_EnableFastMath;
Matthew Sloyan42432112021-01-08 10:30:51 +0000299 inferenceModelParams.m_SaveCachedNetwork = params.m_SaveCachedNetwork;
300 inferenceModelParams.m_CachedNetworkFilePath = params.m_CachedNetworkFilePath;
Matthew Sloyan0a7dc6b2021-02-10 16:50:53 +0000301 inferenceModelParams.m_NumberOfThreads = params.m_NumberOfThreads;
Finn Williams40646322021-02-11 16:16:42 +0000302 inferenceModelParams.m_MLGOTuningFilePath = params.m_MLGOTuningFilePath;
Sadik Armagana04a9d72021-04-27 10:02:10 +0100303 inferenceModelParams.m_AsyncEnabled = params.m_Concurrent;
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100304 inferenceModelParams.m_ThreadPoolSize = params.m_ThreadPoolSize;
Jan Eilers45274902020-10-15 18:34:43 +0100305
306 for(const std::string& inputName: params.m_InputNames)
307 {
308 inferenceModelParams.m_InputBindings.push_back(inputName);
309 }
310
311 for(unsigned int i = 0; i < params.m_InputTensorShapes.size(); ++i)
312 {
313 inferenceModelParams.m_InputShapes.push_back(*params.m_InputTensorShapes[i]);
314 }
315
316 for(const std::string& outputName: params.m_OutputNames)
317 {
318 inferenceModelParams.m_OutputBindings.push_back(outputName);
319 }
320
321 inferenceModelParams.m_SubgraphId = params.m_SubgraphId;
322 inferenceModelParams.m_EnableFp16TurboMode = params.m_EnableFp16TurboMode;
323 inferenceModelParams.m_EnableBf16TurboMode = params.m_EnableBf16TurboMode;
324
325 InferenceModel<TParser, TDataType> model(inferenceModelParams,
326 params.m_EnableProfiling,
327 params.m_DynamicBackendsPath,
328 runtime);
329
330 const size_t numInputs = inferenceModelParams.m_InputBindings.size();
Sadik Armagana04a9d72021-04-27 10:02:10 +0100331
332 armnn::Optional<QuantizationParams> qParams = params.m_QuantizeInput ?
333 armnn::MakeOptional<QuantizationParams>(
334 model.GetInputQuantizationParams()) :
335 armnn::EmptyOptional();
336
337 for(unsigned int j = 0; j < params.m_SimultaneousIterations ; ++j)
Jan Eilers45274902020-10-15 18:34:43 +0100338 {
Sadik Armagana04a9d72021-04-27 10:02:10 +0100339 std::vector<TContainer> inputDataContainers;
340 for(unsigned int i = 0; i < numInputs; ++i)
Jan Eilers45274902020-10-15 18:34:43 +0100341 {
Sadik Armagana04a9d72021-04-27 10:02:10 +0100342 armnn::Optional<std::string> dataFile = params.m_GenerateTensorData ?
343 armnn::EmptyOptional() :
344 armnn::MakeOptional<std::string>(
345 params.m_InputTensorDataFilePaths[(j * numInputs) + i]);
346
347 unsigned int numElements = model.GetInputSize(i);
348 if (params.m_InputTensorShapes.size() > i && params.m_InputTensorShapes[i])
349 {
350 // If the user has provided a tensor shape for the current input,
351 // override numElements
352 numElements = params.m_InputTensorShapes[i]->GetNumElements();
353 }
354
355 TContainer tensorData;
356 PopulateTensorWithData(tensorData,
357 numElements,
358 params.m_InputTypes[i],
359 qParams,
360 dataFile);
361
362 inputDataContainers.push_back(tensorData);
Jan Eilers45274902020-10-15 18:34:43 +0100363 }
Sadik Armagana04a9d72021-04-27 10:02:10 +0100364 inputs.push_back(inputDataContainers);
Jan Eilers45274902020-10-15 18:34:43 +0100365 }
366
367 const size_t numOutputs = inferenceModelParams.m_OutputBindings.size();
Jan Eilers45274902020-10-15 18:34:43 +0100368
Sadik Armagana04a9d72021-04-27 10:02:10 +0100369 for (unsigned int j = 0; j < params.m_SimultaneousIterations; ++j)
Jan Eilers45274902020-10-15 18:34:43 +0100370 {
Sadik Armagana04a9d72021-04-27 10:02:10 +0100371 std::vector <TContainer> outputDataContainers;
372 for (unsigned int i = 0; i < numOutputs; ++i)
Jan Eilers45274902020-10-15 18:34:43 +0100373 {
Sadik Armagana04a9d72021-04-27 10:02:10 +0100374 if (params.m_OutputTypes[i].compare("float") == 0)
Jan Eilers45274902020-10-15 18:34:43 +0100375 {
Sadik Armagana04a9d72021-04-27 10:02:10 +0100376 outputDataContainers.push_back(std::vector<float>(model.GetOutputSize(i)));
377 } else if (params.m_OutputTypes[i].compare("int") == 0)
378 {
379 outputDataContainers.push_back(std::vector<int>(model.GetOutputSize(i)));
380 } else if (params.m_OutputTypes[i].compare("qasymm8") == 0)
381 {
382 outputDataContainers.push_back(std::vector<uint8_t>(model.GetOutputSize(i)));
383 } else if (params.m_OutputTypes[i].compare("qsymms8") == 0)
384 {
385 outputDataContainers.push_back(std::vector<int8_t>(model.GetOutputSize(i)));
386 } else
387 {
388 ARMNN_LOG(fatal) << "Unsupported tensor data type \"" << params.m_OutputTypes[i] << "\". ";
389 return EXIT_FAILURE;
Jan Eilers45274902020-10-15 18:34:43 +0100390 }
391 }
Sadik Armagana04a9d72021-04-27 10:02:10 +0100392 outputs.push_back(outputDataContainers);
393 }
394
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100395 // Synchronous execution
Sadik Armagana04a9d72021-04-27 10:02:10 +0100396 if (!params.m_Concurrent)
397 {
Sadik Armagana04a9d72021-04-27 10:02:10 +0100398 for (size_t x = 0; x < params.m_Iterations; x++)
399 {
400 // model.Run returns the inference time elapsed in EnqueueWorkload (in milliseconds)
401 auto inference_duration = model.Run(inputs[0], outputs[0]);
402
403 if (params.m_GenerateTensorData)
404 {
405 ARMNN_LOG(warning) << "The input data was generated, note that the output will not be useful";
406 }
407
408 // Print output tensors
409 const auto& infosOut = model.GetOutputBindingInfos();
410 for (size_t i = 0; i < numOutputs; i++)
411 {
412 const armnn::TensorInfo& infoOut = infosOut[i].second;
413 auto outputTensorFile = params.m_OutputTensorFiles.empty() ? "" : params.m_OutputTensorFiles[i];
414
415 TensorPrinter printer(inferenceModelParams.m_OutputBindings[i],
416 infoOut,
417 outputTensorFile,
418 params.m_DequantizeOutput);
419 mapbox::util::apply_visitor(printer, outputs[0][i]);
420 }
421
422 ARMNN_LOG(info) << "\nInference time: " << std::setprecision(2)
423 << std::fixed << inference_duration.count() << " ms\n";
424
425 // If thresholdTime == 0.0 (default), then it hasn't been supplied at command line
426 if (params.m_ThresholdTime != 0.0)
427 {
428 ARMNN_LOG(info) << "Threshold time: " << std::setprecision(2)
429 << std::fixed << params.m_ThresholdTime << " ms";
430 auto thresholdMinusInference = params.m_ThresholdTime - inference_duration.count();
431 ARMNN_LOG(info) << "Threshold time - Inference time: " << std::setprecision(2)
432 << std::fixed << thresholdMinusInference << " ms" << "\n";
433
434 if (thresholdMinusInference < 0)
435 {
436 std::string errorMessage = "Elapsed inference time is greater than provided threshold time.";
437 ARMNN_LOG(fatal) << errorMessage;
438 }
439 }
440 }
441 }
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100442 // Asynchronous execution using the Arm NN thread pool
Kevin May94dd4db2021-05-26 16:01:08 +0100443 else if (params.m_ThreadPoolSize >= 1)
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100444 {
445 try
446 {
447 ARMNN_LOG(info) << "Asynchronous execution with Arm NN thread pool... \n";
Finn Williamsf364d532021-06-09 17:07:33 +0100448 armnn::AsyncCallbackManager callbackManager;
449 std::unordered_map<armnn::InferenceId, std::vector<TContainer>&> inferenceOutputMap;
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100450
451 // Declare the latest and earliest inference times here to be used when calculating overall time
452 std::chrono::high_resolution_clock::time_point earliestStartTime;
453 std::chrono::high_resolution_clock::time_point latestEndTime =
454 std::chrono::high_resolution_clock::now();
455
456 // For the asynchronous execution, we are adding a pool of working memory handles (1 per thread) in the
457 // LoadedNetwork with each scheduled inference having a specific priority
Finn Williamsf364d532021-06-09 17:07:33 +0100458 for (size_t i = 0; i < params.m_SimultaneousIterations; ++i)
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100459 {
Finn Williamsf364d532021-06-09 17:07:33 +0100460 std::shared_ptr<armnn::AsyncExecutionCallback> cb = callbackManager.GetNewCallback();
461 inferenceOutputMap.insert({cb->GetInferenceId(), outputs[i]});
462 model.RunAsync(inputs[i], outputs[i], cb);
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100463 }
464
465 // Check the results
466 unsigned int j = 0;
Finn Williamsf364d532021-06-09 17:07:33 +0100467 for (size_t iteration = 0; iteration < params.m_SimultaneousIterations; ++iteration)
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100468 {
Finn Williamsf364d532021-06-09 17:07:33 +0100469 auto cb = callbackManager.GetNotifiedCallback();
470
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100471 // Get the results
472 auto endTime = time_point_cast<std::chrono::milliseconds>(cb->GetEndTime());
473 auto startTime = time_point_cast<std::chrono::milliseconds>(cb->GetStartTime());
474 auto inferenceDuration = endTime - startTime;
475
476 if (latestEndTime < cb->GetEndTime())
477 {
478 latestEndTime = cb->GetEndTime();
479 }
480
481 if (earliestStartTime.time_since_epoch().count() == 0)
482 {
483 earliestStartTime = cb->GetStartTime();
484 }
485 else if (earliestStartTime > cb->GetStartTime())
486 {
487 earliestStartTime = cb->GetStartTime();
488 }
489
490 if (params.m_GenerateTensorData)
491 {
492 ARMNN_LOG(warning) << "The input data was generated, note that the output will not be useful";
493 }
494
495 // Print output tensors
496 const auto& infosOut = model.GetOutputBindingInfos();
497 for (size_t i = 0; i < numOutputs; i++)
498 {
499 const armnn::TensorInfo& infoOut = infosOut[i].second;
500 auto outputTensorFile = params.m_OutputTensorFiles.empty()
501 ? ""
502 : params.m_OutputTensorFiles[(j * numOutputs) + i];
503
504 TensorPrinter printer(inferenceModelParams.m_OutputBindings[i],
505 infoOut,
506 outputTensorFile,
507 params.m_DequantizeOutput);
Finn Williamsf364d532021-06-09 17:07:33 +0100508 mapbox::util::apply_visitor(printer, inferenceOutputMap.at(cb->GetInferenceId())[i]);
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100509 }
510
511 ARMNN_LOG(info) << "\nInference time: " << std::setprecision(2)
512 << std::fixed << inferenceDuration.count() << " ms\n";
513
514 // If thresholdTime == 0.0 (default), then it hasn't been supplied at command line
515 if (params.m_ThresholdTime != 0.0)
516 {
517 ARMNN_LOG(info) << "Threshold time: " << std::setprecision(2)
518 << std::fixed << params.m_ThresholdTime << " ms";
519 auto thresholdMinusInference =
520 params.m_ThresholdTime - duration<double, std::milli>(inferenceDuration).count();
521 ARMNN_LOG(info) << "Threshold time - Inference time: " << std::setprecision(2)
522 << std::fixed << thresholdMinusInference << " ms" << "\n";
523
524 if (thresholdMinusInference < 0)
525 {
526 ARMNN_LOG(fatal) << "Elapsed inference time is greater than provided threshold time. \n";
527 }
528 }
529 ++j;
530 }
531 //print duration difference between overallStartTime and overallEndTime
532 auto overallEndTime = time_point_cast<std::chrono::milliseconds>(latestEndTime);
533 auto overallStartTime = time_point_cast<std::chrono::milliseconds>(earliestStartTime);
534 auto totalInferenceDuration = overallEndTime - overallStartTime;
535 ARMNN_LOG(info) << "\nOverall Inference time: " << std::setprecision(2)
536 << std::fixed << totalInferenceDuration.count() << " ms\n";
537 }
538 catch (const armnn::Exception& e)
539 {
540 ARMNN_LOG(fatal) << "Armnn Error: " << e.what();
541 return EXIT_FAILURE;
542 }
543 }
544 // Asynchronous execution using std::launch::async
Sadik Armagana04a9d72021-04-27 10:02:10 +0100545 else
546 {
547 try
548 {
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100549 ARMNN_LOG(info) << "Asynchronous Execution with std::launch:async... \n";
Finn Williamsf364d532021-06-09 17:07:33 +0100550 std::vector<std::future<std::tuple<unsigned int,
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100551 std::chrono::duration<double, std::milli>>>> inferenceResults;
Sadik Armagana04a9d72021-04-27 10:02:10 +0100552 inferenceResults.reserve(params.m_SimultaneousIterations);
553
554 // Create WorkingMemHandles for each inference
555 std::vector<std::unique_ptr<armnn::experimental::IWorkingMemHandle>> workingMemHandles;
556 workingMemHandles.reserve(params.m_SimultaneousIterations);
557 for (unsigned int i = 0; i < params.m_SimultaneousIterations; ++i)
558 {
559 workingMemHandles.push_back(model.CreateWorkingMemHandle());
560 }
561
562 // Run each inference in its own thread
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100563 // start a timer
564 const auto start_time = armnn::GetTimeNow();
Sadik Armagana04a9d72021-04-27 10:02:10 +0100565 for (unsigned int i = 0; i < params.m_SimultaneousIterations; ++i)
566 {
567 armnn::experimental::IWorkingMemHandle& workingMemHandleRef = *workingMemHandles[i].get();
Finn Williamsf364d532021-06-09 17:07:33 +0100568
Sadik Armagana04a9d72021-04-27 10:02:10 +0100569 inferenceResults.push_back(std::async(
570 std::launch::async, [&model, &workingMemHandleRef, &inputs, &outputs, i]() {
Finn Williamsf364d532021-06-09 17:07:33 +0100571 return model.RunAsync(workingMemHandleRef, inputs[i], outputs[i], i);
Sadik Armagana04a9d72021-04-27 10:02:10 +0100572 }
573 ));
574 }
575
576 // Check the results
577 for (unsigned int j = 0; j < inferenceResults.size(); ++j)
578 {
579 // Get the results
580 auto inferenceResult = inferenceResults[j].get();
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100581 auto inferenceDuration = std::get<1>(inferenceResult);
Sadik Armagana04a9d72021-04-27 10:02:10 +0100582 auto inferenceID = std::get<0>(inferenceResult);
583
584 if (params.m_GenerateTensorData)
585 {
586 ARMNN_LOG(warning) << "The input data was generated, note that the output will not be useful";
587 }
588
589 // Print output tensors
590 const auto& infosOut = model.GetOutputBindingInfos();
591 for (size_t i = 0; i < numOutputs; i++)
592 {
593 const armnn::TensorInfo& infoOut = infosOut[i].second;
594 auto outputTensorFile = params.m_OutputTensorFiles.empty()
595 ? ""
596 : params.m_OutputTensorFiles[(j * numOutputs) + i];
597
598 TensorPrinter printer(inferenceModelParams.m_OutputBindings[i],
599 infoOut,
600 outputTensorFile,
601 params.m_DequantizeOutput);
602 mapbox::util::apply_visitor(printer, outputs[j][i]);
603 }
604
605 ARMNN_LOG(info) << "\nInference time: " << std::setprecision(2)
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100606 << std::fixed << inferenceDuration.count() << " ms\n";
Sadik Armagana04a9d72021-04-27 10:02:10 +0100607
608 // If thresholdTime == 0.0 (default), then it hasn't been supplied at command line
609 if (params.m_ThresholdTime != 0.0)
610 {
611 ARMNN_LOG(info) << "Threshold time: " << std::setprecision(2)
612 << std::fixed << params.m_ThresholdTime << " ms";
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100613 auto thresholdMinusInference = params.m_ThresholdTime - inferenceDuration.count();
Sadik Armagana04a9d72021-04-27 10:02:10 +0100614 ARMNN_LOG(info) << "Threshold time - Inference time: " << std::setprecision(2)
615 << std::fixed << thresholdMinusInference << " ms" << "\n";
616
617 if (thresholdMinusInference < 0)
618 {
619 ARMNN_LOG(fatal) << "Elapsed inference time is greater than provided threshold time. \n";
620 }
621 }
622 ARMNN_LOG(info) << "Asynchronous Execution is finished for Inference ID: " << inferenceID << " \n";
623
624 }
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100625 // finish timer
626 const auto duration = armnn::GetTimeDuration(start_time);
627 ARMNN_LOG(info) << "\nOverall Inference time: " << std::setprecision(2)
628 << std::fixed << duration.count() << " ms\n";
Sadik Armagana04a9d72021-04-27 10:02:10 +0100629 }
630 catch (const armnn::Exception& e)
631 {
632 ARMNN_LOG(fatal) << "Armnn Error: " << e.what();
633 return EXIT_FAILURE;
634 }
Jan Eilers45274902020-10-15 18:34:43 +0100635 }
636 }
637 catch (const armnn::Exception& e)
638 {
639 ARMNN_LOG(fatal) << "Armnn Error: " << e.what();
640 return EXIT_FAILURE;
641 }
642
643 return EXIT_SUCCESS;
644}
645
telsoa01c577f2c2018-08-31 09:22:23 +0100646
James Conroy7b4886f2019-04-11 10:23:58 +0100647// MAIN
telsoa01c577f2c2018-08-31 09:22:23 +0100648int main(int argc, const char* argv[])
649{
650 // Configures logging for both the ARMNN library and this test program.
Jan Eilers45274902020-10-15 18:34:43 +0100651 #ifdef NDEBUG
telsoa01c577f2c2018-08-31 09:22:23 +0100652 armnn::LogSeverity level = armnn::LogSeverity::Info;
Jan Eilers45274902020-10-15 18:34:43 +0100653 #else
telsoa01c577f2c2018-08-31 09:22:23 +0100654 armnn::LogSeverity level = armnn::LogSeverity::Debug;
Jan Eilers45274902020-10-15 18:34:43 +0100655 #endif
telsoa01c577f2c2018-08-31 09:22:23 +0100656 armnn::ConfigureLogging(true, true, level);
telsoa01c577f2c2018-08-31 09:22:23 +0100657
telsoa01c577f2c2018-08-31 09:22:23 +0100658
Jan Eilers45274902020-10-15 18:34:43 +0100659 // Get ExecuteNetwork parameters and runtime options from command line
660 ProgramOptions ProgramOptions(argc, argv);
Narumol Prangnawaratd8cc8112020-03-24 13:54:05 +0000661
Finn Williamsd7fcafa2020-04-23 17:55:18 +0100662 // Create runtime
Jan Eilers45274902020-10-15 18:34:43 +0100663 std::shared_ptr<armnn::IRuntime> runtime(armnn::IRuntime::Create(ProgramOptions.m_RuntimeOptions));
Finn Williamsd7fcafa2020-04-23 17:55:18 +0100664
Jan Eilers45274902020-10-15 18:34:43 +0100665 std::string modelFormat = ProgramOptions.m_ExNetParams.m_ModelFormat;
666
667 // Forward to implementation based on the parser type
668 if (modelFormat.find("armnn") != std::string::npos)
Finn Williamsd7fcafa2020-04-23 17:55:18 +0100669 {
Jan Eilers45274902020-10-15 18:34:43 +0100670 #if defined(ARMNN_SERIALIZER)
671 return MainImpl<armnnDeserializer::IDeserializer, float>(ProgramOptions.m_ExNetParams, runtime);
672 #else
673 ARMNN_LOG(fatal) << "Not built with serialization support.";
Finn Williamsd7fcafa2020-04-23 17:55:18 +0100674 return EXIT_FAILURE;
Jan Eilers45274902020-10-15 18:34:43 +0100675 #endif
Finn Williamsd7fcafa2020-04-23 17:55:18 +0100676 }
Jan Eilers45274902020-10-15 18:34:43 +0100677 else if (modelFormat.find("onnx") != std::string::npos)
telsoa01c577f2c2018-08-31 09:22:23 +0100678 {
Jan Eilers45274902020-10-15 18:34:43 +0100679 #if defined(ARMNN_ONNX_PARSER)
680 return MainImpl<armnnOnnxParser::IOnnxParser, float>(ProgramOptions.m_ExNetParams, runtime);
681 #else
682 ARMNN_LOG(fatal) << "Not built with Onnx parser support.";
683 return EXIT_FAILURE;
684 #endif
685 }
Jan Eilers45274902020-10-15 18:34:43 +0100686 else if(modelFormat.find("tflite") != std::string::npos)
687 {
Finn Williamsf806c4d2021-02-22 15:13:12 +0000688 if (ProgramOptions.m_ExNetParams.m_TfLiteExecutor == ExecuteNetworkParams::TfLiteExecutor::ArmNNTfLiteParser)
689 {
690 #if defined(ARMNN_TF_LITE_PARSER)
691 return MainImpl<armnnTfLiteParser::ITfLiteParser, float>(ProgramOptions.m_ExNetParams, runtime);
692 #else
693 ARMNN_LOG(fatal) << "Not built with Tensorflow-Lite parser support.";
694 return EXIT_FAILURE;
695 #endif
696 }
697 else if (ProgramOptions.m_ExNetParams.m_TfLiteExecutor ==
698 ExecuteNetworkParams::TfLiteExecutor::ArmNNTfLiteDelegate ||
699 ProgramOptions.m_ExNetParams.m_TfLiteExecutor ==
700 ExecuteNetworkParams::TfLiteExecutor::TfliteInterpreter)
Sadik Armagan5d03e312020-11-17 16:43:56 +0000701 {
702 #if defined(ARMNN_TF_LITE_DELEGATE)
703 return TfLiteDelegateMainImpl(ProgramOptions.m_ExNetParams, runtime);
704 #else
Finn Williamsbbbefec2020-11-25 14:32:42 +0000705 ARMNN_LOG(fatal) << "Not built with Arm NN Tensorflow-Lite delegate support.";
Sadik Armagan5d03e312020-11-17 16:43:56 +0000706 return EXIT_FAILURE;
707 #endif
708 }
Jan Eilers45274902020-10-15 18:34:43 +0100709 }
710 else
711 {
712 ARMNN_LOG(fatal) << "Unknown model format: '" << modelFormat
Nikhil Raj5d955cf2021-04-19 16:59:48 +0100713 << "'. Please include 'tflite' or 'onnx'";
Jan Eilers45274902020-10-15 18:34:43 +0100714 return EXIT_FAILURE;
telsoa014fcda012018-03-09 14:13:49 +0000715 }
716}