| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include "edge-impulse-sdk/tensorflow/lite/micro/micro_graph.h" |
|
|
| #include "edge-impulse-sdk/third_party/flatbuffers/include/flatbuffers/flatbuffers.h" |
| #include "edge-impulse-sdk/tensorflow/lite/c/common.h" |
| #include "edge-impulse-sdk/tensorflow/lite/kernels/internal/compatibility.h" |
| #include "edge-impulse-sdk/tensorflow/lite/micro/flatbuffer_utils.h" |
| #include "edge-impulse-sdk/tensorflow/lite/micro/memory_helpers.h" |
| #include "edge-impulse-sdk/tensorflow/lite/micro/micro_log.h" |
| #include "edge-impulse-sdk/tensorflow/lite/micro/micro_profiler.h" |
| #include "edge-impulse-sdk/tensorflow/lite/schema/schema_generated.h" |
|
|
| namespace tflite { |
| namespace { |
|
|
| const char* OpNameFromRegistration(const TfLiteRegistration* registration) { |
| if (registration->builtin_code == BuiltinOperator_CUSTOM) { |
| return registration->custom_name; |
| } else { |
| return EnumNameBuiltinOperator(BuiltinOperator(registration->builtin_code)); |
| } |
| } |
|
|
| } |
|
|
| MicroGraph::MicroGraph(TfLiteContext* context, const Model* model, |
| MicroAllocator* allocator, |
| MicroResourceVariables* resource_variables) |
| : context_(context), |
| model_(model), |
| allocator_(allocator), |
| current_subgraph_index_(0), |
| resource_variables_(resource_variables) { |
| if (model != nullptr) { |
| subgraphs_ = model->subgraphs(); |
| } |
| } |
|
|
| MicroGraph::~MicroGraph() {} |
|
|
| TfLiteStatus MicroGraph::InitSubgraphs() { |
| int previous_subgraph_idx = current_subgraph_index_; |
|
|
| for (size_t subgraph_idx = 0; subgraph_idx < subgraphs_->size(); |
| subgraph_idx++) { |
| current_subgraph_index_ = subgraph_idx; |
| uint32_t operators_size = NumSubgraphOperators(model_, subgraph_idx); |
| for (size_t i = 0; i < operators_size; ++i) { |
| TfLiteNode* node = |
| &(subgraph_allocations_[subgraph_idx].node_and_registrations[i].node); |
| const TfLiteRegistration* registration = |
| subgraph_allocations_[subgraph_idx] |
| .node_and_registrations[i] |
| .registration; |
| size_t init_data_size; |
| const char* init_data; |
| if (registration->builtin_code == BuiltinOperator_CUSTOM) { |
| init_data = reinterpret_cast<const char*>(node->custom_initial_data); |
| init_data_size = node->custom_initial_data_size; |
| } else { |
| init_data = reinterpret_cast<const char*>(node->builtin_data); |
| init_data_size = 0; |
| } |
| if (registration->init) { |
| node->user_data = |
| registration->init(context_, init_data, init_data_size); |
| } |
| } |
| } |
| current_subgraph_index_ = previous_subgraph_idx; |
|
|
| return kTfLiteOk; |
| } |
|
|
| TfLiteStatus MicroGraph::PrepareSubgraphs(bool run_all_prep_ops) { |
| int previous_subgraph_idx = current_subgraph_index_; |
| bool all_prep_ops_ok = true; |
|
|
| for (size_t subgraph_idx = 0; subgraph_idx < subgraphs_->size(); |
| subgraph_idx++) { |
| current_subgraph_index_ = subgraph_idx; |
| uint32_t operators_size = NumSubgraphOperators(model_, subgraph_idx); |
| for (size_t i = 0; i < operators_size; ++i) { |
| TfLiteNode* node = |
| &(subgraph_allocations_[subgraph_idx].node_and_registrations[i].node); |
| const TfLiteRegistration* registration = |
| subgraph_allocations_[subgraph_idx] |
| .node_and_registrations[i] |
| .registration; |
| if (registration->prepare != nullptr) { |
| TfLiteStatus prepare_status = registration->prepare(context_, node); |
| if (prepare_status != kTfLiteOk) { |
| MicroPrintf("Node %s (number %df) failed to prepare with status %d", |
| OpNameFromRegistration(registration), i, prepare_status); |
|
|
| all_prep_ops_ok = false; |
| if (!run_all_prep_ops) { |
| return kTfLiteError; |
| } |
| } |
| } |
| allocator_->FinishPrepareNodeAllocations(i); |
| } |
|
|
| if (!all_prep_ops_ok) { |
| return kTfLiteError; |
| } |
|
|
| } |
| current_subgraph_index_ = previous_subgraph_idx; |
|
|
| return kTfLiteOk; |
| } |
|
|
| TfLiteStatus MicroGraph::FreeSubgraphs() { |
| int previous_subgraph_idx = current_subgraph_index_; |
|
|
| for (size_t subgraph_idx = 0; subgraph_idx < subgraphs_->size(); |
| subgraph_idx++) { |
| current_subgraph_index_ = subgraph_idx; |
| uint32_t operators_size = NumSubgraphOperators(model_, subgraph_idx); |
| for (size_t i = 0; i < operators_size; ++i) { |
| TfLiteNode* node = |
| &(subgraph_allocations_[subgraph_idx].node_and_registrations[i].node); |
| const TfLiteRegistration* registration = |
| subgraph_allocations_[subgraph_idx] |
| .node_and_registrations[i] |
| .registration; |
| |
| |
| if (registration != nullptr && registration->free != nullptr) { |
| registration->free(context_, node->user_data); |
| } |
| } |
| } |
| current_subgraph_index_ = previous_subgraph_idx; |
|
|
| return kTfLiteOk; |
| } |
|
|
| TfLiteStatus MicroGraph::InvokeSubgraph(int subgraph_idx) { |
| int previous_subgraph_idx = current_subgraph_index_; |
| current_subgraph_index_ = subgraph_idx; |
|
|
| if (static_cast<size_t>(subgraph_idx) >= subgraphs_->size()) { |
| MicroPrintf("Accessing subgraph %d but only %d subgraphs found", |
| subgraph_idx, subgraphs_->size()); |
| return kTfLiteError; |
| } |
| uint32_t operators_size = NumSubgraphOperators(model_, subgraph_idx); |
| for (size_t i = 0; i < operators_size; ++i) { |
| TfLiteNode* node = |
| &(subgraph_allocations_[subgraph_idx].node_and_registrations[i].node); |
| const TfLiteRegistration* registration = subgraph_allocations_[subgraph_idx] |
| .node_and_registrations[i] |
| .registration; |
|
|
| |
| |
| |
| #if !defined(TF_LITE_STRIP_ERROR_STRINGS) |
| ScopedMicroProfiler scoped_profiler( |
| OpNameFromRegistration(registration), |
| reinterpret_cast<MicroProfilerInterface*>(context_->profiler)); |
| #endif |
|
|
| TFLITE_DCHECK(registration->invoke); |
| TfLiteStatus invoke_status = registration->invoke(context_, node); |
|
|
| |
| |
| |
| |
| allocator_->ResetTempAllocations(); |
|
|
| if (invoke_status == kTfLiteError) { |
| MicroPrintf("Node %s (number %d) failed to invoke with status %d", |
| OpNameFromRegistration(registration), i, invoke_status); |
| return kTfLiteError; |
| } else if (invoke_status != kTfLiteOk) { |
| return invoke_status; |
| } |
| } |
| current_subgraph_index_ = previous_subgraph_idx; |
| return kTfLiteOk; |
| } |
|
|
| TfLiteStatus MicroGraph::ResetVariableTensors() { |
| for (size_t subgraph_idx = 0; subgraph_idx < subgraphs_->size(); |
| subgraph_idx++) { |
| const SubGraph* subgraph = (*subgraphs_)[subgraph_idx]; |
| for (size_t i = 0; i < subgraph->tensors()->size(); ++i) { |
| auto* tensor = subgraph->tensors()->Get(i); |
| if (tensor->is_variable()) { |
| size_t buffer_size; |
| TF_LITE_ENSURE_STATUS(TfLiteEvalTensorByteLength( |
| &subgraph_allocations_[subgraph_idx].tensors[i], &buffer_size)); |
|
|
| int value = 0; |
| if (tensor->type() == tflite::TensorType_INT8) { |
| value = tensor->quantization()->zero_point()->Get(0); |
| } |
| memset(subgraph_allocations_[subgraph_idx].tensors[i].data.raw, value, |
| buffer_size); |
| } |
| } |
| } |
| if (resource_variables_ != nullptr) { |
| resource_variables_->ResetAll(); |
| } |
|
|
| return kTfLiteOk; |
| } |
|
|
| int MicroGraph::NumSubgraphs() { return model_->subgraphs()->size(); } |
|
|
| void MicroGraph::SetSubgraphAllocations( |
| SubgraphAllocations* subgraph_allocations) { |
| subgraph_allocations_ = subgraph_allocations; |
| } |
|
|
| size_t MicroGraph::NumSubgraphInputs(int subgraph_idx) { |
| return model_->subgraphs()->Get(subgraph_idx)->inputs()->size(); |
| } |
|
|
| TfLiteEvalTensor* MicroGraph::GetSubgraphInput(int subgraph_idx, |
| int input_idx) { |
| int tensor_idx = |
| model_->subgraphs()->Get(subgraph_idx)->inputs()->Get(input_idx); |
| return &subgraph_allocations_[subgraph_idx].tensors[tensor_idx]; |
| } |
|
|
| size_t MicroGraph::NumSubgraphOutputs(int subgraph_idx) { |
| return model_->subgraphs()->Get(subgraph_idx)->outputs()->size(); |
| } |
|
|
| TfLiteEvalTensor* MicroGraph::GetSubgraphOutput(int subgraph_idx, |
| int output_idx) { |
| int tensor_idx = |
| model_->subgraphs()->Get(subgraph_idx)->outputs()->Get(output_idx); |
| return &subgraph_allocations_[subgraph_idx].tensors[tensor_idx]; |
| } |
|
|
| } |
|
|