2. TFLite模型加载与推理框架集成

任务目标

在STM32F407开发板上集成TensorFlow Lite for Microcontrollers(TFLM)推理库,完成模型加载与基本推理闭环。本案例使用官方提供的person_detect模型(已量化,约50KB),输入为8×8灰度图像,输出为2类概率(无人/有人)。

环境与依赖

  • 硬件:STM32F407VET6(Cortex-M4F,192KB RAM)
  • IDE:STM32CubeIDE 1.15+(或任意支持ARM GCC的工程)
  • 依赖库:tflite-micro(GitHub: tensorflow/tflite-micro,commit: 2024-01-15后版本)
  • 模型文件:person_detect_model_data.cpp(由TFLM官方示例提供,含g_person_detect_model_data数组)

实现方案

将TFLM库源码加入工程,核心流程为:初始化MicroInterpreter → 分配张量内存 → 设置输入数据 → 调用Invoke() → 读取输出。关键点在于正确配置TensorArena大小(本模型需约10KB)以及将模型数组以extern方式引用。

关键完整代码

// main.c 核心推理逻辑(省略外设初始化)
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
#include "tensorflow/lite/schema/schema_generated.h"
#include "person_detect_model_data.h"  // 模型数组头文件

// 模型输入尺寸(由模型文件定义)
#define INPUT_CHANNELS 1
#define INPUT_WIDTH 8
#define INPUT_HEIGHT 8

// TensorArena:模型中间计算缓冲区(按模型需求调整)
static uint8_t tensor_arena[10 * 1024];

// 输入图像数据(示例:全零表示"无人")
static uint8_t input_data[INPUT_CHANNELS * INPUT_WIDTH * INPUT_HEIGHT] = {0};

void run_inference(void) {
    // 1. 注册模型所需算子(仅包含当前模型使用的算子)
    static tflite::MicroMutableOpResolver<5> resolver;
    resolver.AddFullyConnected();
    resolver.AddConv2D();
    resolver.AddMaxPool2D();
    resolver.AddReshape();
    resolver.AddSoftmax();

    // 2. 加载模型
    const tflite::Model* model = tflite::GetModel(g_person_detect_model_data);
    if (model->version() != TFLITE_SCHEMA_VERSION) {
        // 版本不匹配处理
        return;
    }

    // 3. 创建解释器
    static tflite::MicroInterpreter interpreter(
        model, resolver, tensor_arena, sizeof(tensor_arena));
    
    // 4. 分配张量内存
    TfLiteStatus allocate_status = interpreter.AllocateTensors();
    if (allocate_status != kTfLiteOk) {
        return;
    }

    // 5. 获取输入张量并填充数据
    TfLiteTensor* input = interpreter.input(0);
    memcpy(input->data.uint8, input_data, sizeof(input_data));

    // 6. 执行推理
    TfLiteStatus invoke_status = interpreter.Invoke();
    if (invoke_status != kTfLiteOk) {
        return;
    }

    // 7. 读取输出(2类概率)
    TfLiteTensor* output = interpreter.output(0);
    uint8_t person_score = output->data.uint8[1];  // 索引1为"有人"概率
    // person_score > 128 表示检测到人(量化阈值)
}

工程集成步骤

  1. 将tflite-micro仓库的tensorflow/目录复制到工程Middlewares/下
  2. 在CubeIDE中设置头文件路径:Middlewares/tensorflow及Middlewares/tensorflow/lite/micro/tools/make/downloads(若使用第三方算子)
  3. 将person_detect_model_data.cpp加入工程源码目录
  4. 在链接器设置中增加:-Wl,--gc-sections(裁剪未用段)和-u _printf_float(若需浮点打印)
  5. 编译时需定义TF_LITE_STATIC_MEMORY宏(在编译器预定义中添加)

验证方法

通过条件:在run_inference()末尾设置断点,观察person_score值。当输入全零时,预期输出person_score < 128(表示无人)。若需验证"有人"场景,可将input_data替换为官方示例中的人像灰度数据(可从TFLM测试用例获取),此时person_score应大于128。

附加检查:通过UART打印allocate_status和invoke_status,两者均为kTfLiteOk(0)即表示模型加载与推理链路正常。若分配失败,需增大tensor_arena数组。

常见问题

  • 编译报错找不到头文件:确认所有tflite-micro子目录已复制完整,且路径无中文
  • 链接时Flash溢出:TFLM库约占用80KB Flash,需确认MCU型号及链接脚本中Flash起始地址正确
  • 推理结果恒为0:检查输入张量的数据类型是否为kTfLiteUInt8,若为kTfLiteInt8需将输入数据转为有符号类型