blob: 04f6ddb72a2a520897915f028824249f13982a1f [file] [log] [blame]
Teresa Charlin83b42912022-07-07 14:24:59 +01001//
Mike Kelly5446a4d2023-01-20 15:51:05 +00002// Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved.
Teresa Charlin83b42912022-07-07 14:24:59 +01003// SPDX-License-Identifier: MIT
4//
5
Narumol Prangnawarat46e574e2023-05-05 16:39:05 +01006#if defined(ARMNN_TFLITE_OPAQUE_DELEGATE)
7#include <../delegate/opaque/include/armnn_delegate.hpp>
8#endif
9
10#include <tensorflow/lite/core/c/c_api.h>
Teresa Charlin83b42912022-07-07 14:24:59 +010011#include "TfliteExecutor.hpp"
Colm Donelan3811a972023-01-25 21:19:49 +000012#include "tensorflow/lite/kernels/kernel_util.h"
Teresa Charlin83b42912022-07-07 14:24:59 +010013
Colm Donelan35a06892023-02-06 15:01:57 +000014TfLiteExecutor::TfLiteExecutor(const ExecuteNetworkParams& params, armnn::IRuntime::CreationOptions runtimeOptions)
15 : m_Params(params)
Teresa Charlin83b42912022-07-07 14:24:59 +010016{
Teresa Charlinc814e802022-08-05 13:57:04 +010017 m_Model = tflite::FlatBufferModel::BuildFromFile(m_Params.m_ModelPath.c_str());
Colm Donelan18e6f042023-01-24 22:10:12 +000018 if (!m_Model)
19 {
20 LogAndThrow("Failed to load TfLite model from: " + m_Params.m_ModelPath);
21 }
Teresa Charlin83b42912022-07-07 14:24:59 +010022 m_TfLiteInterpreter = std::make_unique<Interpreter>();
23 tflite::ops::builtin::BuiltinOpResolver resolver;
24
Teresa Charlinc814e802022-08-05 13:57:04 +010025 tflite::InterpreterBuilder builder(*m_Model, resolver);
Colm Donelanf0755de2023-04-04 21:41:29 +010026 if (builder(&m_TfLiteInterpreter) != kTfLiteOk)
27 {
28 LogAndThrow("Error loading the model into the TfLiteInterpreter.");
29 }
30 if (m_TfLiteInterpreter->AllocateTensors() != kTfLiteOk)
31 {
32 LogAndThrow("Failed to allocate tensors in the TfLiteInterpreter.");
33 }
Narumol Prangnawarat46e574e2023-05-05 16:39:05 +010034
35 if (m_Params.m_TfLiteExecutor == ExecuteNetworkParams::TfLiteExecutor::ArmNNTfLiteOpaqueDelegate)
Teresa Charlin83b42912022-07-07 14:24:59 +010036 {
Narumol Prangnawarat46e574e2023-05-05 16:39:05 +010037#if defined(ARMNN_TFLITE_OPAQUE_DELEGATE)
38 // Use default settings until options have been enabled
39 flatbuffers::FlatBufferBuilder flatBufferBuilder;
40 TFLiteSettingsBuilder tfliteSettingsBuilder(flatBufferBuilder);
41 flatbuffers::Offset<TFLiteSettings> tfliteSettings = tfliteSettingsBuilder.Finish();
42 flatBufferBuilder.Finish(tfliteSettings);
43 const TFLiteSettings* settings =
44 flatbuffers::GetRoot<TFLiteSettings>(flatBufferBuilder.GetBufferPointer());
45
46 std::unique_ptr<delegates::DelegatePluginInterface> delegatePlugIn =
47 delegates::DelegatePluginRegistry::CreateByName("armnn_delegate", *settings);
48
49 // Create Armnn Opaque Delegate from Armnn Delegate Plugin
50 delegates::TfLiteDelegatePtr armnnDelegate = delegatePlugIn->Create();
51
52 // Add Delegate to the builder
53 builder.AddDelegate(armnnDelegate.get());
54#else
55 LogAndThrow("Not built with Arm NN Tensorflow-Lite opaque delegate support.");
56#endif
57 }
58 else if (m_Params.m_TfLiteExecutor == ExecuteNetworkParams::TfLiteExecutor::ArmNNTfLiteDelegate)
59 {
60#if defined(ARMNN_TFLITE_DELEGATE)
Teresa Charlin83b42912022-07-07 14:24:59 +010061 // Create the Armnn Delegate
62 // Populate a DelegateOptions from the ExecuteNetworkParams.
63 armnnDelegate::DelegateOptions delegateOptions = m_Params.ToDelegateOptions();
Colm Donelan35a06892023-02-06 15:01:57 +000064 delegateOptions.SetRuntimeOptions(runtimeOptions);
Teresa Charlin83b42912022-07-07 14:24:59 +010065 std::unique_ptr<TfLiteDelegate, decltype(&armnnDelegate::TfLiteArmnnDelegateDelete)>
66 theArmnnDelegate(armnnDelegate::TfLiteArmnnDelegateCreate(delegateOptions),
67 armnnDelegate::TfLiteArmnnDelegateDelete);
68 // Register armnn_delegate to TfLiteInterpreter
Colm Donelanf0755de2023-04-04 21:41:29 +010069 if (m_TfLiteInterpreter->ModifyGraphWithDelegate(std::move(theArmnnDelegate)) != kTfLiteOk)
Teresa Charlin83b42912022-07-07 14:24:59 +010070 {
Colm Donelanf0755de2023-04-04 21:41:29 +010071 LogAndThrow("Could not register ArmNN TfLite Delegate to TfLiteInterpreter.");
Teresa Charlin83b42912022-07-07 14:24:59 +010072 }
Narumol Prangnawarat46e574e2023-05-05 16:39:05 +010073#else
74 LogAndThrow("Not built with Arm NN Tensorflow-Lite delegate support.");
75#endif
Teresa Charlin83b42912022-07-07 14:24:59 +010076 }
77 else
78 {
79 std::cout << "Running on TfLite without ArmNN delegate\n";
80 }
81
Teresa Charlinf53b28f2022-11-11 11:14:50 +000082 const size_t numInputs = m_TfLiteInterpreter->inputs().size();
Teresa Charlin83b42912022-07-07 14:24:59 +010083
84 for(unsigned int inputIndex = 0; inputIndex < numInputs; ++inputIndex)
85 {
Cathal Corbettaa212302022-08-04 17:58:09 +010086 armnn::Optional<std::string> dataFile = m_Params.m_GenerateTensorData
87 ? armnn::EmptyOptional()
88 : armnn::MakeOptional<std::string>(m_Params.m_InputTensorDataFilePaths[inputIndex]);
89
Teresa Charlin83b42912022-07-07 14:24:59 +010090 int input = m_TfLiteInterpreter->inputs()[inputIndex];
Cathal Corbettaa212302022-08-04 17:58:09 +010091 const auto& inputName = m_TfLiteInterpreter->tensor(input)->name;
Teresa Charlin83b42912022-07-07 14:24:59 +010092
Colm Donelan3811a972023-01-25 21:19:49 +000093 // Before we start, check if the tensor is constant.
94 if (!tflite::IsConstantTensor(m_TfLiteInterpreter->tensor(input)))
Teresa Charlin83b42912022-07-07 14:24:59 +010095 {
Colm Donelan3811a972023-01-25 21:19:49 +000096 TfLiteIntArray* inputDims = m_TfLiteInterpreter->tensor(input)->dims;
97
98 unsigned int inputSize = 1;
99 for (unsigned int dim = 0; dim < static_cast<unsigned int>(inputDims->size); ++dim)
Teresa Charlin83b42912022-07-07 14:24:59 +0100100 {
Colm Donelan3811a972023-01-25 21:19:49 +0000101 inputSize *= inputDims->data[dim];
Teresa Charlin83b42912022-07-07 14:24:59 +0100102 }
Colm Donelan3811a972023-01-25 21:19:49 +0000103
104 const auto& dataType = m_TfLiteInterpreter->tensor(input)->type;
105
106 switch (dataType)
Teresa Charlin83b42912022-07-07 14:24:59 +0100107 {
Colm Donelan3811a972023-01-25 21:19:49 +0000108 case kTfLiteFloat32:
109 {
110 auto inputData = m_TfLiteInterpreter->typed_tensor<float>(input);
111 PopulateTensorWithData<float>(inputData, inputSize, dataFile, inputName);
112 break;
113 }
114 case kTfLiteInt32:
115 {
116 auto inputData = m_TfLiteInterpreter->typed_tensor<int32_t>(input);
117 PopulateTensorWithData<int32_t>(inputData, inputSize, dataFile, inputName);
118 break;
119 }
120 case kTfLiteUInt8:
121 {
122 auto inputData = m_TfLiteInterpreter->typed_tensor<uint8_t>(input);
123 PopulateTensorWithData<uint8_t>(inputData, inputSize, dataFile, inputName);
124 break;
125 }
126 case kTfLiteInt16:
127 {
128 auto inputData = m_TfLiteInterpreter->typed_tensor<int16_t>(input);
129 PopulateTensorWithData<int16_t>(inputData, inputSize, dataFile, inputName);
130 break;
131 }
132 case kTfLiteInt8:
133 {
134 auto inputData = m_TfLiteInterpreter->typed_tensor<int8_t>(input);
135 PopulateTensorWithData<int8_t>(inputData, inputSize, dataFile, inputName);
136 break;
137 }
138 default:
139 {
140 LogAndThrow("Unsupported input tensor data type");
141 }
Teresa Charlin83b42912022-07-07 14:24:59 +0100142 }
Colm Donelan3811a972023-01-25 21:19:49 +0000143 }
144 else
145 {
146 ARMNN_LOG(info) << "Input tensor \"" << inputName << "\" is constant and will not be populated with data.";
Teresa Charlin83b42912022-07-07 14:24:59 +0100147 }
148 }
149}
150
151std::vector<const void *> TfLiteExecutor::Execute()
152{
153 int status = 0;
154 std::vector<const void*> results;
155 for (size_t x = 0; x < m_Params.m_Iterations; x++)
156 {
157 // Start timer to record inference time in milliseconds.
158 const auto start_time = armnn::GetTimeNow();
159 // Run the inference
160 status = m_TfLiteInterpreter->Invoke();
161 const auto duration = armnn::GetTimeDuration(start_time);
162
Kevin May2fef6f62022-11-14 17:07:49 +0000163 if (!m_Params.m_DontPrintOutputs)
Teresa Charlin83b42912022-07-07 14:24:59 +0100164 {
Kevin May2fef6f62022-11-14 17:07:49 +0000165 // Print out the output
166 for (unsigned int outputIndex = 0; outputIndex < m_TfLiteInterpreter->outputs().size(); ++outputIndex)
Teresa Charlin83b42912022-07-07 14:24:59 +0100167 {
Kevin May2fef6f62022-11-14 17:07:49 +0000168 auto tfLiteDelegateOutputId = m_TfLiteInterpreter->outputs()[outputIndex];
169 TfLiteIntArray* outputDims = m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->dims;
170 // If we've been asked to write to a file then set a file output stream. Otherwise use stdout.
171 FILE* outputTensorFile = stdout;
172 if (!m_Params.m_OutputTensorFiles.empty())
Teresa Charlin83b42912022-07-07 14:24:59 +0100173 {
Kevin May2fef6f62022-11-14 17:07:49 +0000174 outputTensorFile = fopen(m_Params.m_OutputTensorFiles[outputIndex].c_str(), "w");
175 if (outputTensorFile == NULL)
176 {
177 LogAndThrow("Specified output tensor file, \"" + m_Params.m_OutputTensorFiles[outputIndex] +
178 "\", cannot be created. Defaulting to stdout. Error was: " + std::strerror(errno));
179 }
180 else
181 {
182 ARMNN_LOG(info) << "Writing output " << outputIndex << "' of iteration: " << x + 1
183 << " to file: '" << m_Params.m_OutputTensorFiles[outputIndex] << "'";
184 }
Teresa Charlin83b42912022-07-07 14:24:59 +0100185 }
Kevin May2fef6f62022-11-14 17:07:49 +0000186 long outputSize = 1;
187 for (unsigned int dim = 0; dim < static_cast<unsigned int>(outputDims->size); ++dim)
Teresa Charlin83b42912022-07-07 14:24:59 +0100188 {
Kevin May2fef6f62022-11-14 17:07:49 +0000189 outputSize *= outputDims->data[dim];
Teresa Charlin83b42912022-07-07 14:24:59 +0100190 }
Kevin May2fef6f62022-11-14 17:07:49 +0000191
192 std::cout << m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->name << ": ";
193 results.push_back(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation);
194
195 switch (m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->type)
196 {
197
198 case kTfLiteFloat32:
199 {
200 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<float>(
201 tfLiteDelegateOutputId);
202
203 for (int i = 0; i < outputSize; ++i)
204 {
205 fprintf(outputTensorFile, "%f ", tfLiteDelegateOutputData[i]);
206 }
207 break;
208 }
209 case kTfLiteInt32:
210 {
211 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<int32_t>(
212 tfLiteDelegateOutputId);
213 for (int i = 0; i < outputSize; ++i)
214 {
215 fprintf(outputTensorFile, "%d ", tfLiteDelegateOutputData[i]);
216 }
217 break;
218 }
219 case kTfLiteUInt8:
220 {
221 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<uint8_t>(
222 tfLiteDelegateOutputId);
223 for (int i = 0; i < outputSize; ++i)
224 {
225 fprintf(outputTensorFile, "%u ", tfLiteDelegateOutputData[i]);
226 }
227 break;
228 }
229 case kTfLiteInt8:
230 {
231 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<int8_t>(
232 tfLiteDelegateOutputId);
233 for (int i = 0; i < outputSize; ++i)
234 {
235 fprintf(outputTensorFile, "%d ", tfLiteDelegateOutputData[i]);
236 }
237 break;
238 }
Ryan OShea39831da2023-01-26 17:43:45 +0000239 case kTfLiteBool:
240 {
241 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<bool>(
242 tfLiteDelegateOutputId);
243 for (int i = 0; i < outputSize; ++i) {
244 fprintf(outputTensorFile, "%u ", tfLiteDelegateOutputData[i]);
245 }
246 break;
247 }
Kevin May2fef6f62022-11-14 17:07:49 +0000248 default:
249 {
250 LogAndThrow("Unsupported output type");
251 }
252 }
253
254 std::cout << std::endl;
Teresa Charlin83b42912022-07-07 14:24:59 +0100255 }
Teresa Charlin83b42912022-07-07 14:24:59 +0100256 }
257 CheckInferenceTimeThreshold(duration, m_Params.m_ThresholdTime);
258 }
259
260 std::cout << status;
261 return results;
262}
263
264void TfLiteExecutor::CompareAndPrintResult(std::vector<const void*> otherOutput)
265{
266 for (unsigned int outputIndex = 0; outputIndex < m_TfLiteInterpreter->outputs().size(); ++outputIndex)
267 {
268 auto tfLiteDelegateOutputId = m_TfLiteInterpreter->outputs()[outputIndex];
Colm Doneland0472622023-03-06 12:34:54 +0000269 size_t size = m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->bytes;
270 double result = ComputeByteLevelRMSE(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation,
271 otherOutput[outputIndex], size);
272 std::cout << "Byte level root mean square error: " << result << "\n";
Teresa Charlin83b42912022-07-07 14:24:59 +0100273 }
274};