TensorFlow Lite 移植步骤
WangGaojie Lv4

无论你使用CMake还是makefile,亦或是使用某些IDE,基本上都可以按照这样的步骤来操作。

1. 获取源码

从官方地址获取最新的 TFLite 源码:

1
https://github.com/tensorflow/tflite-micro

将其克隆到 Linux 主机上进行交叉编译,得到嵌入式平台的静态库。

2. 编译静态库

参考 tensorflow/lite/micro/cortex_m_generic/README.md 文件能够得到编译说明。

编译指令

1
make -f tensorflow/lite/micro/tools/make/Makefile TARGET=cortex_m_generic TARGET_ARCH=cortex-m7+fp OPTIMIZED_KERNEL_DIR=cmsis_nn BUILD_TYPE=debug microlite

参数说明

  • TARGET=cortex_m_generic: 指定嵌入式平台为 Cortex-M7
  • TARGET_ARCH=cortex-m7+fp: 开启硬件浮点单元
  • OPTIMIZED_KERNEL_DIR=cmsis_nn: 使用 CMSIS 的神经网络库来优化计算
  • BUILD_TYPE=debug: 开启调试信息方便调试代码

编译结果

执行指令后会在 gen/cortex_m_generic_cortex-m7+fp_debug_cmsis_nn_gcc/lib 目录中得到 libtensorflow-microlite.a 文件,这个文件就是需要添加到工程中的静态库。

3. 工程配置

3.1 转换为 C++ 工程

TFLite 为 C++ 工程,需要将我们的工程也转为 C++ 工程。

3.2 添加源码文件

除了静态库文件外,还需要将整个源码也加入到工程中。这些源码不参与编译,仅仅使用里面的头文件。

3.3 添加依赖库

在 Linux 主机端编译时,编译工具还额外下载了一些库,它们位于 /tensorflow/lite/micro/tools/make/downloads/ 目录中。根据需要将 gemmlowpflatbuffers 也拷贝到工程中。

4. 工程设置

在工程中需要做 3 个关键动作:

4.1 设置头文件路径

包括:

  • TFLite 源码根目录
  • downloads/flatbuffers/include
  • downloads/gemmlowp

4.2 设置静态库和静态库路径

1
-ltensorflow-microlite -L"/tflite-micro"

4.3 设置编译宏

设置编译宏 TF_LITE_STATIC_MEMORY,这是为了和静态库编译脚本中保持一致。

5. 集成示例代码

保证编译通过后,可以尝试将代码示例中的 hello_world 工程加入进来。

5.1 添加示例代码

文件路径:/tensorflow/lite/micro/examples/hello_world/hello_world_test.cc

5.2 添加模型文件

模型文件在 gen/cortex_m_generic_cortex-m7+fp_debug_cmsis_nn_gcc/genfiles 目录中,包含四个文件:

  • hello_world_float_model_data.cc
  • hello_world_float_model_data.h
  • hello_world_int8_model_data.cc
  • hello_world_int8_model_data.h

5.3 修改 main 函数

由于工程中已经有 main 函数了,需要将 hello_world_test.cc 中的 main 函数名称修改一下,然后在 main 函数中调用它即可。

需要注意的是 变量tflite::MicroProfiler profiler;是一个较大的对象,会分配较大的栈空间,这里需要根据实际情况对代码进行调整。

5.4 调整头文件引用路径

两个 model_data.cc 文件中的头文件引用路径可能和实际情况不一致,按照实际情况进行调整即可。

6. 日志输出配置

为了观察代码运行情况,需要向 TFLite 注入一个日志函数接口。

6.1 实现日志函数

1
2
3
4
5
6
#include "tensorflow/lite/micro/cortex_m_generic/debug_log_callback.h"
#include "usart/usart.h"

static void tflite_log(const char *s){
uart_puts(s);
}

6.2 注册日志回调

1
2
3
4
5
int main(void){
// ...
RegisterDebugLogCallback(tflite_log);
// ...
}

主要通过 RegisterDebugLogCallback 注册一个输出接口。

$icon-size = 1.2rem $search-header-height = 3rem .search-pop-overlay { position fixed top 0 left 0 z-index $z-index-8 display flex width 100% height 100% background rgba(0, 0, 0, 0) visibility hidden transition-t("visibility, background", "0, 0", "0.3, 0.3", "ease, ease") &.active { background rgba(0, 0, 0, 0.35) visibility visible .search-popup { transform scale(1) } } .search-popup { z-index $z-index-6 width 70% height 80% margin auto background var(--background-color-1) border-radius 0.4rem transform scale(0) transition-t("transform", "0", "0.3", "ease") +keep-tablet() { width 80% } +keep-mobile() { width 90% } .search-header { display flex align-items center height $search-header-height padding 0 1rem background var(--text-color-6) border-top-left-radius 0.2rem border-top-right-radius 0.2rem .search-input-field-pre { margin-right 0.2rem color var(--text-color-3) font-size 1.3rem cursor pointer } .search-input-container { flex-grow 1 padding 0.2rem .search-input { width 100% color var(--text-color-3) font-size 1.2rem background transparent border 0 outline 0 &::-webkit-search-cancel-button { display none } &::-webkit-input-placeholder { color var(--text-color-4) font-size 1rem } } } .close-popup-btn { color var(--text-color-3) font-size $icon-size cursor pointer &:hover { color var(--text-color-1) } } } #search-result { position relative display flex box-sizing border-box height 'calc(100% - %s)' % $search-header-height padding 0.3rem 1.5rem overflow auto .search-result-list { width 100% height 100% font-size 1rem li { box-sizing border-box margin 0.8rem 0 padding 0.8rem 0 border-bottom 0.1rem dashed var(--border-color) &:last-child { border-bottom none } .search-result-title { position relative display flex align-items center margin-bottom 0.8rem padding-left 1rem font-weight bold &::after { position absolute top 50% left 0 width 0.4rem height 0.4rem background var(--text-color-3) border-radius 50% transform translateY(-50%) content '' } } .search-result { margin 0 padding-left 1rem line-height 2rem word-wrap break-word } a { &:hover { color var(--text-color-3) } } .search-keyword { color var(--primary-color) font-weight bold border-bottom 0.1rem dashed var(--primary-color) } } } #no-result { margin auto color var(--text-color-4) } } } }