blob: a0a08d31b0eed5b29580dc61fb5766a55a4decac [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
Colm Donelanc5e41982021-10-28 20:19:43 +0100477 // The user is allowed to specify the data type of each output tensor. It is used here to construct the
478 // result tensors for each iteration. It is possible for the user to specify a type that does not match
479 // the data type of the corresponding model output. It may not make sense, but it is historically allowed.
480 // The potential problem here is a buffer overrun when a larger data type is written into the space for a
481 // smaller one. Issue a warning to highlight the potential problem.
482 for (unsigned int outputIdx = 0; outputIdx < model.GetOutputBindingInfos().size(); ++outputIdx)
483 {
484 armnn::DataType type = model.GetOutputBindingInfo(outputIdx).second.GetDataType();
485 switch (type)
486 {
David Monahan67cc5fc2021-11-03 12:56:41 +0000487 // --output-type only supports float, int, qasymms8 or qasymmu8.
Colm Donelanc5e41982021-10-28 20:19:43 +0100488 case armnn::DataType::Float32:
489 if (params.m_OutputTypes[outputIdx].compare("float") != 0)
490 {
491 ARMNN_LOG(warning) << "Model output index: " << outputIdx << " has data type Float32. The " <<
492 "corresponding --output-type is " << params.m_OutputTypes[outputIdx] <<
493 ". This may cause unexpected problems or random failures.";
494 }
495 break;
496 case armnn::DataType::QAsymmU8:
497 if (params.m_OutputTypes[outputIdx].compare("qasymmu8") != 0)
498 {
499 ARMNN_LOG(warning) << "Model output index: " << outputIdx << " has data type QAsymmU8. The " <<
500 "corresponding --output-type is " << params.m_OutputTypes[outputIdx] <<
501 ". This may cause unexpected problemsor random failures.";
502 }
503 break;
504 case armnn::DataType::Signed32:
505 if (params.m_OutputTypes[outputIdx].compare("int") != 0)
506 {
507 ARMNN_LOG(warning) << "Model output index: " << outputIdx << " has data type Signed32. The " <<
508 "corresponding --output-type is " << params.m_OutputTypes[outputIdx] <<
509 ". This may cause unexpected problems or random failures.";
510 }
511 break;
512 case armnn::DataType::QAsymmS8:
513 if (params.m_OutputTypes[outputIdx].compare("qasymms8") != 0)
514 {
515 ARMNN_LOG(warning) << "Model output index: " << outputIdx << " has data type QAsymmS8. The " <<
516 "corresponding --output-type is " << params.m_OutputTypes[outputIdx] <<
517 ". This may cause unexpected problems or random failures.";
518 }
519 break;
520 default:
521 break;
522 }
523 }
Jan Eilersf17fcd52021-07-26 22:20:00 +0100524 for (unsigned int j = 0; j < params.m_Iterations; ++j)
Jan Eilers45274902020-10-15 18:34:43 +0100525 {
Francis Murtagh40d27412021-10-28 11:11:35 +0100526 std::vector <armnnUtils::TContainer> outputDataContainers;
Sadik Armagana04a9d72021-04-27 10:02:10 +0100527 for (unsigned int i = 0; i < numOutputs; ++i)
Jan Eilers45274902020-10-15 18:34:43 +0100528 {
Sadik Armagana04a9d72021-04-27 10:02:10 +0100529 if (params.m_OutputTypes[i].compare("float") == 0)
Jan Eilers45274902020-10-15 18:34:43 +0100530 {
Sadik Armagana04a9d72021-04-27 10:02:10 +0100531 outputDataContainers.push_back(std::vector<float>(model.GetOutputSize(i)));
Mike Kellyd7ed6d42021-07-21 09:42:43 +0100532 }
533 else if (params.m_OutputTypes[i].compare("int") == 0)
Sadik Armagana04a9d72021-04-27 10:02:10 +0100534 {
535 outputDataContainers.push_back(std::vector<int>(model.GetOutputSize(i)));
Mike Kellyd7ed6d42021-07-21 09:42:43 +0100536 }
537 else if (params.m_OutputTypes[i].compare("qasymm8") == 0 ||
538 params.m_OutputTypes[i].compare("qasymmu8") == 0)
Sadik Armagana04a9d72021-04-27 10:02:10 +0100539 {
540 outputDataContainers.push_back(std::vector<uint8_t>(model.GetOutputSize(i)));
Mike Kellyd7ed6d42021-07-21 09:42:43 +0100541 }
542 else if (params.m_OutputTypes[i].compare("qasymms8") == 0)
Sadik Armagana04a9d72021-04-27 10:02:10 +0100543 {
544 outputDataContainers.push_back(std::vector<int8_t>(model.GetOutputSize(i)));
545 } else
546 {
547 ARMNN_LOG(fatal) << "Unsupported tensor data type \"" << params.m_OutputTypes[i] << "\". ";
548 return EXIT_FAILURE;
Jan Eilers45274902020-10-15 18:34:43 +0100549 }
550 }
Sadik Armagana04a9d72021-04-27 10:02:10 +0100551 outputs.push_back(outputDataContainers);
552 }
553
Jan Eilersf17fcd52021-07-26 22:20:00 +0100554 if (params.m_Iterations > 1)
555 {
556 std::stringstream msg;
557 msg << "Network will be executed " << params.m_Iterations;
558 if (params.m_Concurrent)
559 {
560 msg << " times in an asynchronous manner. ";
561 }
562 else
563 {
564 msg << " times successively. ";
565 }
566 msg << "The input-tensor-data files will be reused recursively if the user didn't provide enough to "
567 "cover each execution.";
568 ARMNN_LOG(info) << msg.str();
569 }
570
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100571 // Synchronous execution
Sadik Armagana04a9d72021-04-27 10:02:10 +0100572 if (!params.m_Concurrent)
573 {
Sadik Armagana04a9d72021-04-27 10:02:10 +0100574 for (size_t x = 0; x < params.m_Iterations; x++)
575 {
576 // model.Run returns the inference time elapsed in EnqueueWorkload (in milliseconds)
Jan Eilersf17fcd52021-07-26 22:20:00 +0100577 auto inference_duration = model.Run(inputs[x], outputs[x]);
Sadik Armagana04a9d72021-04-27 10:02:10 +0100578
579 if (params.m_GenerateTensorData)
580 {
581 ARMNN_LOG(warning) << "The input data was generated, note that the output will not be useful";
582 }
Jan Eilers284b5d12021-09-07 12:46:15 +0100583 if (params.m_DontPrintOutputs)
584 {
585 ARMNN_LOG(info) << "Printing outputs to console is disabled.";
586 }
Sadik Armagana04a9d72021-04-27 10:02:10 +0100587
588 // Print output tensors
589 const auto& infosOut = model.GetOutputBindingInfos();
590 for (size_t i = 0; i < numOutputs; i++)
591 {
592 const armnn::TensorInfo& infoOut = infosOut[i].second;
Jan Eilersf17fcd52021-07-26 22:20:00 +0100593
Jan Eilers284b5d12021-09-07 12:46:15 +0100594 // We've made sure before that the number of output files either equals numOutputs, in which
595 // case we override those files when processing the results of each iteration (only the result
596 // of the last iteration will be stored), or there are enough
Jan Eilersf17fcd52021-07-26 22:20:00 +0100597 // output files for each output of each iteration.
598 size_t outputFileIndex = x * numOutputs + i;
599 if (!params.m_OutputTensorFiles.empty())
600 {
601 outputFileIndex = outputFileIndex % params.m_OutputTensorFiles.size();
602 ARMNN_LOG(info) << "Writing output " << i << " named: '"
603 << inferenceModelParams.m_OutputBindings[i]
604 << "' of iteration: " << x+1 << " to file: '"
605 << params.m_OutputTensorFiles[outputFileIndex] << "'";
606 }
607 auto outputTensorFile = params.m_OutputTensorFiles.empty()
608 ? ""
609 : params.m_OutputTensorFiles[outputFileIndex];
Sadik Armagana04a9d72021-04-27 10:02:10 +0100610
611 TensorPrinter printer(inferenceModelParams.m_OutputBindings[i],
612 infoOut,
613 outputTensorFile,
Jan Eilers284b5d12021-09-07 12:46:15 +0100614 params.m_DequantizeOutput,
615 !params.m_DontPrintOutputs);
Jan Eilersf17fcd52021-07-26 22:20:00 +0100616 mapbox::util::apply_visitor(printer, outputs[x][i]);
Sadik Armagana04a9d72021-04-27 10:02:10 +0100617 }
618
619 ARMNN_LOG(info) << "\nInference time: " << std::setprecision(2)
620 << std::fixed << inference_duration.count() << " ms\n";
621
622 // If thresholdTime == 0.0 (default), then it hasn't been supplied at command line
623 if (params.m_ThresholdTime != 0.0)
624 {
625 ARMNN_LOG(info) << "Threshold time: " << std::setprecision(2)
626 << std::fixed << params.m_ThresholdTime << " ms";
627 auto thresholdMinusInference = params.m_ThresholdTime - inference_duration.count();
628 ARMNN_LOG(info) << "Threshold time - Inference time: " << std::setprecision(2)
629 << std::fixed << thresholdMinusInference << " ms" << "\n";
630
631 if (thresholdMinusInference < 0)
632 {
633 std::string errorMessage = "Elapsed inference time is greater than provided threshold time.";
634 ARMNN_LOG(fatal) << errorMessage;
635 }
636 }
637 }
638 }
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100639 // Asynchronous execution using the Arm NN thread pool
Kevin May94dd4db2021-05-26 16:01:08 +0100640 else if (params.m_ThreadPoolSize >= 1)
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100641 {
642 try
643 {
644 ARMNN_LOG(info) << "Asynchronous execution with Arm NN thread pool... \n";
Finn Williamsf364d532021-06-09 17:07:33 +0100645 armnn::AsyncCallbackManager callbackManager;
Francis Murtagh40d27412021-10-28 11:11:35 +0100646 std::unordered_map<armnn::InferenceId, std::vector<armnnUtils::TContainer>&> inferenceOutputMap;
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100647
648 // Declare the latest and earliest inference times here to be used when calculating overall time
649 std::chrono::high_resolution_clock::time_point earliestStartTime;
650 std::chrono::high_resolution_clock::time_point latestEndTime =
651 std::chrono::high_resolution_clock::now();
652
653 // For the asynchronous execution, we are adding a pool of working memory handles (1 per thread) in the
654 // LoadedNetwork with each scheduled inference having a specific priority
Jan Eilersf17fcd52021-07-26 22:20:00 +0100655 for (size_t i = 0; i < params.m_Iterations; ++i)
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100656 {
Finn Williamsf364d532021-06-09 17:07:33 +0100657 std::shared_ptr<armnn::AsyncExecutionCallback> cb = callbackManager.GetNewCallback();
658 inferenceOutputMap.insert({cb->GetInferenceId(), outputs[i]});
659 model.RunAsync(inputs[i], outputs[i], cb);
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100660 }
661
662 // Check the results
663 unsigned int j = 0;
Jan Eilersf17fcd52021-07-26 22:20:00 +0100664 for (size_t iteration = 0; iteration < params.m_Iterations; ++iteration)
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100665 {
Finn Williamsf364d532021-06-09 17:07:33 +0100666 auto cb = callbackManager.GetNotifiedCallback();
667
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100668 // Get the results
669 auto endTime = time_point_cast<std::chrono::milliseconds>(cb->GetEndTime());
670 auto startTime = time_point_cast<std::chrono::milliseconds>(cb->GetStartTime());
671 auto inferenceDuration = endTime - startTime;
672
673 if (latestEndTime < cb->GetEndTime())
674 {
675 latestEndTime = cb->GetEndTime();
676 }
677
678 if (earliestStartTime.time_since_epoch().count() == 0)
679 {
680 earliestStartTime = cb->GetStartTime();
681 }
682 else if (earliestStartTime > cb->GetStartTime())
683 {
684 earliestStartTime = cb->GetStartTime();
685 }
686
687 if (params.m_GenerateTensorData)
688 {
689 ARMNN_LOG(warning) << "The input data was generated, note that the output will not be useful";
690 }
Jan Eilers284b5d12021-09-07 12:46:15 +0100691 if (params.m_DontPrintOutputs)
692 {
693 ARMNN_LOG(info) << "Printing outputs to console is disabled.";
694 }
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100695
696 // Print output tensors
697 const auto& infosOut = model.GetOutputBindingInfos();
698 for (size_t i = 0; i < numOutputs; i++)
699 {
Jan Eilersf17fcd52021-07-26 22:20:00 +0100700 // We've made sure before that the number of output files either equals numOutputs, in which
Jan Eilers284b5d12021-09-07 12:46:15 +0100701 // case we override those files when processing the results of each iteration (only the
702 // result of the last iteration will be stored), or there are enough
Jan Eilersf17fcd52021-07-26 22:20:00 +0100703 // output files for each output of each iteration.
704 size_t outputFileIndex = iteration * numOutputs + i;
705 if (!params.m_OutputTensorFiles.empty())
706 {
707 outputFileIndex = outputFileIndex % params.m_OutputTensorFiles.size();
708 ARMNN_LOG(info) << "Writing output " << i << " named: '"
709 << inferenceModelParams.m_OutputBindings[i]
710 << "' of iteration: " << iteration+1 << " to file: '"
711 << params.m_OutputTensorFiles[outputFileIndex] << "'";
712 }
713
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100714 const armnn::TensorInfo& infoOut = infosOut[i].second;
715 auto outputTensorFile = params.m_OutputTensorFiles.empty()
716 ? ""
Jan Eilersf17fcd52021-07-26 22:20:00 +0100717 : params.m_OutputTensorFiles[outputFileIndex];
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100718
719 TensorPrinter printer(inferenceModelParams.m_OutputBindings[i],
720 infoOut,
721 outputTensorFile,
Jan Eilers284b5d12021-09-07 12:46:15 +0100722 params.m_DequantizeOutput,
723 !params.m_DontPrintOutputs);
Finn Williamsf364d532021-06-09 17:07:33 +0100724 mapbox::util::apply_visitor(printer, inferenceOutputMap.at(cb->GetInferenceId())[i]);
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100725 }
726
Colm Donelan3cff15a2021-10-12 15:06:19 +0100727 CheckInferenceTimeThreshold(inferenceDuration, params.m_ThresholdTime);
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100728 ++j;
729 }
730 //print duration difference between overallStartTime and overallEndTime
731 auto overallEndTime = time_point_cast<std::chrono::milliseconds>(latestEndTime);
732 auto overallStartTime = time_point_cast<std::chrono::milliseconds>(earliestStartTime);
733 auto totalInferenceDuration = overallEndTime - overallStartTime;
734 ARMNN_LOG(info) << "\nOverall Inference time: " << std::setprecision(2)
735 << std::fixed << totalInferenceDuration.count() << " ms\n";
736 }
737 catch (const armnn::Exception& e)
738 {
739 ARMNN_LOG(fatal) << "Armnn Error: " << e.what();
740 return EXIT_FAILURE;
741 }
742 }
743 // Asynchronous execution using std::launch::async
Sadik Armagana04a9d72021-04-27 10:02:10 +0100744 else
745 {
746 try
747 {
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100748 ARMNN_LOG(info) << "Asynchronous Execution with std::launch:async... \n";
Finn Williamsf364d532021-06-09 17:07:33 +0100749 std::vector<std::future<std::tuple<unsigned int,
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100750 std::chrono::duration<double, std::milli>>>> inferenceResults;
Jan Eilersf17fcd52021-07-26 22:20:00 +0100751 inferenceResults.reserve(params.m_Iterations);
Sadik Armagana04a9d72021-04-27 10:02:10 +0100752
753 // Create WorkingMemHandles for each inference
754 std::vector<std::unique_ptr<armnn::experimental::IWorkingMemHandle>> workingMemHandles;
Jan Eilersf17fcd52021-07-26 22:20:00 +0100755 workingMemHandles.reserve(params.m_Iterations);
756 for (unsigned int i = 0; i < params.m_Iterations; ++i)
Sadik Armagana04a9d72021-04-27 10:02:10 +0100757 {
758 workingMemHandles.push_back(model.CreateWorkingMemHandle());
759 }
760
761 // Run each inference in its own thread
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100762 // start a timer
763 const auto start_time = armnn::GetTimeNow();
Jan Eilersf17fcd52021-07-26 22:20:00 +0100764 for (unsigned int i = 0; i < params.m_Iterations; ++i)
Sadik Armagana04a9d72021-04-27 10:02:10 +0100765 {
766 armnn::experimental::IWorkingMemHandle& workingMemHandleRef = *workingMemHandles[i].get();
Finn Williamsf364d532021-06-09 17:07:33 +0100767
Sadik Armagana04a9d72021-04-27 10:02:10 +0100768 inferenceResults.push_back(std::async(
769 std::launch::async, [&model, &workingMemHandleRef, &inputs, &outputs, i]() {
Finn Williamsf364d532021-06-09 17:07:33 +0100770 return model.RunAsync(workingMemHandleRef, inputs[i], outputs[i], i);
Sadik Armagana04a9d72021-04-27 10:02:10 +0100771 }
772 ));
773 }
774
775 // Check the results
776 for (unsigned int j = 0; j < inferenceResults.size(); ++j)
777 {
778 // Get the results
779 auto inferenceResult = inferenceResults[j].get();
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100780 auto inferenceDuration = std::get<1>(inferenceResult);
Sadik Armagana04a9d72021-04-27 10:02:10 +0100781 auto inferenceID = std::get<0>(inferenceResult);
782
783 if (params.m_GenerateTensorData)
784 {
785 ARMNN_LOG(warning) << "The input data was generated, note that the output will not be useful";
786 }
Jan Eilers284b5d12021-09-07 12:46:15 +0100787 if (params.m_DontPrintOutputs)
788 {
789 ARMNN_LOG(info) << "Printing outputs to console is disabled.";
790 }
Sadik Armagana04a9d72021-04-27 10:02:10 +0100791
792 // Print output tensors
793 const auto& infosOut = model.GetOutputBindingInfos();
794 for (size_t i = 0; i < numOutputs; i++)
795 {
Jan Eilersf17fcd52021-07-26 22:20:00 +0100796 // We've made sure before that the number of output files either equals numOutputs, in which
Jan Eilers284b5d12021-09-07 12:46:15 +0100797 // case we override those files when processing the results of each iteration (only the
798 // result of the last iteration will be stored), or there are enough
Jan Eilersf17fcd52021-07-26 22:20:00 +0100799 // output files for each output of each iteration.
800 size_t outputFileIndex = j * numOutputs + i;
801 if (!params.m_OutputTensorFiles.empty())
802 {
803 outputFileIndex = outputFileIndex % params.m_OutputTensorFiles.size();
804 ARMNN_LOG(info) << "Writing output " << i << " named: '"
805 << inferenceModelParams.m_OutputBindings[i]
806 << "' of iteration: " << j+1 << " to file: '"
807 << params.m_OutputTensorFiles[outputFileIndex] << "'";
808 }
Sadik Armagana04a9d72021-04-27 10:02:10 +0100809 const armnn::TensorInfo& infoOut = infosOut[i].second;
810 auto outputTensorFile = params.m_OutputTensorFiles.empty()
811 ? ""
Jan Eilersf17fcd52021-07-26 22:20:00 +0100812 : params.m_OutputTensorFiles[outputFileIndex];
Sadik Armagana04a9d72021-04-27 10:02:10 +0100813
814 TensorPrinter printer(inferenceModelParams.m_OutputBindings[i],
815 infoOut,
816 outputTensorFile,
Jan Eilers284b5d12021-09-07 12:46:15 +0100817 params.m_DequantizeOutput,
818 !params.m_DontPrintOutputs);
Sadik Armagana04a9d72021-04-27 10:02:10 +0100819 mapbox::util::apply_visitor(printer, outputs[j][i]);
820 }
Colm Donelan3cff15a2021-10-12 15:06:19 +0100821 CheckInferenceTimeThreshold(inferenceDuration, params.m_ThresholdTime);
Sadik Armagana04a9d72021-04-27 10:02:10 +0100822 ARMNN_LOG(info) << "Asynchronous Execution is finished for Inference ID: " << inferenceID << " \n";
Sadik Armagana04a9d72021-04-27 10:02:10 +0100823 }
Kevin Mayb4b3ac92021-05-21 16:42:21 +0100824 // finish timer
825 const auto duration = armnn::GetTimeDuration(start_time);
826 ARMNN_LOG(info) << "\nOverall Inference time: " << std::setprecision(2)
827 << std::fixed << duration.count() << " ms\n";
Sadik Armagana04a9d72021-04-27 10:02:10 +0100828 }
829 catch (const armnn::Exception& e)
830 {
831 ARMNN_LOG(fatal) << "Armnn Error: " << e.what();
832 return EXIT_FAILURE;
833 }
Jan Eilers45274902020-10-15 18:34:43 +0100834 }
835 }
836 catch (const armnn::Exception& e)
837 {
838 ARMNN_LOG(fatal) << "Armnn Error: " << e.what();
839 return EXIT_FAILURE;
840 }
841
842 return EXIT_SUCCESS;
843}
844
James Conroy7b4886f2019-04-11 10:23:58 +0100845// MAIN
telsoa01c577f2c2018-08-31 09:22:23 +0100846int main(int argc, const char* argv[])
847{
848 // Configures logging for both the ARMNN library and this test program.
Jan Eilers45274902020-10-15 18:34:43 +0100849 #ifdef NDEBUG
telsoa01c577f2c2018-08-31 09:22:23 +0100850 armnn::LogSeverity level = armnn::LogSeverity::Info;
Jan Eilers45274902020-10-15 18:34:43 +0100851 #else
telsoa01c577f2c2018-08-31 09:22:23 +0100852 armnn::LogSeverity level = armnn::LogSeverity::Debug;
Jan Eilers45274902020-10-15 18:34:43 +0100853 #endif
telsoa01c577f2c2018-08-31 09:22:23 +0100854 armnn::ConfigureLogging(true, true, level);
telsoa01c577f2c2018-08-31 09:22:23 +0100855
telsoa01c577f2c2018-08-31 09:22:23 +0100856
Jan Eilers45274902020-10-15 18:34:43 +0100857 // Get ExecuteNetwork parameters and runtime options from command line
Jan Eilersf17fcd52021-07-26 22:20:00 +0100858 // This might throw an InvalidArgumentException if the user provided invalid inputs
859 ProgramOptions ProgramOptions;
860 try {
861 ProgramOptions.ParseOptions(argc, argv);
862 } catch (const std::exception &e){
863 ARMNN_LOG(fatal) << e.what();
864 return EXIT_FAILURE;
865 }
Narumol Prangnawaratd8cc8112020-03-24 13:54:05 +0000866
Keith Davis4914d0c2021-08-18 17:14:05 +0100867 if ((ProgramOptions.m_ExNetParams.m_OutputDetailsToStdOut ||
868 ProgramOptions.m_ExNetParams.m_OutputDetailsOnlyToStdOut)
869 && !ProgramOptions.m_ExNetParams.m_EnableProfiling)
Keith Davisf4874862021-08-09 16:49:18 +0100870 {
871 ARMNN_LOG(fatal) << "You must enable profiling if you would like to output layer details";
872 return EXIT_FAILURE;
873 }
874
Finn Williamsd7fcafa2020-04-23 17:55:18 +0100875 // Create runtime
Jan Eilers45274902020-10-15 18:34:43 +0100876 std::shared_ptr<armnn::IRuntime> runtime(armnn::IRuntime::Create(ProgramOptions.m_RuntimeOptions));
Finn Williamsd7fcafa2020-04-23 17:55:18 +0100877
Jan Eilers45274902020-10-15 18:34:43 +0100878 std::string modelFormat = ProgramOptions.m_ExNetParams.m_ModelFormat;
879
880 // Forward to implementation based on the parser type
881 if (modelFormat.find("armnn") != std::string::npos)
Finn Williamsd7fcafa2020-04-23 17:55:18 +0100882 {
Jan Eilers45274902020-10-15 18:34:43 +0100883 #if defined(ARMNN_SERIALIZER)
884 return MainImpl<armnnDeserializer::IDeserializer, float>(ProgramOptions.m_ExNetParams, runtime);
885 #else
886 ARMNN_LOG(fatal) << "Not built with serialization support.";
Finn Williamsd7fcafa2020-04-23 17:55:18 +0100887 return EXIT_FAILURE;
Jan Eilers45274902020-10-15 18:34:43 +0100888 #endif
Finn Williamsd7fcafa2020-04-23 17:55:18 +0100889 }
Jan Eilers45274902020-10-15 18:34:43 +0100890 else if (modelFormat.find("onnx") != std::string::npos)
telsoa01c577f2c2018-08-31 09:22:23 +0100891 {
Jan Eilers45274902020-10-15 18:34:43 +0100892 #if defined(ARMNN_ONNX_PARSER)
893 return MainImpl<armnnOnnxParser::IOnnxParser, float>(ProgramOptions.m_ExNetParams, runtime);
894 #else
895 ARMNN_LOG(fatal) << "Not built with Onnx parser support.";
896 return EXIT_FAILURE;
897 #endif
898 }
Jan Eilers45274902020-10-15 18:34:43 +0100899 else if(modelFormat.find("tflite") != std::string::npos)
900 {
Finn Williamsf806c4d2021-02-22 15:13:12 +0000901 if (ProgramOptions.m_ExNetParams.m_TfLiteExecutor == ExecuteNetworkParams::TfLiteExecutor::ArmNNTfLiteParser)
902 {
903 #if defined(ARMNN_TF_LITE_PARSER)
904 return MainImpl<armnnTfLiteParser::ITfLiteParser, float>(ProgramOptions.m_ExNetParams, runtime);
905 #else
906 ARMNN_LOG(fatal) << "Not built with Tensorflow-Lite parser support.";
907 return EXIT_FAILURE;
908 #endif
909 }
910 else if (ProgramOptions.m_ExNetParams.m_TfLiteExecutor ==
911 ExecuteNetworkParams::TfLiteExecutor::ArmNNTfLiteDelegate ||
912 ProgramOptions.m_ExNetParams.m_TfLiteExecutor ==
913 ExecuteNetworkParams::TfLiteExecutor::TfliteInterpreter)
Sadik Armagan5d03e312020-11-17 16:43:56 +0000914 {
915 #if defined(ARMNN_TF_LITE_DELEGATE)
Colm Donelan45142282021-10-21 23:39:52 +0100916 return TfLiteDelegateMainImpl(ProgramOptions.m_ExNetParams, ProgramOptions.m_RuntimeOptions);
Sadik Armagan5d03e312020-11-17 16:43:56 +0000917 #else
Finn Williamsbbbefec2020-11-25 14:32:42 +0000918 ARMNN_LOG(fatal) << "Not built with Arm NN Tensorflow-Lite delegate support.";
Sadik Armagan5d03e312020-11-17 16:43:56 +0000919 return EXIT_FAILURE;
920 #endif
921 }
Jan Eilers45274902020-10-15 18:34:43 +0100922 }
923 else
924 {
925 ARMNN_LOG(fatal) << "Unknown model format: '" << modelFormat
Nikhil Raj5d955cf2021-04-19 16:59:48 +0100926 << "'. Please include 'tflite' or 'onnx'";
Jan Eilers45274902020-10-15 18:34:43 +0100927 return EXIT_FAILURE;
telsoa014fcda012018-03-09 14:13:49 +0000928 }
929}