blob: b344a534a85f9406f947b1693b1b5be769240559 [file] [log] [blame]
alexander3c798932021-03-26 21:42:19 +00001/*
Richard Burtondf88c5d2023-05-30 17:40:39 +01002 * SPDX-FileCopyrightText: Copyright 2021-2023 Arm Limited and/or its affiliates
Kshitij Sisodia47406fe2022-12-05 17:18:50 +00003 * <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>
Liam Barry677d43f2023-08-03 18:21:58 +010021#include <memory>
alexander3c798932021-03-26 21:42:19 +000022
Liam Barry677d43f2023-08-03 18:21:58 +010023arm::app::Model::~Model() = default;
alexander3c798932021-03-26 21:42:19 +000024
Kshitij Sisodia47406fe2022-12-05 17:18:50 +000025arm::app::Model::Model() : m_inited(false), m_type(kTfLiteNoType) {}
alexander3c798932021-03-26 21:42:19 +000026
Liam Barry677d43f2023-08-03 18:21:58 +010027/* Initialise the model */
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +010028bool arm::app::Model::Init(uint8_t* tensorArenaAddr,
29 uint32_t tensorArenaSize,
Kshitij Sisodia937052d2022-05-13 16:44:16 +010030 const uint8_t* nnModelAddr,
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +010031 uint32_t nnModelSize,
32 tflite::MicroAllocator* allocator)
alexander3c798932021-03-26 21:42:19 +000033{
34 /* Following tf lite micro example:
35 * Map the model into a usable data structure. This doesn't involve any
36 * copying or parsing, it's a very lightweight operation. */
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +010037 debug("loading model from @ 0x%p\n", nnModelAddr);
38 debug("model size: %" PRIu32 " bytes.\n", nnModelSize);
39
40 this->m_pModel = ::tflite::GetModel(nnModelAddr);
alexander3c798932021-03-26 21:42:19 +000041
Isabella Gottardi56ee6202021-05-12 08:27:15 +010042 if (this->m_pModel->version() != TFLITE_SCHEMA_VERSION) {
Kshitij Sisodia47406fe2022-12-05 17:18:50 +000043 printf_err("Model's schema version %" PRIu32 " is not equal "
44 "to supported version %d.",
45 this->m_pModel->version(),
46 TFLITE_SCHEMA_VERSION);
alexander3c798932021-03-26 21:42:19 +000047 return false;
48 }
49
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +010050 this->m_modelAddr = nnModelAddr;
51 this->m_modelSize = nnModelSize;
52
alexander3c798932021-03-26 21:42:19 +000053 /* Pull in only the operation implementations we need.
54 * This relies on a complete list of all the ops needed by this graph.
55 * An easier approach is to just use the AllOpsResolver, but this will
56 * incur some penalty in code space for op implementations that are not
57 * needed by this graph.
58 * static ::tflite::ops::micro::AllOpsResolver resolver; */
59 /* NOLINTNEXTLINE(runtime-global-variables) */
60 debug("loading op resolver\n");
61
62 this->EnlistOperations();
63
64 /* Create allocator instance, if it doesn't exist */
Isabella Gottardi56ee6202021-05-12 08:27:15 +010065 this->m_pAllocator = allocator;
66 if (!this->m_pAllocator) {
alexander3c798932021-03-26 21:42:19 +000067 /* Create an allocator instance */
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +010068 info("Creating allocator using tensor arena at 0x%p\n", tensorArenaAddr);
alexander3c798932021-03-26 21:42:19 +000069
Kshitij Sisodia47406fe2022-12-05 17:18:50 +000070 this->m_pAllocator = tflite::MicroAllocator::Create(tensorArenaAddr, tensorArenaSize);
alexander3c798932021-03-26 21:42:19 +000071
Isabella Gottardi56ee6202021-05-12 08:27:15 +010072 if (!this->m_pAllocator) {
alexander3c798932021-03-26 21:42:19 +000073 printf_err("Failed to create allocator\n");
74 return false;
75 }
Isabella Gottardi56ee6202021-05-12 08:27:15 +010076 debug("Created new allocator @ 0x%p\n", this->m_pAllocator);
alexander3c798932021-03-26 21:42:19 +000077 } else {
Isabella Gottardi56ee6202021-05-12 08:27:15 +010078 debug("Using existing allocator @ 0x%p\n", this->m_pAllocator);
alexander3c798932021-03-26 21:42:19 +000079 }
80
Liam Barry677d43f2023-08-03 18:21:58 +010081 this->m_pInterpreter = std::make_unique<tflite::MicroInterpreter>(
82 this->m_pModel, this->GetOpResolver(), this->m_pAllocator);
alexander3c798932021-03-26 21:42:19 +000083
Isabella Gottardi56ee6202021-05-12 08:27:15 +010084 if (!this->m_pInterpreter) {
alexander3c798932021-03-26 21:42:19 +000085 printf_err("Failed to allocate interpreter\n");
86 return false;
87 }
88
89 /* Allocate memory from the tensor_arena for the model's tensors. */
90 info("Allocating tensors\n");
Isabella Gottardi56ee6202021-05-12 08:27:15 +010091 TfLiteStatus allocate_status = this->m_pInterpreter->AllocateTensors();
alexander3c798932021-03-26 21:42:19 +000092
93 if (allocate_status != kTfLiteOk) {
alexander3c798932021-03-26 21:42:19 +000094 printf_err("tensor allocation failed!\n");
alexander3c798932021-03-26 21:42:19 +000095 return false;
96 }
97
98 /* Get information about the memory area to use for the model's input. */
Isabella Gottardi56ee6202021-05-12 08:27:15 +010099 this->m_input.resize(this->GetNumInputs());
alexander3c798932021-03-26 21:42:19 +0000100 for (size_t inIndex = 0; inIndex < this->GetNumInputs(); inIndex++)
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100101 this->m_input[inIndex] = this->m_pInterpreter->input(inIndex);
alexander3c798932021-03-26 21:42:19 +0000102
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100103 this->m_output.resize(this->GetNumOutputs());
alexander3c798932021-03-26 21:42:19 +0000104 for (size_t outIndex = 0; outIndex < this->GetNumOutputs(); outIndex++)
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100105 this->m_output[outIndex] = this->m_pInterpreter->output(outIndex);
alexander3c798932021-03-26 21:42:19 +0000106
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100107 if (this->m_input.empty() || this->m_output.empty()) {
alexander3c798932021-03-26 21:42:19 +0000108 printf_err("failed to get tensors\n");
109 return false;
110 } else {
Kshitij Sisodia47406fe2022-12-05 17:18:50 +0000111 this->m_type = this->m_input[0]->type; /* Input 0 should be the main input */
alexander3c798932021-03-26 21:42:19 +0000112
113 /* Clear the input & output tensors */
114 for (size_t inIndex = 0; inIndex < this->GetNumInputs(); inIndex++) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100115 std::memset(this->m_input[inIndex]->data.data, 0, this->m_input[inIndex]->bytes);
alexander3c798932021-03-26 21:42:19 +0000116 }
117 for (size_t outIndex = 0; outIndex < this->GetNumOutputs(); outIndex++) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100118 std::memset(this->m_output[outIndex]->data.data, 0, this->m_output[outIndex]->bytes);
alexander3c798932021-03-26 21:42:19 +0000119 }
120
121 this->LogInterpreterInfo();
122 }
123
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100124 this->m_inited = true;
alexander3c798932021-03-26 21:42:19 +0000125 return true;
126}
127
128tflite::MicroAllocator* arm::app::Model::GetAllocator()
129{
130 if (this->IsInited()) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100131 return this->m_pAllocator;
alexander3c798932021-03-26 21:42:19 +0000132 }
133 return nullptr;
134}
135
136void arm::app::Model::LogTensorInfo(TfLiteTensor* tensor)
137{
138 if (!tensor) {
139 printf_err("Invalid tensor\n");
140 assert(tensor);
141 return;
142 }
143
144 debug("\ttensor is assigned to 0x%p\n", tensor);
145 info("\ttensor type is %s\n", TfLiteTypeGetName(tensor->type));
Kshitij Sisodia47406fe2022-12-05 17:18:50 +0000146 info("\ttensor occupies %zu bytes with dimensions\n", tensor->bytes);
147 for (int i = 0; i < tensor->dims->size; ++i) {
148 info("\t\t%d: %3d\n", i, tensor->dims->data[i]);
alexander3c798932021-03-26 21:42:19 +0000149 }
150
151 TfLiteQuantization quant = tensor->quantization;
152 if (kTfLiteAffineQuantization == quant.type) {
153 auto* quantParams = (TfLiteAffineQuantization*)quant.params;
Kshitij Sisodiaf9c19ea2021-05-07 16:08:14 +0100154 info("Quant dimension: %" PRIi32 "\n", quantParams->quantized_dimension);
alexander3c798932021-03-26 21:42:19 +0000155 for (int i = 0; i < quantParams->scale->size; ++i) {
156 info("Scale[%d] = %f\n", i, quantParams->scale->data[i]);
157 }
158 for (int i = 0; i < quantParams->zero_point->size; ++i) {
159 info("ZeroPoint[%d] = %d\n", i, quantParams->zero_point->data[i]);
160 }
161 }
162}
163
164void arm::app::Model::LogInterpreterInfo()
165{
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100166 if (!this->m_pInterpreter) {
alexander3c798932021-03-26 21:42:19 +0000167 printf_err("Invalid interpreter\n");
168 return;
169 }
170
171 info("Model INPUT tensors: \n");
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100172 for (auto input : this->m_input) {
alexander3c798932021-03-26 21:42:19 +0000173 this->LogTensorInfo(input);
174 }
175
176 info("Model OUTPUT tensors: \n");
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100177 for (auto output : this->m_output) {
alexander3c798932021-03-26 21:42:19 +0000178 this->LogTensorInfo(output);
179 }
180
181 info("Activation buffer (a.k.a tensor arena) size used: %zu\n",
Kshitij Sisodia47406fe2022-12-05 17:18:50 +0000182 this->m_pInterpreter->arena_used_bytes());
alexander3c798932021-03-26 21:42:19 +0000183
Richard Burton0d110592021-08-12 17:26:30 +0100184 /* We expect there to be only one subgraph. */
185 const uint32_t nOperators = tflite::NumSubgraphOperators(this->m_pModel, 0);
186 info("Number of operators: %" PRIu32 "\n", nOperators);
alexander3c798932021-03-26 21:42:19 +0000187
Richard Burton0d110592021-08-12 17:26:30 +0100188 const tflite::SubGraph* subgraph = this->m_pModel->subgraphs()->Get(0);
189
190 auto* opcodes = this->m_pModel->operator_codes();
191
192 /* For each operator, display registration information. */
Kshitij Sisodia47406fe2022-12-05 17:18:50 +0000193 for (size_t i = 0; i < nOperators; ++i) {
194 const tflite::Operator* op = subgraph->operators()->Get(i);
Richard Burton0d110592021-08-12 17:26:30 +0100195 const tflite::OperatorCode* opcode = opcodes->Get(op->opcode_index());
Nina Drozd05c1c5a2023-08-22 12:41:55 +0100196 const TFLMRegistration* reg = nullptr;
Richard Burton0d110592021-08-12 17:26:30 +0100197
Richard Burton71f282e2022-12-01 12:31:23 +0000198 tflite::GetRegistrationFromOpCode(opcode, this->GetOpResolver(), &reg);
alexander31ae9f02022-02-10 16:15:54 +0000199 std::string opName;
alexander3c798932021-03-26 21:42:19 +0000200
201 if (reg) {
202 if (tflite::BuiltinOperator_CUSTOM == reg->builtin_code) {
203 opName = std::string(reg->custom_name);
204 } else {
Kshitij Sisodia47406fe2022-12-05 17:18:50 +0000205 opName = std::string(
206 EnumNameBuiltinOperator(tflite::BuiltinOperator(reg->builtin_code)));
alexander3c798932021-03-26 21:42:19 +0000207 }
208 }
Kshitij Sisodiaf9c19ea2021-05-07 16:08:14 +0100209 info("\tOperator %zu: %s\n", i, opName.c_str());
alexander3c798932021-03-26 21:42:19 +0000210 }
211}
212
213bool arm::app::Model::IsInited() const
214{
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100215 return this->m_inited;
alexander3c798932021-03-26 21:42:19 +0000216}
217
218bool arm::app::Model::IsDataSigned() const
219{
220 return this->GetType() == kTfLiteInt8;
221}
222
Cisco Cervellera02101092021-09-07 11:34:43 +0100223bool arm::app::Model::ContainsEthosUOperator() const
224{
225 /* We expect there to be only one subgraph. */
Kshitij Sisodia47406fe2022-12-05 17:18:50 +0000226 const uint32_t nOperators = tflite::NumSubgraphOperators(this->m_pModel, 0);
Cisco Cervellera02101092021-09-07 11:34:43 +0100227 const tflite::SubGraph* subgraph = this->m_pModel->subgraphs()->Get(0);
Kshitij Sisodia47406fe2022-12-05 17:18:50 +0000228 const auto* opcodes = this->m_pModel->operator_codes();
Cisco Cervellera02101092021-09-07 11:34:43 +0100229
230 /* check for custom operators */
Kshitij Sisodia47406fe2022-12-05 17:18:50 +0000231 for (size_t i = 0; (i < nOperators); ++i) {
232 const tflite::Operator* op = subgraph->operators()->Get(i);
Cisco Cervellera02101092021-09-07 11:34:43 +0100233 const tflite::OperatorCode* opcode = opcodes->Get(op->opcode_index());
234
235 auto builtin_code = tflite::GetBuiltinCode(opcode);
236 if ((builtin_code == tflite::BuiltinOperator_CUSTOM) &&
Kshitij Sisodia47406fe2022-12-05 17:18:50 +0000237 (nullptr != opcode->custom_code()) &&
238 ("ethos-u" == std::string(opcode->custom_code()->c_str()))) {
Cisco Cervellera02101092021-09-07 11:34:43 +0100239 return true;
240 }
241 }
242 return false;
243}
244
alexander3c798932021-03-26 21:42:19 +0000245bool arm::app::Model::RunInference()
246{
247 bool inference_state = false;
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100248 if (this->m_pModel && this->m_pInterpreter) {
249 if (kTfLiteOk != this->m_pInterpreter->Invoke()) {
alexander3c798932021-03-26 21:42:19 +0000250 printf_err("Invoke failed.\n");
251 } else {
252 inference_state = true;
253 }
254 } else {
255 printf_err("Error: No interpreter!\n");
256 }
257 return inference_state;
258}
259
260TfLiteTensor* arm::app::Model::GetInputTensor(size_t index) const
261{
262 if (index < this->GetNumInputs()) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100263 return this->m_input.at(index);
alexander3c798932021-03-26 21:42:19 +0000264 }
265 return nullptr;
266}
267
268TfLiteTensor* arm::app::Model::GetOutputTensor(size_t index) const
269{
270 if (index < this->GetNumOutputs()) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100271 return this->m_output.at(index);
alexander3c798932021-03-26 21:42:19 +0000272 }
273 return nullptr;
274}
275
276size_t arm::app::Model::GetNumInputs() const
277{
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100278 if (this->m_pModel && this->m_pInterpreter) {
279 return this->m_pInterpreter->inputs_size();
alexander3c798932021-03-26 21:42:19 +0000280 }
281 return 0;
282}
283
284size_t arm::app::Model::GetNumOutputs() const
285{
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100286 if (this->m_pModel && this->m_pInterpreter) {
287 return this->m_pInterpreter->outputs_size();
alexander3c798932021-03-26 21:42:19 +0000288 }
289 return 0;
290}
291
alexander3c798932021-03-26 21:42:19 +0000292TfLiteType arm::app::Model::GetType() const
293{
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100294 return this->m_type;
alexander3c798932021-03-26 21:42:19 +0000295}
296
297TfLiteIntArray* arm::app::Model::GetInputShape(size_t index) const
298{
299 if (index < this->GetNumInputs()) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100300 return this->m_input.at(index)->dims;
alexander3c798932021-03-26 21:42:19 +0000301 }
302 return nullptr;
303}
304
305TfLiteIntArray* arm::app::Model::GetOutputShape(size_t index) const
306{
307 if (index < this->GetNumOutputs()) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100308 return this->m_output.at(index)->dims;
alexander3c798932021-03-26 21:42:19 +0000309 }
310 return nullptr;
311}
312
313bool arm::app::Model::ShowModelInfoHandler()
314{
315 if (!this->IsInited()) {
316 printf_err("Model is not initialised! Terminating processing.\n");
317 return false;
318 }
319
320 PrintTensorFlowVersion();
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +0100321 info("Model address: 0x%p", this->ModelPointer());
322 info("Model size: %" PRIu32 " bytes.", this->ModelSize());
alexander3c798932021-03-26 21:42:19 +0000323 info("Model info:\n");
324 this->LogInterpreterInfo();
325
Kshitij Sisodia47406fe2022-12-05 17:18:50 +0000326 info("The model is optimised for Ethos-U NPU: %s.\n",
327 this->ContainsEthosUOperator() ? "yes" : "no");
alexander3c798932021-03-26 21:42:19 +0000328
329 return true;
330}
alexander3c798932021-03-26 21:42:19 +0000331
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +0100332const uint8_t* arm::app::Model::ModelPointer()
alexander3c798932021-03-26 21:42:19 +0000333{
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +0100334 return this->m_modelAddr;
alexander3c798932021-03-26 21:42:19 +0000335}
336
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +0100337uint32_t arm::app::Model::ModelSize()
alexander3c798932021-03-26 21:42:19 +0000338{
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +0100339 return this->m_modelSize;
340}