blob: 8467d71b58aeaf35a731e3dcc39c167756a30d34 [file] [log] [blame]
alexander3c798932021-03-26 21:42:19 +00001/*
Richard Burton71f282e2022-12-01 12:31:23 +00002 * SPDX-FileCopyrightText: Copyright 2021-2022 Arm Limited and/or its affiliates <open-source-office@arm.com>
alexander3c798932021-03-26 21:42:19 +00003 * SPDX-License-Identifier: Apache-2.0
4 *
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{
alexander31ae9f02022-02-10 16:15:54 +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
31arm::app::Model::Model() :
Isabella Gottardi56ee6202021-05-12 08:27:15 +010032 m_inited (false),
33 m_type(kTfLiteNoType)
Richard Burton71f282e2022-12-01 12:31:23 +000034{}
alexander3c798932021-03-26 21:42:19 +000035
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +010036bool arm::app::Model::Init(uint8_t* tensorArenaAddr,
37 uint32_t tensorArenaSize,
Kshitij Sisodia937052d2022-05-13 16:44:16 +010038 const uint8_t* nnModelAddr,
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +010039 uint32_t nnModelSize,
40 tflite::MicroAllocator* allocator)
alexander3c798932021-03-26 21:42:19 +000041{
42 /* Following tf lite micro example:
43 * Map the model into a usable data structure. This doesn't involve any
44 * copying or parsing, it's a very lightweight operation. */
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +010045 debug("loading model from @ 0x%p\n", nnModelAddr);
46 debug("model size: %" PRIu32 " bytes.\n", nnModelSize);
47
48 this->m_pModel = ::tflite::GetModel(nnModelAddr);
alexander3c798932021-03-26 21:42:19 +000049
Isabella Gottardi56ee6202021-05-12 08:27:15 +010050 if (this->m_pModel->version() != TFLITE_SCHEMA_VERSION) {
Richard Burton71f282e2022-12-01 12:31:23 +000051 printf_err(
52 "Model's schema version %d is not equal "
alexander3c798932021-03-26 21:42:19 +000053 "to supported version %d.",
Isabella Gottardi56ee6202021-05-12 08:27:15 +010054 this->m_pModel->version(), TFLITE_SCHEMA_VERSION);
alexander3c798932021-03-26 21:42:19 +000055 return false;
56 }
57
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +010058 this->m_modelAddr = nnModelAddr;
59 this->m_modelSize = nnModelSize;
60
alexander3c798932021-03-26 21:42:19 +000061 /* Pull in only the operation implementations we need.
62 * This relies on a complete list of all the ops needed by this graph.
63 * An easier approach is to just use the AllOpsResolver, but this will
64 * incur some penalty in code space for op implementations that are not
65 * needed by this graph.
66 * static ::tflite::ops::micro::AllOpsResolver resolver; */
67 /* NOLINTNEXTLINE(runtime-global-variables) */
68 debug("loading op resolver\n");
69
70 this->EnlistOperations();
71
72 /* Create allocator instance, if it doesn't exist */
Isabella Gottardi56ee6202021-05-12 08:27:15 +010073 this->m_pAllocator = allocator;
74 if (!this->m_pAllocator) {
alexander3c798932021-03-26 21:42:19 +000075 /* Create an allocator instance */
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +010076 info("Creating allocator using tensor arena at 0x%p\n", tensorArenaAddr);
alexander3c798932021-03-26 21:42:19 +000077
Isabella Gottardi56ee6202021-05-12 08:27:15 +010078 this->m_pAllocator = tflite::MicroAllocator::Create(
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +010079 tensorArenaAddr,
Richard Burton71f282e2022-12-01 12:31:23 +000080 tensorArenaSize);
alexander3c798932021-03-26 21:42:19 +000081
Isabella Gottardi56ee6202021-05-12 08:27:15 +010082 if (!this->m_pAllocator) {
alexander3c798932021-03-26 21:42:19 +000083 printf_err("Failed to create allocator\n");
84 return false;
85 }
Isabella Gottardi56ee6202021-05-12 08:27:15 +010086 debug("Created new allocator @ 0x%p\n", this->m_pAllocator);
alexander3c798932021-03-26 21:42:19 +000087 } else {
Isabella Gottardi56ee6202021-05-12 08:27:15 +010088 debug("Using existing allocator @ 0x%p\n", this->m_pAllocator);
alexander3c798932021-03-26 21:42:19 +000089 }
90
Isabella Gottardi56ee6202021-05-12 08:27:15 +010091 this->m_pInterpreter = new ::tflite::MicroInterpreter(
92 this->m_pModel, this->GetOpResolver(),
Richard Burton71f282e2022-12-01 12:31:23 +000093 this->m_pAllocator);
alexander3c798932021-03-26 21:42:19 +000094
Isabella Gottardi56ee6202021-05-12 08:27:15 +010095 if (!this->m_pInterpreter) {
alexander3c798932021-03-26 21:42:19 +000096 printf_err("Failed to allocate interpreter\n");
97 return false;
98 }
99
100 /* Allocate memory from the tensor_arena for the model's tensors. */
101 info("Allocating tensors\n");
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100102 TfLiteStatus allocate_status = this->m_pInterpreter->AllocateTensors();
alexander3c798932021-03-26 21:42:19 +0000103
104 if (allocate_status != kTfLiteOk) {
alexander3c798932021-03-26 21:42:19 +0000105 printf_err("tensor allocation failed!\n");
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100106 delete this->m_pInterpreter;
alexander3c798932021-03-26 21:42:19 +0000107 return false;
108 }
109
110 /* Get information about the memory area to use for the model's input. */
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100111 this->m_input.resize(this->GetNumInputs());
alexander3c798932021-03-26 21:42:19 +0000112 for (size_t inIndex = 0; inIndex < this->GetNumInputs(); inIndex++)
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100113 this->m_input[inIndex] = this->m_pInterpreter->input(inIndex);
alexander3c798932021-03-26 21:42:19 +0000114
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100115 this->m_output.resize(this->GetNumOutputs());
alexander3c798932021-03-26 21:42:19 +0000116 for (size_t outIndex = 0; outIndex < this->GetNumOutputs(); outIndex++)
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100117 this->m_output[outIndex] = this->m_pInterpreter->output(outIndex);
alexander3c798932021-03-26 21:42:19 +0000118
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100119 if (this->m_input.empty() || this->m_output.empty()) {
alexander3c798932021-03-26 21:42:19 +0000120 printf_err("failed to get tensors\n");
121 return false;
122 } else {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100123 this->m_type = this->m_input[0]->type; /* Input 0 should be the main input */
alexander3c798932021-03-26 21:42:19 +0000124
125 /* Clear the input & output tensors */
126 for (size_t inIndex = 0; inIndex < this->GetNumInputs(); inIndex++) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100127 std::memset(this->m_input[inIndex]->data.data, 0, this->m_input[inIndex]->bytes);
alexander3c798932021-03-26 21:42:19 +0000128 }
129 for (size_t outIndex = 0; outIndex < this->GetNumOutputs(); outIndex++) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100130 std::memset(this->m_output[outIndex]->data.data, 0, this->m_output[outIndex]->bytes);
alexander3c798932021-03-26 21:42:19 +0000131 }
132
133 this->LogInterpreterInfo();
134 }
135
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100136 this->m_inited = true;
alexander3c798932021-03-26 21:42:19 +0000137 return true;
138}
139
140tflite::MicroAllocator* arm::app::Model::GetAllocator()
141{
142 if (this->IsInited()) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100143 return this->m_pAllocator;
alexander3c798932021-03-26 21:42:19 +0000144 }
145 return nullptr;
146}
147
148void arm::app::Model::LogTensorInfo(TfLiteTensor* tensor)
149{
150 if (!tensor) {
151 printf_err("Invalid tensor\n");
152 assert(tensor);
153 return;
154 }
155
156 debug("\ttensor is assigned to 0x%p\n", tensor);
157 info("\ttensor type is %s\n", TfLiteTypeGetName(tensor->type));
Kshitij Sisodiaf9c19ea2021-05-07 16:08:14 +0100158 info("\ttensor occupies %zu bytes with dimensions\n",
159 tensor->bytes);
alexander3c798932021-03-26 21:42:19 +0000160 for (int i = 0 ; i < tensor->dims->size; ++i) {
161 info ("\t\t%d: %3d\n", i, tensor->dims->data[i]);
162 }
163
164 TfLiteQuantization quant = tensor->quantization;
165 if (kTfLiteAffineQuantization == quant.type) {
166 auto* quantParams = (TfLiteAffineQuantization*)quant.params;
Kshitij Sisodiaf9c19ea2021-05-07 16:08:14 +0100167 info("Quant dimension: %" PRIi32 "\n", quantParams->quantized_dimension);
alexander3c798932021-03-26 21:42:19 +0000168 for (int i = 0; i < quantParams->scale->size; ++i) {
169 info("Scale[%d] = %f\n", i, quantParams->scale->data[i]);
170 }
171 for (int i = 0; i < quantParams->zero_point->size; ++i) {
172 info("ZeroPoint[%d] = %d\n", i, quantParams->zero_point->data[i]);
173 }
174 }
175}
176
177void arm::app::Model::LogInterpreterInfo()
178{
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100179 if (!this->m_pInterpreter) {
alexander3c798932021-03-26 21:42:19 +0000180 printf_err("Invalid interpreter\n");
181 return;
182 }
183
184 info("Model INPUT tensors: \n");
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100185 for (auto input : this->m_input) {
alexander3c798932021-03-26 21:42:19 +0000186 this->LogTensorInfo(input);
187 }
188
189 info("Model OUTPUT tensors: \n");
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100190 for (auto output : this->m_output) {
alexander3c798932021-03-26 21:42:19 +0000191 this->LogTensorInfo(output);
192 }
193
194 info("Activation buffer (a.k.a tensor arena) size used: %zu\n",
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100195 this->m_pInterpreter->arena_used_bytes());
alexander3c798932021-03-26 21:42:19 +0000196
Richard Burton0d110592021-08-12 17:26:30 +0100197 /* We expect there to be only one subgraph. */
198 const uint32_t nOperators = tflite::NumSubgraphOperators(this->m_pModel, 0);
199 info("Number of operators: %" PRIu32 "\n", nOperators);
alexander3c798932021-03-26 21:42:19 +0000200
Richard Burton0d110592021-08-12 17:26:30 +0100201 const tflite::SubGraph* subgraph = this->m_pModel->subgraphs()->Get(0);
202
203 auto* opcodes = this->m_pModel->operator_codes();
204
205 /* For each operator, display registration information. */
Kshitij Sisodiaf9c19ea2021-05-07 16:08:14 +0100206 for (size_t i = 0 ; i < nOperators; ++i) {
Richard Burton0d110592021-08-12 17:26:30 +0100207 const tflite::Operator* op = subgraph->operators()->Get(i);
208 const tflite::OperatorCode* opcode = opcodes->Get(op->opcode_index());
209 const TfLiteRegistration* reg = nullptr;
210
Richard Burton71f282e2022-12-01 12:31:23 +0000211 tflite::GetRegistrationFromOpCode(opcode, this->GetOpResolver(), &reg);
alexander31ae9f02022-02-10 16:15:54 +0000212 std::string opName;
alexander3c798932021-03-26 21:42:19 +0000213
214 if (reg) {
215 if (tflite::BuiltinOperator_CUSTOM == reg->builtin_code) {
216 opName = std::string(reg->custom_name);
217 } else {
218 opName = std::string(EnumNameBuiltinOperator(
219 tflite::BuiltinOperator(reg->builtin_code)));
220 }
221 }
Kshitij Sisodiaf9c19ea2021-05-07 16:08:14 +0100222 info("\tOperator %zu: %s\n", i, opName.c_str());
alexander3c798932021-03-26 21:42:19 +0000223 }
224}
225
226bool arm::app::Model::IsInited() const
227{
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100228 return this->m_inited;
alexander3c798932021-03-26 21:42:19 +0000229}
230
231bool arm::app::Model::IsDataSigned() const
232{
233 return this->GetType() == kTfLiteInt8;
234}
235
Cisco Cervellera02101092021-09-07 11:34:43 +0100236bool arm::app::Model::ContainsEthosUOperator() const
237{
238 /* We expect there to be only one subgraph. */
239 const uint32_t nOperators = tflite::NumSubgraphOperators(this->m_pModel, 0);
240 const tflite::SubGraph* subgraph = this->m_pModel->subgraphs()->Get(0);
241 const auto* opcodes = this->m_pModel->operator_codes();
242
243 /* check for custom operators */
244 for (size_t i = 0; (i < nOperators); ++i)
245 {
246 const tflite::Operator* op = subgraph->operators()->Get(i);
247 const tflite::OperatorCode* opcode = opcodes->Get(op->opcode_index());
248
249 auto builtin_code = tflite::GetBuiltinCode(opcode);
250 if ((builtin_code == tflite::BuiltinOperator_CUSTOM) &&
251 ( nullptr != opcode->custom_code()) &&
alexander31ae9f02022-02-10 16:15:54 +0000252 ( "ethos-u" == std::string(opcode->custom_code()->c_str())))
Cisco Cervellera02101092021-09-07 11:34:43 +0100253 {
254 return true;
255 }
256 }
257 return false;
258}
259
alexander3c798932021-03-26 21:42:19 +0000260bool arm::app::Model::RunInference()
261{
262 bool inference_state = false;
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100263 if (this->m_pModel && this->m_pInterpreter) {
264 if (kTfLiteOk != this->m_pInterpreter->Invoke()) {
alexander3c798932021-03-26 21:42:19 +0000265 printf_err("Invoke failed.\n");
266 } else {
267 inference_state = true;
268 }
269 } else {
270 printf_err("Error: No interpreter!\n");
271 }
272 return inference_state;
273}
274
275TfLiteTensor* arm::app::Model::GetInputTensor(size_t index) const
276{
277 if (index < this->GetNumInputs()) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100278 return this->m_input.at(index);
alexander3c798932021-03-26 21:42:19 +0000279 }
280 return nullptr;
281}
282
283TfLiteTensor* arm::app::Model::GetOutputTensor(size_t index) const
284{
285 if (index < this->GetNumOutputs()) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100286 return this->m_output.at(index);
alexander3c798932021-03-26 21:42:19 +0000287 }
288 return nullptr;
289}
290
291size_t arm::app::Model::GetNumInputs() const
292{
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100293 if (this->m_pModel && this->m_pInterpreter) {
294 return this->m_pInterpreter->inputs_size();
alexander3c798932021-03-26 21:42:19 +0000295 }
296 return 0;
297}
298
299size_t arm::app::Model::GetNumOutputs() const
300{
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100301 if (this->m_pModel && this->m_pInterpreter) {
302 return this->m_pInterpreter->outputs_size();
alexander3c798932021-03-26 21:42:19 +0000303 }
304 return 0;
305}
306
307
308TfLiteType arm::app::Model::GetType() const
309{
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100310 return this->m_type;
alexander3c798932021-03-26 21:42:19 +0000311}
312
313TfLiteIntArray* arm::app::Model::GetInputShape(size_t index) const
314{
315 if (index < this->GetNumInputs()) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100316 return this->m_input.at(index)->dims;
alexander3c798932021-03-26 21:42:19 +0000317 }
318 return nullptr;
319}
320
321TfLiteIntArray* arm::app::Model::GetOutputShape(size_t index) const
322{
323 if (index < this->GetNumOutputs()) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100324 return this->m_output.at(index)->dims;
alexander3c798932021-03-26 21:42:19 +0000325 }
326 return nullptr;
327}
328
329bool arm::app::Model::ShowModelInfoHandler()
330{
331 if (!this->IsInited()) {
332 printf_err("Model is not initialised! Terminating processing.\n");
333 return false;
334 }
335
336 PrintTensorFlowVersion();
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +0100337 info("Model address: 0x%p", this->ModelPointer());
338 info("Model size: %" PRIu32 " bytes.", this->ModelSize());
alexander3c798932021-03-26 21:42:19 +0000339 info("Model info:\n");
340 this->LogInterpreterInfo();
341
alexander31ae9f02022-02-10 16:15:54 +0000342 info("The model is optimised for Ethos-U NPU: %s.\n", this->ContainsEthosUOperator()? "yes": "no");
alexander3c798932021-03-26 21:42:19 +0000343
344 return true;
345}
alexander3c798932021-03-26 21:42:19 +0000346
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +0100347const uint8_t* arm::app::Model::ModelPointer()
alexander3c798932021-03-26 21:42:19 +0000348{
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +0100349 return this->m_modelAddr;
alexander3c798932021-03-26 21:42:19 +0000350}
351
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +0100352uint32_t arm::app::Model::ModelSize()
alexander3c798932021-03-26 21:42:19 +0000353{
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +0100354 return this->m_modelSize;
355}