blob: d750fcccc78ad93224e4d8fe7141db61669b4d7f [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{
Teresa Charlin7dbaaa52022-08-05 13:57:04 +010010 m_Model = tflite::FlatBufferModel::BuildFromFile(m_Params.m_ModelPath.c_str());
Teresa Charlinfbd28172022-07-07 14:24:59 +010011
12 m_TfLiteInterpreter = std::make_unique<Interpreter>();
13 tflite::ops::builtin::BuiltinOpResolver resolver;
14
Teresa Charlin7dbaaa52022-08-05 13:57:04 +010015 tflite::InterpreterBuilder builder(*m_Model, resolver);
Teresa Charlinfbd28172022-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 Corbett4869c542022-08-04 17:58:09 +010032 if (status != kTfLiteOk)
Teresa Charlinfbd28172022-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 Charlinfbd28172022-07-07 14:24:59 +010042 const size_t numInputs = m_Params.m_InputNames.size();
43
44 for(unsigned int inputIndex = 0; inputIndex < numInputs; ++inputIndex)
45 {
Cathal Corbett4869c542022-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 Charlinfbd28172022-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 Corbett4869c542022-08-04 17:58:09 +010060 const auto& inputName = m_TfLiteInterpreter->tensor(input)->name;
61 const auto& dataType = m_TfLiteInterpreter->tensor(input)->type;
Teresa Charlinfbd28172022-07-07 14:24:59 +010062
63 switch (dataType)
64 {
65 case kTfLiteFloat32:
66 {
67 auto inputData = m_TfLiteInterpreter->typed_tensor<float>(input);
Cathal Corbett4869c542022-08-04 17:58:09 +010068 PopulateTensorWithData<float>(inputData, inputSize, dataFile, inputName);
Teresa Charlinfbd28172022-07-07 14:24:59 +010069 break;
70 }
71 case kTfLiteInt32:
72 {
Cathal Corbett4869c542022-08-04 17:58:09 +010073 auto inputData = m_TfLiteInterpreter->typed_tensor<int32_t>(input);
74 PopulateTensorWithData<int32_t>(inputData, inputSize, dataFile, inputName);
Teresa Charlinfbd28172022-07-07 14:24:59 +010075 break;
76 }
77 case kTfLiteUInt8:
78 {
79 auto inputData = m_TfLiteInterpreter->typed_tensor<uint8_t>(input);
Cathal Corbett4869c542022-08-04 17:58:09 +010080 PopulateTensorWithData<uint8_t>(inputData, inputSize, dataFile, inputName);
Teresa Charlinfbd28172022-07-07 14:24:59 +010081 break;
82 }
83 case kTfLiteInt16:
84 {
85 auto inputData = m_TfLiteInterpreter->typed_tensor<int16_t>(input);
Cathal Corbett4869c542022-08-04 17:58:09 +010086 PopulateTensorWithData<int16_t>(inputData, inputSize, dataFile, inputName);
Teresa Charlinfbd28172022-07-07 14:24:59 +010087 break;
88 }
89 case kTfLiteInt8:
90 {
91 auto inputData = m_TfLiteInterpreter->typed_tensor<int8_t>(input);
Cathal Corbett4869c542022-08-04 17:58:09 +010092 PopulateTensorWithData<int8_t>(inputData, inputSize, dataFile, inputName);
Teresa Charlinfbd28172022-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
115 if (m_Params.m_DontPrintOutputs || m_Params.m_ReuseBuffers)
116 {
117 break;
118 }
119 // Print out the output
120 for (unsigned int outputIndex = 0; outputIndex < m_TfLiteInterpreter->outputs().size(); ++outputIndex)
121 {
122 auto tfLiteDelegateOutputId = m_TfLiteInterpreter->outputs()[outputIndex];
123 TfLiteIntArray* outputDims = m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->dims;
124 // If we've been asked to write to a file then set a file output stream. Otherwise use stdout.
125 FILE* outputTensorFile = stdout;
126 if (!m_Params.m_OutputTensorFiles.empty())
127 {
128 outputTensorFile = fopen(m_Params.m_OutputTensorFiles[outputIndex].c_str(), "w");
129 if (outputTensorFile == NULL)
130 {
131 LogAndThrow("Specified output tensor file, \"" + m_Params.m_OutputTensorFiles[outputIndex] +
132 "\", cannot be created. Defaulting to stdout. Error was: " + std::strerror(errno));
133 }
134 else
135 {
136 ARMNN_LOG(info) << "Writing output " << outputIndex << "' of iteration: " << x+1 << " to file: '"
137 << m_Params.m_OutputTensorFiles[outputIndex] << "'";
138 }
139 }
140 long outputSize = 1;
141 for (unsigned int dim = 0; dim < static_cast<unsigned int>(outputDims->size); ++dim)
142 {
143 outputSize *= outputDims->data[dim];
144 }
145
Teresa Charlin7dbaaa52022-08-05 13:57:04 +0100146 std::cout << m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->name << ": ";
Teresa Charlinfbd28172022-07-07 14:24:59 +0100147 results.push_back(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation);
148
149 switch (m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->type)
150 {
151
152 case kTfLiteFloat32:
153 {
Teresa Charlin0ea0a082022-08-02 14:17:39 +0100154 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<float>(tfLiteDelegateOutputId);
Teresa Charlinfbd28172022-07-07 14:24:59 +0100155
156 for (int i = 0; i < outputSize; ++i)
157 {
Teresa Charlin0ea0a082022-08-02 14:17:39 +0100158 fprintf(outputTensorFile, "%f ", tfLiteDelegateOutputData[i]);
Teresa Charlinfbd28172022-07-07 14:24:59 +0100159 }
160 break;
161 }
162 case kTfLiteInt32:
163 {
Teresa Charlin0ea0a082022-08-02 14:17:39 +0100164 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<int32_t>(tfLiteDelegateOutputId);
Teresa Charlinfbd28172022-07-07 14:24:59 +0100165 for (int i = 0; i < outputSize; ++i)
166 {
Teresa Charlin0ea0a082022-08-02 14:17:39 +0100167 fprintf(outputTensorFile, "%d ", tfLiteDelegateOutputData[i]);
Teresa Charlinfbd28172022-07-07 14:24:59 +0100168 }
169 break;
170 }
171 case kTfLiteUInt8:
172 {
Teresa Charlin0ea0a082022-08-02 14:17:39 +0100173 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<uint8_t>(tfLiteDelegateOutputId);
Teresa Charlinfbd28172022-07-07 14:24:59 +0100174 for (int i = 0; i < outputSize; ++i)
175 {
Teresa Charlin0ea0a082022-08-02 14:17:39 +0100176 fprintf(outputTensorFile, "%u ", tfLiteDelegateOutputData[i]);
Teresa Charlinfbd28172022-07-07 14:24:59 +0100177 }
178 break;
179 }
180 case kTfLiteInt8:
181 {
Teresa Charlin0ea0a082022-08-02 14:17:39 +0100182 auto tfLiteDelegateOutputData = m_TfLiteInterpreter->typed_tensor<int8_t>(tfLiteDelegateOutputId);
Teresa Charlinfbd28172022-07-07 14:24:59 +0100183 for (int i = 0; i < outputSize; ++i)
184 {
Teresa Charlin0ea0a082022-08-02 14:17:39 +0100185 fprintf(outputTensorFile, "%d ", tfLiteDelegateOutputData[i]);
Teresa Charlinfbd28172022-07-07 14:24:59 +0100186 }
187 break;
188 }
189 default:
190 {
191 LogAndThrow("Unsupported output type");
192 }
193 }
194
195 std::cout << std::endl;
196 }
197 CheckInferenceTimeThreshold(duration, m_Params.m_ThresholdTime);
198 }
199
200 std::cout << status;
201 return results;
202}
203
204void TfLiteExecutor::CompareAndPrintResult(std::vector<const void*> otherOutput)
205{
206 for (unsigned int outputIndex = 0; outputIndex < m_TfLiteInterpreter->outputs().size(); ++outputIndex)
207 {
208 auto tfLiteDelegateOutputId = m_TfLiteInterpreter->outputs()[outputIndex];
209 float result = 0;
210 switch (m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->type)
211 {
212 case kTfLiteFloat32:
213 {
214 result = ComputeRMSE<float>(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation,
215 otherOutput[outputIndex],
216 m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->bytes);
217
218 break;
219 }
220 case kTfLiteInt32:
221 {
222 result = ComputeRMSE<int32_t>(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation,
223 otherOutput[outputIndex],
224 m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->bytes);
225 break;
226 }
227 case kTfLiteUInt8:
228 {
229 result = ComputeRMSE<uint8_t>(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation,
230 otherOutput[outputIndex],
231 m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->bytes);
232 break;
233 }
234 case kTfLiteInt8:
235 {
236 result = ComputeRMSE<int8_t>(m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->allocation,
237 otherOutput[outputIndex],
238 m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->bytes);
239 break;
240 }
241 default:
242 {
243 }
244 }
245
246 std::cout << "RMSE of "
247 << m_TfLiteInterpreter->tensor(tfLiteDelegateOutputId)->name
248 << ": " << result << std::endl;
249 }
250};