blob: f365623d6233ae804625c1ab52054900868ec4a9 [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
6#include "TfliteExecutor.hpp"
Colm Donelan3811a972023-01-25 21:19:49 +00007#include "tensorflow/lite/kernels/kernel_util.h"
Teresa Charlin83b42912022-07-07 14:24:59 +01008
Colm Donelan35a06892023-02-06 15:01:57 +00009TfLiteExecutor::TfLiteExecutor(const ExecuteNetworkParams& params, armnn::IRuntime::CreationOptions runtimeOptions)
10 : m_Params(params)
Teresa Charlin83b42912022-07-07 14:24:59 +010011{
Teresa Charlinc814e802022-08-05 13:57:04 +010012 m_Model = tflite::FlatBufferModel::BuildFromFile(m_Params.m_ModelPath.c_str());
Colm Donelan18e6f042023-01-24 22:10:12 +000013 if (!m_Model)
14 {
15 LogAndThrow("Failed to load TfLite model from: " + m_Params.m_ModelPath);
16 }
Teresa Charlin83b42912022-07-07 14:24:59 +010017 m_TfLiteInterpreter = std::make_unique<Interpreter>();
18 tflite::ops::builtin::BuiltinOpResolver resolver;
19
Teresa Charlinc814e802022-08-05 13:57:04 +010020 tflite::InterpreterBuilder builder(*m_Model, resolver);
Teresa Charlin83b42912022-07-07 14:24:59 +010021 builder(&m_TfLiteInterpreter);
22 m_TfLiteInterpreter->AllocateTensors();
23
24 int status = kTfLiteError;
25 if (m_Params.m_TfLiteExecutor == ExecuteNetworkParams::TfLiteExecutor::ArmNNTfLiteDelegate)
26 {
27 // Create the Armnn Delegate
28 // Populate a DelegateOptions from the ExecuteNetworkParams.
29 armnnDelegate::DelegateOptions delegateOptions = m_Params.ToDelegateOptions();
Colm Donelan35a06892023-02-06 15:01:57 +000030 delegateOptions.SetRuntimeOptions(runtimeOptions);
Teresa Charlin83b42912022-07-07 14:24:59 +010031 std::unique_ptr<TfLiteDelegate, decltype(&armnnDelegate::TfLiteArmnnDelegateDelete)>
32 theArmnnDelegate(armnnDelegate::TfLiteArmnnDelegateCreate(delegateOptions),
33 armnnDelegate::TfLiteArmnnDelegateDelete);
34 // Register armnn_delegate to TfLiteInterpreter
35 status = m_TfLiteInterpreter->ModifyGraphWithDelegate(std::move(theArmnnDelegate));
Cathal Corbettaa212302022-08-04 17:58:09 +010036 if (status != kTfLiteOk)
Teresa Charlin83b42912022-07-07 14:24:59 +010037 {
38 LogAndThrow("Could not register ArmNN TfLite Delegate to TfLiteInterpreter");
39 }
40 }
41 else
42 {
43 std::cout << "Running on TfLite without ArmNN delegate\n";
44 }
45
Teresa Charlinf53b28f2022-11-11 11:14:50 +000046 const size_t numInputs = m_TfLiteInterpreter->inputs().size();
Teresa Charlin83b42912022-07-07 14:24:59 +010047
48 for(unsigned int inputIndex = 0; inputIndex < numInputs; ++inputIndex)
49 {
Cathal Corbettaa212302022-08-04 17:58:09 +010050 armnn::Optional<std::string> dataFile = m_Params.m_GenerateTensorData
51 ? armnn::EmptyOptional()
52 : armnn::MakeOptional<std::string>(m_Params.m_InputTensorDataFilePaths[inputIndex]);
53
Teresa Charlin83b42912022-07-07 14:24:59 +010054 int input = m_TfLiteInterpreter->inputs()[inputIndex];
Cathal Corbettaa212302022-08-04 17:58:09 +010055 const auto& inputName = m_TfLiteInterpreter->tensor(input)->name;
Teresa Charlin83b42912022-07-07 14:24:59 +010056
Colm Donelan3811a972023-01-25 21:19:49 +000057 // Before we start, check if the tensor is constant.
58 if (!tflite::IsConstantTensor(m_TfLiteInterpreter->tensor(input)))
Teresa Charlin83b42912022-07-07 14:24:59 +010059 {
Colm Donelan3811a972023-01-25 21:19:49 +000060 TfLiteIntArray* inputDims = m_TfLiteInterpreter->tensor(input)->dims;
61
62 unsigned int inputSize = 1;
63 for (unsigned int dim = 0; dim < static_cast<unsigned int>(inputDims->size); ++dim)
Teresa Charlin83b42912022-07-07 14:24:59 +010064 {
Colm Donelan3811a972023-01-25 21:19:49 +000065 inputSize *= inputDims->data[dim];
Teresa Charlin83b42912022-07-07 14:24:59 +010066 }
Colm Donelan3811a972023-01-25 21:19:49 +000067
68 const auto& dataType = m_TfLiteInterpreter->tensor(input)->type;
69
70 switch (dataType)
Teresa Charlin83b42912022-07-07 14:24:59 +010071 {
Colm Donelan3811a972023-01-25 21:19:49 +000072 case kTfLiteFloat32:
73 {
74 auto inputData = m_TfLiteInterpreter->typed_tensor<float>(input);
75 PopulateTensorWithData<float>(inputData, inputSize, dataFile, inputName);
76 break;
77 }
78 case kTfLiteInt32:
79 {
80 auto inputData = m_TfLiteInterpreter->typed_tensor<int32_t>(input);
81 PopulateTensorWithData<int32_t>(inputData, inputSize, dataFile, inputName);
82 break;
83 }
84 case kTfLiteUInt8:
85 {
86 auto inputData = m_TfLiteInterpreter->typed_tensor<uint8_t>(input);
87 PopulateTensorWithData<uint8_t>(inputData, inputSize, dataFile, inputName);
88 break;
89 }
90 case kTfLiteInt16:
91 {
92 auto inputData = m_TfLiteInterpreter->typed_tensor<int16_t>(input);
93 PopulateTensorWithData<int16_t>(inputData, inputSize, dataFile, inputName);
94 break;
95 }
96 case kTfLiteInt8:
97 {
98 auto inputData = m_TfLiteInterpreter->typed_tensor<int8_t>(input);
99 PopulateTensorWithData<int8_t>(inputData, inputSize, dataFile, inputName);
100 break;
101 }
102 default:
103 {
104 LogAndThrow("Unsupported input tensor data type");
105 }
Teresa Charlin83b42912022-07-07 14:24:59 +0100106 }
Colm Donelan3811a972023-01-25 21:19:49 +0000107 }
108 else
109 {
110 ARMNN_LOG(info) << "Input tensor \"" << inputName << "\" is constant and will not be populated with data.";
Teresa Charlin83b42912022-07-07 14:24:59 +0100111 }
112 }
113}
114
115std::vector<const void *> TfLiteExecutor::Execute()
116{
117 int status = 0;
118 std::vector<const void*> results;
119 for (size_t x = 0; x < m_Params.m_Iterations; x++)
120 {
121 // Start timer to record inference time in milliseconds.
122 const auto start_time = armnn::GetTimeNow();
123 // Run the inference
124 status = m_TfLiteInterpreter->Invoke();
125 const auto duration = armnn::GetTimeDuration(start_time);
126
Kevin May2fef6f62022-11-14 17:07:49 +0000127 if (!m_Params.m_DontPrintOutputs)
Teresa Charlin83b42912022-07-07 14:24:59 +0100128 {
Kevin May2fef6f62022-11-14 17:07:49 +0000129 // Print out the output
130 for (unsigned int outputIndex = 0; outputIndex < m_TfLiteInterpreter->outputs().size(); ++outputIndex)
Teresa Charlin83b42912022-07-07 14:24:59 +0100131 {
Kevin May2fef6f62022-11-14 17:07:49 +0000132 auto tfLiteDelegateOutputId = m_TfLiteInterpreter->outputs()[outputIndex];
133 TfLiteIntArray* outputDims = m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->dims;
134 // If we've been asked to write to a file then set a file output stream. Otherwise use stdout.
135 FILE* outputTensorFile = stdout;
136 if (!m_Params.m_OutputTensorFiles.empty())
Teresa Charlin83b42912022-07-07 14:24:59 +0100137 {
Kevin May2fef6f62022-11-14 17:07:49 +0000138 outputTensorFile = fopen(m_Params.m_OutputTensorFiles[outputIndex].c_str(), "w");
139 if (outputTensorFile == NULL)
140 {
141 LogAndThrow("Specified output tensor file, \"" + m_Params.m_OutputTensorFiles[outputIndex] +
142 "\", cannot be created. Defaulting to stdout. Error was: " + std::strerror(errno));
143 }
144 else
145 {
146 ARMNN_LOG(info) << "Writing output " << outputIndex << "' of iteration: " << x + 1
147 << " to file: '" << m_Params.m_OutputTensorFiles[outputIndex] << "'";
148 }
Teresa Charlin83b42912022-07-07 14:24:59 +0100149 }
Kevin May2fef6f62022-11-14 17:07:49 +0000150 long outputSize = 1;
151 for (unsigned int dim = 0; dim < static_cast<unsigned int>(outputDims->size); ++dim)
Teresa Charlin83b42912022-07-07 14:24:59 +0100152 {
Kevin May2fef6f62022-11-14 17:07:49 +0000153 outputSize *= outputDims->data[dim];
Teresa Charlin83b42912022-07-07 14:24:59 +0100154 }
Kevin May2fef6f62022-11-14 17:07:49 +0000155
156 std::cout << m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->name << ": ";
157 results.push_back(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation);
158
159 switch (m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->type)
160 {
161
162 case kTfLiteFloat32:
163 {
164 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<float>(
165 tfLiteDelegateOutputId);
166
167 for (int i = 0; i < outputSize; ++i)
168 {
169 fprintf(outputTensorFile, "%f ", tfLiteDelegateOutputData[i]);
170 }
171 break;
172 }
173 case kTfLiteInt32:
174 {
175 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<int32_t>(
176 tfLiteDelegateOutputId);
177 for (int i = 0; i < outputSize; ++i)
178 {
179 fprintf(outputTensorFile, "%d ", tfLiteDelegateOutputData[i]);
180 }
181 break;
182 }
183 case kTfLiteUInt8:
184 {
185 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<uint8_t>(
186 tfLiteDelegateOutputId);
187 for (int i = 0; i < outputSize; ++i)
188 {
189 fprintf(outputTensorFile, "%u ", tfLiteDelegateOutputData[i]);
190 }
191 break;
192 }
193 case kTfLiteInt8:
194 {
195 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<int8_t>(
196 tfLiteDelegateOutputId);
197 for (int i = 0; i < outputSize; ++i)
198 {
199 fprintf(outputTensorFile, "%d ", tfLiteDelegateOutputData[i]);
200 }
201 break;
202 }
Ryan OShea39831da2023-01-26 17:43:45 +0000203 case kTfLiteBool:
204 {
205 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<bool>(
206 tfLiteDelegateOutputId);
207 for (int i = 0; i < outputSize; ++i) {
208 fprintf(outputTensorFile, "%u ", tfLiteDelegateOutputData[i]);
209 }
210 break;
211 }
Kevin May2fef6f62022-11-14 17:07:49 +0000212 default:
213 {
214 LogAndThrow("Unsupported output type");
215 }
216 }
217
218 std::cout << std::endl;
Teresa Charlin83b42912022-07-07 14:24:59 +0100219 }
Teresa Charlin83b42912022-07-07 14:24:59 +0100220 }
221 CheckInferenceTimeThreshold(duration, m_Params.m_ThresholdTime);
222 }
223
224 std::cout << status;
225 return results;
226}
227
228void TfLiteExecutor::CompareAndPrintResult(std::vector<const void*> otherOutput)
229{
230 for (unsigned int outputIndex = 0; outputIndex < m_TfLiteInterpreter->outputs().size(); ++outputIndex)
231 {
232 auto tfLiteDelegateOutputId = m_TfLiteInterpreter->outputs()[outputIndex];
Colm Doneland0472622023-03-06 12:34:54 +0000233 size_t size = m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->bytes;
234 double result = ComputeByteLevelRMSE(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation,
235 otherOutput[outputIndex], size);
236 std::cout << "Byte level root mean square error: " << result << "\n";
Teresa Charlin83b42912022-07-07 14:24:59 +0100237 }
238};