blob: 7de6fdeecfab7a9f31be0c782a8c6b3289dd590a [file] [log] [blame]
alexander3c798932021-03-26 21:42:19 +00001/*
Kshitij Sisodia47406fe2022-12-05 17:18:50 +00002 * SPDX-FileCopyrightText: Copyright 2021-2022 Arm Limited and/or its affiliates
3 * <open-source-office@arm.com> SPDX-License-Identifier: Apache-2.0
alexander3c798932021-03-26 21:42:19 +00004 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17#include "Model.hpp"
alexander31ae9f02022-02-10 16:15:54 +000018#include "log_macros.h"
alexander3c798932021-03-26 21:42:19 +000019
alexander31ae9f02022-02-10 16:15:54 +000020#include <cinttypes>
alexander3c798932021-03-26 21:42:19 +000021
22/* Initialise the model */
23arm::app::Model::~Model()
24{
Kshitij Sisodia47406fe2022-12-05 17:18:50 +000025 delete this->m_pInterpreter;
alexander3c798932021-03-26 21:42:19 +000026 /**
27 * No clean-up function available for allocator in TensorFlow Lite Micro yet.
28 **/
29}
30
Kshitij Sisodia47406fe2022-12-05 17:18:50 +000031arm::app::Model::Model() : m_inited(false), m_type(kTfLiteNoType) {}
alexander3c798932021-03-26 21:42:19 +000032
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +010033bool arm::app::Model::Init(uint8_t* tensorArenaAddr,
34 uint32_t tensorArenaSize,
Kshitij Sisodia937052d2022-05-13 16:44:16 +010035 const uint8_t* nnModelAddr,
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +010036 uint32_t nnModelSize,
37 tflite::MicroAllocator* allocator)
alexander3c798932021-03-26 21:42:19 +000038{
39 /* Following tf lite micro example:
40 * Map the model into a usable data structure. This doesn't involve any
41 * copying or parsing, it's a very lightweight operation. */
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +010042 debug("loading model from @ 0x%p\n", nnModelAddr);
43 debug("model size: %" PRIu32 " bytes.\n", nnModelSize);
44
45 this->m_pModel = ::tflite::GetModel(nnModelAddr);
alexander3c798932021-03-26 21:42:19 +000046
Isabella Gottardi56ee6202021-05-12 08:27:15 +010047 if (this->m_pModel->version() != TFLITE_SCHEMA_VERSION) {
Kshitij Sisodia47406fe2022-12-05 17:18:50 +000048 printf_err("Model's schema version %" PRIu32 " is not equal "
49 "to supported version %d.",
50 this->m_pModel->version(),
51 TFLITE_SCHEMA_VERSION);
alexander3c798932021-03-26 21:42:19 +000052 return false;
53 }
54
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +010055 this->m_modelAddr = nnModelAddr;
56 this->m_modelSize = nnModelSize;
57
alexander3c798932021-03-26 21:42:19 +000058 /* Pull in only the operation implementations we need.
59 * This relies on a complete list of all the ops needed by this graph.
60 * An easier approach is to just use the AllOpsResolver, but this will
61 * incur some penalty in code space for op implementations that are not
62 * needed by this graph.
63 * static ::tflite::ops::micro::AllOpsResolver resolver; */
64 /* NOLINTNEXTLINE(runtime-global-variables) */
65 debug("loading op resolver\n");
66
67 this->EnlistOperations();
68
69 /* Create allocator instance, if it doesn't exist */
Isabella Gottardi56ee6202021-05-12 08:27:15 +010070 this->m_pAllocator = allocator;
71 if (!this->m_pAllocator) {
alexander3c798932021-03-26 21:42:19 +000072 /* Create an allocator instance */
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +010073 info("Creating allocator using tensor arena at 0x%p\n", tensorArenaAddr);
alexander3c798932021-03-26 21:42:19 +000074
Kshitij Sisodia47406fe2022-12-05 17:18:50 +000075 this->m_pAllocator = tflite::MicroAllocator::Create(tensorArenaAddr, tensorArenaSize);
alexander3c798932021-03-26 21:42:19 +000076
Isabella Gottardi56ee6202021-05-12 08:27:15 +010077 if (!this->m_pAllocator) {
alexander3c798932021-03-26 21:42:19 +000078 printf_err("Failed to create allocator\n");
79 return false;
80 }
Isabella Gottardi56ee6202021-05-12 08:27:15 +010081 debug("Created new allocator @ 0x%p\n", this->m_pAllocator);
alexander3c798932021-03-26 21:42:19 +000082 } else {
Isabella Gottardi56ee6202021-05-12 08:27:15 +010083 debug("Using existing allocator @ 0x%p\n", this->m_pAllocator);
alexander3c798932021-03-26 21:42:19 +000084 }
85
Kshitij Sisodia47406fe2022-12-05 17:18:50 +000086 this->m_pInterpreter =
87 new ::tflite::MicroInterpreter(this->m_pModel, this->GetOpResolver(), this->m_pAllocator);
alexander3c798932021-03-26 21:42:19 +000088
Isabella Gottardi56ee6202021-05-12 08:27:15 +010089 if (!this->m_pInterpreter) {
alexander3c798932021-03-26 21:42:19 +000090 printf_err("Failed to allocate interpreter\n");
91 return false;
92 }
93
94 /* Allocate memory from the tensor_arena for the model's tensors. */
95 info("Allocating tensors\n");
Isabella Gottardi56ee6202021-05-12 08:27:15 +010096 TfLiteStatus allocate_status = this->m_pInterpreter->AllocateTensors();
alexander3c798932021-03-26 21:42:19 +000097
98 if (allocate_status != kTfLiteOk) {
alexander3c798932021-03-26 21:42:19 +000099 printf_err("tensor allocation failed!\n");
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100100 delete this->m_pInterpreter;
alexander3c798932021-03-26 21:42:19 +0000101 return false;
102 }
103
104 /* Get information about the memory area to use for the model's input. */
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100105 this->m_input.resize(this->GetNumInputs());
alexander3c798932021-03-26 21:42:19 +0000106 for (size_t inIndex = 0; inIndex < this->GetNumInputs(); inIndex++)
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100107 this->m_input[inIndex] = this->m_pInterpreter->input(inIndex);
alexander3c798932021-03-26 21:42:19 +0000108
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100109 this->m_output.resize(this->GetNumOutputs());
alexander3c798932021-03-26 21:42:19 +0000110 for (size_t outIndex = 0; outIndex < this->GetNumOutputs(); outIndex++)
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100111 this->m_output[outIndex] = this->m_pInterpreter->output(outIndex);
alexander3c798932021-03-26 21:42:19 +0000112
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100113 if (this->m_input.empty() || this->m_output.empty()) {
alexander3c798932021-03-26 21:42:19 +0000114 printf_err("failed to get tensors\n");
115 return false;
116 } else {
Kshitij Sisodia47406fe2022-12-05 17:18:50 +0000117 this->m_type = this->m_input[0]->type; /* Input 0 should be the main input */
alexander3c798932021-03-26 21:42:19 +0000118
119 /* Clear the input & output tensors */
120 for (size_t inIndex = 0; inIndex < this->GetNumInputs(); inIndex++) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100121 std::memset(this->m_input[inIndex]->data.data, 0, this->m_input[inIndex]->bytes);
alexander3c798932021-03-26 21:42:19 +0000122 }
123 for (size_t outIndex = 0; outIndex < this->GetNumOutputs(); outIndex++) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100124 std::memset(this->m_output[outIndex]->data.data, 0, this->m_output[outIndex]->bytes);
alexander3c798932021-03-26 21:42:19 +0000125 }
126
127 this->LogInterpreterInfo();
128 }
129
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100130 this->m_inited = true;
alexander3c798932021-03-26 21:42:19 +0000131 return true;
132}
133
134tflite::MicroAllocator* arm::app::Model::GetAllocator()
135{
136 if (this->IsInited()) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100137 return this->m_pAllocator;
alexander3c798932021-03-26 21:42:19 +0000138 }
139 return nullptr;
140}
141
142void arm::app::Model::LogTensorInfo(TfLiteTensor* tensor)
143{
144 if (!tensor) {
145 printf_err("Invalid tensor\n");
146 assert(tensor);
147 return;
148 }
149
150 debug("\ttensor is assigned to 0x%p\n", tensor);
151 info("\ttensor type is %s\n", TfLiteTypeGetName(tensor->type));
Kshitij Sisodia47406fe2022-12-05 17:18:50 +0000152 info("\ttensor occupies %zu bytes with dimensions\n", tensor->bytes);
153 for (int i = 0; i < tensor->dims->size; ++i) {
154 info("\t\t%d: %3d\n", i, tensor->dims->data[i]);
alexander3c798932021-03-26 21:42:19 +0000155 }
156
157 TfLiteQuantization quant = tensor->quantization;
158 if (kTfLiteAffineQuantization == quant.type) {
159 auto* quantParams = (TfLiteAffineQuantization*)quant.params;
Kshitij Sisodiaf9c19ea2021-05-07 16:08:14 +0100160 info("Quant dimension: %" PRIi32 "\n", quantParams->quantized_dimension);
alexander3c798932021-03-26 21:42:19 +0000161 for (int i = 0; i < quantParams->scale->size; ++i) {
162 info("Scale[%d] = %f\n", i, quantParams->scale->data[i]);
163 }
164 for (int i = 0; i < quantParams->zero_point->size; ++i) {
165 info("ZeroPoint[%d] = %d\n", i, quantParams->zero_point->data[i]);
166 }
167 }
168}
169
170void arm::app::Model::LogInterpreterInfo()
171{
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100172 if (!this->m_pInterpreter) {
alexander3c798932021-03-26 21:42:19 +0000173 printf_err("Invalid interpreter\n");
174 return;
175 }
176
177 info("Model INPUT tensors: \n");
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100178 for (auto input : this->m_input) {
alexander3c798932021-03-26 21:42:19 +0000179 this->LogTensorInfo(input);
180 }
181
182 info("Model OUTPUT tensors: \n");
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100183 for (auto output : this->m_output) {
alexander3c798932021-03-26 21:42:19 +0000184 this->LogTensorInfo(output);
185 }
186
187 info("Activation buffer (a.k.a tensor arena) size used: %zu\n",
Kshitij Sisodia47406fe2022-12-05 17:18:50 +0000188 this->m_pInterpreter->arena_used_bytes());
alexander3c798932021-03-26 21:42:19 +0000189
Richard Burton0d110592021-08-12 17:26:30 +0100190 /* We expect there to be only one subgraph. */
191 const uint32_t nOperators = tflite::NumSubgraphOperators(this->m_pModel, 0);
192 info("Number of operators: %" PRIu32 "\n", nOperators);
alexander3c798932021-03-26 21:42:19 +0000193
Richard Burton0d110592021-08-12 17:26:30 +0100194 const tflite::SubGraph* subgraph = this->m_pModel->subgraphs()->Get(0);
195
196 auto* opcodes = this->m_pModel->operator_codes();
197
198 /* For each operator, display registration information. */
Kshitij Sisodia47406fe2022-12-05 17:18:50 +0000199 for (size_t i = 0; i < nOperators; ++i) {
200 const tflite::Operator* op = subgraph->operators()->Get(i);
Richard Burton0d110592021-08-12 17:26:30 +0100201 const tflite::OperatorCode* opcode = opcodes->Get(op->opcode_index());
Kshitij Sisodia47406fe2022-12-05 17:18:50 +0000202 const TfLiteRegistration* reg = nullptr;
Richard Burton0d110592021-08-12 17:26:30 +0100203
Richard Burton71f282e2022-12-01 12:31:23 +0000204 tflite::GetRegistrationFromOpCode(opcode, this->GetOpResolver(), &reg);
alexander31ae9f02022-02-10 16:15:54 +0000205 std::string opName;
alexander3c798932021-03-26 21:42:19 +0000206
207 if (reg) {
208 if (tflite::BuiltinOperator_CUSTOM == reg->builtin_code) {
209 opName = std::string(reg->custom_name);
210 } else {
Kshitij Sisodia47406fe2022-12-05 17:18:50 +0000211 opName = std::string(
212 EnumNameBuiltinOperator(tflite::BuiltinOperator(reg->builtin_code)));
alexander3c798932021-03-26 21:42:19 +0000213 }
214 }
Kshitij Sisodiaf9c19ea2021-05-07 16:08:14 +0100215 info("\tOperator %zu: %s\n", i, opName.c_str());
alexander3c798932021-03-26 21:42:19 +0000216 }
217}
218
219bool arm::app::Model::IsInited() const
220{
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100221 return this->m_inited;
alexander3c798932021-03-26 21:42:19 +0000222}
223
224bool arm::app::Model::IsDataSigned() const
225{
226 return this->GetType() == kTfLiteInt8;
227}
228
Cisco Cervellera02101092021-09-07 11:34:43 +0100229bool arm::app::Model::ContainsEthosUOperator() const
230{
231 /* We expect there to be only one subgraph. */
Kshitij Sisodia47406fe2022-12-05 17:18:50 +0000232 const uint32_t nOperators = tflite::NumSubgraphOperators(this->m_pModel, 0);
Cisco Cervellera02101092021-09-07 11:34:43 +0100233 const tflite::SubGraph* subgraph = this->m_pModel->subgraphs()->Get(0);
Kshitij Sisodia47406fe2022-12-05 17:18:50 +0000234 const auto* opcodes = this->m_pModel->operator_codes();
Cisco Cervellera02101092021-09-07 11:34:43 +0100235
236 /* check for custom operators */
Kshitij Sisodia47406fe2022-12-05 17:18:50 +0000237 for (size_t i = 0; (i < nOperators); ++i) {
238 const tflite::Operator* op = subgraph->operators()->Get(i);
Cisco Cervellera02101092021-09-07 11:34:43 +0100239 const tflite::OperatorCode* opcode = opcodes->Get(op->opcode_index());
240
241 auto builtin_code = tflite::GetBuiltinCode(opcode);
242 if ((builtin_code == tflite::BuiltinOperator_CUSTOM) &&
Kshitij Sisodia47406fe2022-12-05 17:18:50 +0000243 (nullptr != opcode->custom_code()) &&
244 ("ethos-u" == std::string(opcode->custom_code()->c_str()))) {
Cisco Cervellera02101092021-09-07 11:34:43 +0100245 return true;
246 }
247 }
248 return false;
249}
250
alexander3c798932021-03-26 21:42:19 +0000251bool arm::app::Model::RunInference()
252{
253 bool inference_state = false;
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100254 if (this->m_pModel && this->m_pInterpreter) {
255 if (kTfLiteOk != this->m_pInterpreter->Invoke()) {
alexander3c798932021-03-26 21:42:19 +0000256 printf_err("Invoke failed.\n");
257 } else {
258 inference_state = true;
259 }
260 } else {
261 printf_err("Error: No interpreter!\n");
262 }
263 return inference_state;
264}
265
266TfLiteTensor* arm::app::Model::GetInputTensor(size_t index) const
267{
268 if (index < this->GetNumInputs()) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100269 return this->m_input.at(index);
alexander3c798932021-03-26 21:42:19 +0000270 }
271 return nullptr;
272}
273
274TfLiteTensor* arm::app::Model::GetOutputTensor(size_t index) const
275{
276 if (index < this->GetNumOutputs()) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100277 return this->m_output.at(index);
alexander3c798932021-03-26 21:42:19 +0000278 }
279 return nullptr;
280}
281
282size_t arm::app::Model::GetNumInputs() const
283{
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100284 if (this->m_pModel && this->m_pInterpreter) {
285 return this->m_pInterpreter->inputs_size();
alexander3c798932021-03-26 21:42:19 +0000286 }
287 return 0;
288}
289
290size_t arm::app::Model::GetNumOutputs() const
291{
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100292 if (this->m_pModel && this->m_pInterpreter) {
293 return this->m_pInterpreter->outputs_size();
alexander3c798932021-03-26 21:42:19 +0000294 }
295 return 0;
296}
297
alexander3c798932021-03-26 21:42:19 +0000298TfLiteType arm::app::Model::GetType() const
299{
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100300 return this->m_type;
alexander3c798932021-03-26 21:42:19 +0000301}
302
303TfLiteIntArray* arm::app::Model::GetInputShape(size_t index) const
304{
305 if (index < this->GetNumInputs()) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100306 return this->m_input.at(index)->dims;
alexander3c798932021-03-26 21:42:19 +0000307 }
308 return nullptr;
309}
310
311TfLiteIntArray* arm::app::Model::GetOutputShape(size_t index) const
312{
313 if (index < this->GetNumOutputs()) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100314 return this->m_output.at(index)->dims;
alexander3c798932021-03-26 21:42:19 +0000315 }
316 return nullptr;
317}
318
319bool arm::app::Model::ShowModelInfoHandler()
320{
321 if (!this->IsInited()) {
322 printf_err("Model is not initialised! Terminating processing.\n");
323 return false;
324 }
325
326 PrintTensorFlowVersion();
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +0100327 info("Model address: 0x%p", this->ModelPointer());
328 info("Model size: %" PRIu32 " bytes.", this->ModelSize());
alexander3c798932021-03-26 21:42:19 +0000329 info("Model info:\n");
330 this->LogInterpreterInfo();
331
Kshitij Sisodia47406fe2022-12-05 17:18:50 +0000332 info("The model is optimised for Ethos-U NPU: %s.\n",
333 this->ContainsEthosUOperator() ? "yes" : "no");
alexander3c798932021-03-26 21:42:19 +0000334
335 return true;
336}
alexander3c798932021-03-26 21:42:19 +0000337
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +0100338const uint8_t* arm::app::Model::ModelPointer()
alexander3c798932021-03-26 21:42:19 +0000339{
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +0100340 return this->m_modelAddr;
alexander3c798932021-03-26 21:42:19 +0000341}
342
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +0100343uint32_t arm::app::Model::ModelSize()
alexander3c798932021-03-26 21:42:19 +0000344{
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +0100345 return this->m_modelSize;
346}