blob: dd3c0a32a1d9838ee487740a7fd281eb712d6bf6 [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>
Rob Hughes9542f902021-07-14 09:48:54 +010012#include <armnnUtils/Filesystem.hpp>
Francis Murtagh40d27412021-10-28 11:11:35 +010013#include <armnnUtils/TContainer.hpp>
Jan Eilers45274902020-10-15 18:34:43 +010014#include <InferenceTest.hpp>
15
16#if defined(ARMNN_SERIALIZER)
17#include "armnnDeserializer/IDeserializer.hpp"
18#endif
Jan Eilers45274902020-10-15 18:34:43 +010019#if defined(ARMNN_TF_LITE_PARSER)
20#include "armnnTfLiteParser/ITfLiteParser.hpp"
21#endif
22#if defined(ARMNN_ONNX_PARSER)
23#include "armnnOnnxParser/IOnnxParser.hpp"
24#endif
Sadik Armagan5d03e312020-11-17 16:43:56 +000025#if defined(ARMNN_TFLITE_DELEGATE)
26#include <armnn_delegate.hpp>
27#include <DelegateOptions.hpp>
28
29#include <tensorflow/lite/builtin_ops.h>
30#include <tensorflow/lite/c/builtin_op_data.h>
31#include <tensorflow/lite/c/common.h>
32#include <tensorflow/lite/optional_debug_tools.h>
33#include <tensorflow/lite/kernels/builtin_op_kernels.h>
34#include <tensorflow/lite/interpreter.h>
35#include <tensorflow/lite/kernels/register.h>
36#endif
Jan Eilers45274902020-10-15 18:34:43 +010037
38#include <future>
Colm Donelan3cff15a2021-10-12 15:06:19 +010039
40/**
41 * Given a measured duration and a threshold time tell the user whether we succeeded or not.
42 *
43 * @param duration the measured inference duration.
44 * @param thresholdTime the threshold time in milliseconds.
45 * @return false if the measured time exceeded the threshold.
46 */
47bool CheckInferenceTimeThreshold(const std::chrono::duration<double, std::milli>& duration,
48 const double& thresholdTime)
49{
50 ARMNN_LOG(info) << "\nInference time: " << std::setprecision(2)
51 << std::fixed << duration.count() << " ms\n";
52 // If thresholdTime == 0.0 (default), then it hasn't been supplied at command line
53 if (thresholdTime != 0.0)
54 {
55 ARMNN_LOG(info) << "Threshold time: " << std::setprecision(2)
56 << std::fixed << thresholdTime << " ms";
57 auto thresholdMinusInference = thresholdTime - duration.count();
58 ARMNN_LOG(info) << "Threshold time - Inference time: " << std::setprecision(2)
59 << std::fixed << thresholdMinusInference << " ms" << "\n";
60 if (thresholdMinusInference < 0)
61 {
62 std::string errorMessage = "Elapsed inference time is greater than provided threshold time.";
63 ARMNN_LOG(fatal) << errorMessage;
64 return false;
65 }
66 }
67 return true;
68}
69
Sadik Armagan5d03e312020-11-17 16:43:56 +000070#if defined(ARMNN_TFLITE_DELEGATE)
Colm Donelan45142282021-10-21 23:39:52 +010071int TfLiteDelegateMainImpl(const ExecuteNetworkParams& params, const armnn::IRuntime::CreationOptions runtimeOptions)
Sadik Armagan5d03e312020-11-17 16:43:56 +000072{
73 using namespace tflite;
Jan Eilers45274902020-10-15 18:34:43 +010074
Sadik Armagan5d03e312020-11-17 16:43:56 +000075 std::unique_ptr<tflite::FlatBufferModel> model = tflite::FlatBufferModel::BuildFromFile(params.m_ModelPath.c_str());
76
77 auto tfLiteInterpreter = std::make_unique<Interpreter>();
78 tflite::ops::builtin::BuiltinOpResolver resolver;
79
80 tflite::InterpreterBuilder builder(*model, resolver);
81 builder(&tfLiteInterpreter);
82 tfLiteInterpreter->AllocateTensors();
83
Finn Williamsf806c4d2021-02-22 15:13:12 +000084 int status = 0;
85 if (params.m_TfLiteExecutor == ExecuteNetworkParams::TfLiteExecutor::ArmNNTfLiteDelegate)
Sadik Armagan19a1c032021-01-20 12:17:00 +000086 {
Finn Williamsf806c4d2021-02-22 15:13:12 +000087 // Create the Armnn Delegate
Colm Donelan3cff15a2021-10-12 15:06:19 +010088 // Populate a DelegateOptions from the ExecuteNetworkParams.
89 armnnDelegate::DelegateOptions delegateOptions = params.ToDelegateOptions();
90 delegateOptions.SetExternalProfilingParams(runtimeOptions.m_ProfilingOptions);
91
Finn Williamsf806c4d2021-02-22 15:13:12 +000092 std::unique_ptr<TfLiteDelegate, decltype(&armnnDelegate::TfLiteArmnnDelegateDelete)>
93 theArmnnDelegate(armnnDelegate::TfLiteArmnnDelegateCreate(delegateOptions),
94 armnnDelegate::TfLiteArmnnDelegateDelete);
95 // Register armnn_delegate to TfLiteInterpreter
96 status = tfLiteInterpreter->ModifyGraphWithDelegate(std::move(theArmnnDelegate));
97 if (status == kTfLiteError)
98 {
99 ARMNN_LOG(fatal) << "Could not register ArmNN TfLite Delegate to TfLiteInterpreter!";
100 return EXIT_FAILURE;
101 }
Sadik Armagan19a1c032021-01-20 12:17:00 +0000102 }
Finn Williamsf806c4d2021-02-22 15:13:12 +0000103 else
104 {
105 std::cout << "Running on TfLite without ArmNN delegate\n";
106 }
107
Sadik Armagan5d03e312020-11-17 16:43:56 +0000108 armnn::Optional<std::string> dataFile = params.m_GenerateTensorData
109 ? armnn::EmptyOptional()
110 : armnn::MakeOptional<std::string>(params.m_InputTensorDataFilePaths[0]);
111
Colm Donelan3cff15a2021-10-12 15:06:19 +0100112 const size_t numInputs = params.m_InputNames.size();
Sadik Armagan5d03e312020-11-17 16:43:56 +0000113
114 for(unsigned int inputIndex = 0; inputIndex < numInputs; ++inputIndex)
115 {
116 int input = tfLiteInterpreter->inputs()[inputIndex];
Sadik Armagan15f7fae2020-11-18 09:37:03 +0000117 TfLiteIntArray* inputDims = tfLiteInterpreter->tensor(input)->dims;
118
Mike Kelly00e9ebf2021-09-01 17:09:12 +0100119 unsigned int inputSize = 1;
120 if (params.m_InputTensorShapes.size() > 0)
Sadik Armagan15f7fae2020-11-18 09:37:03 +0000121 {
Mike Kelly00e9ebf2021-09-01 17:09:12 +0100122 inputSize = params.m_InputTensorShapes[inputIndex]->GetNumElements();
123 }
124 else
125 {
126 for (unsigned int dim = 0; dim < static_cast<unsigned int>(inputDims->size); ++dim)
127 {
128 inputSize *= inputDims->data[dim];
129 }
Sadik Armagan15f7fae2020-11-18 09:37:03 +0000130 }
131
Sadik Armagan5d03e312020-11-17 16:43:56 +0000132 if (params.m_InputTypes[inputIndex].compare("float") == 0)
133 {
134 auto inputData = tfLiteInterpreter->typed_tensor<float>(input);
Finn Williamsbbbefec2020-11-25 14:32:42 +0000135
Matthew Sloyanf00f6c22020-12-07 13:33:24 +0000136 if(inputData == NULL)
Finn Williamsbbbefec2020-11-25 14:32:42 +0000137 {
138 ARMNN_LOG(fatal) << "Input tensor is null, input type: "
139 "\"" << params.m_InputTypes[inputIndex] << "\" may be incorrect.";
140 return EXIT_FAILURE;
141 }
142
Finn Williams56870182020-11-20 13:57:53 +0000143 std::vector<float> tensorData;
144 PopulateTensorWithDataGeneric<float>(tensorData,
Mike Kelly00e9ebf2021-09-01 17:09:12 +0100145 inputSize,
146 dataFile,
147 [](const std::string& s)
148 { return std::stof(s); });
Sadik Armagan15f7fae2020-11-18 09:37:03 +0000149
Finn Williams56870182020-11-20 13:57:53 +0000150 std::copy(tensorData.begin(), tensorData.end(), inputData);
151 }
Finn Williamsf806c4d2021-02-22 15:13:12 +0000152 else if (params.m_InputTypes[inputIndex].compare("qsymms8") == 0)
Finn Williams56870182020-11-20 13:57:53 +0000153 {
154 auto inputData = tfLiteInterpreter->typed_tensor<int8_t>(input);
Finn Williamsbbbefec2020-11-25 14:32:42 +0000155
Matthew Sloyanf00f6c22020-12-07 13:33:24 +0000156 if(inputData == NULL)
Finn Williamsbbbefec2020-11-25 14:32:42 +0000157 {
158 ARMNN_LOG(fatal) << "Input tensor is null, input type: "
159 "\"" << params.m_InputTypes[inputIndex] << "\" may be incorrect.";
160 return EXIT_FAILURE;
161 }
162
Finn Williams56870182020-11-20 13:57:53 +0000163 std::vector<int8_t> tensorData;
164 PopulateTensorWithDataGeneric<int8_t>(tensorData,
Mike Kelly00e9ebf2021-09-01 17:09:12 +0100165 inputSize,
Finn Williams56870182020-11-20 13:57:53 +0000166 dataFile,
167 [](const std::string& s)
168 { return armnn::numeric_cast<int8_t>(std::stoi(s)); });
169
170 std::copy(tensorData.begin(), tensorData.end(), inputData);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000171 }
172 else if (params.m_InputTypes[inputIndex].compare("int") == 0)
173 {
174 auto inputData = tfLiteInterpreter->typed_tensor<int32_t>(input);
Finn Williamsbbbefec2020-11-25 14:32:42 +0000175
Matthew Sloyanf00f6c22020-12-07 13:33:24 +0000176 if(inputData == NULL)
Finn Williamsbbbefec2020-11-25 14:32:42 +0000177 {
178 ARMNN_LOG(fatal) << "Input tensor is null, input type: "
179 "\"" << params.m_InputTypes[inputIndex] << "\" may be incorrect.";
180 return EXIT_FAILURE;
181 }
182
Finn Williams56870182020-11-20 13:57:53 +0000183 std::vector<int32_t> tensorData;
184 PopulateTensorWithDataGeneric<int32_t>(tensorData,
Mike Kelly00e9ebf2021-09-01 17:09:12 +0100185 inputSize,
Finn Williams56870182020-11-20 13:57:53 +0000186 dataFile,
187 [](const std::string& s)
188 { return std::stoi(s); });
189
190 std::copy(tensorData.begin(), tensorData.end(), inputData);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000191 }
Mike Kellyd7ed6d42021-07-21 09:42:43 +0100192 else if (params.m_InputTypes[inputIndex].compare("qasymm8") == 0 ||
193 params.m_InputTypes[inputIndex].compare("qasymmu8") == 0)
Sadik Armagan5d03e312020-11-17 16:43:56 +0000194 {
195 auto inputData = tfLiteInterpreter->typed_tensor<uint8_t>(input);
Finn Williamsbbbefec2020-11-25 14:32:42 +0000196
Matthew Sloyanf00f6c22020-12-07 13:33:24 +0000197 if(inputData == NULL)
Finn Williamsbbbefec2020-11-25 14:32:42 +0000198 {
199 ARMNN_LOG(fatal) << "Input tensor is null, input type: "
200 "\"" << params.m_InputTypes[inputIndex] << "\" may be incorrect.";
201 return EXIT_FAILURE;
202 }
203
Finn Williams56870182020-11-20 13:57:53 +0000204 std::vector<uint8_t> tensorData;
205 PopulateTensorWithDataGeneric<uint8_t>(tensorData,
Mike Kelly00e9ebf2021-09-01 17:09:12 +0100206 inputSize,
Finn Williams56870182020-11-20 13:57:53 +0000207 dataFile,
208 [](const std::string& s)
209 { return armnn::numeric_cast<uint8_t>(std::stoi(s)); });
210
211 std::copy(tensorData.begin(), tensorData.end(), inputData);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000212 }
Mike Kellyd7ed6d42021-07-21 09:42:43 +0100213 else if (params.m_InputTypes[inputIndex].compare("qasymms8") == 0)
214 {
215 auto inputData = tfLiteInterpreter->typed_tensor<int8_t>(input);
216
217 if(inputData == NULL)
218 {
219 ARMNN_LOG(fatal) << "Input tensor is null, input type: "
220 "\"" << params.m_InputTypes[inputIndex] << "\" may be incorrect.";
221 return EXIT_FAILURE;
222 }
223
224 std::vector<int8_t> tensorData;
225 PopulateTensorWithDataGeneric<int8_t>(tensorData,
Mike Kelly00e9ebf2021-09-01 17:09:12 +0100226 inputSize,
Mike Kellyd7ed6d42021-07-21 09:42:43 +0100227 dataFile,
228 [](const std::string& s)
229 { return armnn::numeric_cast<int8_t>(std::stoi(s)); });
230
231 std::copy(tensorData.begin(), tensorData.end(), inputData);
232 }
Sadik Armagan5d03e312020-11-17 16:43:56 +0000233 else
234 {
235 ARMNN_LOG(fatal) << "Unsupported input tensor data type \"" << params.m_InputTypes[inputIndex] << "\". ";
236 return EXIT_FAILURE;
237 }
238 }
239
240 for (size_t x = 0; x < params.m_Iterations; x++)
241 {
Colm Donelan3cff15a2021-10-12 15:06:19 +0100242 // Start timer to record inference time in milliseconds.
243 const auto start_time = armnn::GetTimeNow();
Sadik Armagan5d03e312020-11-17 16:43:56 +0000244 // Run the inference
Finn Williamsf806c4d2021-02-22 15:13:12 +0000245 status = tfLiteInterpreter->Invoke();
Colm Donelan3cff15a2021-10-12 15:06:19 +0100246 const auto duration = armnn::GetTimeDuration(start_time);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000247
248 // Print out the output
249 for (unsigned int outputIndex = 0; outputIndex < params.m_OutputNames.size(); ++outputIndex)
250 {
Sadik Armagan5d03e312020-11-17 16:43:56 +0000251 auto tfLiteDelegateOutputId = tfLiteInterpreter->outputs()[outputIndex];
Sadik Armagan15f7fae2020-11-18 09:37:03 +0000252 TfLiteIntArray* outputDims = tfLiteInterpreter->tensor(tfLiteDelegateOutputId)->dims;
Colm Donelan3cff15a2021-10-12 15:06:19 +0100253 // If we've been asked to write to a file then set a file output stream. Otherwise use stdout.
254 FILE* outputTensorFile = stdout;
255 if (!params.m_OutputTensorFiles.empty())
256 {
257 outputTensorFile = fopen(params.m_OutputTensorFiles[outputIndex].c_str(), "w");
258 if (outputTensorFile == NULL)
259 {
260 ARMNN_LOG(fatal) << "Specified output tensor file, \"" <<
261 params.m_OutputTensorFiles[outputIndex] <<
262 "\", cannot be created. Defaulting to stdout. " <<
263 "Error was: " << std::strerror(errno);
264 outputTensorFile = stdout;
265 }
266 else
267 {
268 ARMNN_LOG(info) << "Writing output " << outputIndex << "' of iteration: " << x+1 << " to file: '"
269 << params.m_OutputTensorFiles[outputIndex] << "'";
270 }
271 }
Sadik Armagan15f7fae2020-11-18 09:37:03 +0000272 long outputSize = 1;
Sadik Armagan5d03e312020-11-17 16:43:56 +0000273 for (unsigned int dim = 0; dim < static_cast<unsigned int>(outputDims->size); ++dim)
274 {
Sadik Armagan15f7fae2020-11-18 09:37:03 +0000275 outputSize *= outputDims->data[dim];
Sadik Armagan5d03e312020-11-17 16:43:56 +0000276 }
277
278 std::cout << params.m_OutputNames[outputIndex] << ": ";
279 if (params.m_OutputTypes[outputIndex].compare("float") == 0)
280 {
281 auto tfLiteDelageOutputData = tfLiteInterpreter->typed_tensor<float>(tfLiteDelegateOutputId);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000282 if(tfLiteDelageOutputData == NULL)
283 {
284 ARMNN_LOG(fatal) << "Output tensor is null, output type: "
285 "\"" << params.m_OutputTypes[outputIndex] << "\" may be incorrect.";
286 return EXIT_FAILURE;
287 }
288
Jan Eilers284b5d12021-09-07 12:46:15 +0100289 if (!params.m_DontPrintOutputs)
Sadik Armagan5d03e312020-11-17 16:43:56 +0000290 {
Jan Eilers284b5d12021-09-07 12:46:15 +0100291 for (int i = 0; i < outputSize; ++i)
292 {
Colm Donelan3cff15a2021-10-12 15:06:19 +0100293 fprintf(outputTensorFile, "%f ", tfLiteDelageOutputData[i]);
Jan Eilers284b5d12021-09-07 12:46:15 +0100294 }
Sadik Armagan5d03e312020-11-17 16:43:56 +0000295 }
296 }
297 else if (params.m_OutputTypes[outputIndex].compare("int") == 0)
298 {
299 auto tfLiteDelageOutputData = tfLiteInterpreter->typed_tensor<int32_t>(tfLiteDelegateOutputId);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000300 if(tfLiteDelageOutputData == NULL)
301 {
302 ARMNN_LOG(fatal) << "Output tensor is null, output type: "
303 "\"" << params.m_OutputTypes[outputIndex] << "\" may be incorrect.";
304 return EXIT_FAILURE;
305 }
306
Jan Eilers284b5d12021-09-07 12:46:15 +0100307 if (!params.m_DontPrintOutputs)
Sadik Armagan5d03e312020-11-17 16:43:56 +0000308 {
Jan Eilers284b5d12021-09-07 12:46:15 +0100309 for (int i = 0; i < outputSize; ++i)
310 {
Colm Donelan3cff15a2021-10-12 15:06:19 +0100311 fprintf(outputTensorFile, "%d ", tfLiteDelageOutputData[i]);
Jan Eilers284b5d12021-09-07 12:46:15 +0100312 }
Sadik Armagan5d03e312020-11-17 16:43:56 +0000313 }
314 }
Finn Williamsf806c4d2021-02-22 15:13:12 +0000315 else if (params.m_OutputTypes[outputIndex].compare("qsymms8") == 0)
Finn Williams56870182020-11-20 13:57:53 +0000316 {
317 auto tfLiteDelageOutputData = tfLiteInterpreter->typed_tensor<int8_t>(tfLiteDelegateOutputId);
318 if(tfLiteDelageOutputData == NULL)
319 {
320 ARMNN_LOG(fatal) << "Output tensor is null, output type: "
321 "\"" << params.m_OutputTypes[outputIndex] << "\" may be incorrect.";
322 return EXIT_FAILURE;
323 }
324
Jan Eilers284b5d12021-09-07 12:46:15 +0100325 if (!params.m_DontPrintOutputs)
Finn Williams56870182020-11-20 13:57:53 +0000326 {
Jan Eilers284b5d12021-09-07 12:46:15 +0100327 for (int i = 0; i < outputSize; ++i)
328 {
Colm Donelan3cff15a2021-10-12 15:06:19 +0100329 fprintf(outputTensorFile, "%d ", tfLiteDelageOutputData[i]);
Jan Eilers284b5d12021-09-07 12:46:15 +0100330 }
Finn Williams56870182020-11-20 13:57:53 +0000331 }
332 }
Mike Kellyd7ed6d42021-07-21 09:42:43 +0100333 else if (params.m_OutputTypes[outputIndex].compare("qasymm8") == 0 ||
334 params.m_OutputTypes[outputIndex].compare("qasymmu8") == 0)
Sadik Armagan5d03e312020-11-17 16:43:56 +0000335 {
336 auto tfLiteDelageOutputData = tfLiteInterpreter->typed_tensor<uint8_t>(tfLiteDelegateOutputId);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000337 if(tfLiteDelageOutputData == NULL)
338 {
339 ARMNN_LOG(fatal) << "Output tensor is null, output type: "
340 "\"" << params.m_OutputTypes[outputIndex] << "\" may be incorrect.";
341 return EXIT_FAILURE;
342 }
343
Jan Eilers284b5d12021-09-07 12:46:15 +0100344 if (!params.m_DontPrintOutputs)
Sadik Armagan5d03e312020-11-17 16:43:56 +0000345 {
Jan Eilers284b5d12021-09-07 12:46:15 +0100346 for (int i = 0; i < outputSize; ++i)
347 {
Colm Donelan3cff15a2021-10-12 15:06:19 +0100348 fprintf(outputTensorFile, "%u ", tfLiteDelageOutputData[i]);
Jan Eilers284b5d12021-09-07 12:46:15 +0100349 }
Sadik Armagan5d03e312020-11-17 16:43:56 +0000350 }
351 }
352 else
353 {
354 ARMNN_LOG(fatal) << "Output tensor is null, output type: "
355 "\"" << params.m_OutputTypes[outputIndex] <<
356 "\" may be incorrect. Output type can be specified with -z argument";
357 return EXIT_FAILURE;
358 }
359 std::cout << std::endl;
360 }
Colm Donelan3cff15a2021-10-12 15:06:19 +0100361 CheckInferenceTimeThreshold(duration, params.m_ThresholdTime);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000362 }
363
364 return status;
365}
366#endif
Jan Eilers45274902020-10-15 18:34:43 +0100367template<typename TParser, typename TDataType>
368int MainImpl(const ExecuteNetworkParams& params,
369 const std::shared_ptr<armnn::IRuntime>& runtime = nullptr)
370{
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100371 using namespace std::chrono;
Jan Eilers45274902020-10-15 18:34:43 +0100372
Francis Murtagh40d27412021-10-28 11:11:35 +0100373 std::vector<std::vector<armnnUtils::TContainer>> inputs;
374 std::vector<std::vector<armnnUtils::TContainer>> outputs;
Jan Eilers45274902020-10-15 18:34:43 +0100375
376 try
377 {
378 // Creates an InferenceModel, which will parse the model and load it into an IRuntime.
379 typename InferenceModel<TParser, TDataType>::Params inferenceModelParams;
380 inferenceModelParams.m_ModelPath = params.m_ModelPath;
381 inferenceModelParams.m_IsModelBinary = params.m_IsModelBinary;
382 inferenceModelParams.m_ComputeDevices = params.m_ComputeDevices;
383 inferenceModelParams.m_DynamicBackendsPath = params.m_DynamicBackendsPath;
384 inferenceModelParams.m_PrintIntermediateLayers = params.m_PrintIntermediate;
385 inferenceModelParams.m_VisualizePostOptimizationModel = params.m_EnableLayerDetails;
386 inferenceModelParams.m_ParseUnsupported = params.m_ParseUnsupported;
387 inferenceModelParams.m_InferOutputShape = params.m_InferOutputShape;
388 inferenceModelParams.m_EnableFastMath = params.m_EnableFastMath;
Matthew Sloyan42432112021-01-08 10:30:51 +0000389 inferenceModelParams.m_SaveCachedNetwork = params.m_SaveCachedNetwork;
390 inferenceModelParams.m_CachedNetworkFilePath = params.m_CachedNetworkFilePath;
Matthew Sloyan0a7dc6b2021-02-10 16:50:53 +0000391 inferenceModelParams.m_NumberOfThreads = params.m_NumberOfThreads;
Finn Williams40646322021-02-11 16:16:42 +0000392 inferenceModelParams.m_MLGOTuningFilePath = params.m_MLGOTuningFilePath;
Sadik Armagana04a9d72021-04-27 10:02:10 +0100393 inferenceModelParams.m_AsyncEnabled = params.m_Concurrent;
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100394 inferenceModelParams.m_ThreadPoolSize = params.m_ThreadPoolSize;
Keith Davisf4874862021-08-09 16:49:18 +0100395 inferenceModelParams.m_OutputDetailsToStdOut = params.m_OutputDetailsToStdOut;
Keith Davis4914d0c2021-08-18 17:14:05 +0100396 inferenceModelParams.m_OutputDetailsOnlyToStdOut = params.m_OutputDetailsOnlyToStdOut;
Jan Eilers45274902020-10-15 18:34:43 +0100397
398 for(const std::string& inputName: params.m_InputNames)
399 {
400 inferenceModelParams.m_InputBindings.push_back(inputName);
401 }
402
403 for(unsigned int i = 0; i < params.m_InputTensorShapes.size(); ++i)
404 {
405 inferenceModelParams.m_InputShapes.push_back(*params.m_InputTensorShapes[i]);
406 }
407
408 for(const std::string& outputName: params.m_OutputNames)
409 {
410 inferenceModelParams.m_OutputBindings.push_back(outputName);
411 }
412
413 inferenceModelParams.m_SubgraphId = params.m_SubgraphId;
414 inferenceModelParams.m_EnableFp16TurboMode = params.m_EnableFp16TurboMode;
415 inferenceModelParams.m_EnableBf16TurboMode = params.m_EnableBf16TurboMode;
416
417 InferenceModel<TParser, TDataType> model(inferenceModelParams,
418 params.m_EnableProfiling,
419 params.m_DynamicBackendsPath,
420 runtime);
421
422 const size_t numInputs = inferenceModelParams.m_InputBindings.size();
Sadik Armagana04a9d72021-04-27 10:02:10 +0100423
424 armnn::Optional<QuantizationParams> qParams = params.m_QuantizeInput ?
425 armnn::MakeOptional<QuantizationParams>(
426 model.GetInputQuantizationParams()) :
427 armnn::EmptyOptional();
428
Jan Eilersf17fcd52021-07-26 22:20:00 +0100429 if (params.m_InputTensorDataFilePaths.size() > numInputs)
430 {
431 ARMNN_LOG(info) << "Given network has " << numInputs << " input/s. One input-tensor-data file is required "
432 << "for each input. The user provided "
433 << params.m_InputTensorDataFilePaths.size()
434 << " input-tensor-data file/s which will be used to fill the input/s.\n";
435 }
436
437 for(unsigned int j = 0; j < params.m_Iterations ; ++j)
Jan Eilers45274902020-10-15 18:34:43 +0100438 {
Francis Murtagh40d27412021-10-28 11:11:35 +0100439 std::vector<armnnUtils::TContainer> inputDataContainers;
Sadik Armagana04a9d72021-04-27 10:02:10 +0100440 for(unsigned int i = 0; i < numInputs; ++i)
Jan Eilers45274902020-10-15 18:34:43 +0100441 {
Jan Eilersf17fcd52021-07-26 22:20:00 +0100442 // If there are less input files given than required for the execution of
443 // params.m_Iterations we simply start with the first input file again
444 size_t inputFileIndex = j * numInputs + i;
445 if (!params.m_InputTensorDataFilePaths.empty())
446 {
447 inputFileIndex = inputFileIndex % params.m_InputTensorDataFilePaths.size();
448 }
449
Sadik Armagana04a9d72021-04-27 10:02:10 +0100450 armnn::Optional<std::string> dataFile = params.m_GenerateTensorData ?
451 armnn::EmptyOptional() :
452 armnn::MakeOptional<std::string>(
Jan Eilersf17fcd52021-07-26 22:20:00 +0100453 params.m_InputTensorDataFilePaths.at(inputFileIndex));
Sadik Armagana04a9d72021-04-27 10:02:10 +0100454
455 unsigned int numElements = model.GetInputSize(i);
456 if (params.m_InputTensorShapes.size() > i && params.m_InputTensorShapes[i])
457 {
458 // If the user has provided a tensor shape for the current input,
459 // override numElements
460 numElements = params.m_InputTensorShapes[i]->GetNumElements();
461 }
462
Francis Murtagh40d27412021-10-28 11:11:35 +0100463 armnnUtils::TContainer tensorData;
Sadik Armagana04a9d72021-04-27 10:02:10 +0100464 PopulateTensorWithData(tensorData,
465 numElements,
466 params.m_InputTypes[i],
467 qParams,
468 dataFile);
469
470 inputDataContainers.push_back(tensorData);
Jan Eilers45274902020-10-15 18:34:43 +0100471 }
Sadik Armagana04a9d72021-04-27 10:02:10 +0100472 inputs.push_back(inputDataContainers);
Jan Eilers45274902020-10-15 18:34:43 +0100473 }
474
475 const size_t numOutputs = inferenceModelParams.m_OutputBindings.size();
Jan Eilers45274902020-10-15 18:34:43 +0100476
Jan Eilersf17fcd52021-07-26 22:20:00 +0100477 for (unsigned int j = 0; j < params.m_Iterations; ++j)
Jan Eilers45274902020-10-15 18:34:43 +0100478 {
Francis Murtagh40d27412021-10-28 11:11:35 +0100479 std::vector <armnnUtils::TContainer> outputDataContainers;
Sadik Armagana04a9d72021-04-27 10:02:10 +0100480 for (unsigned int i = 0; i < numOutputs; ++i)
Jan Eilers45274902020-10-15 18:34:43 +0100481 {
Sadik Armagana04a9d72021-04-27 10:02:10 +0100482 if (params.m_OutputTypes[i].compare("float") == 0)
Jan Eilers45274902020-10-15 18:34:43 +0100483 {
Sadik Armagana04a9d72021-04-27 10:02:10 +0100484 outputDataContainers.push_back(std::vector<float>(model.GetOutputSize(i)));
Mike Kellyd7ed6d42021-07-21 09:42:43 +0100485 }
486 else if (params.m_OutputTypes[i].compare("int") == 0)
Sadik Armagana04a9d72021-04-27 10:02:10 +0100487 {
488 outputDataContainers.push_back(std::vector<int>(model.GetOutputSize(i)));
Mike Kellyd7ed6d42021-07-21 09:42:43 +0100489 }
490 else if (params.m_OutputTypes[i].compare("qasymm8") == 0 ||
491 params.m_OutputTypes[i].compare("qasymmu8") == 0)
Sadik Armagana04a9d72021-04-27 10:02:10 +0100492 {
493 outputDataContainers.push_back(std::vector<uint8_t>(model.GetOutputSize(i)));
Mike Kellyd7ed6d42021-07-21 09:42:43 +0100494 }
495 else if (params.m_OutputTypes[i].compare("qasymms8") == 0)
Sadik Armagana04a9d72021-04-27 10:02:10 +0100496 {
497 outputDataContainers.push_back(std::vector<int8_t>(model.GetOutputSize(i)));
498 } else
499 {
500 ARMNN_LOG(fatal) << "Unsupported tensor data type \"" << params.m_OutputTypes[i] << "\". ";
501 return EXIT_FAILURE;
Jan Eilers45274902020-10-15 18:34:43 +0100502 }
503 }
Sadik Armagana04a9d72021-04-27 10:02:10 +0100504 outputs.push_back(outputDataContainers);
505 }
506
Jan Eilersf17fcd52021-07-26 22:20:00 +0100507 if (params.m_Iterations > 1)
508 {
509 std::stringstream msg;
510 msg << "Network will be executed " << params.m_Iterations;
511 if (params.m_Concurrent)
512 {
513 msg << " times in an asynchronous manner. ";
514 }
515 else
516 {
517 msg << " times successively. ";
518 }
519 msg << "The input-tensor-data files will be reused recursively if the user didn't provide enough to "
520 "cover each execution.";
521 ARMNN_LOG(info) << msg.str();
522 }
523
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100524 // Synchronous execution
Sadik Armagana04a9d72021-04-27 10:02:10 +0100525 if (!params.m_Concurrent)
526 {
Sadik Armagana04a9d72021-04-27 10:02:10 +0100527 for (size_t x = 0; x < params.m_Iterations; x++)
528 {
529 // model.Run returns the inference time elapsed in EnqueueWorkload (in milliseconds)
Jan Eilersf17fcd52021-07-26 22:20:00 +0100530 auto inference_duration = model.Run(inputs[x], outputs[x]);
Sadik Armagana04a9d72021-04-27 10:02:10 +0100531
532 if (params.m_GenerateTensorData)
533 {
534 ARMNN_LOG(warning) << "The input data was generated, note that the output will not be useful";
535 }
Jan Eilers284b5d12021-09-07 12:46:15 +0100536 if (params.m_DontPrintOutputs)
537 {
538 ARMNN_LOG(info) << "Printing outputs to console is disabled.";
539 }
Sadik Armagana04a9d72021-04-27 10:02:10 +0100540
541 // Print output tensors
542 const auto& infosOut = model.GetOutputBindingInfos();
543 for (size_t i = 0; i < numOutputs; i++)
544 {
545 const armnn::TensorInfo& infoOut = infosOut[i].second;
Jan Eilersf17fcd52021-07-26 22:20:00 +0100546
Jan Eilers284b5d12021-09-07 12:46:15 +0100547 // We've made sure before that the number of output files either equals numOutputs, in which
548 // case we override those files when processing the results of each iteration (only the result
549 // of the last iteration will be stored), or there are enough
Jan Eilersf17fcd52021-07-26 22:20:00 +0100550 // output files for each output of each iteration.
551 size_t outputFileIndex = x * numOutputs + i;
552 if (!params.m_OutputTensorFiles.empty())
553 {
554 outputFileIndex = outputFileIndex % params.m_OutputTensorFiles.size();
555 ARMNN_LOG(info) << "Writing output " << i << " named: '"
556 << inferenceModelParams.m_OutputBindings[i]
557 << "' of iteration: " << x+1 << " to file: '"
558 << params.m_OutputTensorFiles[outputFileIndex] << "'";
559 }
560 auto outputTensorFile = params.m_OutputTensorFiles.empty()
561 ? ""
562 : params.m_OutputTensorFiles[outputFileIndex];
Sadik Armagana04a9d72021-04-27 10:02:10 +0100563
564 TensorPrinter printer(inferenceModelParams.m_OutputBindings[i],
565 infoOut,
566 outputTensorFile,
Jan Eilers284b5d12021-09-07 12:46:15 +0100567 params.m_DequantizeOutput,
568 !params.m_DontPrintOutputs);
Jan Eilersf17fcd52021-07-26 22:20:00 +0100569 mapbox::util::apply_visitor(printer, outputs[x][i]);
Sadik Armagana04a9d72021-04-27 10:02:10 +0100570 }
571
572 ARMNN_LOG(info) << "\nInference time: " << std::setprecision(2)
573 << std::fixed << inference_duration.count() << " ms\n";
574
575 // If thresholdTime == 0.0 (default), then it hasn't been supplied at command line
576 if (params.m_ThresholdTime != 0.0)
577 {
578 ARMNN_LOG(info) << "Threshold time: " << std::setprecision(2)
579 << std::fixed << params.m_ThresholdTime << " ms";
580 auto thresholdMinusInference = params.m_ThresholdTime - inference_duration.count();
581 ARMNN_LOG(info) << "Threshold time - Inference time: " << std::setprecision(2)
582 << std::fixed << thresholdMinusInference << " ms" << "\n";
583
584 if (thresholdMinusInference < 0)
585 {
586 std::string errorMessage = "Elapsed inference time is greater than provided threshold time.";
587 ARMNN_LOG(fatal) << errorMessage;
588 }
589 }
590 }
591 }
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100592 // Asynchronous execution using the Arm NN thread pool
Kevin May94dd4db2021-05-26 16:01:08 +0100593 else if (params.m_ThreadPoolSize >= 1)
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100594 {
595 try
596 {
597 ARMNN_LOG(info) << "Asynchronous execution with Arm NN thread pool... \n";
Finn Williamsf364d532021-06-09 17:07:33 +0100598 armnn::AsyncCallbackManager callbackManager;
Francis Murtagh40d27412021-10-28 11:11:35 +0100599 std::unordered_map<armnn::InferenceId, std::vector<armnnUtils::TContainer>&> inferenceOutputMap;
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100600
601 // Declare the latest and earliest inference times here to be used when calculating overall time
602 std::chrono::high_resolution_clock::time_point earliestStartTime;
603 std::chrono::high_resolution_clock::time_point latestEndTime =
604 std::chrono::high_resolution_clock::now();
605
606 // For the asynchronous execution, we are adding a pool of working memory handles (1 per thread) in the
607 // LoadedNetwork with each scheduled inference having a specific priority
Jan Eilersf17fcd52021-07-26 22:20:00 +0100608 for (size_t i = 0; i < params.m_Iterations; ++i)
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100609 {
Finn Williamsf364d532021-06-09 17:07:33 +0100610 std::shared_ptr<armnn::AsyncExecutionCallback> cb = callbackManager.GetNewCallback();
611 inferenceOutputMap.insert({cb->GetInferenceId(), outputs[i]});
612 model.RunAsync(inputs[i], outputs[i], cb);
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100613 }
614
615 // Check the results
616 unsigned int j = 0;
Jan Eilersf17fcd52021-07-26 22:20:00 +0100617 for (size_t iteration = 0; iteration < params.m_Iterations; ++iteration)
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100618 {
Finn Williamsf364d532021-06-09 17:07:33 +0100619 auto cb = callbackManager.GetNotifiedCallback();
620
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100621 // Get the results
622 auto endTime = time_point_cast<std::chrono::milliseconds>(cb->GetEndTime());
623 auto startTime = time_point_cast<std::chrono::milliseconds>(cb->GetStartTime());
624 auto inferenceDuration = endTime - startTime;
625
626 if (latestEndTime < cb->GetEndTime())
627 {
628 latestEndTime = cb->GetEndTime();
629 }
630
631 if (earliestStartTime.time_since_epoch().count() == 0)
632 {
633 earliestStartTime = cb->GetStartTime();
634 }
635 else if (earliestStartTime > cb->GetStartTime())
636 {
637 earliestStartTime = cb->GetStartTime();
638 }
639
640 if (params.m_GenerateTensorData)
641 {
642 ARMNN_LOG(warning) << "The input data was generated, note that the output will not be useful";
643 }
Jan Eilers284b5d12021-09-07 12:46:15 +0100644 if (params.m_DontPrintOutputs)
645 {
646 ARMNN_LOG(info) << "Printing outputs to console is disabled.";
647 }
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100648
649 // Print output tensors
650 const auto& infosOut = model.GetOutputBindingInfos();
651 for (size_t i = 0; i < numOutputs; i++)
652 {
Jan Eilersf17fcd52021-07-26 22:20:00 +0100653 // We've made sure before that the number of output files either equals numOutputs, in which
Jan Eilers284b5d12021-09-07 12:46:15 +0100654 // case we override those files when processing the results of each iteration (only the
655 // result of the last iteration will be stored), or there are enough
Jan Eilersf17fcd52021-07-26 22:20:00 +0100656 // output files for each output of each iteration.
657 size_t outputFileIndex = iteration * numOutputs + i;
658 if (!params.m_OutputTensorFiles.empty())
659 {
660 outputFileIndex = outputFileIndex % params.m_OutputTensorFiles.size();
661 ARMNN_LOG(info) << "Writing output " << i << " named: '"
662 << inferenceModelParams.m_OutputBindings[i]
663 << "' of iteration: " << iteration+1 << " to file: '"
664 << params.m_OutputTensorFiles[outputFileIndex] << "'";
665 }
666
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100667 const armnn::TensorInfo& infoOut = infosOut[i].second;
668 auto outputTensorFile = params.m_OutputTensorFiles.empty()
669 ? ""
Jan Eilersf17fcd52021-07-26 22:20:00 +0100670 : params.m_OutputTensorFiles[outputFileIndex];
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100671
672 TensorPrinter printer(inferenceModelParams.m_OutputBindings[i],
673 infoOut,
674 outputTensorFile,
Jan Eilers284b5d12021-09-07 12:46:15 +0100675 params.m_DequantizeOutput,
676 !params.m_DontPrintOutputs);
Finn Williamsf364d532021-06-09 17:07:33 +0100677 mapbox::util::apply_visitor(printer, inferenceOutputMap.at(cb->GetInferenceId())[i]);
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100678 }
679
Colm Donelan3cff15a2021-10-12 15:06:19 +0100680 CheckInferenceTimeThreshold(inferenceDuration, params.m_ThresholdTime);
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100681 ++j;
682 }
683 //print duration difference between overallStartTime and overallEndTime
684 auto overallEndTime = time_point_cast<std::chrono::milliseconds>(latestEndTime);
685 auto overallStartTime = time_point_cast<std::chrono::milliseconds>(earliestStartTime);
686 auto totalInferenceDuration = overallEndTime - overallStartTime;
687 ARMNN_LOG(info) << "\nOverall Inference time: " << std::setprecision(2)
688 << std::fixed << totalInferenceDuration.count() << " ms\n";
689 }
690 catch (const armnn::Exception& e)
691 {
692 ARMNN_LOG(fatal) << "Armnn Error: " << e.what();
693 return EXIT_FAILURE;
694 }
695 }
696 // Asynchronous execution using std::launch::async
Sadik Armagana04a9d72021-04-27 10:02:10 +0100697 else
698 {
699 try
700 {
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100701 ARMNN_LOG(info) << "Asynchronous Execution with std::launch:async... \n";
Finn Williamsf364d532021-06-09 17:07:33 +0100702 std::vector<std::future<std::tuple<unsigned int,
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100703 std::chrono::duration<double, std::milli>>>> inferenceResults;
Jan Eilersf17fcd52021-07-26 22:20:00 +0100704 inferenceResults.reserve(params.m_Iterations);
Sadik Armagana04a9d72021-04-27 10:02:10 +0100705
706 // Create WorkingMemHandles for each inference
707 std::vector<std::unique_ptr<armnn::experimental::IWorkingMemHandle>> workingMemHandles;
Jan Eilersf17fcd52021-07-26 22:20:00 +0100708 workingMemHandles.reserve(params.m_Iterations);
709 for (unsigned int i = 0; i < params.m_Iterations; ++i)
Sadik Armagana04a9d72021-04-27 10:02:10 +0100710 {
711 workingMemHandles.push_back(model.CreateWorkingMemHandle());
712 }
713
714 // Run each inference in its own thread
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100715 // start a timer
716 const auto start_time = armnn::GetTimeNow();
Jan Eilersf17fcd52021-07-26 22:20:00 +0100717 for (unsigned int i = 0; i < params.m_Iterations; ++i)
Sadik Armagana04a9d72021-04-27 10:02:10 +0100718 {
719 armnn::experimental::IWorkingMemHandle& workingMemHandleRef = *workingMemHandles[i].get();
Finn Williamsf364d532021-06-09 17:07:33 +0100720
Sadik Armagana04a9d72021-04-27 10:02:10 +0100721 inferenceResults.push_back(std::async(
722 std::launch::async, [&model, &workingMemHandleRef, &inputs, &outputs, i]() {
Finn Williamsf364d532021-06-09 17:07:33 +0100723 return model.RunAsync(workingMemHandleRef, inputs[i], outputs[i], i);
Sadik Armagana04a9d72021-04-27 10:02:10 +0100724 }
725 ));
726 }
727
728 // Check the results
729 for (unsigned int j = 0; j < inferenceResults.size(); ++j)
730 {
731 // Get the results
732 auto inferenceResult = inferenceResults[j].get();
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100733 auto inferenceDuration = std::get<1>(inferenceResult);
Sadik Armagana04a9d72021-04-27 10:02:10 +0100734 auto inferenceID = std::get<0>(inferenceResult);
735
736 if (params.m_GenerateTensorData)
737 {
738 ARMNN_LOG(warning) << "The input data was generated, note that the output will not be useful";
739 }
Jan Eilers284b5d12021-09-07 12:46:15 +0100740 if (params.m_DontPrintOutputs)
741 {
742 ARMNN_LOG(info) << "Printing outputs to console is disabled.";
743 }
Sadik Armagana04a9d72021-04-27 10:02:10 +0100744
745 // Print output tensors
746 const auto& infosOut = model.GetOutputBindingInfos();
747 for (size_t i = 0; i < numOutputs; i++)
748 {
Jan Eilersf17fcd52021-07-26 22:20:00 +0100749 // We've made sure before that the number of output files either equals numOutputs, in which
Jan Eilers284b5d12021-09-07 12:46:15 +0100750 // case we override those files when processing the results of each iteration (only the
751 // result of the last iteration will be stored), or there are enough
Jan Eilersf17fcd52021-07-26 22:20:00 +0100752 // output files for each output of each iteration.
753 size_t outputFileIndex = j * numOutputs + i;
754 if (!params.m_OutputTensorFiles.empty())
755 {
756 outputFileIndex = outputFileIndex % params.m_OutputTensorFiles.size();
757 ARMNN_LOG(info) << "Writing output " << i << " named: '"
758 << inferenceModelParams.m_OutputBindings[i]
759 << "' of iteration: " << j+1 << " to file: '"
760 << params.m_OutputTensorFiles[outputFileIndex] << "'";
761 }
Sadik Armagana04a9d72021-04-27 10:02:10 +0100762 const armnn::TensorInfo& infoOut = infosOut[i].second;
763 auto outputTensorFile = params.m_OutputTensorFiles.empty()
764 ? ""
Jan Eilersf17fcd52021-07-26 22:20:00 +0100765 : params.m_OutputTensorFiles[outputFileIndex];
Sadik Armagana04a9d72021-04-27 10:02:10 +0100766
767 TensorPrinter printer(inferenceModelParams.m_OutputBindings[i],
768 infoOut,
769 outputTensorFile,
Jan Eilers284b5d12021-09-07 12:46:15 +0100770 params.m_DequantizeOutput,
771 !params.m_DontPrintOutputs);
Sadik Armagana04a9d72021-04-27 10:02:10 +0100772 mapbox::util::apply_visitor(printer, outputs[j][i]);
773 }
Colm Donelan3cff15a2021-10-12 15:06:19 +0100774 CheckInferenceTimeThreshold(inferenceDuration, params.m_ThresholdTime);
Sadik Armagana04a9d72021-04-27 10:02:10 +0100775 ARMNN_LOG(info) << "Asynchronous Execution is finished for Inference ID: " << inferenceID << " \n";
Sadik Armagana04a9d72021-04-27 10:02:10 +0100776 }
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100777 // finish timer
778 const auto duration = armnn::GetTimeDuration(start_time);
779 ARMNN_LOG(info) << "\nOverall Inference time: " << std::setprecision(2)
780 << std::fixed << duration.count() << " ms\n";
Sadik Armagana04a9d72021-04-27 10:02:10 +0100781 }
782 catch (const armnn::Exception& e)
783 {
784 ARMNN_LOG(fatal) << "Armnn Error: " << e.what();
785 return EXIT_FAILURE;
786 }
Jan Eilers45274902020-10-15 18:34:43 +0100787 }
788 }
789 catch (const armnn::Exception& e)
790 {
791 ARMNN_LOG(fatal) << "Armnn Error: " << e.what();
792 return EXIT_FAILURE;
793 }
794
795 return EXIT_SUCCESS;
796}
797
James Conroy7b4886f2019-04-11 10:23:58 +0100798// MAIN
telsoa01c577f2c2018-08-31 09:22:23 +0100799int main(int argc, const char* argv[])
800{
801 // Configures logging for both the ARMNN library and this test program.
Jan Eilers45274902020-10-15 18:34:43 +0100802 #ifdef NDEBUG
telsoa01c577f2c2018-08-31 09:22:23 +0100803 armnn::LogSeverity level = armnn::LogSeverity::Info;
Jan Eilers45274902020-10-15 18:34:43 +0100804 #else
telsoa01c577f2c2018-08-31 09:22:23 +0100805 armnn::LogSeverity level = armnn::LogSeverity::Debug;
Jan Eilers45274902020-10-15 18:34:43 +0100806 #endif
telsoa01c577f2c2018-08-31 09:22:23 +0100807 armnn::ConfigureLogging(true, true, level);
telsoa01c577f2c2018-08-31 09:22:23 +0100808
telsoa01c577f2c2018-08-31 09:22:23 +0100809
Jan Eilers45274902020-10-15 18:34:43 +0100810 // Get ExecuteNetwork parameters and runtime options from command line
Jan Eilersf17fcd52021-07-26 22:20:00 +0100811 // This might throw an InvalidArgumentException if the user provided invalid inputs
812 ProgramOptions ProgramOptions;
813 try {
814 ProgramOptions.ParseOptions(argc, argv);
815 } catch (const std::exception &e){
816 ARMNN_LOG(fatal) << e.what();
817 return EXIT_FAILURE;
818 }
Narumol Prangnawaratd8cc8112020-03-24 13:54:05 +0000819
Keith Davis4914d0c2021-08-18 17:14:05 +0100820 if ((ProgramOptions.m_ExNetParams.m_OutputDetailsToStdOut ||
821 ProgramOptions.m_ExNetParams.m_OutputDetailsOnlyToStdOut)
822 && !ProgramOptions.m_ExNetParams.m_EnableProfiling)
Keith Davisf4874862021-08-09 16:49:18 +0100823 {
824 ARMNN_LOG(fatal) << "You must enable profiling if you would like to output layer details";
825 return EXIT_FAILURE;
826 }
827
Finn Williamsd7fcafa2020-04-23 17:55:18 +0100828 // Create runtime
Jan Eilers45274902020-10-15 18:34:43 +0100829 std::shared_ptr<armnn::IRuntime> runtime(armnn::IRuntime::Create(ProgramOptions.m_RuntimeOptions));
Finn Williamsd7fcafa2020-04-23 17:55:18 +0100830
Jan Eilers45274902020-10-15 18:34:43 +0100831 std::string modelFormat = ProgramOptions.m_ExNetParams.m_ModelFormat;
832
833 // Forward to implementation based on the parser type
834 if (modelFormat.find("armnn") != std::string::npos)
Finn Williamsd7fcafa2020-04-23 17:55:18 +0100835 {
Jan Eilers45274902020-10-15 18:34:43 +0100836 #if defined(ARMNN_SERIALIZER)
837 return MainImpl<armnnDeserializer::IDeserializer, float>(ProgramOptions.m_ExNetParams, runtime);
838 #else
839 ARMNN_LOG(fatal) << "Not built with serialization support.";
Finn Williamsd7fcafa2020-04-23 17:55:18 +0100840 return EXIT_FAILURE;
Jan Eilers45274902020-10-15 18:34:43 +0100841 #endif
Finn Williamsd7fcafa2020-04-23 17:55:18 +0100842 }
Jan Eilers45274902020-10-15 18:34:43 +0100843 else if (modelFormat.find("onnx") != std::string::npos)
telsoa01c577f2c2018-08-31 09:22:23 +0100844 {
Jan Eilers45274902020-10-15 18:34:43 +0100845 #if defined(ARMNN_ONNX_PARSER)
846 return MainImpl<armnnOnnxParser::IOnnxParser, float>(ProgramOptions.m_ExNetParams, runtime);
847 #else
848 ARMNN_LOG(fatal) << "Not built with Onnx parser support.";
849 return EXIT_FAILURE;
850 #endif
851 }
Jan Eilers45274902020-10-15 18:34:43 +0100852 else if(modelFormat.find("tflite") != std::string::npos)
853 {
Finn Williamsf806c4d2021-02-22 15:13:12 +0000854 if (ProgramOptions.m_ExNetParams.m_TfLiteExecutor == ExecuteNetworkParams::TfLiteExecutor::ArmNNTfLiteParser)
855 {
856 #if defined(ARMNN_TF_LITE_PARSER)
857 return MainImpl<armnnTfLiteParser::ITfLiteParser, float>(ProgramOptions.m_ExNetParams, runtime);
858 #else
859 ARMNN_LOG(fatal) << "Not built with Tensorflow-Lite parser support.";
860 return EXIT_FAILURE;
861 #endif
862 }
863 else if (ProgramOptions.m_ExNetParams.m_TfLiteExecutor ==
864 ExecuteNetworkParams::TfLiteExecutor::ArmNNTfLiteDelegate ||
865 ProgramOptions.m_ExNetParams.m_TfLiteExecutor ==
866 ExecuteNetworkParams::TfLiteExecutor::TfliteInterpreter)
Sadik Armagan5d03e312020-11-17 16:43:56 +0000867 {
868 #if defined(ARMNN_TF_LITE_DELEGATE)
Colm Donelan45142282021-10-21 23:39:52 +0100869 return TfLiteDelegateMainImpl(ProgramOptions.m_ExNetParams, ProgramOptions.m_RuntimeOptions);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000870 #else
Finn Williamsbbbefec2020-11-25 14:32:42 +0000871 ARMNN_LOG(fatal) << "Not built with Arm NN Tensorflow-Lite delegate support.";
Sadik Armagan5d03e312020-11-17 16:43:56 +0000872 return EXIT_FAILURE;
873 #endif
874 }
Jan Eilers45274902020-10-15 18:34:43 +0100875 }
876 else
877 {
878 ARMNN_LOG(fatal) << "Unknown model format: '" << modelFormat
Nikhil Raj5d955cf2021-04-19 16:59:48 +0100879 << "'. Please include 'tflite' or 'onnx'";
Jan Eilers45274902020-10-15 18:34:43 +0100880 return EXIT_FAILURE;
telsoa014fcda012018-03-09 14:13:49 +0000881 }
882}