blob: 41716ffb9374fc925d0b38bca81825fab838584e [file] [log] [blame]
Teresa Charlin83b42912022-07-07 14:24:59 +01001//
2// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
3// 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());
Teresa Charlin83b42912022-07-07 14:24:59 +010011
12 m_TfLiteInterpreter = std::make_unique<Interpreter>();
13 tflite::ops::builtin::BuiltinOpResolver resolver;
14
Teresa Charlinc814e802022-08-05 13:57:04 +010015 tflite::InterpreterBuilder builder(*m_Model, resolver);
Teresa Charlin83b42912022-07-07 14:24:59 +010016 builder(&m_TfLiteInterpreter);
17 m_TfLiteInterpreter->AllocateTensors();
18
19 int status = kTfLiteError;
20 if (m_Params.m_TfLiteExecutor == ExecuteNetworkParams::TfLiteExecutor::ArmNNTfLiteDelegate)
21 {
22 // Create the Armnn Delegate
23 // Populate a DelegateOptions from the ExecuteNetworkParams.
24 armnnDelegate::DelegateOptions delegateOptions = m_Params.ToDelegateOptions();
25 delegateOptions.SetExternalProfilingParams(delegateOptions.GetExternalProfilingParams());
26
27 std::unique_ptr<TfLiteDelegate, decltype(&armnnDelegate::TfLiteArmnnDelegateDelete)>
28 theArmnnDelegate(armnnDelegate::TfLiteArmnnDelegateCreate(delegateOptions),
29 armnnDelegate::TfLiteArmnnDelegateDelete);
30 // Register armnn_delegate to TfLiteInterpreter
31 status = m_TfLiteInterpreter->ModifyGraphWithDelegate(std::move(theArmnnDelegate));
Cathal Corbettaa212302022-08-04 17:58:09 +010032 if (status != kTfLiteOk)
Teresa Charlin83b42912022-07-07 14:24:59 +010033 {
34 LogAndThrow("Could not register ArmNN TfLite Delegate to TfLiteInterpreter");
35 }
36 }
37 else
38 {
39 std::cout << "Running on TfLite without ArmNN delegate\n";
40 }
41
Teresa Charlinf53b28f2022-11-11 11:14:50 +000042 const size_t numInputs = m_TfLiteInterpreter->inputs().size();
Teresa Charlin83b42912022-07-07 14:24:59 +010043
44 for(unsigned int inputIndex = 0; inputIndex < numInputs; ++inputIndex)
45 {
Cathal Corbettaa212302022-08-04 17:58:09 +010046 armnn::Optional<std::string> dataFile = m_Params.m_GenerateTensorData
47 ? armnn::EmptyOptional()
48 : armnn::MakeOptional<std::string>(m_Params.m_InputTensorDataFilePaths[inputIndex]);
49
Teresa Charlin83b42912022-07-07 14:24:59 +010050 int input = m_TfLiteInterpreter->inputs()[inputIndex];
51
52 TfLiteIntArray* inputDims = m_TfLiteInterpreter->tensor(input)->dims;
53
54 unsigned int inputSize = 1;
55 for (unsigned int dim = 0; dim < static_cast<unsigned int>(inputDims->size); ++dim)
56 {
57 inputSize *= inputDims->data[dim];
58 }
59
Cathal Corbettaa212302022-08-04 17:58:09 +010060 const auto& inputName = m_TfLiteInterpreter->tensor(input)->name;
61 const auto& dataType = m_TfLiteInterpreter->tensor(input)->type;
Teresa Charlin83b42912022-07-07 14:24:59 +010062
63 switch (dataType)
64 {
65 case kTfLiteFloat32:
66 {
67 auto inputData = m_TfLiteInterpreter->typed_tensor<float>(input);
Cathal Corbettaa212302022-08-04 17:58:09 +010068 PopulateTensorWithData<float>(inputData, inputSize, dataFile, inputName);
Teresa Charlin83b42912022-07-07 14:24:59 +010069 break;
70 }
71 case kTfLiteInt32:
72 {
Cathal Corbettaa212302022-08-04 17:58:09 +010073 auto inputData = m_TfLiteInterpreter->typed_tensor<int32_t>(input);
74 PopulateTensorWithData<int32_t>(inputData, inputSize, dataFile, inputName);
Teresa Charlin83b42912022-07-07 14:24:59 +010075 break;
76 }
77 case kTfLiteUInt8:
78 {
79 auto inputData = m_TfLiteInterpreter->typed_tensor<uint8_t>(input);
Cathal Corbettaa212302022-08-04 17:58:09 +010080 PopulateTensorWithData<uint8_t>(inputData, inputSize, dataFile, inputName);
Teresa Charlin83b42912022-07-07 14:24:59 +010081 break;
82 }
83 case kTfLiteInt16:
84 {
85 auto inputData = m_TfLiteInterpreter->typed_tensor<int16_t>(input);
Cathal Corbettaa212302022-08-04 17:58:09 +010086 PopulateTensorWithData<int16_t>(inputData, inputSize, dataFile, inputName);
Teresa Charlin83b42912022-07-07 14:24:59 +010087 break;
88 }
89 case kTfLiteInt8:
90 {
91 auto inputData = m_TfLiteInterpreter->typed_tensor<int8_t>(input);
Cathal Corbettaa212302022-08-04 17:58:09 +010092 PopulateTensorWithData<int8_t>(inputData, inputSize, dataFile, inputName);
Teresa Charlin83b42912022-07-07 14:24:59 +010093 break;
94 }
95 default:
96 {
97 LogAndThrow("Unsupported input tensor data type");
98 }
99 }
100 }
101}
102
103std::vector<const void *> TfLiteExecutor::Execute()
104{
105 int status = 0;
106 std::vector<const void*> results;
107 for (size_t x = 0; x < m_Params.m_Iterations; x++)
108 {
109 // Start timer to record inference time in milliseconds.
110 const auto start_time = armnn::GetTimeNow();
111 // Run the inference
112 status = m_TfLiteInterpreter->Invoke();
113 const auto duration = armnn::GetTimeDuration(start_time);
114
Kevin May2fef6f62022-11-14 17:07:49 +0000115 if (!m_Params.m_DontPrintOutputs)
Teresa Charlin83b42912022-07-07 14:24:59 +0100116 {
Kevin May2fef6f62022-11-14 17:07:49 +0000117 // Print out the output
118 for (unsigned int outputIndex = 0; outputIndex < m_TfLiteInterpreter->outputs().size(); ++outputIndex)
Teresa Charlin83b42912022-07-07 14:24:59 +0100119 {
Kevin May2fef6f62022-11-14 17:07:49 +0000120 auto tfLiteDelegateOutputId = m_TfLiteInterpreter->outputs()[outputIndex];
121 TfLiteIntArray* outputDims = m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->dims;
122 // If we've been asked to write to a file then set a file output stream. Otherwise use stdout.
123 FILE* outputTensorFile = stdout;
124 if (!m_Params.m_OutputTensorFiles.empty())
Teresa Charlin83b42912022-07-07 14:24:59 +0100125 {
Kevin May2fef6f62022-11-14 17:07:49 +0000126 outputTensorFile = fopen(m_Params.m_OutputTensorFiles[outputIndex].c_str(), "w");
127 if (outputTensorFile == NULL)
128 {
129 LogAndThrow("Specified output tensor file, \"" + m_Params.m_OutputTensorFiles[outputIndex] +
130 "\", cannot be created. Defaulting to stdout. Error was: " + std::strerror(errno));
131 }
132 else
133 {
134 ARMNN_LOG(info) << "Writing output " << outputIndex << "' of iteration: " << x + 1
135 << " to file: '" << m_Params.m_OutputTensorFiles[outputIndex] << "'";
136 }
Teresa Charlin83b42912022-07-07 14:24:59 +0100137 }
Kevin May2fef6f62022-11-14 17:07:49 +0000138 long outputSize = 1;
139 for (unsigned int dim = 0; dim < static_cast<unsigned int>(outputDims->size); ++dim)
Teresa Charlin83b42912022-07-07 14:24:59 +0100140 {
Kevin May2fef6f62022-11-14 17:07:49 +0000141 outputSize *= outputDims->data[dim];
Teresa Charlin83b42912022-07-07 14:24:59 +0100142 }
Kevin May2fef6f62022-11-14 17:07:49 +0000143
144 std::cout << m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->name << ": ";
145 results.push_back(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation);
146
147 switch (m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->type)
148 {
149
150 case kTfLiteFloat32:
151 {
152 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<float>(
153 tfLiteDelegateOutputId);
154
155 for (int i = 0; i < outputSize; ++i)
156 {
157 fprintf(outputTensorFile, "%f ", tfLiteDelegateOutputData[i]);
158 }
159 break;
160 }
161 case kTfLiteInt32:
162 {
163 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<int32_t>(
164 tfLiteDelegateOutputId);
165 for (int i = 0; i < outputSize; ++i)
166 {
167 fprintf(outputTensorFile, "%d ", tfLiteDelegateOutputData[i]);
168 }
169 break;
170 }
171 case kTfLiteUInt8:
172 {
173 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<uint8_t>(
174 tfLiteDelegateOutputId);
175 for (int i = 0; i < outputSize; ++i)
176 {
177 fprintf(outputTensorFile, "%u ", tfLiteDelegateOutputData[i]);
178 }
179 break;
180 }
181 case kTfLiteInt8:
182 {
183 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<int8_t>(
184 tfLiteDelegateOutputId);
185 for (int i = 0; i < outputSize; ++i)
186 {
187 fprintf(outputTensorFile, "%d ", tfLiteDelegateOutputData[i]);
188 }
189 break;
190 }
191 default:
192 {
193 LogAndThrow("Unsupported output type");
194 }
195 }
196
197 std::cout << std::endl;
Teresa Charlin83b42912022-07-07 14:24:59 +0100198 }
Teresa Charlin83b42912022-07-07 14:24:59 +0100199 }
200 CheckInferenceTimeThreshold(duration, m_Params.m_ThresholdTime);
201 }
202
203 std::cout << status;
204 return results;
205}
206
207void TfLiteExecutor::CompareAndPrintResult(std::vector<const void*> otherOutput)
208{
209 for (unsigned int outputIndex = 0; outputIndex < m_TfLiteInterpreter->outputs().size(); ++outputIndex)
210 {
211 auto tfLiteDelegateOutputId = m_TfLiteInterpreter->outputs()[outputIndex];
212 float result = 0;
213 switch (m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->type)
214 {
215 case kTfLiteFloat32:
216 {
217 result = ComputeRMSE<float>(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation,
218 otherOutput[outputIndex],
219 m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->bytes);
220
221 break;
222 }
223 case kTfLiteInt32:
224 {
225 result = ComputeRMSE<int32_t>(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation,
226 otherOutput[outputIndex],
227 m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->bytes);
228 break;
229 }
230 case kTfLiteUInt8:
231 {
232 result = ComputeRMSE<uint8_t>(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation,
233 otherOutput[outputIndex],
234 m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->bytes);
235 break;
236 }
237 case kTfLiteInt8:
238 {
239 result = ComputeRMSE<int8_t>(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation,
240 otherOutput[outputIndex],
241 m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->bytes);
242 break;
243 }
244 default:
245 {
246 }
247 }
248
249 std::cout << "RMSE of "
250 << m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->name
251 << ": " << result << std::endl;
252 }
253};