blob: 0d5271158b009287165014a8c2f6a1f32178165b [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>
David Monahan2d995612021-11-01 10:16:37 +000015#include <Half.hpp>
Jan Eilers45274902020-10-15 18:34:43 +010016
17#if defined(ARMNN_SERIALIZER)
18#include "armnnDeserializer/IDeserializer.hpp"
19#endif
Jan Eilers45274902020-10-15 18:34:43 +010020#if defined(ARMNN_TF_LITE_PARSER)
21#include "armnnTfLiteParser/ITfLiteParser.hpp"
22#endif
23#if defined(ARMNN_ONNX_PARSER)
24#include "armnnOnnxParser/IOnnxParser.hpp"
25#endif
Sadik Armagan5d03e312020-11-17 16:43:56 +000026#if defined(ARMNN_TFLITE_DELEGATE)
27#include <armnn_delegate.hpp>
28#include <DelegateOptions.hpp>
29
30#include <tensorflow/lite/builtin_ops.h>
31#include <tensorflow/lite/c/builtin_op_data.h>
32#include <tensorflow/lite/c/common.h>
33#include <tensorflow/lite/optional_debug_tools.h>
34#include <tensorflow/lite/kernels/builtin_op_kernels.h>
35#include <tensorflow/lite/interpreter.h>
36#include <tensorflow/lite/kernels/register.h>
37#endif
Jan Eilers45274902020-10-15 18:34:43 +010038
39#include <future>
Colm Donelan3cff15a2021-10-12 15:06:19 +010040
41/**
42 * Given a measured duration and a threshold time tell the user whether we succeeded or not.
43 *
44 * @param duration the measured inference duration.
45 * @param thresholdTime the threshold time in milliseconds.
46 * @return false if the measured time exceeded the threshold.
47 */
48bool CheckInferenceTimeThreshold(const std::chrono::duration<double, std::milli>& duration,
49 const double& thresholdTime)
50{
51 ARMNN_LOG(info) << "\nInference time: " << std::setprecision(2)
52 << std::fixed << duration.count() << " ms\n";
53 // If thresholdTime == 0.0 (default), then it hasn't been supplied at command line
54 if (thresholdTime != 0.0)
55 {
56 ARMNN_LOG(info) << "Threshold time: " << std::setprecision(2)
57 << std::fixed << thresholdTime << " ms";
58 auto thresholdMinusInference = thresholdTime - duration.count();
59 ARMNN_LOG(info) << "Threshold time - Inference time: " << std::setprecision(2)
60 << std::fixed << thresholdMinusInference << " ms" << "\n";
61 if (thresholdMinusInference < 0)
62 {
63 std::string errorMessage = "Elapsed inference time is greater than provided threshold time.";
64 ARMNN_LOG(fatal) << errorMessage;
65 return false;
66 }
67 }
68 return true;
69}
70
Sadik Armagan5d03e312020-11-17 16:43:56 +000071#if defined(ARMNN_TFLITE_DELEGATE)
Colm Donelan45142282021-10-21 23:39:52 +010072int TfLiteDelegateMainImpl(const ExecuteNetworkParams& params, const armnn::IRuntime::CreationOptions runtimeOptions)
Sadik Armagan5d03e312020-11-17 16:43:56 +000073{
74 using namespace tflite;
Jan Eilers45274902020-10-15 18:34:43 +010075
Sadik Armagan5d03e312020-11-17 16:43:56 +000076 std::unique_ptr<tflite::FlatBufferModel> model = tflite::FlatBufferModel::BuildFromFile(params.m_ModelPath.c_str());
77
78 auto tfLiteInterpreter = std::make_unique<Interpreter>();
79 tflite::ops::builtin::BuiltinOpResolver resolver;
80
81 tflite::InterpreterBuilder builder(*model, resolver);
82 builder(&tfLiteInterpreter);
83 tfLiteInterpreter->AllocateTensors();
84
Finn Williamsf806c4d2021-02-22 15:13:12 +000085 int status = 0;
86 if (params.m_TfLiteExecutor == ExecuteNetworkParams::TfLiteExecutor::ArmNNTfLiteDelegate)
Sadik Armagan19a1c032021-01-20 12:17:00 +000087 {
Finn Williamsf806c4d2021-02-22 15:13:12 +000088 // Create the Armnn Delegate
Colm Donelan3cff15a2021-10-12 15:06:19 +010089 // Populate a DelegateOptions from the ExecuteNetworkParams.
90 armnnDelegate::DelegateOptions delegateOptions = params.ToDelegateOptions();
91 delegateOptions.SetExternalProfilingParams(runtimeOptions.m_ProfilingOptions);
92
Finn Williamsf806c4d2021-02-22 15:13:12 +000093 std::unique_ptr<TfLiteDelegate, decltype(&armnnDelegate::TfLiteArmnnDelegateDelete)>
94 theArmnnDelegate(armnnDelegate::TfLiteArmnnDelegateCreate(delegateOptions),
95 armnnDelegate::TfLiteArmnnDelegateDelete);
96 // Register armnn_delegate to TfLiteInterpreter
97 status = tfLiteInterpreter->ModifyGraphWithDelegate(std::move(theArmnnDelegate));
98 if (status == kTfLiteError)
99 {
100 ARMNN_LOG(fatal) << "Could not register ArmNN TfLite Delegate to TfLiteInterpreter!";
101 return EXIT_FAILURE;
102 }
Sadik Armagan19a1c032021-01-20 12:17:00 +0000103 }
Finn Williamsf806c4d2021-02-22 15:13:12 +0000104 else
105 {
106 std::cout << "Running on TfLite without ArmNN delegate\n";
107 }
108
Sadik Armagan5d03e312020-11-17 16:43:56 +0000109 armnn::Optional<std::string> dataFile = params.m_GenerateTensorData
110 ? armnn::EmptyOptional()
111 : armnn::MakeOptional<std::string>(params.m_InputTensorDataFilePaths[0]);
112
Colm Donelan3cff15a2021-10-12 15:06:19 +0100113 const size_t numInputs = params.m_InputNames.size();
Sadik Armagan5d03e312020-11-17 16:43:56 +0000114
115 for(unsigned int inputIndex = 0; inputIndex < numInputs; ++inputIndex)
116 {
117 int input = tfLiteInterpreter->inputs()[inputIndex];
Sadik Armagan15f7fae2020-11-18 09:37:03 +0000118 TfLiteIntArray* inputDims = tfLiteInterpreter->tensor(input)->dims;
119
Mike Kelly00e9ebf2021-09-01 17:09:12 +0100120 unsigned int inputSize = 1;
121 if (params.m_InputTensorShapes.size() > 0)
Sadik Armagan15f7fae2020-11-18 09:37:03 +0000122 {
Mike Kelly00e9ebf2021-09-01 17:09:12 +0100123 inputSize = params.m_InputTensorShapes[inputIndex]->GetNumElements();
124 }
125 else
126 {
127 for (unsigned int dim = 0; dim < static_cast<unsigned int>(inputDims->size); ++dim)
128 {
129 inputSize *= inputDims->data[dim];
130 }
Sadik Armagan15f7fae2020-11-18 09:37:03 +0000131 }
132
Sadik Armagan5d03e312020-11-17 16:43:56 +0000133 if (params.m_InputTypes[inputIndex].compare("float") == 0)
134 {
135 auto inputData = tfLiteInterpreter->typed_tensor<float>(input);
Finn Williamsbbbefec2020-11-25 14:32:42 +0000136
Matthew Sloyanf00f6c22020-12-07 13:33:24 +0000137 if(inputData == NULL)
Finn Williamsbbbefec2020-11-25 14:32:42 +0000138 {
139 ARMNN_LOG(fatal) << "Input tensor is null, input type: "
140 "\"" << params.m_InputTypes[inputIndex] << "\" may be incorrect.";
141 return EXIT_FAILURE;
142 }
143
Finn Williams56870182020-11-20 13:57:53 +0000144 std::vector<float> tensorData;
145 PopulateTensorWithDataGeneric<float>(tensorData,
Mike Kelly00e9ebf2021-09-01 17:09:12 +0100146 inputSize,
147 dataFile,
148 [](const std::string& s)
149 { return std::stof(s); });
Sadik Armagan15f7fae2020-11-18 09:37:03 +0000150
Finn Williams56870182020-11-20 13:57:53 +0000151 std::copy(tensorData.begin(), tensorData.end(), inputData);
152 }
Finn Williamsf806c4d2021-02-22 15:13:12 +0000153 else if (params.m_InputTypes[inputIndex].compare("qsymms8") == 0)
Finn Williams56870182020-11-20 13:57:53 +0000154 {
155 auto inputData = tfLiteInterpreter->typed_tensor<int8_t>(input);
Finn Williamsbbbefec2020-11-25 14:32:42 +0000156
Matthew Sloyanf00f6c22020-12-07 13:33:24 +0000157 if(inputData == NULL)
Finn Williamsbbbefec2020-11-25 14:32:42 +0000158 {
159 ARMNN_LOG(fatal) << "Input tensor is null, input type: "
160 "\"" << params.m_InputTypes[inputIndex] << "\" may be incorrect.";
161 return EXIT_FAILURE;
162 }
163
Finn Williams56870182020-11-20 13:57:53 +0000164 std::vector<int8_t> tensorData;
165 PopulateTensorWithDataGeneric<int8_t>(tensorData,
Mike Kelly00e9ebf2021-09-01 17:09:12 +0100166 inputSize,
Finn Williams56870182020-11-20 13:57:53 +0000167 dataFile,
168 [](const std::string& s)
169 { return armnn::numeric_cast<int8_t>(std::stoi(s)); });
170
171 std::copy(tensorData.begin(), tensorData.end(), inputData);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000172 }
173 else if (params.m_InputTypes[inputIndex].compare("int") == 0)
174 {
175 auto inputData = tfLiteInterpreter->typed_tensor<int32_t>(input);
Finn Williamsbbbefec2020-11-25 14:32:42 +0000176
Matthew Sloyanf00f6c22020-12-07 13:33:24 +0000177 if(inputData == NULL)
Finn Williamsbbbefec2020-11-25 14:32:42 +0000178 {
179 ARMNN_LOG(fatal) << "Input tensor is null, input type: "
180 "\"" << params.m_InputTypes[inputIndex] << "\" may be incorrect.";
181 return EXIT_FAILURE;
182 }
183
Finn Williams56870182020-11-20 13:57:53 +0000184 std::vector<int32_t> tensorData;
185 PopulateTensorWithDataGeneric<int32_t>(tensorData,
Mike Kelly00e9ebf2021-09-01 17:09:12 +0100186 inputSize,
Finn Williams56870182020-11-20 13:57:53 +0000187 dataFile,
188 [](const std::string& s)
189 { return std::stoi(s); });
190
191 std::copy(tensorData.begin(), tensorData.end(), inputData);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000192 }
Mike Kellyd7ed6d42021-07-21 09:42:43 +0100193 else if (params.m_InputTypes[inputIndex].compare("qasymm8") == 0 ||
194 params.m_InputTypes[inputIndex].compare("qasymmu8") == 0)
Sadik Armagan5d03e312020-11-17 16:43:56 +0000195 {
196 auto inputData = tfLiteInterpreter->typed_tensor<uint8_t>(input);
Finn Williamsbbbefec2020-11-25 14:32:42 +0000197
Matthew Sloyanf00f6c22020-12-07 13:33:24 +0000198 if(inputData == NULL)
Finn Williamsbbbefec2020-11-25 14:32:42 +0000199 {
200 ARMNN_LOG(fatal) << "Input tensor is null, input type: "
201 "\"" << params.m_InputTypes[inputIndex] << "\" may be incorrect.";
202 return EXIT_FAILURE;
203 }
204
Finn Williams56870182020-11-20 13:57:53 +0000205 std::vector<uint8_t> tensorData;
206 PopulateTensorWithDataGeneric<uint8_t>(tensorData,
Mike Kelly00e9ebf2021-09-01 17:09:12 +0100207 inputSize,
Finn Williams56870182020-11-20 13:57:53 +0000208 dataFile,
209 [](const std::string& s)
210 { return armnn::numeric_cast<uint8_t>(std::stoi(s)); });
211
212 std::copy(tensorData.begin(), tensorData.end(), inputData);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000213 }
Mike Kellyd7ed6d42021-07-21 09:42:43 +0100214 else if (params.m_InputTypes[inputIndex].compare("qasymms8") == 0)
215 {
216 auto inputData = tfLiteInterpreter->typed_tensor<int8_t>(input);
217
218 if(inputData == NULL)
219 {
220 ARMNN_LOG(fatal) << "Input tensor is null, input type: "
221 "\"" << params.m_InputTypes[inputIndex] << "\" may be incorrect.";
222 return EXIT_FAILURE;
223 }
224
225 std::vector<int8_t> tensorData;
226 PopulateTensorWithDataGeneric<int8_t>(tensorData,
Mike Kelly00e9ebf2021-09-01 17:09:12 +0100227 inputSize,
Mike Kellyd7ed6d42021-07-21 09:42:43 +0100228 dataFile,
229 [](const std::string& s)
230 { return armnn::numeric_cast<int8_t>(std::stoi(s)); });
231
232 std::copy(tensorData.begin(), tensorData.end(), inputData);
233 }
Sadik Armagan5d03e312020-11-17 16:43:56 +0000234 else
235 {
236 ARMNN_LOG(fatal) << "Unsupported input tensor data type \"" << params.m_InputTypes[inputIndex] << "\". ";
237 return EXIT_FAILURE;
238 }
239 }
240
241 for (size_t x = 0; x < params.m_Iterations; x++)
242 {
Colm Donelan3cff15a2021-10-12 15:06:19 +0100243 // Start timer to record inference time in milliseconds.
244 const auto start_time = armnn::GetTimeNow();
Sadik Armagan5d03e312020-11-17 16:43:56 +0000245 // Run the inference
Finn Williamsf806c4d2021-02-22 15:13:12 +0000246 status = tfLiteInterpreter->Invoke();
Colm Donelan3cff15a2021-10-12 15:06:19 +0100247 const auto duration = armnn::GetTimeDuration(start_time);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000248
249 // Print out the output
250 for (unsigned int outputIndex = 0; outputIndex < params.m_OutputNames.size(); ++outputIndex)
251 {
Sadik Armagan5d03e312020-11-17 16:43:56 +0000252 auto tfLiteDelegateOutputId = tfLiteInterpreter->outputs()[outputIndex];
Sadik Armagan15f7fae2020-11-18 09:37:03 +0000253 TfLiteIntArray* outputDims = tfLiteInterpreter->tensor(tfLiteDelegateOutputId)->dims;
Colm Donelan3cff15a2021-10-12 15:06:19 +0100254 // If we've been asked to write to a file then set a file output stream. Otherwise use stdout.
255 FILE* outputTensorFile = stdout;
256 if (!params.m_OutputTensorFiles.empty())
257 {
258 outputTensorFile = fopen(params.m_OutputTensorFiles[outputIndex].c_str(), "w");
259 if (outputTensorFile == NULL)
260 {
261 ARMNN_LOG(fatal) << "Specified output tensor file, \"" <<
262 params.m_OutputTensorFiles[outputIndex] <<
263 "\", cannot be created. Defaulting to stdout. " <<
264 "Error was: " << std::strerror(errno);
265 outputTensorFile = stdout;
266 }
267 else
268 {
269 ARMNN_LOG(info) << "Writing output " << outputIndex << "' of iteration: " << x+1 << " to file: '"
270 << params.m_OutputTensorFiles[outputIndex] << "'";
271 }
272 }
Sadik Armagan15f7fae2020-11-18 09:37:03 +0000273 long outputSize = 1;
Sadik Armagan5d03e312020-11-17 16:43:56 +0000274 for (unsigned int dim = 0; dim < static_cast<unsigned int>(outputDims->size); ++dim)
275 {
Sadik Armagan15f7fae2020-11-18 09:37:03 +0000276 outputSize *= outputDims->data[dim];
Sadik Armagan5d03e312020-11-17 16:43:56 +0000277 }
278
279 std::cout << params.m_OutputNames[outputIndex] << ": ";
280 if (params.m_OutputTypes[outputIndex].compare("float") == 0)
281 {
282 auto tfLiteDelageOutputData = tfLiteInterpreter->typed_tensor<float>(tfLiteDelegateOutputId);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000283 if(tfLiteDelageOutputData == NULL)
284 {
285 ARMNN_LOG(fatal) << "Output tensor is null, output type: "
286 "\"" << params.m_OutputTypes[outputIndex] << "\" may be incorrect.";
287 return EXIT_FAILURE;
288 }
289
Jan Eilers284b5d12021-09-07 12:46:15 +0100290 if (!params.m_DontPrintOutputs)
Sadik Armagan5d03e312020-11-17 16:43:56 +0000291 {
Jan Eilers284b5d12021-09-07 12:46:15 +0100292 for (int i = 0; i < outputSize; ++i)
293 {
Colm Donelan3cff15a2021-10-12 15:06:19 +0100294 fprintf(outputTensorFile, "%f ", tfLiteDelageOutputData[i]);
Jan Eilers284b5d12021-09-07 12:46:15 +0100295 }
Sadik Armagan5d03e312020-11-17 16:43:56 +0000296 }
297 }
298 else if (params.m_OutputTypes[outputIndex].compare("int") == 0)
299 {
300 auto tfLiteDelageOutputData = tfLiteInterpreter->typed_tensor<int32_t>(tfLiteDelegateOutputId);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000301 if(tfLiteDelageOutputData == NULL)
302 {
303 ARMNN_LOG(fatal) << "Output tensor is null, output type: "
304 "\"" << params.m_OutputTypes[outputIndex] << "\" may be incorrect.";
305 return EXIT_FAILURE;
306 }
307
Jan Eilers284b5d12021-09-07 12:46:15 +0100308 if (!params.m_DontPrintOutputs)
Sadik Armagan5d03e312020-11-17 16:43:56 +0000309 {
Jan Eilers284b5d12021-09-07 12:46:15 +0100310 for (int i = 0; i < outputSize; ++i)
311 {
Colm Donelan3cff15a2021-10-12 15:06:19 +0100312 fprintf(outputTensorFile, "%d ", tfLiteDelageOutputData[i]);
Jan Eilers284b5d12021-09-07 12:46:15 +0100313 }
Sadik Armagan5d03e312020-11-17 16:43:56 +0000314 }
315 }
Finn Williamsf806c4d2021-02-22 15:13:12 +0000316 else if (params.m_OutputTypes[outputIndex].compare("qsymms8") == 0)
Finn Williams56870182020-11-20 13:57:53 +0000317 {
318 auto tfLiteDelageOutputData = tfLiteInterpreter->typed_tensor<int8_t>(tfLiteDelegateOutputId);
319 if(tfLiteDelageOutputData == NULL)
320 {
321 ARMNN_LOG(fatal) << "Output tensor is null, output type: "
322 "\"" << params.m_OutputTypes[outputIndex] << "\" may be incorrect.";
323 return EXIT_FAILURE;
324 }
325
Jan Eilers284b5d12021-09-07 12:46:15 +0100326 if (!params.m_DontPrintOutputs)
Finn Williams56870182020-11-20 13:57:53 +0000327 {
Jan Eilers284b5d12021-09-07 12:46:15 +0100328 for (int i = 0; i < outputSize; ++i)
329 {
Colm Donelan3cff15a2021-10-12 15:06:19 +0100330 fprintf(outputTensorFile, "%d ", tfLiteDelageOutputData[i]);
Jan Eilers284b5d12021-09-07 12:46:15 +0100331 }
Finn Williams56870182020-11-20 13:57:53 +0000332 }
333 }
Mike Kellyd7ed6d42021-07-21 09:42:43 +0100334 else if (params.m_OutputTypes[outputIndex].compare("qasymm8") == 0 ||
335 params.m_OutputTypes[outputIndex].compare("qasymmu8") == 0)
Sadik Armagan5d03e312020-11-17 16:43:56 +0000336 {
337 auto tfLiteDelageOutputData = tfLiteInterpreter->typed_tensor<uint8_t>(tfLiteDelegateOutputId);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000338 if(tfLiteDelageOutputData == NULL)
339 {
340 ARMNN_LOG(fatal) << "Output tensor is null, output type: "
341 "\"" << params.m_OutputTypes[outputIndex] << "\" may be incorrect.";
342 return EXIT_FAILURE;
343 }
344
Jan Eilers284b5d12021-09-07 12:46:15 +0100345 if (!params.m_DontPrintOutputs)
Sadik Armagan5d03e312020-11-17 16:43:56 +0000346 {
Jan Eilers284b5d12021-09-07 12:46:15 +0100347 for (int i = 0; i < outputSize; ++i)
348 {
Colm Donelan3cff15a2021-10-12 15:06:19 +0100349 fprintf(outputTensorFile, "%u ", tfLiteDelageOutputData[i]);
Jan Eilers284b5d12021-09-07 12:46:15 +0100350 }
Sadik Armagan5d03e312020-11-17 16:43:56 +0000351 }
352 }
353 else
354 {
355 ARMNN_LOG(fatal) << "Output tensor is null, output type: "
356 "\"" << params.m_OutputTypes[outputIndex] <<
357 "\" may be incorrect. Output type can be specified with -z argument";
358 return EXIT_FAILURE;
359 }
360 std::cout << std::endl;
361 }
Colm Donelan3cff15a2021-10-12 15:06:19 +0100362 CheckInferenceTimeThreshold(duration, params.m_ThresholdTime);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000363 }
364
365 return status;
366}
367#endif
Jan Eilers45274902020-10-15 18:34:43 +0100368template<typename TParser, typename TDataType>
369int MainImpl(const ExecuteNetworkParams& params,
370 const std::shared_ptr<armnn::IRuntime>& runtime = nullptr)
371{
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100372 using namespace std::chrono;
Jan Eilers45274902020-10-15 18:34:43 +0100373
Francis Murtagh40d27412021-10-28 11:11:35 +0100374 std::vector<std::vector<armnnUtils::TContainer>> inputs;
375 std::vector<std::vector<armnnUtils::TContainer>> outputs;
Jan Eilers45274902020-10-15 18:34:43 +0100376
377 try
378 {
379 // Creates an InferenceModel, which will parse the model and load it into an IRuntime.
380 typename InferenceModel<TParser, TDataType>::Params inferenceModelParams;
381 inferenceModelParams.m_ModelPath = params.m_ModelPath;
382 inferenceModelParams.m_IsModelBinary = params.m_IsModelBinary;
383 inferenceModelParams.m_ComputeDevices = params.m_ComputeDevices;
384 inferenceModelParams.m_DynamicBackendsPath = params.m_DynamicBackendsPath;
385 inferenceModelParams.m_PrintIntermediateLayers = params.m_PrintIntermediate;
386 inferenceModelParams.m_VisualizePostOptimizationModel = params.m_EnableLayerDetails;
387 inferenceModelParams.m_ParseUnsupported = params.m_ParseUnsupported;
388 inferenceModelParams.m_InferOutputShape = params.m_InferOutputShape;
389 inferenceModelParams.m_EnableFastMath = params.m_EnableFastMath;
Matthew Sloyan42432112021-01-08 10:30:51 +0000390 inferenceModelParams.m_SaveCachedNetwork = params.m_SaveCachedNetwork;
391 inferenceModelParams.m_CachedNetworkFilePath = params.m_CachedNetworkFilePath;
Matthew Sloyan0a7dc6b2021-02-10 16:50:53 +0000392 inferenceModelParams.m_NumberOfThreads = params.m_NumberOfThreads;
Finn Williams40646322021-02-11 16:16:42 +0000393 inferenceModelParams.m_MLGOTuningFilePath = params.m_MLGOTuningFilePath;
Sadik Armagana04a9d72021-04-27 10:02:10 +0100394 inferenceModelParams.m_AsyncEnabled = params.m_Concurrent;
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100395 inferenceModelParams.m_ThreadPoolSize = params.m_ThreadPoolSize;
Keith Davisf4874862021-08-09 16:49:18 +0100396 inferenceModelParams.m_OutputDetailsToStdOut = params.m_OutputDetailsToStdOut;
Keith Davis4914d0c2021-08-18 17:14:05 +0100397 inferenceModelParams.m_OutputDetailsOnlyToStdOut = params.m_OutputDetailsOnlyToStdOut;
Jan Eilers45274902020-10-15 18:34:43 +0100398
399 for(const std::string& inputName: params.m_InputNames)
400 {
401 inferenceModelParams.m_InputBindings.push_back(inputName);
402 }
403
404 for(unsigned int i = 0; i < params.m_InputTensorShapes.size(); ++i)
405 {
406 inferenceModelParams.m_InputShapes.push_back(*params.m_InputTensorShapes[i]);
407 }
408
409 for(const std::string& outputName: params.m_OutputNames)
410 {
411 inferenceModelParams.m_OutputBindings.push_back(outputName);
412 }
413
414 inferenceModelParams.m_SubgraphId = params.m_SubgraphId;
415 inferenceModelParams.m_EnableFp16TurboMode = params.m_EnableFp16TurboMode;
416 inferenceModelParams.m_EnableBf16TurboMode = params.m_EnableBf16TurboMode;
417
418 InferenceModel<TParser, TDataType> model(inferenceModelParams,
419 params.m_EnableProfiling,
420 params.m_DynamicBackendsPath,
421 runtime);
422
423 const size_t numInputs = inferenceModelParams.m_InputBindings.size();
Sadik Armagana04a9d72021-04-27 10:02:10 +0100424
425 armnn::Optional<QuantizationParams> qParams = params.m_QuantizeInput ?
426 armnn::MakeOptional<QuantizationParams>(
427 model.GetInputQuantizationParams()) :
428 armnn::EmptyOptional();
429
Jan Eilersf17fcd52021-07-26 22:20:00 +0100430 if (params.m_InputTensorDataFilePaths.size() > numInputs)
431 {
432 ARMNN_LOG(info) << "Given network has " << numInputs << " input/s. One input-tensor-data file is required "
433 << "for each input. The user provided "
434 << params.m_InputTensorDataFilePaths.size()
435 << " input-tensor-data file/s which will be used to fill the input/s.\n";
436 }
437
438 for(unsigned int j = 0; j < params.m_Iterations ; ++j)
Jan Eilers45274902020-10-15 18:34:43 +0100439 {
Francis Murtagh40d27412021-10-28 11:11:35 +0100440 std::vector<armnnUtils::TContainer> inputDataContainers;
Sadik Armagana04a9d72021-04-27 10:02:10 +0100441 for(unsigned int i = 0; i < numInputs; ++i)
Jan Eilers45274902020-10-15 18:34:43 +0100442 {
Jan Eilersf17fcd52021-07-26 22:20:00 +0100443 // If there are less input files given than required for the execution of
444 // params.m_Iterations we simply start with the first input file again
445 size_t inputFileIndex = j * numInputs + i;
446 if (!params.m_InputTensorDataFilePaths.empty())
447 {
448 inputFileIndex = inputFileIndex % params.m_InputTensorDataFilePaths.size();
449 }
450
Sadik Armagana04a9d72021-04-27 10:02:10 +0100451 armnn::Optional<std::string> dataFile = params.m_GenerateTensorData ?
452 armnn::EmptyOptional() :
453 armnn::MakeOptional<std::string>(
Jan Eilersf17fcd52021-07-26 22:20:00 +0100454 params.m_InputTensorDataFilePaths.at(inputFileIndex));
Sadik Armagana04a9d72021-04-27 10:02:10 +0100455
456 unsigned int numElements = model.GetInputSize(i);
457 if (params.m_InputTensorShapes.size() > i && params.m_InputTensorShapes[i])
458 {
459 // If the user has provided a tensor shape for the current input,
460 // override numElements
461 numElements = params.m_InputTensorShapes[i]->GetNumElements();
462 }
463
Francis Murtagh40d27412021-10-28 11:11:35 +0100464 armnnUtils::TContainer tensorData;
Sadik Armagana04a9d72021-04-27 10:02:10 +0100465 PopulateTensorWithData(tensorData,
466 numElements,
467 params.m_InputTypes[i],
468 qParams,
469 dataFile);
470
471 inputDataContainers.push_back(tensorData);
Jan Eilers45274902020-10-15 18:34:43 +0100472 }
Sadik Armagana04a9d72021-04-27 10:02:10 +0100473 inputs.push_back(inputDataContainers);
Jan Eilers45274902020-10-15 18:34:43 +0100474 }
475
476 const size_t numOutputs = inferenceModelParams.m_OutputBindings.size();
Jan Eilers45274902020-10-15 18:34:43 +0100477
Colm Donelanc5e41982021-10-28 20:19:43 +0100478 // The user is allowed to specify the data type of each output tensor. It is used here to construct the
479 // result tensors for each iteration. It is possible for the user to specify a type that does not match
480 // the data type of the corresponding model output. It may not make sense, but it is historically allowed.
481 // The potential problem here is a buffer overrun when a larger data type is written into the space for a
482 // smaller one. Issue a warning to highlight the potential problem.
483 for (unsigned int outputIdx = 0; outputIdx < model.GetOutputBindingInfos().size(); ++outputIdx)
484 {
485 armnn::DataType type = model.GetOutputBindingInfo(outputIdx).second.GetDataType();
486 switch (type)
487 {
David Monahan2d995612021-11-01 10:16:37 +0000488 // --output-type only supports float, float16, int, qasymms8 or qasymmu8.
Colm Donelanc5e41982021-10-28 20:19:43 +0100489 case armnn::DataType::Float32:
490 if (params.m_OutputTypes[outputIdx].compare("float") != 0)
491 {
492 ARMNN_LOG(warning) << "Model output index: " << outputIdx << " has data type Float32. The " <<
493 "corresponding --output-type is " << params.m_OutputTypes[outputIdx] <<
494 ". This may cause unexpected problems or random failures.";
495 }
496 break;
David Monahan2d995612021-11-01 10:16:37 +0000497 case armnn::DataType::Float16:
498 if (params.m_OutputTypes[outputIdx].compare("float16") != 0)
499 {
500 ARMNN_LOG(warning) << "Model output index: " << outputIdx << " has data type Float16. The " <<
501 "corresponding --output-type is " << params.m_OutputTypes[outputIdx] <<
502 ". This may cause unexpected problems or random failures.";
503 }
504 break;
Colm Donelanc5e41982021-10-28 20:19:43 +0100505 case armnn::DataType::QAsymmU8:
506 if (params.m_OutputTypes[outputIdx].compare("qasymmu8") != 0)
507 {
508 ARMNN_LOG(warning) << "Model output index: " << outputIdx << " has data type QAsymmU8. The " <<
509 "corresponding --output-type is " << params.m_OutputTypes[outputIdx] <<
510 ". This may cause unexpected problemsor random failures.";
511 }
512 break;
513 case armnn::DataType::Signed32:
514 if (params.m_OutputTypes[outputIdx].compare("int") != 0)
515 {
516 ARMNN_LOG(warning) << "Model output index: " << outputIdx << " has data type Signed32. The " <<
517 "corresponding --output-type is " << params.m_OutputTypes[outputIdx] <<
518 ". This may cause unexpected problems or random failures.";
519 }
520 break;
521 case armnn::DataType::QAsymmS8:
522 if (params.m_OutputTypes[outputIdx].compare("qasymms8") != 0)
523 {
524 ARMNN_LOG(warning) << "Model output index: " << outputIdx << " has data type QAsymmS8. The " <<
525 "corresponding --output-type is " << params.m_OutputTypes[outputIdx] <<
526 ". This may cause unexpected problems or random failures.";
527 }
528 break;
529 default:
530 break;
531 }
532 }
Jan Eilersf17fcd52021-07-26 22:20:00 +0100533 for (unsigned int j = 0; j < params.m_Iterations; ++j)
Jan Eilers45274902020-10-15 18:34:43 +0100534 {
Francis Murtagh40d27412021-10-28 11:11:35 +0100535 std::vector <armnnUtils::TContainer> outputDataContainers;
Sadik Armagana04a9d72021-04-27 10:02:10 +0100536 for (unsigned int i = 0; i < numOutputs; ++i)
Jan Eilers45274902020-10-15 18:34:43 +0100537 {
Sadik Armagana04a9d72021-04-27 10:02:10 +0100538 if (params.m_OutputTypes[i].compare("float") == 0)
Jan Eilers45274902020-10-15 18:34:43 +0100539 {
Sadik Armagana04a9d72021-04-27 10:02:10 +0100540 outputDataContainers.push_back(std::vector<float>(model.GetOutputSize(i)));
Mike Kellyd7ed6d42021-07-21 09:42:43 +0100541 }
David Monahan2d995612021-11-01 10:16:37 +0000542 else if (params.m_OutputTypes[i].compare("float16") == 0)
543 {
544 outputDataContainers.push_back(std::vector<armnn::Half>(model.GetOutputSize(i)));
545 }
Mike Kellyd7ed6d42021-07-21 09:42:43 +0100546 else if (params.m_OutputTypes[i].compare("int") == 0)
Sadik Armagana04a9d72021-04-27 10:02:10 +0100547 {
548 outputDataContainers.push_back(std::vector<int>(model.GetOutputSize(i)));
Mike Kellyd7ed6d42021-07-21 09:42:43 +0100549 }
550 else if (params.m_OutputTypes[i].compare("qasymm8") == 0 ||
551 params.m_OutputTypes[i].compare("qasymmu8") == 0)
Sadik Armagana04a9d72021-04-27 10:02:10 +0100552 {
553 outputDataContainers.push_back(std::vector<uint8_t>(model.GetOutputSize(i)));
Mike Kellyd7ed6d42021-07-21 09:42:43 +0100554 }
555 else if (params.m_OutputTypes[i].compare("qasymms8") == 0)
Sadik Armagana04a9d72021-04-27 10:02:10 +0100556 {
557 outputDataContainers.push_back(std::vector<int8_t>(model.GetOutputSize(i)));
558 } else
559 {
560 ARMNN_LOG(fatal) << "Unsupported tensor data type \"" << params.m_OutputTypes[i] << "\". ";
561 return EXIT_FAILURE;
Jan Eilers45274902020-10-15 18:34:43 +0100562 }
563 }
Sadik Armagana04a9d72021-04-27 10:02:10 +0100564 outputs.push_back(outputDataContainers);
565 }
566
Jan Eilersf17fcd52021-07-26 22:20:00 +0100567 if (params.m_Iterations > 1)
568 {
569 std::stringstream msg;
570 msg << "Network will be executed " << params.m_Iterations;
571 if (params.m_Concurrent)
572 {
573 msg << " times in an asynchronous manner. ";
574 }
575 else
576 {
577 msg << " times successively. ";
578 }
579 msg << "The input-tensor-data files will be reused recursively if the user didn't provide enough to "
580 "cover each execution.";
581 ARMNN_LOG(info) << msg.str();
582 }
583
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100584 // Synchronous execution
Sadik Armagana04a9d72021-04-27 10:02:10 +0100585 if (!params.m_Concurrent)
586 {
Sadik Armagana04a9d72021-04-27 10:02:10 +0100587 for (size_t x = 0; x < params.m_Iterations; x++)
588 {
589 // model.Run returns the inference time elapsed in EnqueueWorkload (in milliseconds)
Jan Eilersf17fcd52021-07-26 22:20:00 +0100590 auto inference_duration = model.Run(inputs[x], outputs[x]);
Sadik Armagana04a9d72021-04-27 10:02:10 +0100591
592 if (params.m_GenerateTensorData)
593 {
594 ARMNN_LOG(warning) << "The input data was generated, note that the output will not be useful";
595 }
Jan Eilers284b5d12021-09-07 12:46:15 +0100596 if (params.m_DontPrintOutputs)
597 {
598 ARMNN_LOG(info) << "Printing outputs to console is disabled.";
599 }
Sadik Armagana04a9d72021-04-27 10:02:10 +0100600
601 // Print output tensors
602 const auto& infosOut = model.GetOutputBindingInfos();
603 for (size_t i = 0; i < numOutputs; i++)
604 {
605 const armnn::TensorInfo& infoOut = infosOut[i].second;
Jan Eilersf17fcd52021-07-26 22:20:00 +0100606
Jan Eilers284b5d12021-09-07 12:46:15 +0100607 // We've made sure before that the number of output files either equals numOutputs, in which
608 // case we override those files when processing the results of each iteration (only the result
609 // of the last iteration will be stored), or there are enough
Jan Eilersf17fcd52021-07-26 22:20:00 +0100610 // output files for each output of each iteration.
611 size_t outputFileIndex = x * numOutputs + i;
612 if (!params.m_OutputTensorFiles.empty())
613 {
614 outputFileIndex = outputFileIndex % params.m_OutputTensorFiles.size();
615 ARMNN_LOG(info) << "Writing output " << i << " named: '"
616 << inferenceModelParams.m_OutputBindings[i]
617 << "' of iteration: " << x+1 << " to file: '"
618 << params.m_OutputTensorFiles[outputFileIndex] << "'";
619 }
620 auto outputTensorFile = params.m_OutputTensorFiles.empty()
621 ? ""
622 : params.m_OutputTensorFiles[outputFileIndex];
Sadik Armagana04a9d72021-04-27 10:02:10 +0100623
624 TensorPrinter printer(inferenceModelParams.m_OutputBindings[i],
625 infoOut,
626 outputTensorFile,
Jan Eilers284b5d12021-09-07 12:46:15 +0100627 params.m_DequantizeOutput,
628 !params.m_DontPrintOutputs);
Jan Eilersf17fcd52021-07-26 22:20:00 +0100629 mapbox::util::apply_visitor(printer, outputs[x][i]);
Sadik Armagana04a9d72021-04-27 10:02:10 +0100630 }
631
632 ARMNN_LOG(info) << "\nInference time: " << std::setprecision(2)
633 << std::fixed << inference_duration.count() << " ms\n";
634
635 // If thresholdTime == 0.0 (default), then it hasn't been supplied at command line
636 if (params.m_ThresholdTime != 0.0)
637 {
638 ARMNN_LOG(info) << "Threshold time: " << std::setprecision(2)
639 << std::fixed << params.m_ThresholdTime << " ms";
640 auto thresholdMinusInference = params.m_ThresholdTime - inference_duration.count();
641 ARMNN_LOG(info) << "Threshold time - Inference time: " << std::setprecision(2)
642 << std::fixed << thresholdMinusInference << " ms" << "\n";
643
644 if (thresholdMinusInference < 0)
645 {
646 std::string errorMessage = "Elapsed inference time is greater than provided threshold time.";
647 ARMNN_LOG(fatal) << errorMessage;
648 }
649 }
650 }
651 }
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100652 // Asynchronous execution using the Arm NN thread pool
Kevin May94dd4db2021-05-26 16:01:08 +0100653 else if (params.m_ThreadPoolSize >= 1)
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100654 {
655 try
656 {
657 ARMNN_LOG(info) << "Asynchronous execution with Arm NN thread pool... \n";
Finn Williamsf364d532021-06-09 17:07:33 +0100658 armnn::AsyncCallbackManager callbackManager;
Francis Murtagh40d27412021-10-28 11:11:35 +0100659 std::unordered_map<armnn::InferenceId, std::vector<armnnUtils::TContainer>&> inferenceOutputMap;
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100660
661 // Declare the latest and earliest inference times here to be used when calculating overall time
662 std::chrono::high_resolution_clock::time_point earliestStartTime;
663 std::chrono::high_resolution_clock::time_point latestEndTime =
664 std::chrono::high_resolution_clock::now();
665
666 // For the asynchronous execution, we are adding a pool of working memory handles (1 per thread) in the
667 // LoadedNetwork with each scheduled inference having a specific priority
Jan Eilersf17fcd52021-07-26 22:20:00 +0100668 for (size_t i = 0; i < params.m_Iterations; ++i)
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100669 {
Finn Williamsf364d532021-06-09 17:07:33 +0100670 std::shared_ptr<armnn::AsyncExecutionCallback> cb = callbackManager.GetNewCallback();
671 inferenceOutputMap.insert({cb->GetInferenceId(), outputs[i]});
672 model.RunAsync(inputs[i], outputs[i], cb);
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100673 }
674
675 // Check the results
676 unsigned int j = 0;
Jan Eilersf17fcd52021-07-26 22:20:00 +0100677 for (size_t iteration = 0; iteration < params.m_Iterations; ++iteration)
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100678 {
Finn Williamsf364d532021-06-09 17:07:33 +0100679 auto cb = callbackManager.GetNotifiedCallback();
680
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100681 // Get the results
682 auto endTime = time_point_cast<std::chrono::milliseconds>(cb->GetEndTime());
683 auto startTime = time_point_cast<std::chrono::milliseconds>(cb->GetStartTime());
684 auto inferenceDuration = endTime - startTime;
685
686 if (latestEndTime < cb->GetEndTime())
687 {
688 latestEndTime = cb->GetEndTime();
689 }
690
691 if (earliestStartTime.time_since_epoch().count() == 0)
692 {
693 earliestStartTime = cb->GetStartTime();
694 }
695 else if (earliestStartTime > cb->GetStartTime())
696 {
697 earliestStartTime = cb->GetStartTime();
698 }
699
700 if (params.m_GenerateTensorData)
701 {
702 ARMNN_LOG(warning) << "The input data was generated, note that the output will not be useful";
703 }
Jan Eilers284b5d12021-09-07 12:46:15 +0100704 if (params.m_DontPrintOutputs)
705 {
706 ARMNN_LOG(info) << "Printing outputs to console is disabled.";
707 }
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100708
709 // Print output tensors
710 const auto& infosOut = model.GetOutputBindingInfos();
711 for (size_t i = 0; i < numOutputs; i++)
712 {
Jan Eilersf17fcd52021-07-26 22:20:00 +0100713 // We've made sure before that the number of output files either equals numOutputs, in which
Jan Eilers284b5d12021-09-07 12:46:15 +0100714 // case we override those files when processing the results of each iteration (only the
715 // result of the last iteration will be stored), or there are enough
Jan Eilersf17fcd52021-07-26 22:20:00 +0100716 // output files for each output of each iteration.
717 size_t outputFileIndex = iteration * numOutputs + i;
718 if (!params.m_OutputTensorFiles.empty())
719 {
720 outputFileIndex = outputFileIndex % params.m_OutputTensorFiles.size();
721 ARMNN_LOG(info) << "Writing output " << i << " named: '"
722 << inferenceModelParams.m_OutputBindings[i]
723 << "' of iteration: " << iteration+1 << " to file: '"
724 << params.m_OutputTensorFiles[outputFileIndex] << "'";
725 }
726
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100727 const armnn::TensorInfo& infoOut = infosOut[i].second;
728 auto outputTensorFile = params.m_OutputTensorFiles.empty()
729 ? ""
Jan Eilersf17fcd52021-07-26 22:20:00 +0100730 : params.m_OutputTensorFiles[outputFileIndex];
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100731
732 TensorPrinter printer(inferenceModelParams.m_OutputBindings[i],
733 infoOut,
734 outputTensorFile,
Jan Eilers284b5d12021-09-07 12:46:15 +0100735 params.m_DequantizeOutput,
736 !params.m_DontPrintOutputs);
Finn Williamsf364d532021-06-09 17:07:33 +0100737 mapbox::util::apply_visitor(printer, inferenceOutputMap.at(cb->GetInferenceId())[i]);
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100738 }
739
Colm Donelan3cff15a2021-10-12 15:06:19 +0100740 CheckInferenceTimeThreshold(inferenceDuration, params.m_ThresholdTime);
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100741 ++j;
742 }
743 //print duration difference between overallStartTime and overallEndTime
744 auto overallEndTime = time_point_cast<std::chrono::milliseconds>(latestEndTime);
745 auto overallStartTime = time_point_cast<std::chrono::milliseconds>(earliestStartTime);
746 auto totalInferenceDuration = overallEndTime - overallStartTime;
747 ARMNN_LOG(info) << "\nOverall Inference time: " << std::setprecision(2)
748 << std::fixed << totalInferenceDuration.count() << " ms\n";
749 }
750 catch (const armnn::Exception& e)
751 {
752 ARMNN_LOG(fatal) << "Armnn Error: " << e.what();
753 return EXIT_FAILURE;
754 }
755 }
756 // Asynchronous execution using std::launch::async
Sadik Armagana04a9d72021-04-27 10:02:10 +0100757 else
758 {
759 try
760 {
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100761 ARMNN_LOG(info) << "Asynchronous Execution with std::launch:async... \n";
Finn Williamsf364d532021-06-09 17:07:33 +0100762 std::vector<std::future<std::tuple<unsigned int,
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100763 std::chrono::duration<double, std::milli>>>> inferenceResults;
Jan Eilersf17fcd52021-07-26 22:20:00 +0100764 inferenceResults.reserve(params.m_Iterations);
Sadik Armagana04a9d72021-04-27 10:02:10 +0100765
766 // Create WorkingMemHandles for each inference
767 std::vector<std::unique_ptr<armnn::experimental::IWorkingMemHandle>> workingMemHandles;
Jan Eilersf17fcd52021-07-26 22:20:00 +0100768 workingMemHandles.reserve(params.m_Iterations);
769 for (unsigned int i = 0; i < params.m_Iterations; ++i)
Sadik Armagana04a9d72021-04-27 10:02:10 +0100770 {
771 workingMemHandles.push_back(model.CreateWorkingMemHandle());
772 }
773
774 // Run each inference in its own thread
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100775 // start a timer
776 const auto start_time = armnn::GetTimeNow();
Jan Eilersf17fcd52021-07-26 22:20:00 +0100777 for (unsigned int i = 0; i < params.m_Iterations; ++i)
Sadik Armagana04a9d72021-04-27 10:02:10 +0100778 {
779 armnn::experimental::IWorkingMemHandle& workingMemHandleRef = *workingMemHandles[i].get();
Finn Williamsf364d532021-06-09 17:07:33 +0100780
Sadik Armagana04a9d72021-04-27 10:02:10 +0100781 inferenceResults.push_back(std::async(
782 std::launch::async, [&model, &workingMemHandleRef, &inputs, &outputs, i]() {
Finn Williamsf364d532021-06-09 17:07:33 +0100783 return model.RunAsync(workingMemHandleRef, inputs[i], outputs[i], i);
Sadik Armagana04a9d72021-04-27 10:02:10 +0100784 }
785 ));
786 }
787
788 // Check the results
789 for (unsigned int j = 0; j < inferenceResults.size(); ++j)
790 {
791 // Get the results
792 auto inferenceResult = inferenceResults[j].get();
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100793 auto inferenceDuration = std::get<1>(inferenceResult);
Sadik Armagana04a9d72021-04-27 10:02:10 +0100794 auto inferenceID = std::get<0>(inferenceResult);
795
796 if (params.m_GenerateTensorData)
797 {
798 ARMNN_LOG(warning) << "The input data was generated, note that the output will not be useful";
799 }
Jan Eilers284b5d12021-09-07 12:46:15 +0100800 if (params.m_DontPrintOutputs)
801 {
802 ARMNN_LOG(info) << "Printing outputs to console is disabled.";
803 }
Sadik Armagana04a9d72021-04-27 10:02:10 +0100804
805 // Print output tensors
806 const auto& infosOut = model.GetOutputBindingInfos();
807 for (size_t i = 0; i < numOutputs; i++)
808 {
Jan Eilersf17fcd52021-07-26 22:20:00 +0100809 // We've made sure before that the number of output files either equals numOutputs, in which
Jan Eilers284b5d12021-09-07 12:46:15 +0100810 // case we override those files when processing the results of each iteration (only the
811 // result of the last iteration will be stored), or there are enough
Jan Eilersf17fcd52021-07-26 22:20:00 +0100812 // output files for each output of each iteration.
813 size_t outputFileIndex = j * numOutputs + i;
814 if (!params.m_OutputTensorFiles.empty())
815 {
816 outputFileIndex = outputFileIndex % params.m_OutputTensorFiles.size();
817 ARMNN_LOG(info) << "Writing output " << i << " named: '"
818 << inferenceModelParams.m_OutputBindings[i]
819 << "' of iteration: " << j+1 << " to file: '"
820 << params.m_OutputTensorFiles[outputFileIndex] << "'";
821 }
Sadik Armagana04a9d72021-04-27 10:02:10 +0100822 const armnn::TensorInfo& infoOut = infosOut[i].second;
823 auto outputTensorFile = params.m_OutputTensorFiles.empty()
824 ? ""
Jan Eilersf17fcd52021-07-26 22:20:00 +0100825 : params.m_OutputTensorFiles[outputFileIndex];
Sadik Armagana04a9d72021-04-27 10:02:10 +0100826
827 TensorPrinter printer(inferenceModelParams.m_OutputBindings[i],
828 infoOut,
829 outputTensorFile,
Jan Eilers284b5d12021-09-07 12:46:15 +0100830 params.m_DequantizeOutput,
831 !params.m_DontPrintOutputs);
Sadik Armagana04a9d72021-04-27 10:02:10 +0100832 mapbox::util::apply_visitor(printer, outputs[j][i]);
833 }
Colm Donelan3cff15a2021-10-12 15:06:19 +0100834 CheckInferenceTimeThreshold(inferenceDuration, params.m_ThresholdTime);
Sadik Armagana04a9d72021-04-27 10:02:10 +0100835 ARMNN_LOG(info) << "Asynchronous Execution is finished for Inference ID: " << inferenceID << " \n";
Sadik Armagana04a9d72021-04-27 10:02:10 +0100836 }
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100837 // finish timer
838 const auto duration = armnn::GetTimeDuration(start_time);
839 ARMNN_LOG(info) << "\nOverall Inference time: " << std::setprecision(2)
840 << std::fixed << duration.count() << " ms\n";
Sadik Armagana04a9d72021-04-27 10:02:10 +0100841 }
842 catch (const armnn::Exception& e)
843 {
844 ARMNN_LOG(fatal) << "Armnn Error: " << e.what();
845 return EXIT_FAILURE;
846 }
Jan Eilers45274902020-10-15 18:34:43 +0100847 }
848 }
849 catch (const armnn::Exception& e)
850 {
851 ARMNN_LOG(fatal) << "Armnn Error: " << e.what();
852 return EXIT_FAILURE;
853 }
854
855 return EXIT_SUCCESS;
856}
857
James Conroy7b4886f2019-04-11 10:23:58 +0100858// MAIN
telsoa01c577f2c2018-08-31 09:22:23 +0100859int main(int argc, const char* argv[])
860{
861 // Configures logging for both the ARMNN library and this test program.
Jan Eilers45274902020-10-15 18:34:43 +0100862 #ifdef NDEBUG
telsoa01c577f2c2018-08-31 09:22:23 +0100863 armnn::LogSeverity level = armnn::LogSeverity::Info;
Jan Eilers45274902020-10-15 18:34:43 +0100864 #else
telsoa01c577f2c2018-08-31 09:22:23 +0100865 armnn::LogSeverity level = armnn::LogSeverity::Debug;
Jan Eilers45274902020-10-15 18:34:43 +0100866 #endif
telsoa01c577f2c2018-08-31 09:22:23 +0100867 armnn::ConfigureLogging(true, true, level);
telsoa01c577f2c2018-08-31 09:22:23 +0100868
telsoa01c577f2c2018-08-31 09:22:23 +0100869
Jan Eilers45274902020-10-15 18:34:43 +0100870 // Get ExecuteNetwork parameters and runtime options from command line
Jan Eilersf17fcd52021-07-26 22:20:00 +0100871 // This might throw an InvalidArgumentException if the user provided invalid inputs
872 ProgramOptions ProgramOptions;
873 try {
874 ProgramOptions.ParseOptions(argc, argv);
875 } catch (const std::exception &e){
876 ARMNN_LOG(fatal) << e.what();
877 return EXIT_FAILURE;
878 }
Narumol Prangnawaratd8cc8112020-03-24 13:54:05 +0000879
Keith Davis4914d0c2021-08-18 17:14:05 +0100880 if ((ProgramOptions.m_ExNetParams.m_OutputDetailsToStdOut ||
881 ProgramOptions.m_ExNetParams.m_OutputDetailsOnlyToStdOut)
882 && !ProgramOptions.m_ExNetParams.m_EnableProfiling)
Keith Davisf4874862021-08-09 16:49:18 +0100883 {
884 ARMNN_LOG(fatal) << "You must enable profiling if you would like to output layer details";
885 return EXIT_FAILURE;
886 }
887
Finn Williamsd7fcafa2020-04-23 17:55:18 +0100888 // Create runtime
Jan Eilers45274902020-10-15 18:34:43 +0100889 std::shared_ptr<armnn::IRuntime> runtime(armnn::IRuntime::Create(ProgramOptions.m_RuntimeOptions));
Finn Williamsd7fcafa2020-04-23 17:55:18 +0100890
Jan Eilers45274902020-10-15 18:34:43 +0100891 std::string modelFormat = ProgramOptions.m_ExNetParams.m_ModelFormat;
892
893 // Forward to implementation based on the parser type
894 if (modelFormat.find("armnn") != std::string::npos)
Finn Williamsd7fcafa2020-04-23 17:55:18 +0100895 {
Jan Eilers45274902020-10-15 18:34:43 +0100896 #if defined(ARMNN_SERIALIZER)
897 return MainImpl<armnnDeserializer::IDeserializer, float>(ProgramOptions.m_ExNetParams, runtime);
898 #else
899 ARMNN_LOG(fatal) << "Not built with serialization support.";
Finn Williamsd7fcafa2020-04-23 17:55:18 +0100900 return EXIT_FAILURE;
Jan Eilers45274902020-10-15 18:34:43 +0100901 #endif
Finn Williamsd7fcafa2020-04-23 17:55:18 +0100902 }
Jan Eilers45274902020-10-15 18:34:43 +0100903 else if (modelFormat.find("onnx") != std::string::npos)
telsoa01c577f2c2018-08-31 09:22:23 +0100904 {
Jan Eilers45274902020-10-15 18:34:43 +0100905 #if defined(ARMNN_ONNX_PARSER)
906 return MainImpl<armnnOnnxParser::IOnnxParser, float>(ProgramOptions.m_ExNetParams, runtime);
907 #else
908 ARMNN_LOG(fatal) << "Not built with Onnx parser support.";
909 return EXIT_FAILURE;
910 #endif
911 }
Jan Eilers45274902020-10-15 18:34:43 +0100912 else if(modelFormat.find("tflite") != std::string::npos)
913 {
Finn Williamsf806c4d2021-02-22 15:13:12 +0000914 if (ProgramOptions.m_ExNetParams.m_TfLiteExecutor == ExecuteNetworkParams::TfLiteExecutor::ArmNNTfLiteParser)
915 {
916 #if defined(ARMNN_TF_LITE_PARSER)
917 return MainImpl<armnnTfLiteParser::ITfLiteParser, float>(ProgramOptions.m_ExNetParams, runtime);
918 #else
919 ARMNN_LOG(fatal) << "Not built with Tensorflow-Lite parser support.";
920 return EXIT_FAILURE;
921 #endif
922 }
923 else if (ProgramOptions.m_ExNetParams.m_TfLiteExecutor ==
924 ExecuteNetworkParams::TfLiteExecutor::ArmNNTfLiteDelegate ||
925 ProgramOptions.m_ExNetParams.m_TfLiteExecutor ==
926 ExecuteNetworkParams::TfLiteExecutor::TfliteInterpreter)
Sadik Armagan5d03e312020-11-17 16:43:56 +0000927 {
928 #if defined(ARMNN_TF_LITE_DELEGATE)
Colm Donelan45142282021-10-21 23:39:52 +0100929 return TfLiteDelegateMainImpl(ProgramOptions.m_ExNetParams, ProgramOptions.m_RuntimeOptions);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000930 #else
Finn Williamsbbbefec2020-11-25 14:32:42 +0000931 ARMNN_LOG(fatal) << "Not built with Arm NN Tensorflow-Lite delegate support.";
Sadik Armagan5d03e312020-11-17 16:43:56 +0000932 return EXIT_FAILURE;
933 #endif
934 }
Jan Eilers45274902020-10-15 18:34:43 +0100935 }
936 else
937 {
938 ARMNN_LOG(fatal) << "Unknown model format: '" << modelFormat
Nikhil Raj5d955cf2021-04-19 16:59:48 +0100939 << "'. Please include 'tflite' or 'onnx'";
Jan Eilers45274902020-10-15 18:34:43 +0100940 return EXIT_FAILURE;
telsoa014fcda012018-03-09 14:13:49 +0000941 }
942}