摘要:本文把前 7 天学到的 TFLM 知识整理成一份可执行的工程计划,指导如何让一颗新的 MCU、DSP、NPU 或 AI accelerator 稳定运行 TFLM 并逐步获得可量化的性能收益。核心原则是「先跑通 reference,再接入优化,最后用模型和 benchmark 证明收益」。文章按 8 个阶段展开:从需求与 baseline、平台 bring-up、reference 模型闭环、NN library 边界,到第一个 optimized kernel、扩展热点 op、内存与稳定性,再到 CI 与版本维护,并为每个阶段给出目标、工作项、交付物和完成条件,最后补充角色分工、风险应对、验收标准与最小可执行路线图。
轻松学习 TFLM Day 8:AI 芯片接入 TFLM 的工程计划
Day 1 到 Day 7,我们依次学习了 TFLM 的运行时、调用链、内存、kernel、后端目录、模型 op 分析,以及把.tflite模型接入示例。
今天把这些知识整理成一份可以执行的工程计划:
如何让一颗新的 MCU、DSP、NPU 或 AI accelerator 稳定地运行 TFLM,并逐步获得可量化的性能收益?
核心原则只有一句话:
先跑通 reference,再接入优化,最后用模型和 benchmark 证明收益。1. 项目目标和边界
1.1 最终目标
完成后,目标平台应能够:
- 编译 TFLM 静态库和目标平台应用。
- 加载至少一个
.tflite模型。 - 使用静态
tensor_arena完成AllocateTensors()。 - 调用
Invoke()获得正确输出。 - 通过 UART、RTT 或平台日志观察运行状态。
- 测量单算子和整模型 latency。
- 按需将热点 op 替换为芯片优化实现。
- 在 reference 与 optimized 之间进行正确性和性能对比。
1.2 不属于第一阶段的内容
以下内容不要作为项目第一步:
- 一开始就支持所有 TFLM op。
- 一开始就实现完整 graph compiler。
- 一开始就重写 TFLM reference kernel。
- 没有 baseline 就声称硬件加速有效。
- 只测试一个输入就宣布模型兼容。
TFLM 的 reference kernel 是正确性基线。芯片优化应放在目标平台 kernel 子目录中,而不是破坏共享的 reference 实现。
2. 推荐的总体架构
用户应用 | v TFLM MicroInterpreter | v MicroMutableOpResolver | v your_chip optimized kernels | v your_chip NN library / driver | v NPU / DSP / AI accelerator建议把工程拆成三个独立模块:
| 模块 | 主要职责 |
|---|---|
| 平台适配 | 工具链、启动、日志、计时、系统初始化、链接脚本。 |
| TFLM 后端 | conv.cc、fully_connected.cc等薄 wrapper。 |
| 芯片软件栈 | NN library、driver、firmware、DMA、cache 和硬件命令。 |
NN library 不必完全遵循 TFLM 的代码风格,也可以独立发布和测试。TFLM wrapper 只负责 tensor、shape、量化参数和状态码之间的转换。
3. 项目阶段总览
阶段 0 需求和基线 | 阶段 1 平台 bring-up | 阶段 2 reference 模型闭环 | 阶段 3 芯片 NN library 边界 | 阶段 4 第一个优化 kernel | 阶段 5 扩展热点 op | 阶段 6 性能、内存和稳定性 | 阶段 7 CI、发布和版本维护每个阶段都必须有“完成条件”。没有通过当前阶段的验证,就不要把问题带到下一阶段。
4. 阶段 0:需求、模型和 baseline
目标
确定芯片、软件环境、目标模型和可复现的 reference 数据。
工作项
- 确定目标芯片型号、核心、时钟和内存布局。
- 确认 C++17 工具链、SDK、IDE 和链接器版本。
- 选择一到三个代表性
.tflite模型。 - 用 Day 6 的工具找出每个模型的唯一 op。
- 记录模型输入、输出、类型、shape 和量化参数。
- 在 host 上保存 reference 输出和测试输入。
- 定义 latency、arena、代码体积和功耗的测量方法。
交付物
requirements.md models/ model_a.tflite model_b.tflite baseline/ input_data.* reference_output.* benchmark_definition.md完成条件
[ ] 每个目标模型都有明确输入和输出 [ ] 每个模型的 op 集合已经确认 [ ] host reference 输出可以重复得到 [ ] latency 和内存的测量方法已经确定不要只选择一个“最容易跑”的模型。至少应包含一个小模型用于 bring-up,以及一个能代表实际业务负载的模型用于性能评估。
5. 阶段 1:平台 bring-up
TFLM 官方建议先不接硬件优化,使用 reference kernel 建立平台运行环境。
目标
让 TFLM 在目标芯片上完成最小示例运行。
主要工作
5.1 工具链和链接
确认:
- 编译器支持 C++17。
- include 路径和宏定义正确。
- 链接脚本能放下代码、只读模型和 tensor arena。
- C/C++ ABI 和浮点 ABI 设置一致。
- 栈、全局区、堆策略符合芯片 SDK。
5.2 平台文件
准备目标平台版本的:
tensorflow/lite/micro/debug_log.cc tensorflow/lite/micro/micro_time.cc tensorflow/lite/micro/system_setup.cc它们分别负责日志输出、时间测量和系统初始化。实现可以放在平台自己的目录,只要最终链接时能提供对应接口。
5.3 项目裁剪
可以使用项目生成脚本创建只包含所需示例的源码树:
python3 tensorflow/lite/micro/tools/project_generation/create_tflm_tree.py\-ehello_world\-eperson_detection\/tmp/tflm-tree然后用芯片自己的构建系统编译 TFLM 静态库,例如:
libtensorflow-microlite.a交付物
tensorflow/lite/micro/your_chip/ README.md debug_log.cc micro_time.cc system_setup.cc platform_build/ toolchain file linker script startup code完成条件
[ ] 编译通过 [ ] 日志可以输出 [ ] 计时接口返回有效值 [ ] 系统初始化完成 [ ] 目标板能运行最小程序6. 阶段 2:reference 模型闭环
目标
在不使用芯片 optimized kernel 的情况下,让一个真实模型完成正确推理。
推荐顺序
hello_world -> 一个小型 int8 模型 -> person_detection 或 micro_speech -> 实际业务模型工作项
- 把
.tflite转成 C 数组,或由构建系统生成数组。 - 将模型
.cc和.h加入目标工程。 - 根据模型 op 创建最小 resolver。
- 分配静态 tensor arena。
- 检查模型 schema 版本。
- 检查输入 tensor 的 type、shape 和 bytes。
- 进行输入预处理和量化。
- 调用
AllocateTensors()。 - 调用
Invoke()。 - 对输出进行反量化并和 host reference 比较。
典型代码结构
consttflite::Model*model=tflite::GetModel(g_model_data);TFLITE_CHECK_EQ(model->version(),TFLITE_SCHEMA_VERSION);usingResolver=tflite::MicroMutableOpResolver<3>;Resolver resolver;resolver.AddConv2D();resolver.AddFullyConnected();resolver.AddSoftmax();uint8_ttensor_arena[128*1024];tflite::MicroInterpreterinterpreter(model,resolver,tensor_arena,sizeof(tensor_arena));TF_LITE_ENSURE_STATUS(interpreter.AllocateTensors());TF_LITE_ENSURE_STATUS(interpreter.Invoke());下面是一个完整的main.cc示例,展示从模型数据加载、输入预处理、调用AllocateTensors和Invoke,到输出反量化并与 host reference 比较的完整流程:
// examples/your_chip_model/main.cc#include"tensorflow/lite/micro/micro_interpreter.h"#include"tensorflow/lite/micro/micro_mutable_op_resolver.h"#include"tensorflow/lite/micro/system_setup.h"#include"tensorflow/lite/schema/schema_generated.h"#include"model_data.h"// 由 .tflite 转换生成的模型数组#include"input_adapter.h"// 输入预处理:原始数据 -> int8 量化输入#include"output_adapter.h"// 输出解释:int8 输出 -> 反量化浮点值// 静态 tensor arena:大小需根据模型实际需求调整constexprintkTensorArenaSize=128*1024;uint8_ttensor_arena[kTensorArenaSize];// 从 host 端保存的 reference 输出(浮点)中读取期望值externconstfloatkReferenceOutput[];// 定义在 baseline/reference_output.ccexternconstintkReferenceOutputSize;// 反量化:int8 原始值 -> 浮点真实值floatDequantize(int8_tvalue,floatscale,int32_tzero_point){return(static_cast<float>(value)-zero_point)*scale;}// 比较目标板输出与 host reference 输出boolCompareWithReference(constfloat*actual,intsize,floattolerance=0.01f){for(inti=0;i<size;++i){floatdiff=actual[i]-kReferenceOutput[i];if(diff<-tolerance||diff>tolerance){MicroPrintf("Mismatch at [%d]: actual=%f ref=%f",i,actual[i],kReferenceOutput[i]);returnfalse;}}returntrue;}intmain(){// 1. 平台初始化:日志、计时、系统时钟等tflite::InitializeTarget();// 2. 加载模型:从 C 数组解析 FlatB