blob: adcf8d7624350bfe57c6bce8cc0ab237de6f366a [file] [log] [blame]
alexander3c798932021-03-26 21:42:19 +00001/*
2 * Copyright (c) 2021 Arm Limited. All rights reserved.
3 * 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)
alexander3c798932021-03-26 21:42:19 +000034{
Isabella Gottardi56ee6202021-05-12 08:27:15 +010035 this->m_pErrorReporter = &this->m_uErrorReporter;
alexander3c798932021-03-26 21:42:19 +000036}
37
38bool arm::app::Model::Init(tflite::MicroAllocator* allocator)
39{
40 /* Following tf lite micro example:
41 * Map the model into a usable data structure. This doesn't involve any
42 * copying or parsing, it's a very lightweight operation. */
43 const uint8_t* model_addr = ModelPointer();
44 debug("loading model from @ 0x%p\n", model_addr);
Isabella Gottardi56ee6202021-05-12 08:27:15 +010045 this->m_pModel = ::tflite::GetModel(model_addr);
alexander3c798932021-03-26 21:42:19 +000046
Isabella Gottardi56ee6202021-05-12 08:27:15 +010047 if (this->m_pModel->version() != TFLITE_SCHEMA_VERSION) {
48 this->m_pErrorReporter->Report(
alexander3c798932021-03-26 21:42:19 +000049 "[ERROR] model's schema version %d is not equal "
50 "to supported version %d.",
Isabella Gottardi56ee6202021-05-12 08:27:15 +010051 this->m_pModel->version(), TFLITE_SCHEMA_VERSION);
alexander3c798932021-03-26 21:42:19 +000052 return false;
53 }
54
55 /* Pull in only the operation implementations we need.
56 * This relies on a complete list of all the ops needed by this graph.
57 * An easier approach is to just use the AllOpsResolver, but this will
58 * incur some penalty in code space for op implementations that are not
59 * needed by this graph.
60 * static ::tflite::ops::micro::AllOpsResolver resolver; */
61 /* NOLINTNEXTLINE(runtime-global-variables) */
62 debug("loading op resolver\n");
63
64 this->EnlistOperations();
Cisco Cervellera02101092021-09-07 11:34:43 +010065
66#if !defined(ARM_NPU)
67 /* If it is not a NPU build check if the model contains a NPU operator */
68 bool contains_ethosu_operator = this->ContainsEthosUOperator();
69 if (contains_ethosu_operator)
70 {
71 printf_err("Ethos-U operator present in the model but this build does not include Ethos-U drivers\n");
72 return false;
73 }
74#endif /* ARM_NPU */
alexander3c798932021-03-26 21:42:19 +000075
76 /* Create allocator instance, if it doesn't exist */
Isabella Gottardi56ee6202021-05-12 08:27:15 +010077 this->m_pAllocator = allocator;
78 if (!this->m_pAllocator) {
alexander3c798932021-03-26 21:42:19 +000079 /* Create an allocator instance */
80 info("Creating allocator using tensor arena in %s\n",
81 ACTIVATION_BUF_SECTION_NAME);
82
Isabella Gottardi56ee6202021-05-12 08:27:15 +010083 this->m_pAllocator = tflite::MicroAllocator::Create(
alexander3c798932021-03-26 21:42:19 +000084 this->GetTensorArena(),
85 this->GetActivationBufferSize(),
Isabella Gottardi56ee6202021-05-12 08:27:15 +010086 this->m_pErrorReporter);
alexander3c798932021-03-26 21:42:19 +000087
Isabella Gottardi56ee6202021-05-12 08:27:15 +010088 if (!this->m_pAllocator) {
alexander3c798932021-03-26 21:42:19 +000089 printf_err("Failed to create allocator\n");
90 return false;
91 }
Isabella Gottardi56ee6202021-05-12 08:27:15 +010092 debug("Created new allocator @ 0x%p\n", this->m_pAllocator);
alexander3c798932021-03-26 21:42:19 +000093 } else {
Isabella Gottardi56ee6202021-05-12 08:27:15 +010094 debug("Using existing allocator @ 0x%p\n", this->m_pAllocator);
alexander3c798932021-03-26 21:42:19 +000095 }
96
Isabella Gottardi56ee6202021-05-12 08:27:15 +010097 this->m_pInterpreter = new ::tflite::MicroInterpreter(
98 this->m_pModel, this->GetOpResolver(),
99 this->m_pAllocator, this->m_pErrorReporter);
alexander3c798932021-03-26 21:42:19 +0000100
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100101 if (!this->m_pInterpreter) {
alexander3c798932021-03-26 21:42:19 +0000102 printf_err("Failed to allocate interpreter\n");
103 return false;
104 }
105
106 /* Allocate memory from the tensor_arena for the model's tensors. */
107 info("Allocating tensors\n");
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100108 TfLiteStatus allocate_status = this->m_pInterpreter->AllocateTensors();
alexander3c798932021-03-26 21:42:19 +0000109
110 if (allocate_status != kTfLiteOk) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100111 this->m_pErrorReporter->Report("[ERROR] allocateTensors() failed");
alexander3c798932021-03-26 21:42:19 +0000112 printf_err("tensor allocation failed!\n");
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100113 delete this->m_pInterpreter;
alexander3c798932021-03-26 21:42:19 +0000114 return false;
115 }
116
117 /* Get information about the memory area to use for the model's input. */
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100118 this->m_input.resize(this->GetNumInputs());
alexander3c798932021-03-26 21:42:19 +0000119 for (size_t inIndex = 0; inIndex < this->GetNumInputs(); inIndex++)
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100120 this->m_input[inIndex] = this->m_pInterpreter->input(inIndex);
alexander3c798932021-03-26 21:42:19 +0000121
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100122 this->m_output.resize(this->GetNumOutputs());
alexander3c798932021-03-26 21:42:19 +0000123 for (size_t outIndex = 0; outIndex < this->GetNumOutputs(); outIndex++)
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100124 this->m_output[outIndex] = this->m_pInterpreter->output(outIndex);
alexander3c798932021-03-26 21:42:19 +0000125
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100126 if (this->m_input.empty() || this->m_output.empty()) {
alexander3c798932021-03-26 21:42:19 +0000127 printf_err("failed to get tensors\n");
128 return false;
129 } else {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100130 this->m_type = this->m_input[0]->type; /* Input 0 should be the main input */
alexander3c798932021-03-26 21:42:19 +0000131
132 /* Clear the input & output tensors */
133 for (size_t inIndex = 0; inIndex < this->GetNumInputs(); inIndex++) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100134 std::memset(this->m_input[inIndex]->data.data, 0, this->m_input[inIndex]->bytes);
alexander3c798932021-03-26 21:42:19 +0000135 }
136 for (size_t outIndex = 0; outIndex < this->GetNumOutputs(); outIndex++) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100137 std::memset(this->m_output[outIndex]->data.data, 0, this->m_output[outIndex]->bytes);
alexander3c798932021-03-26 21:42:19 +0000138 }
139
140 this->LogInterpreterInfo();
141 }
142
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100143 this->m_inited = true;
alexander3c798932021-03-26 21:42:19 +0000144 return true;
145}
146
147tflite::MicroAllocator* arm::app::Model::GetAllocator()
148{
149 if (this->IsInited()) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100150 return this->m_pAllocator;
alexander3c798932021-03-26 21:42:19 +0000151 }
152 return nullptr;
153}
154
155void arm::app::Model::LogTensorInfo(TfLiteTensor* tensor)
156{
157 if (!tensor) {
158 printf_err("Invalid tensor\n");
159 assert(tensor);
160 return;
161 }
162
163 debug("\ttensor is assigned to 0x%p\n", tensor);
164 info("\ttensor type is %s\n", TfLiteTypeGetName(tensor->type));
Kshitij Sisodiaf9c19ea2021-05-07 16:08:14 +0100165 info("\ttensor occupies %zu bytes with dimensions\n",
166 tensor->bytes);
alexander3c798932021-03-26 21:42:19 +0000167 for (int i = 0 ; i < tensor->dims->size; ++i) {
168 info ("\t\t%d: %3d\n", i, tensor->dims->data[i]);
169 }
170
171 TfLiteQuantization quant = tensor->quantization;
172 if (kTfLiteAffineQuantization == quant.type) {
173 auto* quantParams = (TfLiteAffineQuantization*)quant.params;
Kshitij Sisodiaf9c19ea2021-05-07 16:08:14 +0100174 info("Quant dimension: %" PRIi32 "\n", quantParams->quantized_dimension);
alexander3c798932021-03-26 21:42:19 +0000175 for (int i = 0; i < quantParams->scale->size; ++i) {
176 info("Scale[%d] = %f\n", i, quantParams->scale->data[i]);
177 }
178 for (int i = 0; i < quantParams->zero_point->size; ++i) {
179 info("ZeroPoint[%d] = %d\n", i, quantParams->zero_point->data[i]);
180 }
181 }
182}
183
184void arm::app::Model::LogInterpreterInfo()
185{
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100186 if (!this->m_pInterpreter) {
alexander3c798932021-03-26 21:42:19 +0000187 printf_err("Invalid interpreter\n");
188 return;
189 }
190
191 info("Model INPUT tensors: \n");
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100192 for (auto input : this->m_input) {
alexander3c798932021-03-26 21:42:19 +0000193 this->LogTensorInfo(input);
194 }
195
196 info("Model OUTPUT tensors: \n");
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100197 for (auto output : this->m_output) {
alexander3c798932021-03-26 21:42:19 +0000198 this->LogTensorInfo(output);
199 }
200
201 info("Activation buffer (a.k.a tensor arena) size used: %zu\n",
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100202 this->m_pInterpreter->arena_used_bytes());
alexander3c798932021-03-26 21:42:19 +0000203
Richard Burton0d110592021-08-12 17:26:30 +0100204 /* We expect there to be only one subgraph. */
205 const uint32_t nOperators = tflite::NumSubgraphOperators(this->m_pModel, 0);
206 info("Number of operators: %" PRIu32 "\n", nOperators);
alexander3c798932021-03-26 21:42:19 +0000207
Richard Burton0d110592021-08-12 17:26:30 +0100208 const tflite::SubGraph* subgraph = this->m_pModel->subgraphs()->Get(0);
209
210 auto* opcodes = this->m_pModel->operator_codes();
211
212 /* For each operator, display registration information. */
Kshitij Sisodiaf9c19ea2021-05-07 16:08:14 +0100213 for (size_t i = 0 ; i < nOperators; ++i) {
Richard Burton0d110592021-08-12 17:26:30 +0100214 const tflite::Operator* op = subgraph->operators()->Get(i);
215 const tflite::OperatorCode* opcode = opcodes->Get(op->opcode_index());
216 const TfLiteRegistration* reg = nullptr;
217
218 tflite::GetRegistrationFromOpCode(opcode, this->GetOpResolver(),
219 this->m_pErrorReporter, &reg);
alexander31ae9f02022-02-10 16:15:54 +0000220 std::string opName;
alexander3c798932021-03-26 21:42:19 +0000221
222 if (reg) {
223 if (tflite::BuiltinOperator_CUSTOM == reg->builtin_code) {
224 opName = std::string(reg->custom_name);
225 } else {
226 opName = std::string(EnumNameBuiltinOperator(
227 tflite::BuiltinOperator(reg->builtin_code)));
228 }
229 }
Kshitij Sisodiaf9c19ea2021-05-07 16:08:14 +0100230 info("\tOperator %zu: %s\n", i, opName.c_str());
alexander3c798932021-03-26 21:42:19 +0000231 }
232}
233
234bool arm::app::Model::IsInited() const
235{
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100236 return this->m_inited;
alexander3c798932021-03-26 21:42:19 +0000237}
238
239bool arm::app::Model::IsDataSigned() const
240{
241 return this->GetType() == kTfLiteInt8;
242}
243
Cisco Cervellera02101092021-09-07 11:34:43 +0100244bool arm::app::Model::ContainsEthosUOperator() const
245{
246 /* We expect there to be only one subgraph. */
247 const uint32_t nOperators = tflite::NumSubgraphOperators(this->m_pModel, 0);
248 const tflite::SubGraph* subgraph = this->m_pModel->subgraphs()->Get(0);
249 const auto* opcodes = this->m_pModel->operator_codes();
250
251 /* check for custom operators */
252 for (size_t i = 0; (i < nOperators); ++i)
253 {
254 const tflite::Operator* op = subgraph->operators()->Get(i);
255 const tflite::OperatorCode* opcode = opcodes->Get(op->opcode_index());
256
257 auto builtin_code = tflite::GetBuiltinCode(opcode);
258 if ((builtin_code == tflite::BuiltinOperator_CUSTOM) &&
259 ( nullptr != opcode->custom_code()) &&
alexander31ae9f02022-02-10 16:15:54 +0000260 ( "ethos-u" == std::string(opcode->custom_code()->c_str())))
Cisco Cervellera02101092021-09-07 11:34:43 +0100261 {
262 return true;
263 }
264 }
265 return false;
266}
267
alexander3c798932021-03-26 21:42:19 +0000268bool arm::app::Model::RunInference()
269{
270 bool inference_state = false;
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100271 if (this->m_pModel && this->m_pInterpreter) {
272 if (kTfLiteOk != this->m_pInterpreter->Invoke()) {
alexander3c798932021-03-26 21:42:19 +0000273 printf_err("Invoke failed.\n");
274 } else {
275 inference_state = true;
276 }
277 } else {
278 printf_err("Error: No interpreter!\n");
279 }
280 return inference_state;
281}
282
283TfLiteTensor* arm::app::Model::GetInputTensor(size_t index) const
284{
285 if (index < this->GetNumInputs()) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100286 return this->m_input.at(index);
alexander3c798932021-03-26 21:42:19 +0000287 }
288 return nullptr;
289}
290
291TfLiteTensor* arm::app::Model::GetOutputTensor(size_t index) const
292{
293 if (index < this->GetNumOutputs()) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100294 return this->m_output.at(index);
alexander3c798932021-03-26 21:42:19 +0000295 }
296 return nullptr;
297}
298
299size_t arm::app::Model::GetNumInputs() const
300{
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100301 if (this->m_pModel && this->m_pInterpreter) {
302 return this->m_pInterpreter->inputs_size();
alexander3c798932021-03-26 21:42:19 +0000303 }
304 return 0;
305}
306
307size_t arm::app::Model::GetNumOutputs() const
308{
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100309 if (this->m_pModel && this->m_pInterpreter) {
310 return this->m_pInterpreter->outputs_size();
alexander3c798932021-03-26 21:42:19 +0000311 }
312 return 0;
313}
314
315
316TfLiteType arm::app::Model::GetType() const
317{
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100318 return this->m_type;
alexander3c798932021-03-26 21:42:19 +0000319}
320
321TfLiteIntArray* arm::app::Model::GetInputShape(size_t index) const
322{
323 if (index < this->GetNumInputs()) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100324 return this->m_input.at(index)->dims;
alexander3c798932021-03-26 21:42:19 +0000325 }
326 return nullptr;
327}
328
329TfLiteIntArray* arm::app::Model::GetOutputShape(size_t index) const
330{
331 if (index < this->GetNumOutputs()) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100332 return this->m_output.at(index)->dims;
alexander3c798932021-03-26 21:42:19 +0000333 }
334 return nullptr;
335}
336
337bool arm::app::Model::ShowModelInfoHandler()
338{
339 if (!this->IsInited()) {
340 printf_err("Model is not initialised! Terminating processing.\n");
341 return false;
342 }
343
344 PrintTensorFlowVersion();
345 info("Model info:\n");
346 this->LogInterpreterInfo();
347
alexander31ae9f02022-02-10 16:15:54 +0000348 info("The model is optimised for Ethos-U NPU: %s.\n", this->ContainsEthosUOperator()? "yes": "no");
alexander3c798932021-03-26 21:42:19 +0000349
350 return true;
351}
352namespace arm {
353namespace app {
alexanderc350cdc2021-04-29 20:36:09 +0100354 static uint8_t tensor_arena[ACTIVATION_BUF_SZ] ACTIVATION_BUF_ATTRIBUTE;
alexander3c798932021-03-26 21:42:19 +0000355} /* namespace app */
356} /* namespace arm */
357
358size_t arm::app::Model::GetActivationBufferSize()
359{
360 return ACTIVATION_BUF_SZ;
361}
362
363uint8_t *arm::app::Model::GetTensorArena()
364{
alexanderc350cdc2021-04-29 20:36:09 +0100365 return tensor_arena;
alexander3c798932021-03-26 21:42:19 +0000366}