(九)在MCU上跑AI推理:ESP-DL vs TFLite Micro,选哪个?怎么优化?

📅 2026/7/18 17:03:43 👁️ 阅读次数 📝 编程学习
(九)在MCU上跑AI推理:ESP-DL vs TFLite Micro,选哪个?怎么优化?

在MCU上跑AI推理:ESP-DL vs TFLite Micro,选哪个?怎么优化?

文章目录

  • 在MCU上跑AI推理:ESP-DL vs TFLite Micro,选哪个?怎么优化?
    • 一、MCU上跑AI,不是痴人说梦
    • 二、两条推理路径对比
    • 三、ESP-DL:开箱即用的AI推理
      • 3.1 目标检测(ESPDet)
      • 3.2 YOLO11系列
      • 3.3 图像分类
    • 四、TFLite Micro:通用模型推理
    • 五、模型量化:让模型在MCU上跑得动
      • 5.1 为什么需要量化
      • 5.2 量化流程
    • 六、推理性能优化
      • 6.1 内存管理
      • 6.2 分辨率与帧率
      • 6.3 阈值调优
    • 七、完整推理流程
    • 参考链接
    • 总结与下篇预告

一、MCU上跑AI,不是痴人说梦

“在单片机上跑神经网络?你开玩笑吧?”

2024年我听到这句话的频率很高。但到了2025年,ESP32-P4已经能在端侧跑YOLO11n目标检测,帧率稳定在15fps,功耗不到1W。

ESP-VISION提供两条AI推理路径:ESP-DL(乐鑫自研)和TFLite Micro(Google TensorFlow Lite)。选哪个?怎么用?怎么优化?这篇文章给你答案。

二、两条推理路径对比

乐鑫生态

TensorFlow生态

你的PyTorch/TF模型

选择部署路径

ESP-DL

TFLite Micro

转换为.espdl格式
espdl.Model()

转换为.tflite格式
tflite.Model()

ESP-DL运行时
硬件加速推理

TFLite Micro运行时
通用推理

对比维度ESP-DLTFLite Micro
模型格式.espdl.tflite
支持的模型ESPDet、YOLO11、YOLO11nPose、ImageNet任意TFLite模型
高级API✅ 目标检测/姿态估计/分类❌ 仅原始输出
量化自动处理需手动处理
硬件加速深度优化通用优化
灵活性中等
上手难度中高

💡一句话选型:如果你的任务属于目标检测/姿态估计/图像分类,用ESP-DL;如果你需要跑自定义模型,用TFLite Micro。

三、ESP-DL:开箱即用的AI推理

3.1 目标检测(ESPDet)

importespdl,sensor,image,time sensor.reset()sensor.set_pixformat(sensor.RGB565)sensor.set_framesize(sensor.QVGA)sensor.skip_frames(time=2000)# 加载模型(路径在/sdcard或/flash)detector=espdl.ESPDet("/sdcard/espdet_pico.espdl")clock=time.clock()whileTrue:clock.tick()img=sensor.snapshot()# 推理results=detector.detect(img,score_threshold=0.5,# 置信度阈值iou_threshold=0.45,# NMS IoU阈值max_results=10# 最多返回几个结果)# 绘制结果forresultinresults:x,y,w,h=result["bbox"]img.draw_rectangle(x,y,w,h,color=(0,255,0))img.draw_string(x,y-10,f"{result['label']}:{result['score']:.2f}")print(f"FPS:{clock.fps():.1f}")

3.2 YOLO11系列

# YOLO11 目标检测detector=espdl.YOLO11("/sdcard/yolo11n.espdl")results=detector.detect(img,score_threshold=0.5,topk=10)# YOLO11nPose 姿态估计(17个COCO关键点)pose_detector=espdl.YOLO11nPose("/sdcard/yolo11n_pose.espdl")results=pose_detector.detect(img,score_threshold=0.5)forresultinresults:# result["bbox"]: 检测框# result["keypoints"]: 17个关键点 [(x,y,conf), ...]forkpinresult["keypoints"]:ifkp[2]>0.5:# 置信度足够img.draw_circle(kp[0],kp[1],3,color=(255,0,0))

3.3 图像分类

classifier=espdl.ImageNetCls("/sdcard/imagenet_cls.espdl")results=classifier.classify(img,topk=5)forlabel,scoreinresults:print(f"{label}:{score:.2%}")

四、TFLite Micro:通用模型推理

如果你的模型不在ESP-DL支持列表中,TFLite Micro是唯一选择:

importtflite,sensor,image sensor.reset()sensor.set_pixformat(sensor.RGB565)sensor.set_framesize(sensor.QVGA)sensor.skip_frames(time=2000)# 加载.tflite模型model=tflite.Model("/sdcard/my_model.tflite")# 获取输入输出信息input_details=model.input_details()output_details=model.output_details()print(f"输入shape:{input_details['shape']}")print(f"输出shape:{output_details['shape']}")whileTrue:img=sensor.snapshot()# 预处理:匹配模型输入要求# 1. 缩放到模型输入尺寸img_input=img.resize(input_details['shape'][1],input_details['shape'][2])# 2. 转换为模型期望的格式# 这一步取决于你的模型训练时的预处理方式# 推理model.set_input(img_input)# 设置输入model.invoke()# 执行推理output=model.get_output()# 获取原始输出# 后处理:解码原始输出# 这需要根据你的模型输出格式自行实现# 例如:sigmoid、softmax、NMS、anchor解码等

五、模型量化:让模型在MCU上跑得动

5.1 为什么需要量化

模型版本大小推理时间精度损失
FP3225MB无法运行0%
INT8量化6.5MB80ms<1%
INT8+剪枝3.2MB45ms~2%

量化把浮点tensor映射到整数值,通过scale和zero_point元数据保存映射关系。模型体积缩小4倍,推理速度提升2-3倍,精度损失通常不到1%。

5.2 量化流程

# ESP-DL模型的量化由ESP-DL工具链处理# TFLite模型使用TensorFlow的量化工具# TFLite量化示例(在PC上执行)importtensorflow as tf# 加载模型converter=tf.lite.TFLiteConverter.from_saved_model("my_model")# INT8量化converter.optimizations=[tf.lite.Optimize.DEFAULT]converter.representative_dataset=representative_data_gen# 校准数据集quantized_model=converter.convert()# 保存量化模型with open("my_model_quantized.tflite","wb")as f: f.write(quantized_model)

六、推理性能优化

6.1 内存管理

# ✅ 加载一次模型,跨帧复用detector=espdl.ESPDet("/sdcard/model.espdl")whileTrue:img=sensor.snapshot()results=detector.detect(img)# 复用同一个模型实例# 不要每帧重建模型!# ❌ 每帧重建模型(内存泄漏+性能灾难)whileTrue:img=sensor.snapshot()detector=espdl.ESPDet("/sdcard/model.espdl")# 每帧加载!results=detector.detect(img)detector.deinit()# 可以释放,但何必呢

6.2 分辨率与帧率

# 模型输入尺寸 vs 采集分辨率的权衡# 假设模型输入是224×224:# 方案A:采集VGA(640×480) → 缩小到224×224sensor.set_framesize(sensor.VGA)# 600KBimg=sensor.snapshot()img_input=img.resize(224,224)# 缩放开销# 帧率:~10 fps# 方案B:采集QVGA(320×240) → 缩小到224×224sensor.set_framesize(sensor.QVGA)# 150KBimg=sensor.snapshot()img_input=img.resize(224,224)# 缩放开销小# 帧率:~15 fps

6.3 阈值调优

# 在运行时调整阈值,无需重新加载模型results=detector.detect(img,score_threshold=0.3,# 光线暗时降低阈值iou_threshold=0.45,max_results=5)# vsresults=detector.detect(img,score_threshold=0.7,# 光线好时提高阈值,减少误检iou_threshold=0.45,max_results=5)

七、完整推理流程

模型文件
.espdl / .tflite

加载到PSRAM
model = ESPDet(path)

采集帧
sensor.snapshot()

预处理
resize / 归一化 / 量化

模型推理
model.detect() / model.invoke()

后处理
NMS / softmax / 坐标映射

绘制结果
draw_rectangle / draw_cross

输出到显示/网络


参考链接

  • ESP-VISION AI推理
  • ESP-VISION API - espdl
  • ESP-VISION API - tflite
  • ESP-DL GitHub

总结与下篇预告

在MCU上跑AI的核心是选对框架+量化模型+复用实例。大多数场景用ESP-DL就够了(开箱即用),自定义模型走TFLite Micro(灵活但需要自己写后处理)。记住:模型加载一次,跨帧复用;用量化模型,不要用浮点;直接采集接近模型输入尺寸的分辨率。

下篇我们进入视频编解码——H.264硬件编码和RTSP推流,这是ESP32-P4的独占功能,也是它区别于S3的核心竞争力。


作者:码农阿虎

关键词:ESP-DL、TFLite Micro、模型量化、AI推理、端侧AI、YOLO