第一讲:课程导学与环境搭建

各位同学好,欢迎来到《微控制器上的TensorFlow部署实战》。我是你们的讲师,一个在嵌入式AI领域摸爬滚打多年的工程师。

这一讲,咱们先不急着写代码。先把路铺好,把工具备齐。说白了,就是搞清楚三件事:TensorFlow Lite Micro是什么它能跑在哪些板子上怎么把开发环境搭起来。最后,我们会跑通一个Hello World示例,让你亲眼看到模型在单片机上亮灯或打印数据。

1.1 TensorFlow Lite Micro 到底是什么?

TensorFlow Lite Micro,简称TFLM。它是TensorFlow Lite的一个子集,专门为微控制器设计的推理引擎。

你想想看,普通的TensorFlow模型动辄几十MB,而STM32的Flash可能只有512KB。怎么塞得进去?TFLM就是来解决这个矛盾的。它把模型解释器精简到极致,核心代码只有几千行,占用RAM通常不到几十KB。

它的核心特点:

  • 极小的内存占用:我见过最精简的TFLM实例,RAM只用了不到16KB。
  • 无操作系统依赖:裸机也能跑,当然RTOS也支持。
  • 纯C++实现:没有动态内存分配,没有标准库依赖。
  • 支持量化模型:int8量化是主流,速度比浮点快3-5倍。

重要概念区分:

TensorFlow Lite(手机端) vs TensorFlow Lite Micro(MCU端)

前者支持GPU加速、NNAPI,后者只支持CPU逐层推理。但TFLM的代码量只有前者的十分之一左右。

1.2 硬件选型:STM32 / ESP32 / Cortex-M

我个人习惯把硬件分成三类:入门级、进阶级、专业级。咱们课程主要覆盖前两类。

芯片系列 典型型号 Flash RAM 适合场景
STM32F4系列 STM32F407 1MB 192KB 入门学习、传感器分类
STM32H7系列 STM32H743 2MB 1MB 中等复杂度模型、音频处理
ESP32系列 ESP32-S3 8MB 512KB 带WiFi/蓝牙、需要OTA更新
Cortex-M4/M7 通用内核 视厂商而定 视厂商而定 工业级产品、低功耗场景

这里有个避坑指南:我曾经在STM32F103上尝试跑一个稍微大点的模型,结果Flash不够,折腾了两天才发现是芯片选型的问题。所以,如果你刚开始学,建议直接用STM32F407或ESP32-S3,别在资源太紧的芯片上折磨自己。

1.3 开发环境搭建:PlatformIO vs CMake

搭建环境往往是新手最头疼的一步。我见过太多同学卡在这里。咱们分两条路走:

方案一:PlatformIO(推荐新手)

PlatformIO是VS Code的一个插件。它帮你管理编译器、库依赖、烧录工具。说白了,你装好它,点一下按钮,代码就编译烧录了。

安装步骤:

  1. 安装VS Code
  2. 在扩展中搜索PlatformIO IDE并安装
  3. 重启VS Code,等待PlatformIO初始化完成
  4. 新建项目,选择你的开发板型号

我的小技巧:PlatformIO的库管理器非常好用。你只需要在platformio.ini里写上依赖库的名字,它会自动下载。比如要使用TFLM,写上:

lib_deps = 
    tensorflow/tensorflow-lite-micro @ ^2.12.0

方案二:CMake + ARM GCC(推荐进阶用户)

如果你习惯命令行,或者需要集成到CI/CD流程中,CMake是更好的选择。

基本流程:

  1. 安装ARM GCC工具链(gcc-arm-none-eabi)
  2. 安装CMake(3.16以上版本)
  3. 下载TFLM源码:git clone https://github.com/tensorflow/tflite-micro.git
  4. 创建build目录,运行cmake配置
mkdir build && cd build
cmake .. -DTARGET=STM32F407
make -j4

注意:CMake方式需要你自己配置链接脚本和启动文件。如果你对MCU底层不熟,建议先用PlatformIO。我刚开始用CMake时,光链接脚本就折腾了一下午。

1.4 Hello World 示例:编译与烧录

好了,环境搭好了,咱们来跑第一个例子。这个例子的功能很简单:输入一个正弦波的角度,模型输出对应的正弦值。说白了,就是让MCU学会计算sin函数。

代码结构:

hello_world/
├── main.cpp          # 主程序
├── model.h           # 量化后的模型数据(二进制数组)
├── model.cpp         # 模型加载代码
├── constants.h       # 常量定义
└── platformio.ini    # 项目配置文件

核心代码片段(main.cpp):

#include "tensorflow/lite/micro/all_ops_resolver.h"
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "model.h"

// 分配内存池
constexpr int kTensorArenaSize = 2 * 1024;
uint8_t tensor_arena[kTensorArenaSize];

void setup() {
    // 加载模型
    const tflite::Model* model = tflite::GetModel(g_model);
    
    // 创建解释器
    static tflite::MicroMutableOpResolver<10> resolver;
    static tflite::MicroInterpreter interpreter(model, resolver, 
                                                tensor_arena, kTensorArenaSize);
    
    // 分配张量
    interpreter.AllocateTensors();
    
    // 获取输入输出
    float* input = interpreter.input(0)->data.f;
    float* output = interpreter.output(0)->data.f;
    
    // 推理
    *input = 1.57f;  // 90度
    interpreter.Invoke();
    
    // 输出结果
    printf("sin(90°) = %f\n", *output);
}

编译烧录步骤(PlatformIO):

  1. 在VS Code中打开项目文件夹
  2. 点击底部状态栏的「→」箭头(Build)
  3. 等待编译完成(第一次会下载依赖,稍慢)
  4. 连接开发板,点击「→」旁边的「→·」按钮(Upload)

预期结果:

串口输出:sin(90°) = 0.998765(接近1.0,因为模型是量化的,有微小误差)

如果板子上有LED,可以观察到LED按正弦波规律呼吸闪烁。

1.5 常见问题与排错

嗯,这里我总结几个我经常被问到的问题:

  • 编译报错:找不到头文件 → 检查platformio.ini中的lib_deps是否写对了版本号
  • 烧录后没反应 → 检查串口波特率是否匹配(通常115200)
  • 模型推理结果全为0 → 检查输入数据是否在量化范围内(int8模型输入需归一化到[-128, 127])

我曾经遇到一个特别坑的问题:模型在PC上推理完全正确,烧到MCU上结果全错。查了两天,最后发现是字节序问题——MCU是小端模式,而模型文件是大端存储。所以,记得在模型转换时指定--byte_order=little

1.6 本章小结

这一讲,咱们把地基打好了。你知道了TFLM是什么,选什么硬件合适,怎么搭环境,还跑通了第一个Hello World。说实话,能走到这一步,你已经超过了80%的初学者。

下一讲,我们会深入模型转换的细节。你会学到如何把Keras模型转换成.tflite文件,再转换成C数组,最后烧到MCU上。到时候,你就可以跑自己的模型了。

记住:嵌入式AI的核心不是算法多牛,而是在资源受限的环境下把算法跑起来。这条路没有捷径,但每一步都算数。

咱们下节课见。