blob: 810495fe8ce1f710725f85512f9091a4508faf78 [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"
7
8TfLiteExecutor::TfLiteExecutor(const ExecuteNetworkParams& params) : m_Params(params)
9{
Teresa Charlinc814e802022-08-05 13:57:04 +010010 m_Model = tflite::FlatBufferModel::BuildFromFile(m_Params.m_ModelPath.c_str());
Colm Donelan18e6f042023-01-24 22:10:12 +000011 if (!m_Model)
12 {
13 LogAndThrow("Failed to load TfLite model from: " + m_Params.m_ModelPath);
14 }
Teresa Charlin83b42912022-07-07 14:24:59 +010015 m_TfLiteInterpreter = std::make_unique<Interpreter>();
16 tflite::ops::builtin::BuiltinOpResolver resolver;
17
Teresa Charlinc814e802022-08-05 13:57:04 +010018 tflite::InterpreterBuilder builder(*m_Model, resolver);
Teresa Charlin83b42912022-07-07 14:24:59 +010019 builder(&m_TfLiteInterpreter);
20 m_TfLiteInterpreter->AllocateTensors();
21
22 int status = kTfLiteError;
23 if (m_Params.m_TfLiteExecutor == ExecuteNetworkParams::TfLiteExecutor::ArmNNTfLiteDelegate)
24 {
25 // Create the Armnn Delegate
26 // Populate a DelegateOptions from the ExecuteNetworkParams.
27 armnnDelegate::DelegateOptions delegateOptions = m_Params.ToDelegateOptions();
28 delegateOptions.SetExternalProfilingParams(delegateOptions.GetExternalProfilingParams());
29
30 std::unique_ptr<TfLiteDelegate, decltype(&armnnDelegate::TfLiteArmnnDelegateDelete)>
31 theArmnnDelegate(armnnDelegate::TfLiteArmnnDelegateCreate(delegateOptions),
32 armnnDelegate::TfLiteArmnnDelegateDelete);
33 // Register armnn_delegate to TfLiteInterpreter
34 status = m_TfLiteInterpreter->ModifyGraphWithDelegate(std::move(theArmnnDelegate));
Cathal Corbettaa212302022-08-04 17:58:09 +010035 if (status != kTfLiteOk)
Teresa Charlin83b42912022-07-07 14:24:59 +010036 {
37 LogAndThrow("Could not register ArmNN TfLite Delegate to TfLiteInterpreter");
38 }
39 }
40 else
41 {
42 std::cout << "Running on TfLite without ArmNN delegate\n";
43 }
44
Teresa Charlinf53b28f2022-11-11 11:14:50 +000045 const size_t numInputs = m_TfLiteInterpreter->inputs().size();
Teresa Charlin83b42912022-07-07 14:24:59 +010046
47 for(unsigned int inputIndex = 0; inputIndex < numInputs; ++inputIndex)
48 {
Cathal Corbettaa212302022-08-04 17:58:09 +010049 armnn::Optional<std::string> dataFile = m_Params.m_GenerateTensorData
50 ? armnn::EmptyOptional()
51 : armnn::MakeOptional<std::string>(m_Params.m_InputTensorDataFilePaths[inputIndex]);
52
Teresa Charlin83b42912022-07-07 14:24:59 +010053 int input = m_TfLiteInterpreter->inputs()[inputIndex];
54
55 TfLiteIntArray* inputDims = m_TfLiteInterpreter->tensor(input)->dims;
56
57 unsigned int inputSize = 1;
58 for (unsigned int dim = 0; dim < static_cast<unsigned int>(inputDims->size); ++dim)
59 {
60 inputSize *= inputDims->data[dim];
61 }
62
Cathal Corbettaa212302022-08-04 17:58:09 +010063 const auto& inputName = m_TfLiteInterpreter->tensor(input)->name;
64 const auto& dataType = m_TfLiteInterpreter->tensor(input)->type;
Teresa Charlin83b42912022-07-07 14:24:59 +010065
66 switch (dataType)
67 {
68 case kTfLiteFloat32:
69 {
70 auto inputData = m_TfLiteInterpreter->typed_tensor<float>(input);
Cathal Corbettaa212302022-08-04 17:58:09 +010071 PopulateTensorWithData<float>(inputData, inputSize, dataFile, inputName);
Teresa Charlin83b42912022-07-07 14:24:59 +010072 break;
73 }
74 case kTfLiteInt32:
75 {
Cathal Corbettaa212302022-08-04 17:58:09 +010076 auto inputData = m_TfLiteInterpreter->typed_tensor<int32_t>(input);
77 PopulateTensorWithData<int32_t>(inputData, inputSize, dataFile, inputName);
Teresa Charlin83b42912022-07-07 14:24:59 +010078 break;
79 }
80 case kTfLiteUInt8:
81 {
82 auto inputData = m_TfLiteInterpreter->typed_tensor<uint8_t>(input);
Cathal Corbettaa212302022-08-04 17:58:09 +010083 PopulateTensorWithData<uint8_t>(inputData, inputSize, dataFile, inputName);
Teresa Charlin83b42912022-07-07 14:24:59 +010084 break;
85 }
86 case kTfLiteInt16:
87 {
88 auto inputData = m_TfLiteInterpreter->typed_tensor<int16_t>(input);
Cathal Corbettaa212302022-08-04 17:58:09 +010089 PopulateTensorWithData<int16_t>(inputData, inputSize, dataFile, inputName);
Teresa Charlin83b42912022-07-07 14:24:59 +010090 break;
91 }
92 case kTfLiteInt8:
93 {
94 auto inputData = m_TfLiteInterpreter->typed_tensor<int8_t>(input);
Cathal Corbettaa212302022-08-04 17:58:09 +010095 PopulateTensorWithData<int8_t>(inputData, inputSize, dataFile, inputName);
Teresa Charlin83b42912022-07-07 14:24:59 +010096 break;
97 }
98 default:
99 {
100 LogAndThrow("Unsupported input tensor data type");
101 }
102 }
103 }
104}
105
106std::vector<const void *> TfLiteExecutor::Execute()
107{
108 int status = 0;
109 std::vector<const void*> results;
110 for (size_t x = 0; x < m_Params.m_Iterations; x++)
111 {
112 // Start timer to record inference time in milliseconds.
113 const auto start_time = armnn::GetTimeNow();
114 // Run the inference
115 status = m_TfLiteInterpreter->Invoke();
116 const auto duration = armnn::GetTimeDuration(start_time);
117
Kevin May2fef6f62022-11-14 17:07:49 +0000118 if (!m_Params.m_DontPrintOutputs)
Teresa Charlin83b42912022-07-07 14:24:59 +0100119 {
Kevin May2fef6f62022-11-14 17:07:49 +0000120 // Print out the output
121 for (unsigned int outputIndex = 0; outputIndex < m_TfLiteInterpreter->outputs().size(); ++outputIndex)
Teresa Charlin83b42912022-07-07 14:24:59 +0100122 {
Kevin May2fef6f62022-11-14 17:07:49 +0000123 auto tfLiteDelegateOutputId = m_TfLiteInterpreter->outputs()[outputIndex];
124 TfLiteIntArray* outputDims = m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->dims;
125 // If we've been asked to write to a file then set a file output stream. Otherwise use stdout.
126 FILE* outputTensorFile = stdout;
127 if (!m_Params.m_OutputTensorFiles.empty())
Teresa Charlin83b42912022-07-07 14:24:59 +0100128 {
Kevin May2fef6f62022-11-14 17:07:49 +0000129 outputTensorFile = fopen(m_Params.m_OutputTensorFiles[outputIndex].c_str(), "w");
130 if (outputTensorFile == NULL)
131 {
132 LogAndThrow("Specified output tensor file, \"" + m_Params.m_OutputTensorFiles[outputIndex] +
133 "\", cannot be created. Defaulting to stdout. Error was: " + std::strerror(errno));
134 }
135 else
136 {
137 ARMNN_LOG(info) << "Writing output " << outputIndex << "' of iteration: " << x + 1
138 << " to file: '" << m_Params.m_OutputTensorFiles[outputIndex] << "'";
139 }
Teresa Charlin83b42912022-07-07 14:24:59 +0100140 }
Kevin May2fef6f62022-11-14 17:07:49 +0000141 long outputSize = 1;
142 for (unsigned int dim = 0; dim < static_cast<unsigned int>(outputDims->size); ++dim)
Teresa Charlin83b42912022-07-07 14:24:59 +0100143 {
Kevin May2fef6f62022-11-14 17:07:49 +0000144 outputSize *= outputDims->data[dim];
Teresa Charlin83b42912022-07-07 14:24:59 +0100145 }
Kevin May2fef6f62022-11-14 17:07:49 +0000146
147 std::cout << m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->name << ": ";
148 results.push_back(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation);
149
150 switch (m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->type)
151 {
152
153 case kTfLiteFloat32:
154 {
155 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<float>(
156 tfLiteDelegateOutputId);
157
158 for (int i = 0; i < outputSize; ++i)
159 {
160 fprintf(outputTensorFile, "%f ", tfLiteDelegateOutputData[i]);
161 }
162 break;
163 }
164 case kTfLiteInt32:
165 {
166 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<int32_t>(
167 tfLiteDelegateOutputId);
168 for (int i = 0; i < outputSize; ++i)
169 {
170 fprintf(outputTensorFile, "%d ", tfLiteDelegateOutputData[i]);
171 }
172 break;
173 }
174 case kTfLiteUInt8:
175 {
176 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<uint8_t>(
177 tfLiteDelegateOutputId);
178 for (int i = 0; i < outputSize; ++i)
179 {
180 fprintf(outputTensorFile, "%u ", tfLiteDelegateOutputData[i]);
181 }
182 break;
183 }
184 case kTfLiteInt8:
185 {
186 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<int8_t>(
187 tfLiteDelegateOutputId);
188 for (int i = 0; i < outputSize; ++i)
189 {
190 fprintf(outputTensorFile, "%d ", tfLiteDelegateOutputData[i]);
191 }
192 break;
193 }
194 default:
195 {
196 LogAndThrow("Unsupported output type");
197 }
198 }
199
200 std::cout << std::endl;
Teresa Charlin83b42912022-07-07 14:24:59 +0100201 }
Teresa Charlin83b42912022-07-07 14:24:59 +0100202 }
203 CheckInferenceTimeThreshold(duration, m_Params.m_ThresholdTime);
204 }
205
206 std::cout << status;
207 return results;
208}
209
210void TfLiteExecutor::CompareAndPrintResult(std::vector<const void*> otherOutput)
211{
212 for (unsigned int outputIndex = 0; outputIndex < m_TfLiteInterpreter->outputs().size(); ++outputIndex)
213 {
214 auto tfLiteDelegateOutputId = m_TfLiteInterpreter->outputs()[outputIndex];
215 float result = 0;
216 switch (m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->type)
217 {
218 case kTfLiteFloat32:
219 {
220 result = ComputeRMSE<float>(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation,
221 otherOutput[outputIndex],
222 m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->bytes);
223
224 break;
225 }
226 case kTfLiteInt32:
227 {
228 result = ComputeRMSE<int32_t>(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation,
229 otherOutput[outputIndex],
230 m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->bytes);
231 break;
232 }
233 case kTfLiteUInt8:
234 {
235 result = ComputeRMSE<uint8_t>(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation,
236 otherOutput[outputIndex],
237 m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->bytes);
238 break;
239 }
240 case kTfLiteInt8:
241 {
242 result = ComputeRMSE<int8_t>(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation,
243 otherOutput[outputIndex],
244 m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->bytes);
245 break;
246 }
247 default:
248 {
249 }
250 }
251
252 std::cout << "RMSE of "
253 << m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->name
254 << ": " << result << std::endl;
255 }
256};