blob: 64556504043ad372f64108717659d47e8f6d52af [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);
Narumol Prangnawarat46e574e2023-05-05 16:39:05 +010026
27 if (m_Params.m_TfLiteExecutor == ExecuteNetworkParams::TfLiteExecutor::ArmNNTfLiteOpaqueDelegate)
Teresa Charlin83b42912022-07-07 14:24:59 +010028 {
Narumol Prangnawarat46e574e2023-05-05 16:39:05 +010029#if defined(ARMNN_TFLITE_OPAQUE_DELEGATE)
30 // Use default settings until options have been enabled
31 flatbuffers::FlatBufferBuilder flatBufferBuilder;
32 TFLiteSettingsBuilder tfliteSettingsBuilder(flatBufferBuilder);
33 flatbuffers::Offset<TFLiteSettings> tfliteSettings = tfliteSettingsBuilder.Finish();
34 flatBufferBuilder.Finish(tfliteSettings);
35 const TFLiteSettings* settings =
36 flatbuffers::GetRoot<TFLiteSettings>(flatBufferBuilder.GetBufferPointer());
37
38 std::unique_ptr<delegates::DelegatePluginInterface> delegatePlugIn =
39 delegates::DelegatePluginRegistry::CreateByName("armnn_delegate", *settings);
40
41 // Create Armnn Opaque Delegate from Armnn Delegate Plugin
42 delegates::TfLiteDelegatePtr armnnDelegate = delegatePlugIn->Create();
43
44 // Add Delegate to the builder
45 builder.AddDelegate(armnnDelegate.get());
Narumol Prangnawaratfe1827d2023-05-09 16:01:12 +010046 if (builder(&m_TfLiteInterpreter) != kTfLiteOk)
47 {
48 LogAndThrow("Error loading the model into the TfLiteInterpreter.");
49 }
50
Narumol Prangnawarat46e574e2023-05-05 16:39:05 +010051#else
52 LogAndThrow("Not built with Arm NN Tensorflow-Lite opaque delegate support.");
53#endif
54 }
55 else if (m_Params.m_TfLiteExecutor == ExecuteNetworkParams::TfLiteExecutor::ArmNNTfLiteDelegate)
56 {
57#if defined(ARMNN_TFLITE_DELEGATE)
Narumol Prangnawaratfe1827d2023-05-09 16:01:12 +010058 if (builder(&m_TfLiteInterpreter) != kTfLiteOk)
59 {
60 LogAndThrow("Error loading the model into the TfLiteInterpreter.");
61 }
Teresa Charlin83b42912022-07-07 14:24:59 +010062 // Create the Armnn Delegate
63 // Populate a DelegateOptions from the ExecuteNetworkParams.
64 armnnDelegate::DelegateOptions delegateOptions = m_Params.ToDelegateOptions();
Colm Donelan35a06892023-02-06 15:01:57 +000065 delegateOptions.SetRuntimeOptions(runtimeOptions);
Teresa Charlin83b42912022-07-07 14:24:59 +010066 std::unique_ptr<TfLiteDelegate, decltype(&armnnDelegate::TfLiteArmnnDelegateDelete)>
67 theArmnnDelegate(armnnDelegate::TfLiteArmnnDelegateCreate(delegateOptions),
68 armnnDelegate::TfLiteArmnnDelegateDelete);
69 // Register armnn_delegate to TfLiteInterpreter
Colm Donelanf0755de2023-04-04 21:41:29 +010070 if (m_TfLiteInterpreter->ModifyGraphWithDelegate(std::move(theArmnnDelegate)) != kTfLiteOk)
Teresa Charlin83b42912022-07-07 14:24:59 +010071 {
Colm Donelanf0755de2023-04-04 21:41:29 +010072 LogAndThrow("Could not register ArmNN TfLite Delegate to TfLiteInterpreter.");
Teresa Charlin83b42912022-07-07 14:24:59 +010073 }
Narumol Prangnawarat46e574e2023-05-05 16:39:05 +010074#else
75 LogAndThrow("Not built with Arm NN Tensorflow-Lite delegate support.");
76#endif
Teresa Charlin83b42912022-07-07 14:24:59 +010077 }
78 else
79 {
Narumol Prangnawarate6b0e902023-06-08 12:22:57 +010080 if (builder(&m_TfLiteInterpreter) != kTfLiteOk)
81 {
82 LogAndThrow("Error loading the model into the TfLiteInterpreter.");
83 }
Teresa Charlin83b42912022-07-07 14:24:59 +010084 std::cout << "Running on TfLite without ArmNN delegate\n";
85 }
86
Narumol Prangnawaratfe1827d2023-05-09 16:01:12 +010087 if (m_TfLiteInterpreter->AllocateTensors() != kTfLiteOk)
88 {
89 LogAndThrow("Failed to allocate tensors in the TfLiteInterpreter.");
90 }
91
Teresa Charlinf53b28f2022-11-11 11:14:50 +000092 const size_t numInputs = m_TfLiteInterpreter->inputs().size();
Teresa Charlin83b42912022-07-07 14:24:59 +010093
94 for(unsigned int inputIndex = 0; inputIndex < numInputs; ++inputIndex)
95 {
Cathal Corbettaa212302022-08-04 17:58:09 +010096 armnn::Optional<std::string> dataFile = m_Params.m_GenerateTensorData
97 ? armnn::EmptyOptional()
98 : armnn::MakeOptional<std::string>(m_Params.m_InputTensorDataFilePaths[inputIndex]);
99
Teresa Charlin83b42912022-07-07 14:24:59 +0100100 int input = m_TfLiteInterpreter->inputs()[inputIndex];
Cathal Corbettaa212302022-08-04 17:58:09 +0100101 const auto& inputName = m_TfLiteInterpreter->tensor(input)->name;
Teresa Charlin83b42912022-07-07 14:24:59 +0100102
Colm Donelan3811a972023-01-25 21:19:49 +0000103 // Before we start, check if the tensor is constant.
104 if (!tflite::IsConstantTensor(m_TfLiteInterpreter->tensor(input)))
Teresa Charlin83b42912022-07-07 14:24:59 +0100105 {
Colm Donelan3811a972023-01-25 21:19:49 +0000106 TfLiteIntArray* inputDims = m_TfLiteInterpreter->tensor(input)->dims;
107
108 unsigned int inputSize = 1;
109 for (unsigned int dim = 0; dim < static_cast<unsigned int>(inputDims->size); ++dim)
Teresa Charlin83b42912022-07-07 14:24:59 +0100110 {
Colm Donelan3811a972023-01-25 21:19:49 +0000111 inputSize *= inputDims->data[dim];
Teresa Charlin83b42912022-07-07 14:24:59 +0100112 }
Colm Donelan3811a972023-01-25 21:19:49 +0000113
114 const auto& dataType = m_TfLiteInterpreter->tensor(input)->type;
115
116 switch (dataType)
Teresa Charlin83b42912022-07-07 14:24:59 +0100117 {
Colm Donelan3811a972023-01-25 21:19:49 +0000118 case kTfLiteFloat32:
119 {
120 auto inputData = m_TfLiteInterpreter->typed_tensor<float>(input);
121 PopulateTensorWithData<float>(inputData, inputSize, dataFile, inputName);
122 break;
123 }
124 case kTfLiteInt32:
125 {
126 auto inputData = m_TfLiteInterpreter->typed_tensor<int32_t>(input);
127 PopulateTensorWithData<int32_t>(inputData, inputSize, dataFile, inputName);
128 break;
129 }
130 case kTfLiteUInt8:
131 {
132 auto inputData = m_TfLiteInterpreter->typed_tensor<uint8_t>(input);
133 PopulateTensorWithData<uint8_t>(inputData, inputSize, dataFile, inputName);
134 break;
135 }
136 case kTfLiteInt16:
137 {
138 auto inputData = m_TfLiteInterpreter->typed_tensor<int16_t>(input);
139 PopulateTensorWithData<int16_t>(inputData, inputSize, dataFile, inputName);
140 break;
141 }
142 case kTfLiteInt8:
143 {
144 auto inputData = m_TfLiteInterpreter->typed_tensor<int8_t>(input);
145 PopulateTensorWithData<int8_t>(inputData, inputSize, dataFile, inputName);
146 break;
147 }
148 default:
149 {
150 LogAndThrow("Unsupported input tensor data type");
151 }
Teresa Charlin83b42912022-07-07 14:24:59 +0100152 }
Colm Donelan3811a972023-01-25 21:19:49 +0000153 }
154 else
155 {
156 ARMNN_LOG(info) << "Input tensor \"" << inputName << "\" is constant and will not be populated with data.";
Teresa Charlin83b42912022-07-07 14:24:59 +0100157 }
158 }
159}
160
161std::vector<const void *> TfLiteExecutor::Execute()
162{
163 int status = 0;
164 std::vector<const void*> results;
165 for (size_t x = 0; x < m_Params.m_Iterations; x++)
166 {
167 // Start timer to record inference time in milliseconds.
168 const auto start_time = armnn::GetTimeNow();
169 // Run the inference
170 status = m_TfLiteInterpreter->Invoke();
171 const auto duration = armnn::GetTimeDuration(start_time);
172
Kevin May2fef6f62022-11-14 17:07:49 +0000173 if (!m_Params.m_DontPrintOutputs)
Teresa Charlin83b42912022-07-07 14:24:59 +0100174 {
Kevin May2fef6f62022-11-14 17:07:49 +0000175 // Print out the output
176 for (unsigned int outputIndex = 0; outputIndex < m_TfLiteInterpreter->outputs().size(); ++outputIndex)
Teresa Charlin83b42912022-07-07 14:24:59 +0100177 {
Kevin May2fef6f62022-11-14 17:07:49 +0000178 auto tfLiteDelegateOutputId = m_TfLiteInterpreter->outputs()[outputIndex];
179 TfLiteIntArray* outputDims = m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->dims;
180 // If we've been asked to write to a file then set a file output stream. Otherwise use stdout.
181 FILE* outputTensorFile = stdout;
182 if (!m_Params.m_OutputTensorFiles.empty())
Teresa Charlin83b42912022-07-07 14:24:59 +0100183 {
Kevin May2fef6f62022-11-14 17:07:49 +0000184 outputTensorFile = fopen(m_Params.m_OutputTensorFiles[outputIndex].c_str(), "w");
185 if (outputTensorFile == NULL)
186 {
187 LogAndThrow("Specified output tensor file, \"" + m_Params.m_OutputTensorFiles[outputIndex] +
188 "\", cannot be created. Defaulting to stdout. Error was: " + std::strerror(errno));
189 }
190 else
191 {
192 ARMNN_LOG(info) << "Writing output " << outputIndex << "' of iteration: " << x + 1
193 << " to file: '" << m_Params.m_OutputTensorFiles[outputIndex] << "'";
194 }
Teresa Charlin83b42912022-07-07 14:24:59 +0100195 }
Kevin May2fef6f62022-11-14 17:07:49 +0000196 long outputSize = 1;
197 for (unsigned int dim = 0; dim < static_cast<unsigned int>(outputDims->size); ++dim)
Teresa Charlin83b42912022-07-07 14:24:59 +0100198 {
Kevin May2fef6f62022-11-14 17:07:49 +0000199 outputSize *= outputDims->data[dim];
Teresa Charlin83b42912022-07-07 14:24:59 +0100200 }
Kevin May2fef6f62022-11-14 17:07:49 +0000201
202 std::cout << m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->name << ": ";
203 results.push_back(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation);
204
205 switch (m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->type)
206 {
207
208 case kTfLiteFloat32:
209 {
210 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<float>(
211 tfLiteDelegateOutputId);
212
213 for (int i = 0; i < outputSize; ++i)
214 {
215 fprintf(outputTensorFile, "%f ", tfLiteDelegateOutputData[i]);
216 }
217 break;
218 }
219 case kTfLiteInt32:
220 {
221 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<int32_t>(
222 tfLiteDelegateOutputId);
223 for (int i = 0; i < outputSize; ++i)
224 {
225 fprintf(outputTensorFile, "%d ", tfLiteDelegateOutputData[i]);
226 }
227 break;
228 }
229 case kTfLiteUInt8:
230 {
231 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<uint8_t>(
232 tfLiteDelegateOutputId);
233 for (int i = 0; i < outputSize; ++i)
234 {
235 fprintf(outputTensorFile, "%u ", tfLiteDelegateOutputData[i]);
236 }
237 break;
238 }
239 case kTfLiteInt8:
240 {
241 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<int8_t>(
242 tfLiteDelegateOutputId);
243 for (int i = 0; i < outputSize; ++i)
244 {
245 fprintf(outputTensorFile, "%d ", tfLiteDelegateOutputData[i]);
246 }
247 break;
248 }
Ryan OShea39831da2023-01-26 17:43:45 +0000249 case kTfLiteBool:
250 {
251 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<bool>(
252 tfLiteDelegateOutputId);
253 for (int i = 0; i < outputSize; ++i) {
254 fprintf(outputTensorFile, "%u ", tfLiteDelegateOutputData[i]);
255 }
256 break;
257 }
Kevin May2fef6f62022-11-14 17:07:49 +0000258 default:
259 {
260 LogAndThrow("Unsupported output type");
261 }
262 }
263
264 std::cout << std::endl;
Teresa Charlin83b42912022-07-07 14:24:59 +0100265 }
Teresa Charlin83b42912022-07-07 14:24:59 +0100266 }
267 CheckInferenceTimeThreshold(duration, m_Params.m_ThresholdTime);
268 }
269
270 std::cout << status;
271 return results;
272}
273
274void TfLiteExecutor::CompareAndPrintResult(std::vector<const void*> otherOutput)
275{
276 for (unsigned int outputIndex = 0; outputIndex < m_TfLiteInterpreter->outputs().size(); ++outputIndex)
277 {
278 auto tfLiteDelegateOutputId = m_TfLiteInterpreter->outputs()[outputIndex];
Colm Doneland0472622023-03-06 12:34:54 +0000279 size_t size = m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->bytes;
280 double result = ComputeByteLevelRMSE(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation,
281 otherOutput[outputIndex], size);
282 std::cout << "Byte level root mean square error: " << result << "\n";
Teresa Charlin83b42912022-07-07 14:24:59 +0100283 }
284};