diff --git a/components/ai/tflite_micro/TFlite_Micro_Component_User_Guide.md b/components/ai/tflite_micro/TFlite_Micro_Component_User_Guide.md index 48ceec31aec913a79cc26b5d43e7ea8d67a2fa89..58a80ba58832ac3b4dd05e4e636436b9f0ec2af3 100644 --- a/components/ai/tflite_micro/TFlite_Micro_Component_User_Guide.md +++ b/components/ai/tflite_micro/TFlite_Micro_Component_User_Guide.md @@ -1,28 +1,28 @@ # Tensorflow Lite Micro组件使用说明 -Github ID: [Derekduke](https://github.com/Derekduke) E-mail: dkeji627@gmail.com +Github ID: [Derekduke](https://github.com/Derekduke) E-mail: [dkeji627@gmail.com](mailto:dkeji627@gmail.com) -Github ID: [QingChuanWS](https://github.com/QingChuanWS) E-mail: bingshan45@163.com +Github ID: [QingChuanWS](https://github.com/QingChuanWS) E-mail: [bingshan45@163.com](mailto:bingshan45@163.com) -Github ID: [yangqings](https://github.com/yangqings) E-mail: yangqingsheng12@outlook.com +Github ID: [yangqings](https://github.com/yangqings) E-mail: [yangqingsheng12@outlook.com](mailto:yangqingsheng12@outlook.com) # 概述 -`Tensorflow Lite Micro` 是 ` TensorFlow Lite ` 针对MCU的实验性端口,专门用于在微控制器和其他只有几千字节内存的设备上运行机器学习模型。 +`Tensorflow Lite Micro` 是 `TensorFlow Lite` 针对 AIOT 的轻量级 AI 引擎,专门用于在微控制器和其他资源受限的设备上运行机器学习模型。 # 1. 建立与转换模型 -由于嵌入式设备具有有限的 RAM 和存储空间,因此限制了深度学习模型的规模。同时,TensorFlow Lite Micro 目前只支持有限的一部分深度学习运算算子,因此并非所有的模型结构都是可行的。 +由于嵌入式设备存储空间有限,因此限制了深度学习的应用。同时考虑到平台算力以及算子支持等因素,因此在模型设计以及部署阶段需充分考虑硬件平台资源以及预期性能。 -本部分将介绍由 TensorFlow 模型转换为可在嵌入式设备中上运行的过程。本部分也概述了可支持的运算,并对设计与训练一个模型以使其符合内存限制给出了一些指导。 +本部分将介绍将 TensorFlow 模型转换为可在嵌入式设备上运行的模型的过程。 ## 1.1 模型转换 -将一个已训练好的 TensorFlow 模型转换为可以在嵌入式设备中运行的 Tensorflow Lite 模型可以使用 [TensorFlow Lite 转换器 Python API](https://tensorflow.google.cn/lite/microcontrollers/build_convert) 。它能够将模型转换成 [`FlatBuffer`](https://google.github.io/flatbuffers/) 格式,减小模型规模,并修改模型以使用 TensorFlow Lite 支持的运算。 +将一个已训练好的 TensorFlow 模型转换为可以在嵌入式设备中运行的 Tensorflow Lite 模型可以使用 [TensorFlow Lite 转换器 Python API](https://tensorflow.google.cn/lite/microcontrollers/build_convert) 。它能够将模型转换成 [`FlatBuffer`](https://google.github.io/flatbuffers/) 格式,减小模型规模,并修改模型及算子以支持TensorFlow Lite运算。 ### 1.1.1 量化 -为了获得尽可能小的模型规模,你应该考虑使用[训练后量化](https://tensorflow.google.cn/lite/performance/post_training_quantization)。它会降低你模型中数字的精度,从而减小模型规模。不过,这种操作可能会导致模型推理准确性的下降,对于小规模模型来说尤为如此, 所有我们需要在量化前后分析模型的准确性变换以确保这种损失在可接受范围内。 +为了获得尽可能小的模型,某些情况下可以考虑使用 [训练后量化](https://tensorflow.google.cn/lite/performance/post_training_quantization) 。它会降低模型中数字的精度,从而减小模型规模,比如将 FP32 转化为 Int8。不过,这种操作可能会导致模型推理准确性的下降,对于小规模模型来说尤为如此,所以我们需要在量化前后分析模型的准确性,以确保这种损失在可接受范围内。 以下这段 Python 代码片段展示了如何使用预训练量化进行模型转换: @@ -34,11 +34,11 @@ tflite_quant_model = converter.convert() open("converted_model.tflite", "wb").write(tflite_quant_model) ``` -### 1.1.2 转换为一个 C 数组 +### 1.1.2 将模型文件转换为一个 C 数组 -许多微控制器平台没有本地文件系统的支持。从程序中使用一个模型最简单的方式是将其以一个 C 数组的形式并将其编译进你的程序。 +许多微控制器平台没有本地文件系统的支持。从程序中使用一个模型最简单的方式是将其转换为 C 数组并将其编译进你的程序。 -以下的 unix 命令会生成一个以 `char` 数组形式包含 TensorFlow Lite 模型的 C 源文件: +以下的 unix 命令会生成一个包含 TensorFlow Lite 模型的 C 源文件,其中模型数据以 `char` 数组形式表现: ```bash xxd -i converted_model.tflite > model_data.cc @@ -54,38 +54,36 @@ unsigned char converted_model_tflite[] = { unsigned int converted_model_tflite_len = 18200; ``` -在生成了此文件之后,你可以将它包含到你的程序。在嵌入式平台上,我们需要将该数组声明为 `const` 类型以获得更好的内存效率。 +在生成了此文件之后,你可以将它包含到你的程序中。在嵌入式平台上,我们需要将该数组声明为 `const` 类型以获得更好的内存效率。 ## 1.2 模型结构与训练 -在设计一个面向微控制器的模型时,考虑模型的规模、工作负载,以及用到的运算是非常重要的。 +在设计一个面向微控制器的模型时,考虑模型的规模、工作负载,以及模型所使用到的算子是非常重要的。 ### 1.2.1 模型规模 -一个模型必须在二进制和运行时方面都足够小,以使其可以和你程序的其他部分一起符合你目标设备的内存限制。 +一个模型必须在二进制和运行时方面都足够小,以使其可以和你程序的其他部分满足目标设备的内存限制。 -为了创建一个更小的模型,你可以在你的结构里使用更少和更小的层。然而,小规模的模型更易面临欠拟合问题。这意味着对于许多问题,尝试并使用符合内存限制的尽可能大规模的模型是有意义的。但是,使用更大规模的模型也会导致处理器工作负载的增加。 +为了创建一个更小的模型,你可以在模型设计中采用少而小的层。然而,小规模的模型更易导致欠拟合问题。这意味着对于许多应用,尝试并使用符合内存限制的尽可能大的模型是有意义的。但是,使用更大规模的模型也会导致处理器工作负载的增加。 -注:在一个 Cortex M3 上,面向微控制器的 TensorFlow Lite 的核心运行时占 16 KB。 +注:在一个 Cortex M3 上,TensorFlow Lite Micro的 core runtime 仅占约16 KB。 ### 1.2.2 工作负载 -工作负载受到模型规模与复杂度的影响。大规模、复杂的模型可能会导致更高的功耗,根据实际的应用场景,这种情况所带来的功耗与热量的增加可能会成为一个问题。 +工作负载受到模型规模与复杂度的影响,大规模、复杂的模型可能会导致更高的功耗。在实际的应用场景中,功耗与热量的增加可能会带来其他问题。 ### 1.2.3 运算支持 -面向微控制器的 TensorFlow Lite 目前仅支持有限的部分 TensorFlow 运算,这影响了可以运行的模型结构。我们正致力于在参考实现和针对特定结构的优化方面扩展运算支持。 +TensorFlow Lite Micro 目前仅支持有限的 TensorFlow 算子,因此可运行的模型也有所限制。我们正致力于在参考实现和针对特定结构的优化方面扩展运算支持。Arm 的 CMSIS-NN 开源加速库也为算子的支持和优化提供了另一种可能。 -已支持的运算可以在文件 [`all_ops_resolver.cc`](https://github.com/QingChuanWS/tensorflow/tree/master/tensorflow/lite/micro/all_ops_resolver.cc) 中看到。 +已支持的运算可以在文件 [`all_ops_resolver.cc`](https://github.com/tensorflow/tensorflow/tree/5e0ed38eb746f3a86463f19bcf7138a959ddb2d4/tensorflow/lite/micro/all_ops_resolver.cc) 中看到。 ## 1.3 运行推断 -以下部分将介绍软件包自带语音历程中的 [main_functions.cc](https://github.com/QingChuanWS/tensorflow/tree/master/tensorflow/lite/micro/examples/person_detection_experimental/main_functions.cc) 文件并解释了它如何使用用于微控制器的 Tensorflow Lite 来运行推断。 +以下部分将介绍软件包自带语音历程中的 [main_functions.cc](https://github.com/tensorflow/tensorflow/tree/5e0ed38eb746f3a86463f19bcf7138a959ddb2d4/tensorflow/lite/micro/examples/person_detection_experimental/main_functions.cc) 文件并阐述了如何使用 Tensorflow Lite Micro 来进行 AI 推理。 ### 1.3.1 包含项 -要使用库,必须包含以下头文件: - ```C++ #include "tensorflow/lite/micro/kernels/micro_ops.h" #include "tensorflow/lite/micro/micro_error_reporter.h" @@ -94,36 +92,36 @@ unsigned int converted_model_tflite_len = 18200; #include "tensorflow/lite/version.h" ``` -- [`micro_ops.h`](https://github.com/QingChuanWS/tensorflow/tree/master/tensorflow/lite/micro/kernels/micro_ops.h) 提供给解释器(interpreter)用于运行模型的操作。 -- [`micro_error_reporter.h`](https://github.com/QingChuanWS/tensorflow/tree/master/tensorflow/lite/micro/micro_error_reporter.h) 输出调试信息。 -- [`micro_interpreter.h`](https://github.com/QingChuanWS/tensorflow/tree/master/tensorflow/lite/micro/micro_interpreter.h) 包含处理和运行模型的代码。 -- [`schema_generated.h`](https://github.com/QingChuanWS/tensorflow/tree/master/tensorflow/lite/schema/schema_generated.h) 包含 TensorFlow Lite [`FlatBuffer`](https://google.github.io/flatbuffers/) 模型文件格式的模式。 -- [`version.h`](https://github.com/QingChuanWS/tensorflow/tree/master/tensorflow/lite/version.h) 提供 Tensorflow Lite 架构的版本信息。 +- [`micro_ops.h`](https://github.com/tensorflow/tensorflow/tree/5e0ed38eb746f3a86463f19bcf7138a959ddb2d4/tensorflow/lite/micro/kernels/micro_ops.h) 提供给解释器(interpreter)用于运行模型的操作。 +- [`micro_error_reporter.h`](https://github.com/tensorflow/tensorflow/tree/5e0ed38eb746f3a86463f19bcf7138a959ddb2d4/tensorflow/lite/micro/micro_error_reporter.h) 输出调试信息。 +- [`micro_interpreter.h`](https://github.com/tensorflow/tensorflow/tree/5e0ed38eb746f3a86463f19bcf7138a959ddb2d4/tensorflow/lite/micro/micro_interpreter.h) Tensorflow Lite Micro 解释器,用来运行我们的模型。 +- [`schema_generated.h`](https://github.com/tensorflow/tensorflow/tree/5e0ed38eb746f3a86463f19bcf7138a959ddb2d4/tensorflow/lite/schema/schema_generated.h) 定义 TensorFlow Lite [`FlatBuffer`](https://google.github.io/flatbuffers/) 数据结构。 +- [`version.h`](https://github.com/tensorflow/tensorflow/tree/5e0ed38eb746f3a86463f19bcf7138a959ddb2d4/tensorflow/lite/version.h) 提供 Tensorflow Lite 架构的版本信息。 -示例还包括其他一些文件。以下这些是最重要的: +示例中还包括其他一些文件,比如: ```C++ #include "tensorflow/lite/micro/examples/micro_speech/micro_features/micro_model_settings.h" #include "tensorflow/lite/micro/examples/micro_speech/micro_features/model.h" ``` -- [`model.h`](https://github.com/QingChuanWS/tensorflow/tree/master/tensorflow/lite/micro_speech/micro_features/model.h) 包含存储为 `char` 数组的模型。阅读[“构建与转换模型”](https://tensorflow.google.cn/lite/microcontrollers/build_convert)来了解如何将 Tensorflow Lite 模型转换为该格式。 -- [`micro_model_settings.h`](https://github.com/QingChuanWS/tensorflow/tree/master/tensorflow/lite/micro/examples/micro_speech/micro_features/micro_model_settings.h) 定义与模型相关的各种常量。 +- [`model.h`](https://github.com/tensorflow/tensorflow/tree/5e0ed38eb746f3a86463f19bcf7138a959ddb2d4/tensorflow/lite/micro/examples/micro_speech/micro_features/model.h) 将模型存储为 `char` 类型数组。阅读 [“构建与转换模型”](https://tensorflow.google.cn/lite/microcontrollers/build_convert)来了解如何将 Tensorflow Lite 模型转换为该格式。 +- [`micro_model_settings.h`](https://github.com/tensorflow/tensorflow/tree/5e0ed38eb746f3a86463f19bcf7138a959ddb2d4/tensorflow/lite/micro/examples/micro_speech/micro_features/micro_model_settings.h) 定义与模型相关的各种常量。 ### 1.3.2 设置日志记录 -要设置日志记录,需要使用一个指向 `tflite::MicroErrorReporter` 实例的指针来创建一个 `tflite::ErrorReporter` 指针: +要记录日志,需要实例化 `tflite::MicroErrorReporter` 类: ```C++ tflite::MicroErrorReporter micro_error_reporter; tflite::ErrorReporter* error_reporter = µ_error_reporter; ``` -该变量被传递到解释器(interpreter)中,解释器允许它写日志。由于微控制器通常具有多种日志记录机制,`tflite::MicroErrorReporter` 的实现是为您的特定设备所定制的。 +该对象被传递到解释器(interpreter)中用于记录日志。由于微控制器通常具有多种日志记录机制,因此 `tflite::MicroErrorReporter` 在实现上考虑了不同设备的差异性。 ### 1.3.3 加载模型 -在以下代码中,模型是从一个 `char` 数组中实例化的,`g_tiny_conv_micro_features_model_data` (要了解其是如何构建的,请参见[“构建与转换模型”](ModelConvert.md))。 随后我们检查模型来确保其架构版本与我们使用的版本所兼容: +在以下代码中,实例化的 `char` 数组中包含了模型信息,`g_tiny_conv_micro_features_model_data` (要了解其是如何构建的,请参见 [“构建与转换模型”](https://tensorflow.google.cn/lite/microcontrollers/build_convert) 。随后我们检查模型来确保其架构版本与我们使用的版本所兼容: ```C++ const tflite::Model* model = @@ -137,9 +135,9 @@ if (model->version() != TFLITE_SCHEMA_VERSION) { } ``` -### 1.3.4实例化操作解析器 +### 1.3.4实例化 OP 解析器 -解释器(interpreter)需要一个 [`micro_ops`](https://github.com/QingChuanWS/tensorflow/tree/master/tensorflow/lite/micro/kernels/micro_ops.h) 实例来访问 Tensorflow 操作。可以扩展此类以向您的项目添加自定义操作: +解释器(interpreter)需要一个 [`micro_ops`](https://github.com/tensorflow/tensorflow/tree/5e0ed38eb746f3a86463f19bcf7138a959ddb2d4/tensorflow/lite/micro/kernels/micro_ops.h) 实例来访问 Tensorflow 操作。可以扩展此类来添加自定义操作: ```C++ tflite::ops::micro::micro_op_resolver resolver; @@ -147,7 +145,7 @@ tflite::ops::micro::micro_op_resolver resolver; ### 1.3.5 分配内存 -我们需要预先为输入、输出以及中间数组分配一定的内存。该预分配的内存是一个大小为 `tensor_arena_size` 的 `uint8_t` 数组,它被传递给 `tflite::SimpleTensorAllocator` 实例: +我们需要预先为输入、输出以及中间变量分配一定的内存。该预分配的内存是一个大小为 `tensor_arena_size` 的 `uint8_t` 数组。它将会作为 `tflite::SimpleTensorAllocator` 实例化的参数: ```C++ const int tensor_arena_size = 10 * 1024; @@ -160,7 +158,7 @@ tflite::SimpleTensorAllocator tensor_allocator(tensor_arena, ### 1.3.6 实例化解释器(Interpreter) -我们创建一个 `tflite::MicroInterpreter` 实例,传递给之前创建的变量: +我们创建一个 `tflite::MicroInterpreter` 实例并传递相关变量: ```C++ tflite::MicroInterpreter interpreter(model, resolver, &tensor_allocator, @@ -169,7 +167,7 @@ tflite::MicroInterpreter interpreter(model, resolver, &tensor_allocator, ### 1.3.7 验证输入维度 -`MicroInterpreter` 实例可以通过调用 `.input(0)` 为我们提供一个指向模型输入张量的指针,其中 `0` 代表第一个(也是唯一一个)输入张量。我们检查这个张量以确认它的维度与类型是我们所期望的: +`MicroInterpreter` 实例可以通过调用 `.input(0)` 返回模型输入张量的指针,其中 `0` 代表第一个(也是唯一的)输入张量。我们通过检查这个张量来确认它的维度与类型是否与应用匹配: ```C++ TfLiteTensor* model_input = interpreter.input(0); @@ -182,31 +180,30 @@ if ((model_input->dims->size != 4) || (model_input->dims->data[0] != 1) || } ``` -在这个代码段中,变量 `kFeatureSliceCount` 和 `kFeatureSliceSize` 与输入的属性相关,它们定义在 [`micro_model_settings.h`](https://github.com/QingChuanWS/tensorflow/tree/master/tensorflow/lite/micro/examples/micro_speech/micro_features/micro_model_settings.h) 中。枚举值 `kTfLiteUInt8` 是对 Tensorflow Lite 某一数据类型的引用,它定义在 [`common.h`](https://github.com/QingChuanWS/tensorflow/tree/master/tensorflow/lite/c/common.h) 中。 +在这个代码段中,变量 `kFeatureSliceCount` 和 `kFeatureSliceSize` 与输入属性相关,其定义在 [`micro_model_settings.h`](https://github.com/tensorflow/tensorflow/tree/5e0ed38eb746f3a86463f19bcf7138a959ddb2d4/tensorflow/lite/micro/examples/micro_speech/micro_features/micro_model_settings.h) 中。枚举值 `kTfLiteUInt8` 是对 Tensorflow Lite 某一数据类型的引用,其定义在 [`common.h`](https://github.com/tensorflow/tensorflow/tree/5e0ed38eb746f3a86463f19bcf7138a959ddb2d4/tensorflow/lite/c/common.h) 中。 ### 1.3.8 生成特征 -我们输入到模型中的数据必须由微控制器的音频输入生成。[`feature_provider.h`](https://github.com/QingChuanWS/tensorflow/tree/master/tensorflow/lite/micro/examples/micro_speech/feature_provider.h) 中定义的 `FeatureProvider` 类捕获音频并将其转换为一组将被传入模型的特征集合。当该类被实例化时,我们用之前获取的 `TfLiteTensor` 来传入一个指向输入数组的指针。`FeatureProvider` 使用它来填充将传递给模型的输入数据: +微控制器的音频输入作为输入到模型中的数据。[`feature_provider.h`](https://github.com/tensorflow/tensorflow/tree/5e0ed38eb746f3a86463f19bcf7138a959ddb2d4/tensorflow/lite/micro/examples/micro_speech/feature_provider.h) 中定义的 `FeatureProvider` 类捕获音频并将其转换为一组特征集合。当该类被实例化时,我们将获取的 `TfLiteTensor` 以及 `FeatureProvider` 作为参数,填充输入数据用于模型运算: ```C++ - FeatureProvider feature_provider(kFeatureElementCount, - model_input->data.uint8); +FeatureProvider feature_provider(kFeatureElementCount, model_input->data.uint8); ``` -以下代码使 `FeatureProvider` 从最近一秒的音频生成一组特征并填充进输入张量: +`FeatureProvider` 将计算最近一秒的音频,生成一组特征后填充输入张量: ```C++ TfLiteStatus feature_status = feature_provider.PopulateFeatureData( error_reporter, previous_time, current_time, &how_many_new_slices); ``` -在此例子中,特征生成和推断是在一个循环中发生的,因此设备能够不断地捕捉和处理新的音频。 +在此例中,特征生成和推理发生在同一循环,因此设备能不断捕捉和处理最新的音频数据。 -当在编写自己的程序时,您可能会以其它的方式生成特征,但您总需要在运行模型之前就用数据填充输入张量。 +当您在编写程序时,可能会通过其它的方式生成特征数据,但需要注意的是,特征数据填充完成后才能进行推理。 ### 1.3.9 运行模型 -要运行模型,我们可以在 `tflite::MicroInterpreter` 实例上调用 `Invoke()`: +通过在 `tflite::MicroInterpreter` 实例上调用 `Invoke()` 可快速触发推理过程: ```C++ TfLiteStatus invoke_status = interpreter.Invoke(); @@ -216,118 +213,138 @@ if (invoke_status != kTfLiteOk) { } ``` -我们可以检查返回值 `TfLiteStatus` 以确定运行是否成功。在 [`common.h`](https://github.com/QingChuanWS/tensorflow/tree/master/tensorflow/lite/c/common.h) 中定义的 `TfLiteStatus` 的可能值有 `kTfLiteOk` 和 `kTfLiteError`。 +通过检查返回值 `TfLiteStatus` 来确定运行是否成功。在 [`common.h`](https://github.com/tensorflow/tensorflow/tree/5e0ed38eb746f3a86463f19bcf7138a959ddb2d4/tensorflow/lite/c/common.h) 中定义的 `TfLiteStatus` 的值有 `kTfLiteOk` 和 `kTfLiteError`。 ### 1.3.10 获取输出 -模型的输出张量可以通过在 `tflite::MicroIntepreter` 上调用 `output(0)` 获得,其中 `0` 代表第一个(也是唯一一个)输出张量。 +模型的输出张量可以通过在 `tflite::MicroIntepreter` 上调用 `output(0)` 获得,其中 `0` 代表第一个(也是唯一的)输出张量。 在示例中,输出是一个数组,表示输入属于不同类别(“是”(yes)、“否”(no)、“未知”(unknown)以及“静默”(silence))的概率。由于它们是按照集合顺序排列的,我们可以使用简单的逻辑来确定概率最高的类别: ```C++ - TfLiteTensor* output = interpreter.output(0); - uint8_t top_category_score = 0; - int top_category_index; - for (int category_index = 0; category_index < kCategoryCount; - ++category_index) { - const uint8_t category_score = output->data.uint8[category_index]; - if (category_score > top_category_score) { +TfLiteTensor* output = interpreter.output(0); +uint8_t top_category_score = 0; +int top_category_index; +for (int category_index = 0; category_index < kCategoryCount; + ++category_index) { + const uint8_t category_score = output->data.uint8[category_index]; + if (category_score > top_category_score) { top_category_score = category_score; top_category_index = category_index; - } } +} ``` -在示例其他部分中,使用了一个更加复杂的算法来平滑多帧的识别结果。该部分在 [recognize_commands.h](https://github.com/QingChuanWS/tensorflow/tree/master/tensorflow/lite/micro/examples/micro_speech/recognize_commands.h) 中有所定义。在处理任何连续的数据流时,也可以使用相同的技术来提高可靠性。 +在示例的其他部分中,使用了一个更加复杂的算法来平滑多帧的识别结果。该部分在 [recognize_commands.h](https://github.com/tensorflow/tensorflow/tree/5e0ed38eb746f3a86463f19bcf7138a959ddb2d4/tensorflow/lite/micro/examples/micro_speech/recognize_commands.h) 中有所定义。在处理任何连续的数据流时,也可以使用相同的技术来提高可靠性和准确度。 -# 2. 制作tensorflow_lite_micro.lib +# 2. 制作 tensorflow_lite_micro.lib -## 2.1 获得Tensorflow Lite Micro库 +## 2.1 获得 Tensorflow Lite Micro 库 -要构建库并从主 TensorFlow 存储库中运行测试,请执行以下命令: +构建库并从 TensorFlow master branch 中运行测试,请执行以下命令: -从 GitHub 中把 TensorFlow 存储库克隆到方便的地方。 +将 TensorFlow project 下载到本地,在终端中输入以下命令: -``` +```bash git clone --depth 1 https://github.com/QingChuanWS/tensorflow.git +git checkout 5e0ed38eb746f3a86463f19bcf7138a959ddb2d4 ``` -注:由于Tensorflow官方仓库的迭代速度较快,所以笔者将本组件目前使用的tensorflow版本上传到了个人仓库;同时本教程主要是为了方便开发者学习.lib库的制作方法。 +注:进行 checkout 的原因是由于 Tensorflow 官方仓库的更新速度较快,为了方便开发者学习 .lib 库的制作方法,作者将使用上述版本来进行演示,开发者如果在实际操作过程中出现问题的话也可以通过 [此链接](https://github.com/QingChuanWS/tensorflow) 直接获得作者所使用的Tensorflow工程。 -进入上一步创建的目录。 +进入 clone 好的仓库: -``` +```bash cd tensorflow ``` -项目中的 `Makefile` 能够生成包含所有必需源文件的独立项目,并支持导入目前成熟的嵌入式开发环境。目前支持的环境主要有 Arduino, Keil, Make 和 Mbed。 +项目中的 `Makefile` 能够生成包含所有源文件的独立项目,并支持导入目前成熟的嵌入式开发环境。目前支持的环境主要有 Arduino, Keil, Make 和 Mbed。 -注意:我们为其中一些环境托管预建项目。参阅 [支持的平台](https://tensorflow.google.cn/lite/microcontrollers/overview#supported_platforms) 以下载。 +注意:我们为其中一些环境托管预建项目。参阅 [支持的平台](https://tensorflow.google.cn/lite/microcontrollers/overview#supported_platforms)。 要在 Make 中生成项目,请使用如下指令: -``` +```bash make -f tensorflow/lite/micro/tools/make/Makefile generate_projects ``` -这需要几分钟,因为它需要下载一些大型工具链依赖。结束后,你应看到像这样的路径中,创建了一些文件夹: `tensorflow/lite/micro/tools/make/gen/linux_x86_64/prj/` (确切的路径取决于您的主机操作系统)。这些文件夹包含生成的项目和源文件。例如: `tensorflow/lite/micro/tools/make/gen/linux_x86_64/prj/hello_world/keil` 包含了hello world 的 Keil uVision 目标。 +这需要几分钟下载并配制依赖。结束后,新的文件夹生成并包含源文件,例如 `tensorflow/lite/micro/tools/make/gen/linux_x86_64/prj/hello_world/keil` 包含了 hello world 的 Keil uVision 工程。 -以下我们以hello_world工程为例,分离出与实际应用无关的tflite_micro源文件,用于后续的.lib库生成。 +以下以 hello_world 工程为例,分离出与实际应用无关的 tflite_micro 源文件,用于后续 .lib 库生成。 -运行本目录下的`lib_extra.py`生成tflite micro源文件包: +运行本目录下的 `lib_extra.py` 生成 tflite micro 源文件包: -| 参数 | 含义 | -| ------------------ | ----------------------------------------------- | -| --tensorflow_path | 所下载的tensorflow仓库的仓库根目录(绝对路径) | -| --tflitemicro_path | 存放生成的tensorflow lite micro路径(绝对路径) | +| 参数 | 含义 | +| ------------------ | ------------------------------------------- | +| --tensorflow_path | 下载的tensorflow仓库的根目录(绝对路径) | +| --tflitemicro_path | 生成的tensorflow lite micro路径(绝对路径) | -成功运行之后会打印`--tensorflow lite micro source file extract successful--`字样,并在对应的`tflitemicro_path`路径下生成`Source`文件夹存放生成的tensorflow Lite Micro源文件。 +脚本成功运行后打印 `--tensorflow lite micro source file extract successful--` 信息,并在对应的 `tflitemicro_path` 路径下生成 `Source` 文件夹存放 Tensorflow Lite Micro 源文件。 -## 2.2 将源文件加入 KEIL 工程并生成 .lib 库 +## 2. 将源文件加入 KEIL 工程并生成 .lib 库 -新建目标芯片的KEIL工程(本次示例以 ARM Cortex M4 为例),将Source目录下的`tensorflow`和`third_party`文件夹拷贝到KEIL工程的根目录下,并添加`tensorflow`目录下除`lite/micro/kernels`以及`lite/micro/tools`文件夹以外的所有源文件(包含.c和.cc),例如下图所示: +### 2.1 添加文件 ### +新建目标芯片的 KEIL 工程(本次示例以 ARM Cortex M4 为例),将 `Source` 目录下的 `tensorflow` 和 `third_party` 文件夹导入到 KEIL 工程根目录下,并添加 `tensorflow` 目录中除 `lite/micro/kernels` 以及 `lite/micro/tools` 文件以外的所有源文件(包含 .c 和 .cc),例如下图所示:
- **注意** -在添加`tensorflow/lite/micro/kernel`目录下的源文件时需要区分`reference`算子和应用`CMSIS-NN`加速之后的算子,`tensorflow/lite/micro/kernel`文件夹内容如下图中所示: +在添加 `tensorflow/lite/micro/kernel` 目录下的源文件时需要区分 `reference` 算子和 Arm `CMSIS-NN`优化加速算子,`tensorflow/lite/micro/kernel` 文件夹内容如下图中所示:
-如果在生成lib库时想要采用CMSIS的算子的话,则: +**注:CMSIS-NN 是 Arm 在 AI 领域针对 IOT 设备开发神经网络加速库,其目的是为了让 AI 在算力和资源有限的设备上落地,更好的发挥 Arm 的生态优势。相关代码和文档已经开源 (https://www.keil.com/pack/doc/CMSIS/NN/html/index.html) 。在 Tensorflow Lite Micro 框架下基于 CMSIS-NN 加速库设计的 CMSIS-NN 算子与 reference 算子的性能对比可参考[附录](./TFlite_Micro_Component_User_Guide.md#%E9%99%84%E5%BD%95cmsis-nn-%E5%AF%B9-tensorflow-lite-micro-%E7%9A%84%E8%BF%90%E7%AE%97%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96) 。** + +#### 2.1.1 采用 CMSIS-NN 生成 .lib 文件 #### + +需要: + +1. 添加 `tensorflow/lite/micro/kernel/cmsis-nn` 源文件; +2. 添加 `tensorflow/lite/micro/kernel/` 中的算子时,请不要添加 `add.cc`,`conv.cc`,`depthwise_conv.cc`,`softmax.cc`,`fully_connected.cc`,`pooling.cc`,`mul.cc` 源文件; +3. 添加 `tensorflow/lite/micro/tools` 文件夹下的全部源文件。 -1. 添加`tensorflow/lite/micro/kernel/cmsis-nn`文件夹中的源文件; -2. 在添加`tensorflow/lite/micro/kernel/`中的算子时,请不要添加`add.cc`,`conv.cc`,`depthwise_conv.cc`,`softmax.cc`,`fully_connected.cc`,`pooling.cc`,`mul.cc`这七个源文件。 -3. 添加`tensorflow/lite/micro/tools`文件夹下的全部源文件。 +#### 2.1.2 采用 reference 算子生成 .lib 文件 #### -如果在生成lib库时想要采用reference的算子的话,则: +需要: -1. 添加`tensorflow/lite/micro/kernel/`中的全部算子; -2. 无需添加`tensorflow/lite/micro/tools`文件夹下的源文件。 +1. 添加 `tensorflow/lite/micro/kernel/` 中的全部算子; +2. 无需添加 `tensorflow/lite/micro/tools` 文件夹下的源文件。 -**注:如果使用的是 ARM Cortex M4 以上的 MCU 的话,建议采用 CMSIS-NN 算子来生成 lib 库,可以获得较大的性能提升。** +### 2.2 配制编译选项 ### -同时采用 compiler version 6 编译器并关闭 Microlib: +采用 compiler version 6 编译器并关闭 Microlib :
-选择编译为库并编辑库名为`tensorflow_lite_micro`: +选择 Create Library 选项并修改 .lib 库名为: `tensorflow_lite_micro`
-最后包含的文件路径和优化等级,宏等: +配置有关的宏、包含的头文件路径并设置代码优化等级:
-最后点击编译链接之后,即可在工程根目录的 `Objects` 文件夹下生成 ARM Cortex M4 对应的 .lib 库,其他内核型号的 tflite_micro 库以此类推。 +最后点击编译链接选项,即可在工程根目录的 `Objects` 文件夹下生成 ARM Cortex M4 对应的 .lib 库。其他内核型号的 tflite_micro 库以此类推。 + +## 附录:CMSIS-NN 对 Tensorflow Lite Micro 的运算性能优化 + +- 硬件平台:Necluo STM32L496ZG +- 测试输入图片:`tensorflow\lite\micro\tools\make\downloads\person_model_int8` 目录中 `person_image_data.cc` 和 `no_person_image_data.cc` 保存的 96 * 96 pixels ( uint_8 ) 灰度图。 +- 单次执行和 10 次累计执行的测试结果如下: + +| Case | Disable ARM-CMSIS-NN | Enable ARM-CMSIS-NN | Improvement | +| :--------------------------------------------: | :----------------------: | :------------------: | :---------: | +| Initialize_Benchmark_Runner | 65 ticks (65 ms) | 66 ticks (66 ms) | * | +| Run_Single_Iteration | 12476 ticks (12476 ms) | 633 ticks (633 ms) | 19.71X | +| Person_Detection_Ten_Ierations_With_Person | 124769 ticks (124769 ms) | 6324 ticks (6324 ms) | 19.73X | +| Person_Detection_Ten_Ierations_With_out_Person | 124770 ticks (124770 ms) | 6325 ticks (6325 ms) | 19.72X | \ No newline at end of file diff --git a/components/ai/tflite_micro/readme.md b/components/ai/tflite_micro/readme.md index cf6a209cd2c157a2f89c0a798c8617251ca98138..ae6781874fed26e631d4d710a51572074bf83891 100644 --- a/components/ai/tflite_micro/readme.md +++ b/components/ai/tflite_micro/readme.md @@ -2,16 +2,16 @@ ## 1.组件介绍 -TensorFlow Lite Micro 组件是 Google TensorFlow 团队针对微处理器平台专门设计的端侧推理框架,该推理框架主要解决在资源, 功耗, 性能等资源受限的嵌入式系统中, 部署基于 Tensorflow Lite 框架实现深度学习模型任务。 +TensorFlow Lite Micro 组件是 Google TensorFlow 团队针对微处理器平台设计的端侧推理框架,该推理框架主要解决在资源, 功耗, 性能受限的嵌入式系统中, 如何简单快速高效部署 Tensorflow Lite 深度学习模型。CMSIS 全称 Software Interface Standard for Arm Cortex-based Microcontrollers,其中 CMSIS-NN 组件为 AI 加速库,包含高效的神经网络算子来减小内存占用和最大化硬件性能。相关代码和文档已经开源并在多个平台上得到验证( https://www.keil.com/pack/doc/CMSIS/NN/html/index.html )。 ## 2.目录结构 -组件内部整体的目录结构如下图所示: +组件目录结构如下图所示: ``` tflite_micro - ├─Source //放置了 TensorFlow Lite Micro 的全部源码 - ├─KEIL //针对 KEIL 环境需要的适配文件 + ├─Source // TensorFlow Lite Micro 的全部源码 + ├─KEIL //针对 KEIL 开发环境所需的适配文件 ├─ARM_CortexM4_lib //针对 ARM Cortex M4 生成的 tensorflow_lite_micro.lib 库 ├─ARM_CortexM7_lib //针对 ARM Cortex M7 生成的 tensorflow_lite_micro.lib 库 ├─LICENSE @@ -20,11 +20,11 @@ tflite_micro ``` -其中,KEIL 文件夹中放置了针对 KEIL 编程环境需要额外添加的源文件,如果使用的是 KEIL 编程环境则需要将其中的源文件一同加入工程。 +其中,KEIL 文件夹中包含针对 KEIL 编程环境需要额外添加的源文件(将其中的源文件一同加入工程)。 -ARM_CortexM4_lib 和 ARM_CortexM7_lib 两个文件夹中存放了针对 Cortex M4、M7 平台预先优化编译好的 tensorflow_lite_micro.lib 库,优化后的性能数据可以参考附录部分;如果在开发过程中使用了 ARM Cortex M4 或 M7 系列的芯片可以直接使用对应的 tensorflow_lite_micro.lib 库,并包含相关的头文件,可以极大的简化神经网络任务的部署流程。 +ARM_CortexM4_lib 和 ARM_CortexM7_lib 两个文件夹中存放了针对 Cortex M4、Cortex M7 平台预编译的 tensorflow_lite_micro.lib 库,优化后的性能数据可以参考附录部分;如果在开发过程中采用 ARM Cortex M4 或 Cortex M7 系列芯片可以直接使用对应的 tensorflow_lite_micro.lib 库,并包含相关的头文件,极大的缩短了开发时间。 -在 [TFlite_Micro_Component_User_Guide.md](./TFlite_Micro_Component_User_Guide.md) 中提供了本组件的基本使用流程以及上述 .lib 库的制作流程,可以在使用之前进行参考 +在 [TFlite_Micro_Component_User_Guide.md](./TFlite_Micro_Component_User_Guide.md) 中提供了本组件的使用说明以及上述 .lib 库的制作方法。 ## 3.组件使用案例 @@ -33,14 +33,13 @@ ARM_CortexM4_lib 和 ARM_CortexM7_lib 两个文件夹中存放了针对 Cortex M ## 4. 附录:Tensorflow Lite Micro 性能优化情况 - 硬件平台:Necluo STM32L496ZG -- 涉及的加速库:ARM CMSIS-NN -- 测试输入图片:`tensorflow\lite\micro\tools\make\downloads\person_model_int8` 目录 `person_image_data.cc` 和 `no_person_image_data.cc` 中保存的 96 * 96 ( uint_8 ) 灰度图。 -- 单次执行和 10 次迭代的测试结果如下: +- 加速库:ARM CMSIS-NN +- 测试输入图片:`tensorflow\lite\micro\tools\make\downloads\person_model_int8` 目录中 `person_image_data.cc` 和 `no_person_image_data.cc` 保存的 96 * 96 pixels ( uint_8 ) 灰度图。 +- 单次执行和 10 次累计执行的测试结果如下: -| Case | Without ARM-CMSIS-NN | With ARM-CMSISNN | Improvement | +| Case | Disable ARM-CMSIS-NN | Enable ARM-CMSISNN | Improvement | | :--------------------------------------------: | :----------------------: | :------------------: | :---------: | | Initialize_Benchmark_Runner | 65 ticks (65 ms) | 66 ticks (66 ms) | * | | Run_Single_Iteration | 12476 ticks (12476 ms) | 633 ticks (633 ms) | 19.71X | | Person_Detection_Ten_Ierations_With_Person | 124769 ticks (124769 ms) | 6324 ticks (6324 ms) | 19.73X | -| Person_Detection_Ten_Ierations_With_out_Person | 124770 ticks (124770 ms) | 6325 ticks (6325 ms) | 19.72X | - +| Person_Detection_Ten_Ierations_With_out_Person | 124770 ticks (124770 ms) | 6325 ticks (6325 ms) | 19.72X | \ No newline at end of file