blob: 59c69f9d6a29a2c27ed9a9c9e2eb86eb99b19b60 [file] [log] [blame]
Teresa Charlinfbd28172022-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{
10 std::unique_ptr<tflite::FlatBufferModel> model =
11 tflite::FlatBufferModel::BuildFromFile(m_Params.m_ModelPath.c_str());
12
13 m_TfLiteInterpreter = std::make_unique<Interpreter>();
14 tflite::ops::builtin::BuiltinOpResolver resolver;
15
16 tflite::InterpreterBuilder builder(*model, resolver);
17 builder(&m_TfLiteInterpreter);
18 m_TfLiteInterpreter->AllocateTensors();
19
20 int status = kTfLiteError;
21 if (m_Params.m_TfLiteExecutor == ExecuteNetworkParams::TfLiteExecutor::ArmNNTfLiteDelegate)
22 {
23 // Create the Armnn Delegate
24 // Populate a DelegateOptions from the ExecuteNetworkParams.
25 armnnDelegate::DelegateOptions delegateOptions = m_Params.ToDelegateOptions();
26 delegateOptions.SetExternalProfilingParams(delegateOptions.GetExternalProfilingParams());
27
28 std::unique_ptr<TfLiteDelegate, decltype(&armnnDelegate::TfLiteArmnnDelegateDelete)>
29 theArmnnDelegate(armnnDelegate::TfLiteArmnnDelegateCreate(delegateOptions),
30 armnnDelegate::TfLiteArmnnDelegateDelete);
31 // Register armnn_delegate to TfLiteInterpreter
32 status = m_TfLiteInterpreter->ModifyGraphWithDelegate(std::move(theArmnnDelegate));
Cathal Corbett4869c542022-08-04 17:58:09 +010033 if (status != kTfLiteOk)
Teresa Charlinfbd28172022-07-07 14:24:59 +010034 {
35 LogAndThrow("Could not register ArmNN TfLite Delegate to TfLiteInterpreter");
36 }
37 }
38 else
39 {
40 std::cout << "Running on TfLite without ArmNN delegate\n";
41 }
42
Teresa Charlinfbd28172022-07-07 14:24:59 +010043 const size_t numInputs = m_Params.m_InputNames.size();
44
45 for(unsigned int inputIndex = 0; inputIndex < numInputs; ++inputIndex)
46 {
Cathal Corbett4869c542022-08-04 17:58:09 +010047 armnn::Optional<std::string> dataFile = m_Params.m_GenerateTensorData
48 ? armnn::EmptyOptional()
49 : armnn::MakeOptional<std::string>(m_Params.m_InputTensorDataFilePaths[inputIndex]);
50
Teresa Charlinfbd28172022-07-07 14:24:59 +010051 int input = m_TfLiteInterpreter->inputs()[inputIndex];
52
53 TfLiteIntArray* inputDims = m_TfLiteInterpreter->tensor(input)->dims;
54
55 unsigned int inputSize = 1;
56 for (unsigned int dim = 0; dim < static_cast<unsigned int>(inputDims->size); ++dim)
57 {
58 inputSize *= inputDims->data[dim];
59 }
60
Cathal Corbett4869c542022-08-04 17:58:09 +010061 const auto& inputName = m_TfLiteInterpreter->tensor(input)->name;
62 const auto& dataType = m_TfLiteInterpreter->tensor(input)->type;
Teresa Charlinfbd28172022-07-07 14:24:59 +010063
64 switch (dataType)
65 {
66 case kTfLiteFloat32:
67 {
68 auto inputData = m_TfLiteInterpreter->typed_tensor<float>(input);
Cathal Corbett4869c542022-08-04 17:58:09 +010069 PopulateTensorWithData<float>(inputData, inputSize, dataFile, inputName);
Teresa Charlinfbd28172022-07-07 14:24:59 +010070 break;
71 }
72 case kTfLiteInt32:
73 {
Cathal Corbett4869c542022-08-04 17:58:09 +010074 auto inputData = m_TfLiteInterpreter->typed_tensor<int32_t>(input);
75 PopulateTensorWithData<int32_t>(inputData, inputSize, dataFile, inputName);
Teresa Charlinfbd28172022-07-07 14:24:59 +010076 break;
77 }
78 case kTfLiteUInt8:
79 {
80 auto inputData = m_TfLiteInterpreter->typed_tensor<uint8_t>(input);
Cathal Corbett4869c542022-08-04 17:58:09 +010081 PopulateTensorWithData<uint8_t>(inputData, inputSize, dataFile, inputName);
Teresa Charlinfbd28172022-07-07 14:24:59 +010082 break;
83 }
84 case kTfLiteInt16:
85 {
86 auto inputData = m_TfLiteInterpreter->typed_tensor<int16_t>(input);
Cathal Corbett4869c542022-08-04 17:58:09 +010087 PopulateTensorWithData<int16_t>(inputData, inputSize, dataFile, inputName);
Teresa Charlinfbd28172022-07-07 14:24:59 +010088 break;
89 }
90 case kTfLiteInt8:
91 {
92 auto inputData = m_TfLiteInterpreter->typed_tensor<int8_t>(input);
Cathal Corbett4869c542022-08-04 17:58:09 +010093 PopulateTensorWithData<int8_t>(inputData, inputSize, dataFile, inputName);
Teresa Charlinfbd28172022-07-07 14:24:59 +010094 break;
95 }
96 default:
97 {
98 LogAndThrow("Unsupported input tensor data type");
99 }
100 }
101 }
102}
103
104std::vector<const void *> TfLiteExecutor::Execute()
105{
106 int status = 0;
107 std::vector<const void*> results;
108 for (size_t x = 0; x < m_Params.m_Iterations; x++)
109 {
110 // Start timer to record inference time in milliseconds.
111 const auto start_time = armnn::GetTimeNow();
112 // Run the inference
113 status = m_TfLiteInterpreter->Invoke();
114 const auto duration = armnn::GetTimeDuration(start_time);
115
116 if (m_Params.m_DontPrintOutputs || m_Params.m_ReuseBuffers)
117 {
118 break;
119 }
120 // Print out the output
121 for (unsigned int outputIndex = 0; outputIndex < m_TfLiteInterpreter->outputs().size(); ++outputIndex)
122 {
123 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())
128 {
129 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 << " to file: '"
138 << m_Params.m_OutputTensorFiles[outputIndex] << "'";
139 }
140 }
141 long outputSize = 1;
142 for (unsigned int dim = 0; dim < static_cast<unsigned int>(outputDims->size); ++dim)
143 {
144 outputSize *= outputDims->data[dim];
145 }
146
Teresa Charlin0ea0a082022-08-02 14:17:39 +0100147 std::cout << m_Params.m_OutputNames[outputIndex] << ": ";
Teresa Charlinfbd28172022-07-07 14:24:59 +0100148 results.push_back(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation);
149
150 switch (m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->type)
151 {
152
153 case kTfLiteFloat32:
154 {
Teresa Charlin0ea0a082022-08-02 14:17:39 +0100155 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<float>(tfLiteDelegateOutputId);
Teresa Charlinfbd28172022-07-07 14:24:59 +0100156
157 for (int i = 0; i < outputSize; ++i)
158 {
Teresa Charlin0ea0a082022-08-02 14:17:39 +0100159 fprintf(outputTensorFile, "%f ", tfLiteDelegateOutputData[i]);
Teresa Charlinfbd28172022-07-07 14:24:59 +0100160 }
161 break;
162 }
163 case kTfLiteInt32:
164 {
Teresa Charlin0ea0a082022-08-02 14:17:39 +0100165 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<int32_t>(tfLiteDelegateOutputId);
Teresa Charlinfbd28172022-07-07 14:24:59 +0100166 for (int i = 0; i < outputSize; ++i)
167 {
Teresa Charlin0ea0a082022-08-02 14:17:39 +0100168 fprintf(outputTensorFile, "%d ", tfLiteDelegateOutputData[i]);
Teresa Charlinfbd28172022-07-07 14:24:59 +0100169 }
170 break;
171 }
172 case kTfLiteUInt8:
173 {
Teresa Charlin0ea0a082022-08-02 14:17:39 +0100174 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<uint8_t>(tfLiteDelegateOutputId);
Teresa Charlinfbd28172022-07-07 14:24:59 +0100175 for (int i = 0; i < outputSize; ++i)
176 {
Teresa Charlin0ea0a082022-08-02 14:17:39 +0100177 fprintf(outputTensorFile, "%u ", tfLiteDelegateOutputData[i]);
Teresa Charlinfbd28172022-07-07 14:24:59 +0100178 }
179 break;
180 }
181 case kTfLiteInt8:
182 {
Teresa Charlin0ea0a082022-08-02 14:17:39 +0100183 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<int8_t>(tfLiteDelegateOutputId);
Teresa Charlinfbd28172022-07-07 14:24:59 +0100184 for (int i = 0; i < outputSize; ++i)
185 {
Teresa Charlin0ea0a082022-08-02 14:17:39 +0100186 fprintf(outputTensorFile, "%d ", tfLiteDelegateOutputData[i]);
Teresa Charlinfbd28172022-07-07 14:24:59 +0100187 }
188 break;
189 }
190 default:
191 {
192 LogAndThrow("Unsupported output type");
193 }
194 }
195
196 std::cout << std::endl;
197 }
198 CheckInferenceTimeThreshold(duration, m_Params.m_ThresholdTime);
199 }
200
201 std::cout << status;
202 return results;
203}
204
205void TfLiteExecutor::CompareAndPrintResult(std::vector<const void*> otherOutput)
206{
207 for (unsigned int outputIndex = 0; outputIndex < m_TfLiteInterpreter->outputs().size(); ++outputIndex)
208 {
209 auto tfLiteDelegateOutputId = m_TfLiteInterpreter->outputs()[outputIndex];
210 float result = 0;
211 switch (m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->type)
212 {
213 case kTfLiteFloat32:
214 {
215 result = ComputeRMSE<float>(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation,
216 otherOutput[outputIndex],
217 m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->bytes);
218
219 break;
220 }
221 case kTfLiteInt32:
222 {
223 result = ComputeRMSE<int32_t>(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation,
224 otherOutput[outputIndex],
225 m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->bytes);
226 break;
227 }
228 case kTfLiteUInt8:
229 {
230 result = ComputeRMSE<uint8_t>(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation,
231 otherOutput[outputIndex],
232 m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->bytes);
233 break;
234 }
235 case kTfLiteInt8:
236 {
237 result = ComputeRMSE<int8_t>(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation,
238 otherOutput[outputIndex],
239 m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->bytes);
240 break;
241 }
242 default:
243 {
244 }
245 }
246
247 std::cout << "RMSE of "
248 << m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->name
249 << ": " << result << std::endl;
250 }
251};