diff --git a/tools/README.md b/tools/README.md new file mode 100644 index 0000000..cfa3488 --- /dev/null +++ b/tools/README.md @@ -0,0 +1,80 @@ +# TFlite-Micro Tools for Espressif Chipsets + +This repository offers a code generation tool designed to facilitate the creation of essential C++ code files necessary for deploying TensorFlow Lite models on Espressif micro-controllers. It caters specifically to the requirements of TensorFlow Lite Micro, enabling seamless integration of machine learning models into embedded systems. + +By utilizing this tool, developers can generate C++ code that efficiently executes TensorFlow Lite models. This tool serves as a valuable asset for developers seeking to leverage the power of TensorFlow Lite for developing IoT applications through Espressif Chipsets. + + +# Features + +- Converts TensorFlow Lite model files (.tflite) into C++ unsigned integer arrays storing hex values of .tflite models for efficient deployment on Espressif Chipsets. + +- Generates a micro mutable op resolver based on the model, which extracts all the operations associated with the model. + +- Creates template code for the main function, simplifying the integration of TensorFlow Lite models into Espressif based real time microcontroller applications. + +# Setup Environment +- Clone the [tflite-micro](https://github.com/tensorflow/tflite-micro/) repository locally on your machine. +- Set paths for TFLITE_PATH and PYTHONPATH necessary for running the python scripts associated with generating array for model and micro mutable op resolver which extracts the model's operations. +``` +export TFLITE_PATH=path/to/cloned/repository +export PYTHONPATH=path/to/directory/of/cloned/repository +``` +- Once the paths have been set, create a python virtual environment by following the steps below. +``` +# create virtual environment - env +python3 -m venv env + +# activate the environment +source env/bin/activate + +# install requirements.txt +pip install -r requirements.txt +``` + +# Usage + +This script can convert any tflite model to example template which then can be integrated with any project. + +``` +python main.py model.tflite +``` +This command performs the following: + +- Convert the tflite model to a C++ unsigned integer array representation using generate_cc_arrays.py. + +- Generate a micro mutable operation resolver based on the model using generate_micro_mutable_op_resolver_from_model.py. + +- Generate templates for main functions using generate_main_templates.py. + +- Extract relevant information from the generated files and create C++ files required for the application. + + +# Building the project + +The command idf.py build is typically associated with the ESP-IDF (Espressif IoT Development Framework), which is the official development framework for the Espressif microcontrollers. + +``` +idf.py build +``` + +After executing `idf.py build`, it initiates the build process for the current project. This command compiles the source code files, resolves dependencies, and generates the firmware binary that can be flashed onto the Espressif microcontroller. Developers can further use this image for real time applications and use cases. + +# Customization + +You can modify the templates in the templates.py file to customize the generated code according to your project requirements. + +Adjust the code and templates as needed to suit your specific use case. + + +# Resources + +- [Tensorflow Lite for Microcontrollers](https://github.com/tensorflow/tflite-micro) + +- [TensorFlow Lite Micro for Espressif Chipsets](https://github.com/espressif/tflite-micro-esp-examples) + +- [Espressif IoT Development Framework](https://github.com/espressif/esp-idf) + +- [CMake Documentation](https://cmake.org/documentation/) + +  \ No newline at end of file diff --git a/tools/hello_world.tflite b/tools/hello_world.tflite new file mode 100644 index 0000000..d806e19 Binary files /dev/null and b/tools/hello_world.tflite differ diff --git a/tools/hello_world/CMakeLists.txt b/tools/hello_world/CMakeLists.txt new file mode 100644 index 0000000..07683a8 --- /dev/null +++ b/tools/hello_world/CMakeLists.txt @@ -0,0 +1,7 @@ + +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) +set(EXTRA_COMPONENT_DIRS ../../components) +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(test) diff --git a/tools/hello_world/main/CMakeLists.txt b/tools/hello_world/main/CMakeLists.txt new file mode 100644 index 0000000..b5543b3 --- /dev/null +++ b/tools/hello_world/main/CMakeLists.txt @@ -0,0 +1,3 @@ + +idf_component_register(SRCS main_functions.cc main.cc hello_world_model_data.cc output_handler.cc constants.cc + INCLUDE_DIRS "") diff --git a/tools/hello_world/main/constants.cc b/tools/hello_world/main/constants.cc new file mode 100644 index 0000000..e2f6c31 --- /dev/null +++ b/tools/hello_world/main/constants.cc @@ -0,0 +1,26 @@ + +/* + +SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +SPDX-License-Identifier: Apache-2.0 + + +Copyright 2023 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#include "constants.h" + +// This is a small number so that it's easy to read the logs +const int kInferencesPerCycle = 20; diff --git a/tools/hello_world/main/constants.h b/tools/hello_world/main/constants.h new file mode 100644 index 0000000..bcadf52 --- /dev/null +++ b/tools/hello_world/main/constants.h @@ -0,0 +1,36 @@ + +/* + +SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +SPDX-License-Identifier: Apache-2.0 + +Copyright 2023 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#pragma once + +// This constant represents the range of x values our model was trained on, +// which is from 0 to (2 * Pi). We approximate Pi to avoid requiring additional +// libraries. +const float kXrange = 2.f * 3.14159265359f; + +// This constant determines the number of inferences to perform across the range +// of x values defined above. Since each inference takes time, the higher this +// number, the more time it will take to run through the entire range. The value +// of this constant can be tuned so that one full cycle takes a desired amount +// of time. Since different devices take different amounts of time to perform +// inference, this value should be defined per-device. +extern const int kInferencesPerCycle; + diff --git a/tools/hello_world/main/gen_micro_mutable_op_resolver.h b/tools/hello_world/main/gen_micro_mutable_op_resolver.h new file mode 100644 index 0000000..5091747 --- /dev/null +++ b/tools/hello_world/main/gen_micro_mutable_op_resolver.h @@ -0,0 +1,33 @@ +/* Copyright 2023 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +// Generated based on hello_world.tflite. + +#pragma once + +#include "tensorflow/lite/micro/micro_mutable_op_resolver.h" + +constexpr int kNumberOperators = 3; + +inline tflite::MicroMutableOpResolver get_resolver() +{ + tflite::MicroMutableOpResolver micro_op_resolver; + + micro_op_resolver.AddDequantize(); + micro_op_resolver.AddFullyConnected(); + micro_op_resolver.AddQuantize(); + + return micro_op_resolver; +} diff --git a/tools/hello_world/main/hello_world_model_data.cc b/tools/hello_world/main/hello_world_model_data.cc new file mode 100644 index 0000000..00184ea --- /dev/null +++ b/tools/hello_world/main/hello_world_model_data.cc @@ -0,0 +1,217 @@ +#include + +#include "hello_world_model_data.h" + +const unsigned int g_hello_world_model_data_size = 2512; +alignas(16) const unsigned char g_hello_world_model_data[] = { + 0x1c, 0x00, 0x00, 0x00, 0x54, 0x46, 0x4c, 0x33, 0x00, 0x00, 0x12, 0x00, + 0x1c, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x14, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x12, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x60, 0x09, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x00, 0x90, 0x02, 0x00, 0x00, + 0x3c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x08, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x75, 0x6e, 0x74, + 0x69, 0x6d, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x48, 0x02, 0x00, 0x00, 0x34, 0x02, 0x00, 0x00, + 0x0c, 0x02, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, + 0x8c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xfe, 0xfd, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x31, 0x2e, 0x35, 0x2e, 0x30, 0x00, 0x00, 0x00, + 0x7c, 0xfd, 0xff, 0xff, 0x80, 0xfd, 0xff, 0xff, 0x84, 0xfd, 0xff, 0xff, + 0x88, 0xfd, 0xff, 0xff, 0x22, 0xfe, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x04, 0x00, 0x00, + 0x9f, 0x0a, 0x00, 0x00, 0x65, 0x06, 0x00, 0x00, 0x3d, 0xf8, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xeb, 0x0a, 0x00, 0x00, 0x2f, 0xf8, 0xff, 0xff, + 0xe8, 0x04, 0x00, 0x00, 0x21, 0x0a, 0x00, 0x00, 0x46, 0xfe, 0xff, 0xff, + 0xc8, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, 0xf7, 0xff, 0xff, + 0x28, 0xf9, 0xff, 0xff, 0x9a, 0x05, 0x00, 0x00, 0x6e, 0xfe, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x73, 0x1c, 0x11, 0xe1, + 0x0c, 0x81, 0xa5, 0x43, 0xfe, 0xd5, 0xd5, 0xb2, 0x60, 0x77, 0x19, 0xdf, + 0x8a, 0xfe, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x51, 0x0b, 0x00, 0x00, 0x47, 0xf6, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x9b, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe7, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x92, 0x07, 0x00, 0x00, 0xf4, 0xf4, 0xff, 0xff, 0x55, 0xf0, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xd6, 0xfe, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0xee, 0xfc, 0x00, 0xec, 0x05, 0x16, 0xef, 0xec, + 0xe6, 0xf8, 0x03, 0x01, 0x00, 0xfa, 0xf8, 0xf5, 0xda, 0xeb, 0x27, 0x14, + 0xef, 0xde, 0xe2, 0xda, 0xf0, 0xdf, 0x32, 0x06, 0x01, 0xe6, 0xee, 0xf9, + 0x00, 0x16, 0x07, 0xe0, 0xfe, 0xff, 0xe9, 0x05, 0xe7, 0xef, 0x81, 0x1b, + 0x18, 0xea, 0xca, 0x01, 0x0f, 0x00, 0xdb, 0xf7, 0x0e, 0xec, 0x12, 0x1e, + 0x04, 0x13, 0xb2, 0xe7, 0xfd, 0x06, 0xbb, 0xe0, 0x0c, 0xec, 0xf0, 0xdf, + 0xeb, 0xf7, 0x05, 0x26, 0x19, 0xe4, 0x70, 0x1a, 0xea, 0x1e, 0x34, 0xdf, + 0x19, 0xf3, 0xf1, 0x19, 0x0e, 0x03, 0x1b, 0xe1, 0xde, 0x13, 0xf6, 0x19, + 0xff, 0xf6, 0x1a, 0x17, 0xf1, 0x1c, 0xdb, 0x1a, 0x1a, 0x20, 0xe6, 0x19, + 0xf5, 0xff, 0x97, 0x0b, 0x00, 0x00, 0xce, 0xdf, 0x0d, 0xf7, 0x15, 0xe4, + 0xed, 0xfc, 0x0d, 0xe9, 0xfb, 0xec, 0x5c, 0xfc, 0x1d, 0x02, 0x58, 0xe3, + 0xe0, 0xf4, 0x15, 0xec, 0xf9, 0x00, 0x13, 0x05, 0xec, 0x0c, 0x1c, 0x14, + 0x0c, 0xe9, 0x0a, 0xf4, 0x18, 0x00, 0xd7, 0x05, 0x27, 0x02, 0x15, 0xea, + 0xea, 0x02, 0x9b, 0x00, 0x0c, 0xfa, 0xe9, 0xea, 0xfe, 0x01, 0x14, 0xfd, + 0x0b, 0x02, 0xf0, 0xef, 0x06, 0xee, 0x01, 0x0d, 0x06, 0xe7, 0xf7, 0x11, + 0xf5, 0x0a, 0xf9, 0xf1, 0x23, 0xff, 0x0d, 0xf2, 0xec, 0x11, 0x26, 0x1d, + 0xf2, 0xea, 0x28, 0x18, 0xe0, 0xfb, 0xf3, 0xf4, 0x05, 0x1c, 0x1d, 0xfb, + 0xfd, 0x1e, 0xfc, 0x11, 0xe8, 0x06, 0x09, 0x03, 0x12, 0xf2, 0x35, 0xfb, + 0xdd, 0x1b, 0xf9, 0xef, 0xf3, 0xe7, 0x6f, 0x0c, 0x1d, 0x00, 0x43, 0xfd, + 0x0d, 0xf1, 0x0a, 0x19, 0x1a, 0xfa, 0xe0, 0x18, 0x1e, 0x13, 0x37, 0x1c, + 0x12, 0xec, 0x3a, 0x0c, 0xb6, 0xcb, 0xe6, 0x13, 0xf7, 0xeb, 0xf1, 0x05, + 0x1b, 0xfa, 0x19, 0xe5, 0xec, 0xcf, 0x0c, 0xf4, 0xe2, 0xff, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x21, 0xa2, 0x8c, 0xc9, + 0x5f, 0x1d, 0xce, 0x41, 0x9f, 0xcd, 0x20, 0xb1, 0xdf, 0x53, 0x2f, 0x81, + 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe2, 0xee, 0xff, 0xff, + 0x80, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x54, 0x4f, 0x43, 0x4f, + 0x20, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x2e, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xbc, 0xf9, 0xff, 0xff, + 0x48, 0x01, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, + 0xb8, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x1a, 0xff, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xca, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xba, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x16, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, + 0x07, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x04, 0x00, + 0x08, 0x00, 0x0c, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xdc, 0x04, 0x00, 0x00, + 0x54, 0x04, 0x00, 0x00, 0xc4, 0x03, 0x00, 0x00, 0x54, 0x03, 0x00, 0x00, + 0xd0, 0x02, 0x00, 0x00, 0x4c, 0x02, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, + 0x5c, 0x01, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, + 0x3c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xd8, 0xff, 0xff, 0xff, + 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x32, 0x5f, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc2, 0xfb, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x02, 0x58, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xc4, 0xfc, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xba, 0x2b, 0x4f, 0x38, 0x20, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x31, 0x2f, 0x64, 0x65, 0x6e, + 0x73, 0x65, 0x5f, 0x34, 0x2f, 0x4d, 0x61, 0x74, 0x4d, 0x75, 0x6c, 0x5f, + 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x2a, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, + 0x6c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x2c, 0xfd, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb9, 0x36, 0x0b, 0x3c, + 0x34, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x5f, 0x31, 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x34, + 0x2f, 0x4d, 0x61, 0x74, 0x4d, 0x75, 0x6c, 0x2f, 0x52, 0x65, 0x61, 0x64, + 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x4f, 0x70, 0x2f, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x73, 0x65, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0xaa, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x6c, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x9c, 0xfc, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xaa, 0x7b, 0xbe, 0x3b, 0x01, 0x00, 0x00, 0x00, + 0x2e, 0xbd, 0xbd, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x5f, 0x31, 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x33, + 0x2f, 0x52, 0x65, 0x6c, 0x75, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x2a, 0xfd, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x02, 0x58, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x2c, 0xfe, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xe3, 0x04, 0x20, 0x39, 0x20, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x31, 0x2f, 0x64, 0x65, 0x6e, + 0x73, 0x65, 0x5f, 0x33, 0x2f, 0x4d, 0x61, 0x74, 0x4d, 0x75, 0x6c, 0x5f, + 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x92, 0xfd, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, + 0x6c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x94, 0xfe, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe8, 0x76, 0x51, 0x3c, + 0x34, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x5f, 0x31, 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x33, + 0x2f, 0x4d, 0x61, 0x74, 0x4d, 0x75, 0x6c, 0x2f, 0x52, 0x65, 0x61, 0x64, + 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x4f, 0x70, 0x2f, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x73, 0x65, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x12, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x6c, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0xfe, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xd2, 0x91, 0x43, 0x3c, 0x01, 0x00, 0x00, 0x00, + 0x40, 0xce, 0x42, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x5f, 0x31, 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x32, + 0x2f, 0x52, 0x65, 0x6c, 0x75, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x92, 0xfe, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x02, 0x5c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x94, 0xff, 0xff, 0xff, + 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x28, 0xb3, 0xd9, 0x38, 0x20, 0x00, 0x00, 0x00, + 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x31, + 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x32, 0x2f, 0x4d, 0x61, 0x74, + 0x4d, 0x75, 0x6c, 0x5f, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x09, 0x78, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xd5, 0x6b, 0x8a, 0x3b, 0x34, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x31, 0x2f, 0x64, 0x65, 0x6e, + 0x73, 0x65, 0x5f, 0x32, 0x2f, 0x4d, 0x61, 0x74, 0x4d, 0x75, 0x6c, 0x2f, + 0x52, 0x65, 0x61, 0x64, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, + 0x4f, 0x70, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x73, 0x65, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x8a, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, + 0x60, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x7c, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x01, 0x00, 0x00, 0x00, 0x5d, 0x4f, 0xc9, 0x3c, 0x01, 0x00, 0x00, 0x00, + 0x0e, 0x86, 0xc8, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x00, 0x00, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x32, 0x5f, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x38, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x08, 0x00, 0x07, 0x00, 0x0c, 0x00, + 0x10, 0x00, 0x14, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x04, 0x00, 0x08, 0x00, + 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1a, 0xde, 0x0a, 0x3c, + 0x01, 0x00, 0x00, 0x00, 0x66, 0x64, 0x87, 0x3f, 0x01, 0x00, 0x00, 0x00, + 0x13, 0x42, 0x8d, 0xbf, 0x0d, 0x00, 0x00, 0x00, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x6e, 0x74, 0x38, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x05, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x72, 0x0a, 0x00, 0x0c, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 0x04, 0x00, 0x00, 0x00 +}; \ No newline at end of file diff --git a/tools/hello_world/main/hello_world_model_data.h b/tools/hello_world/main/hello_world_model_data.h new file mode 100644 index 0000000..28c0f46 --- /dev/null +++ b/tools/hello_world/main/hello_world_model_data.h @@ -0,0 +1,4 @@ +#include + +extern const unsigned int g_hello_world_model_data_size; +extern const unsigned char g_hello_world_model_data[]; diff --git a/tools/hello_world/main/main.cc b/tools/hello_world/main/main.cc new file mode 100644 index 0000000..7ce6c29 --- /dev/null +++ b/tools/hello_world/main/main.cc @@ -0,0 +1,16 @@ + +/* + +SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +SPDX-License-Identifier: Apache-2.0 + +*/ + +#include "main_functions.h" + +extern "C" void app_main(void) { + setup(); + while (true) { + loop(); + } +} diff --git a/tools/hello_world/main/main_functions.cc b/tools/hello_world/main/main_functions.cc new file mode 100644 index 0000000..a538a59 --- /dev/null +++ b/tools/hello_world/main/main_functions.cc @@ -0,0 +1,122 @@ + +/* + +SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +SPDX-License-Identifier: Apache-2.0 + +Copyright 2023 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + + +#include "tensorflow/lite/micro/micro_mutable_op_resolver.h" +#include "tensorflow/lite/micro/micro_interpreter.h" +#include "tensorflow/lite/micro/system_setup.h" +#include "tensorflow/lite/schema/schema_generated.h" + +#include "main_functions.h" +#include "gen_micro_mutable_op_resolver.h" +#include "hello_world_model_data.h" +#include "constants.h" +#include "output_handler.h" + +// Globals, used for compatibility with Arduino-style sketches. +namespace { +const tflite::Model* model = nullptr; +tflite::MicroInterpreter* interpreter = nullptr; +TfLiteTensor* input = nullptr; +TfLiteTensor* output = nullptr; +int inference_count = 0; + +// update the value for kTensorArenaSize as per your problem's use case +constexpr int kTensorArenaSize = 50000; +uint8_t tensor_arena[kTensorArenaSize]; +} // namespace + +// The name of this function is important for Arduino compatibility. +void setup() { + // Map the model into a usable data structure. This doesn't involve any + // copying or parsing, it's a very lightweight operation. + + // X: variable = g_hello_world_model_data + model = tflite::GetModel(g_hello_world_model_data); + if (model->version() != TFLITE_SCHEMA_VERSION) { + MicroPrintf("Model provided is schema version %d not equal to supported " + "version %d.", model->version(), TFLITE_SCHEMA_VERSION); + return; + } + + // This pulls in all the operation implementations we need. + // NOLINTNEXTLINE(runtime-global-variables) + // X: variable = Pull all the operations from op_resolver.h file + static tflite::MicroMutableOpResolver<3> micro_op_resolver; + micro_op_resolver = get_resolver(); + + // Build an interpreter to run the model with. + static tflite::MicroInterpreter static_interpreter( + model, micro_op_resolver, tensor_arena, kTensorArenaSize); + interpreter = &static_interpreter; + + // Allocate memory from the tensor_arena for the model's tensors. + TfLiteStatus allocate_status = interpreter->AllocateTensors(); + if (allocate_status != kTfLiteOk) { + MicroPrintf("AllocateTensors() failed"); + return; + } + + // Obtain pointers to the model's input and output tensors. + input = interpreter->input(0); + output = interpreter->output(0); + + // Keep track of how many inferences we have performed. + inference_count = 0; +} + +// The name of this function is important for Arduino compatibility. +void loop() { + // Calculate an x value to feed into the model. We compare the current + // inference_count to the number of inferences per cycle to determine + // our position within the range of possible x values the model was + // trained on, and use this to calculate a value. + float position = static_cast(inference_count) / + static_cast(kInferencesPerCycle); + float x = position * kXrange; + + // Quantize the input from floating-point to integer + int8_t x_quantized = x / input->params.scale + input->params.zero_point; + // Place the quantized input in the model's input tensor + input->data.int8[0] = x_quantized; + + // Run inference, and report any error + TfLiteStatus invoke_status = interpreter->Invoke(); + if (invoke_status != kTfLiteOk) { + MicroPrintf("Invoke failed on x: ", static_cast(x)); + return; + } + + // Obtain the quantized output from model's output tensor + int8_t y_quantized = output->data.int8[0]; + // Dequantize the output from integer to floating-point + float y = (y_quantized - output->params.zero_point) * output->params.scale; + + // Output the results. A custom HandleOutput function can be implemented + // for each supported hardware target. + HandleOutput(x, y); + + // Increment the inference_counter, and reset it if we have reached + // the total number per cycle + inference_count += 1; + if (inference_count >= kInferencesPerCycle) inference_count = 0; +} + diff --git a/tools/hello_world/main/main_functions.h b/tools/hello_world/main/main_functions.h new file mode 100644 index 0000000..dbe4f65 --- /dev/null +++ b/tools/hello_world/main/main_functions.h @@ -0,0 +1,39 @@ + +/* +SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +SPDX-License-Identifier: Apache-2.0 + + +Copyright 2023 The TensorFlow Authors. All Rights Reserved. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#pragma once + +// Expose a C friendly interface for main functions. +#ifdef __cplusplus +extern "C" { +#endif + +// Initializes all data needed for the example. The name is important, and needs +// to be setup() for Arduino compatibility. +void setup(); + +// Runs one iteration of data gathering and inference. This should be called +// repeatedly from the application code. The name needs to be loop() for Arduino +// compatibility. +void loop(); + +#ifdef __cplusplus +} +#endif diff --git a/tools/hello_world/main/output_handler.cc b/tools/hello_world/main/output_handler.cc new file mode 100644 index 0000000..16ee80b --- /dev/null +++ b/tools/hello_world/main/output_handler.cc @@ -0,0 +1,30 @@ + +/* + +SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +SPDX-License-Identifier: Apache-2.0 + + +Copyright 2023 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#include "output_handler.h" +#include "tensorflow/lite/micro/micro_log.h" + +void HandleOutput(float x_value, float y_value) { + // Log the current X and Y values + MicroPrintf("x_value: ", static_cast(x_value)); + MicroPrintf("y_value: ", static_cast(y_value)); +} diff --git a/tools/hello_world/main/output_handler.h b/tools/hello_world/main/output_handler.h new file mode 100644 index 0000000..6e57201 --- /dev/null +++ b/tools/hello_world/main/output_handler.h @@ -0,0 +1,28 @@ + +/* + +SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +SPDX-License-Identifier: Apache-2.0 + + +Copyright 2023 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#pragma once + +#include "tensorflow/lite/c/common.h" + +// Called by the main loop to produce some output based on the x and y values +void HandleOutput(float x_value, float y_value); diff --git a/tools/requirements.txt b/tools/requirements.txt new file mode 100644 index 0000000..eea9b7f --- /dev/null +++ b/tools/requirements.txt @@ -0,0 +1,51 @@ +absl-py==1.4.0 +astunparse==1.6.3 +black==23.3.0 +cachetools==5.3.0 +certifi==2023.5.7 +charset-normalizer==3.1.0 +click==8.1.3 +flatbuffers==23.5.9 +gast==0.4.0 +google-auth==2.18.1 +google-auth-oauthlib==1.0.0 +google-pasta==0.2.0 +grpcio==1.55.0 +h5py==3.8.0 +idna==3.4 +importlib-metadata==6.6.0 +jax==0.4.10 +keras==2.12.0 +libclang==16.0.0 +Mako==1.2.4 +Markdown==3.4.3 +MarkupSafe==2.1.2 +ml-dtypes==0.1.0 +mypy-extensions==1.0.0 +numpy==1.23.5 +oauthlib==3.2.2 +opt-einsum==3.3.0 +packaging==23.1 +pathspec==0.11.1 +Pillow==9.5.0 +platformdirs==3.5.1 +protobuf==4.23.1 +pyasn1==0.5.0 +pyasn1-modules==0.3.0 +requests==2.31.0 +requests-oauthlib==1.3.1 +rsa==4.9 +scipy==1.10.1 +six==1.16.0 +tensorboard==2.12.3 +tensorboard-data-server==0.7.0 +tensorflow==2.12.0 +tensorflow-estimator==2.12.0 +tensorflow-io-gcs-filesystem==0.32.0 +termcolor==2.3.0 +tomli==2.0.1 +typing_extensions==4.6.0 +urllib3==1.26.15 +Werkzeug==2.3.4 +wrapt==1.14.1 +zipp==3.15.0 diff --git a/tools/templates.py b/tools/templates.py new file mode 100644 index 0000000..9a06acf --- /dev/null +++ b/tools/templates.py @@ -0,0 +1,360 @@ +""" + +SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + +SPDX-License-Identifier: Apache-2.0 + +""" + +from string import Template + +# main_functions.cc +cppTemplate = Template( + """ +/* + +SPDX-FileCopyrightText: ${current_year} Espressif Systems (Shanghai) CO LTD +SPDX-License-Identifier: Apache-2.0 + +Copyright ${current_year} The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + + +#include "tensorflow/lite/micro/micro_mutable_op_resolver.h" +#include "tensorflow/lite/micro/micro_interpreter.h" +#include "tensorflow/lite/micro/system_setup.h" +#include "tensorflow/lite/schema/schema_generated.h" + +#include "main_functions.h" +#include "gen_micro_mutable_op_resolver.h" +#include "${model_name_header}_model_data.h" +#include "constants.h" +#include "output_handler.h" + +// Globals, used for compatibility with Arduino-style sketches. +namespace { +const tflite::Model* model = nullptr; +tflite::MicroInterpreter* interpreter = nullptr; +TfLiteTensor* input = nullptr; +TfLiteTensor* output = nullptr; +int inference_count = 0; + +// update the value for kTensorArenaSize as per your problem's use case +constexpr int kTensorArenaSize = 50000; +uint8_t tensor_arena[kTensorArenaSize]; +} // namespace + +// The name of this function is important for Arduino compatibility. +void setup() { + // Map the model into a usable data structure. This doesn't involve any + // copying or parsing, it's a very lightweight operation. + + // X: variable = g_hello_world_model_data + model = tflite::GetModel($model_name); + if (model->version() != TFLITE_SCHEMA_VERSION) { + MicroPrintf("Model provided is schema version %d not equal to supported " + "version %d.", model->version(), TFLITE_SCHEMA_VERSION); + return; + } + + // This pulls in all the operation implementations we need. + // NOLINTNEXTLINE(runtime-global-variables) + // X: variable = Pull all the operations from op_resolver.h file + static tflite::MicroMutableOpResolver<$num_of_operations> $resolver; + $resolver = get_resolver(); + + // Build an interpreter to run the model with. + static tflite::MicroInterpreter static_interpreter( + model, $resolver, tensor_arena, kTensorArenaSize); + interpreter = &static_interpreter; + + // Allocate memory from the tensor_arena for the model's tensors. + TfLiteStatus allocate_status = interpreter->AllocateTensors(); + if (allocate_status != kTfLiteOk) { + MicroPrintf("AllocateTensors() failed"); + return; + } + + // Obtain pointers to the model's input and output tensors. + input = interpreter->input(0); + output = interpreter->output(0); + + // Keep track of how many inferences we have performed. + inference_count = 0; +} + +// The name of this function is important for Arduino compatibility. +void loop() { + // Calculate an x value to feed into the model. We compare the current + // inference_count to the number of inferences per cycle to determine + // our position within the range of possible x values the model was + // trained on, and use this to calculate a value. + float position = static_cast(inference_count) / + static_cast(kInferencesPerCycle); + float x = position * kXrange; + + // Quantize the input from floating-point to integer + int8_t x_quantized = x / input->params.scale + input->params.zero_point; + // Place the quantized input in the model's input tensor + input->data.int8[0] = x_quantized; + + // Run inference, and report any error + TfLiteStatus invoke_status = interpreter->Invoke(); + if (invoke_status != kTfLiteOk) { + MicroPrintf("Invoke failed on x: ", static_cast(x)); + return; + } + + // Obtain the quantized output from model's output tensor + int8_t y_quantized = output->data.int8[0]; + // Dequantize the output from integer to floating-point + float y = (y_quantized - output->params.zero_point) * output->params.scale; + + // Output the results. A custom HandleOutput function can be implemented + // for each supported hardware target. + HandleOutput(x, y); + + // Increment the inference_counter, and reset it if we have reached + // the total number per cycle + inference_count += 1; + if (inference_count >= kInferencesPerCycle) inference_count = 0; +} + +""" +) + +# main_functions.h +main_functions = Template( + """ +/* +SPDX-FileCopyrightText: ${current_year} Espressif Systems (Shanghai) CO LTD +SPDX-License-Identifier: Apache-2.0 + + +Copyright ${current_year} The TensorFlow Authors. All Rights Reserved. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#pragma once + +// Expose a C friendly interface for main functions. +#ifdef __cplusplus +extern "C" { +#endif + +// Initializes all data needed for the example. The name is important, and needs +// to be setup() for Arduino compatibility. +void setup(); + +// Runs one iteration of data gathering and inference. This should be called +// repeatedly from the application code. The name needs to be loop() for Arduino +// compatibility. +void loop(); + +#ifdef __cplusplus +} +#endif +""" +) + +# main.cc +main_cc = Template( + """ +/* + +SPDX-FileCopyrightText: ${current_year} Espressif Systems (Shanghai) CO LTD +SPDX-License-Identifier: Apache-2.0 + +*/ + +#include "main_functions.h" + +extern "C" void app_main(void) { + setup(); + while (true) { + loop(); + } +} +""" +) + +# output_handler.cc +output_handler_cc = Template( + """ +/* + +SPDX-FileCopyrightText: ${current_year} Espressif Systems (Shanghai) CO LTD +SPDX-License-Identifier: Apache-2.0 + + +Copyright ${current_year} The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#include "output_handler.h" +#include "tensorflow/lite/micro/micro_log.h" + +void HandleOutput(float x_value, float y_value) { + // Log the current X and Y values + MicroPrintf("x_value: ", static_cast(x_value)); + MicroPrintf("y_value: ", static_cast(y_value)); +} +""" +) + +# output_handler.h +output_handler_h = Template( +""" +/* + +SPDX-FileCopyrightText: ${current_year} Espressif Systems (Shanghai) CO LTD +SPDX-License-Identifier: Apache-2.0 + + +Copyright ${current_year} The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#pragma once + +#include "tensorflow/lite/c/common.h" + +// Called by the main loop to produce some output based on the x and y values +void HandleOutput(float x_value, float y_value); +""" +) + +# constants.h +constants_h = Template( + """ +/* + +SPDX-FileCopyrightText: ${current_year} Espressif Systems (Shanghai) CO LTD +SPDX-License-Identifier: Apache-2.0 + +Copyright ${current_year} The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#pragma once + +// This constant represents the range of x values our model was trained on, +// which is from 0 to (2 * Pi). We approximate Pi to avoid requiring additional +// libraries. +const float kXrange = 2.f * 3.14159265359f; + +// This constant determines the number of inferences to perform across the range +// of x values defined above. Since each inference takes time, the higher this +// number, the more time it will take to run through the entire range. The value +// of this constant can be tuned so that one full cycle takes a desired amount +// of time. Since different devices take different amounts of time to perform +// inference, this value should be defined per-device. +extern const int kInferencesPerCycle; + +""" +) + +# constants.cc +constants_cc = Template( + """ +/* + +SPDX-FileCopyrightText: ${current_year} Espressif Systems (Shanghai) CO LTD +SPDX-License-Identifier: Apache-2.0 + + +Copyright ${current_year} The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#include "constants.h" + +// This is a small number so that it's easy to read the logs +const int kInferencesPerCycle = 20; +""" +) + +# CMakeLists.txt +CMakeLists_txt = Template( + """ +idf_component_register(SRCS main_functions.cc main.cc ${model_name_header}_model_data.cc output_handler.cc constants.cc + INCLUDE_DIRS "") +""" +) + +topLevelCMake = Template( + r""" +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) +set(EXTRA_COMPONENT_DIRS ../../components) +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(test) +""" +) diff --git a/tools/tflite_code_generator.py b/tools/tflite_code_generator.py new file mode 100644 index 0000000..ae8912e --- /dev/null +++ b/tools/tflite_code_generator.py @@ -0,0 +1,273 @@ +""" + +SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + +SPDX-License-Identifier: Apache-2.0 + +""" + +# import necessary modules +import subprocess +import os +import re +import argparse +from templates import * +import shutil +import datetime + + +current_year = datetime.date.today().year + +# subprocess to run generate_cc_array.py +""" +RUN from tools +> python generate_cc_arrays.py main hello_world.tflite  +""" + +parser = argparse.ArgumentParser( + description="Description: Accept .tflite or .bmp file as input from the user" +) +parser.add_argument("input_file", help=".tflite or .bmp format") +args = parser.parse_args() +tflite_file = args.input_file + +# TFLITE_PATH +tflite_folder_path = os.environ.get('TFLITE_PATH') +print("tflite_folder_path: ", tflite_folder_path) + +# extract model name from .tflite file +x = tflite_file.split(".")[0] + +generate_cc_array = [ + "python", + os.path.join(tflite_folder_path, "tensorflow/lite/micro/tools/generate_cc_arrays.py"), + f"{x}/main", + tflite_file, +] +subprocess.run(generate_cc_array, check=True) + +# subprocess to run generate_micromutable_op_resolver.py +""" +RUN from tools +> python gen_micro_mutable_op_resolver/generate_micro_mutable_op_resolver_from_model.py --common_tflite_path=. --input_tflite_files=hello_world.tflite --output_dir=main +""" +generate_micromutable_op_resolver = [ + "python", + os.path.join(tflite_folder_path, "tensorflow/lite/micro/tools/gen_micro_mutable_op_resolver/generate_micro_mutable_op_resolver_from_model.py"), + f"--common_tflite_path=.", + f"--input_tflite_files={tflite_file}", + f"--output_dir={x}/main", +] +subprocess.run(generate_micromutable_op_resolver, check=True) + +# Define the file path +file_path = f"{x}/main/{x}_model_data.cc" + +# Create a temporary file path +temp_file_path = file_path + ".temp" + +# Open the input file for reading +with open(file_path, "r") as input_file: + lines = input_file.readlines() + +# Modify the include statement +modified_lines = [ + f'#include "{x}_model_data.h"\n' + if line.startswith(f'#include "{x}/main/{x}_model_data.h"') + else line + for line in lines +] + +# Open the temporary file for writing +with open(temp_file_path, "w") as temp_file: + temp_file.writelines(modified_lines) + +# Replace the original file with the temporary file +shutil.move(temp_file_path, file_path) + +# subprocess to generate .cc and .h templates +# generate_main_templates = ["python", "generate_main_templates.py"] +# subprocess.run(generate_main_templates, check=True) + +# extract operations from gen_micro_mutable_op_resolver.h +with open(f"{x}/main/gen_micro_mutable_op_resolver.h") as cppfile: + operations = [] + for line in cppfile: + if "micro_op_resolver." in line: + # print(line) + line = "".join(line.split()) + operations.append(line) +# print(operations) + +# extract the name of the unsigned integer array +with open(f"{x}/main/{x}_model_data.cc", "r") as file: + cpp_content = file.read() + +pattern = r"const\s+unsigned\s+char\s+(\w+)\[\]" +match = re.search(pattern, cpp_content) + +if match: + array_name = match.group(1) + print("/*") + print("Array name:", array_name) +else: + print("Array name not found.") + + +""" +Format the unsigned int array from model_data.cc file +""" +with open(f"{x}/main/{x}_model_data.cc", "r+") as file: + cpp_code = file.read() + + start_index = cpp_code.find("alignas(16) const unsigned char") + end_index = cpp_code.find("};", start_index) + + array_string = cpp_code[start_index:end_index] + + elements = [element.strip() for element in array_string.split(",")] + + formatted_elements = [] + for i, element in enumerate(elements): + if len(element) == 3: + if element == "0x0": + element = "0x00" + else: + element = element[:2] + "0" + element[2:] + formatted_elements.append(element) + + formatted_array_lines = [] + for i in range(0, len(formatted_elements), 12): + line_elements = formatted_elements[i : i + 12] + line = ", ".join(line_elements) + formatted_array_lines.append(line) + + formatted_array_string = ",\n".join(formatted_array_lines) + + formatted_cpp_code = ( + cpp_code[:start_index] + formatted_array_string + cpp_code[end_index:] + ) + + file.seek(0) + file.truncate() + file.write(formatted_cpp_code) + +# add tabs and close the array on a new line +with open(f"{x}/main/{x}_model_data.cc", "r+") as file: + lines = file.readlines() + + formatted_lines = [] + for i in lines[:5]: + formatted_lines.append(i) + lines = lines[5:] + + last_line = lines[-1] + + last_line = last_line.split("};") + last_line = [last_line[0], "};"] + + last_element = last_line[-2] + # last_element = '0x04, 0x00, 0x00, 0x00' + + lines[-1] = last_element + # last_line = ['0x04, 0x00, 0x00, 0x00', '};'] + + closing_bracket = last_line[-1] + + for line in lines: + if "alignas(16) const unsigned char" in line: + formatted_lines.append(line.split("{")[0] + "{\n") + data = line.split("{")[1].split("}")[0].strip().split(", ") + for i in range(0, len(data), 12): + formatted_lines.append(" " + ", ".join(data[i:i+12]) + "\n") + else: + formatted_lines.append(" "+line) + + formatted_lines.append('\n' + closing_bracket) + + file.seek(0) + file.writelines(formatted_lines) + file.truncate() + +# VARIABLES +model_name = array_name +num_of_operations = len(operations) +resolver = "micro_op_resolver" +model_name_header = x +print("Name of the Model:", model_name) +print("Number of Operations:", num_of_operations) +print("Model Name Header:", model_name_header) +print("Description of Operations: ") +for i in operations: + print(i) +print("*/") + +results = cppTemplate.safe_substitute( + model_name=array_name, + num_of_operations=num_of_operations, + resolver=resolver, + model_name_header=x, + current_year=current_year +) +cmake_template = CMakeLists_txt.safe_substitute(model_name_header=x) + +# store the results in main_functions.cc inside main folder +folder_path = f"{x}/main" +file_path = os.path.join(folder_path, "main_functions.cc") + +with open(file_path, "w") as file: + file.write(results) + +# x is passed to ${model_header_name} and written inside CMakeLists.txt +file_path_cmake = os.path.join(folder_path, "CMakeLists.txt") +with open(file_path_cmake, "w") as file: + file.write(cmake_template) + +""" +The following code generates: +- main.cc +- main_functions.h +- output_handler.cc +- output_handler.h +- constants.h +- constants.cc +- Top Level: CMakeLists.txt +""" + +main_cc = main_cc +main_functions_h = main_functions +output_handler_cc = output_handler_cc +output_handler_h = output_handler_h +constants_h = constants_h +constants_cc = constants_cc +CMakeLists_txt = CMakeLists_txt +topLevelCMakeList = topLevelCMake + +result_a = main_cc.safe_substitute(current_year=current_year) +result_b = main_functions_h.safe_substitute(current_year=current_year) +result_c = output_handler_cc.safe_substitute(current_year=current_year) +result_d = output_handler_h.safe_substitute(current_year=current_year) +result_e = constants_h.safe_substitute(current_year=current_year) +result_f = constants_cc.safe_substitute(current_year=current_year) +result_g = topLevelCMakeList.safe_substitute(current_year=current_year) + +files = { + "main.cc": result_a, + "main_functions.h": result_b, + "output_handler.cc": result_c, + "output_handler.h": result_d, + "constants.h": result_e, + "constants.cc": result_f, +} + +# top level CMakeLists.txt +directory = f"{x}/main" +for filename, result in files.items(): + file_path = os.path.join(directory, filename) + with open(file_path, "w") as file: + print(filename) + file.write(result) + +file_path_topCMake = os.path.join(f"{x}", "CMakeLists.txt") +with open(file_path_topCMake, "w") as file_g: + file_g.write(result_g)