欢迎光临
我们一直在努力

AI 边缘部署:MCU 上的轻量级目标检测,从 YOLO 到 TFLite Micro 的全链路优化

AI 边缘部署:MCU 上的轻量级目标检测,从 YOLO 到 TFLite Micro 的全链路优化

cover

一、MCU 上跑目标检测:为什么"不可能"正在变成"勉强可以"

在 STM32H7 这类高端 MCU 上,RAM 通常只有 1MB,Flash 只有 2MB,算力约 480 DMIPS。而 YOLOv5s 模型即使量化到 INT8,参数量仍有 7.2M——光模型就放不进 Flash。更不用说 YOLO 推理过程中间激活值的内存需求,动辄数 MB。

然而,边缘 AI 的需求是真实的:工业质检需要在摄像头端实时检测缺陷;智能家居需要在本地识别入侵行为;可穿戴设备需要在端侧监测健康异常。这些场景无法容忍云端推理的延迟和隐私风险。

解决方案不是把 YOLO 硬塞进 MCU,而是从模型架构、量化策略、推理引擎三个维度同时压缩。MobileNet + SSDLite、FOMO(Faster Objects More Objects)等专为 MCU 设计的检测架构,配合 INT8 量化和 TFLite Micro 的算子融合,可以在 512KB RAM 的 MCU 上实现 10 FPS 的低分辨率目标检测。

二、MCU 目标检测的技术链路

2.1 模型选型:从 YOLO 到 FOMO

模型输入分辨率参数量INT8 模型大小RAM 峰值适用 MCU
YOLOv5n 640×640 1.9M 1.9MB ~30MB 不适用
MobileNetV2-SSDLite 320×320 4.3M 1.1MB ~5MB Cortex-A
MobileNetV1-SSDLite 192×192 1.4M 400KB ~1.5MB Cortex-M7 (H7)
FOMO (Edge Impulse) 96×96 80K 60KB ~200KB Cortex-M4

flowchart TD
A[训练数据集] –> B[模型架构选择]
B –> C{目标 MCU 级别?}
C — Cortex-A / 有 NPU –> D[MobileNetV2-SSDLite<br/>320×320, INT8]
C — Cortex-M7 / 1MB RAM –> E[MobileNetV1-SSDLite<br/>192×192, INT8]
C — Cortex-M4 / 512KB RAM –> F[FOMO 架构<br/>96×96, INT8]
D –> G[TFLite / NCNN 推理]
E –> H[TFLite Micro 推理]
F –> I[TFLite Micro 推理]
G –> J[10-30 FPS]
H –> K[5-15 FPS]
I –> L[10-20 FPS]

2.2 量化策略:PTQ 与 QAT 的精度权衡

训练后量化(PTQ)实现简单但精度损失较大,量化感知训练(QAT)精度更高但需要完整训练流水线:

flowchart LR
A[FP32 模型] –> B{量化方式?}
B — PTQ –> C[校准数据集<br/>统计激活值分布]
C –> D[INT8 量化<br/>精度损失 2-5%]
B — QAT –> E[插入伪量化节点<br/>模拟 INT8 截断]
E –> F[微调训练<br/>恢复精度]
F –> G[INT8 量化<br/>精度损失 < 1%]
D –> H[部署到 MCU]
G –> H

三、TFLite Micro 推理引擎的工程实现

3.1 模型转换与量化

import tensorflow as tf
import numpy as np
from typing import Optional

def convert_to_tflite_micro(
keras_model: tf.keras.Model,
representative_dataset: Optional[tf.data.Dataset] = None,
quantize: bool = True,
input_shape: tuple = (96, 96, 3),
) -> bytes:
"""将 Keras 模型转换为 TFLite Micro 兼容的 INT8 模型"""

converter = tf.lite.TFLiteConverter.from_keras_model(keras_model)

if quantize:
converter.optimizations = [tf.lite.Optimize.DEFAULT]

# 提供代表性数据集用于校准量化参数
if representative_dataset is not None:
def rep_dataset():
for data in representative_dataset.batch(1).take(100):
yield [tf.cast(data, tf.float32)]

converter.representative_dataset = rep_dataset

# 强制全 INT8 量化(包括输入输出)
converter.target_spec.supported_ops = [
tf.lite.OpsSet.TFLITE_BUILTINS_INT8
]
converter.inference_input_type = tf.int8
converter.inference_output_type = tf.int8

tflite_model = converter.convert()

# 验证模型是否兼容 TFLite Micro 的算子集
interpreter = tf.lite.Interpreter(model_content=tflite_model)
interpreter.allocate_tensors()

input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()

print(f"模型大小: {len(tflite_model) / 1024:.1f} KB")
print(f"输入: shape={input_details[0]['shape']}, dtype={input_details[0]['dtype']}")
print(f"输出: shape={output_details[0]['shape']}, dtype={output_details[0]['dtype']}")

return tflite_model

def benchmark_tflite_model(
tflite_model: bytes,
test_input: np.ndarray,
num_runs: int = 100,
) -> dict:
"""基准测试 TFLite 模型的推理延迟和内存占用"""
interpreter = tf.lite.Interpreter(model_content=tflite_model)
interpreter.allocate_tensors()

input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()

# 量化输入数据
input_scale, input_zero_point = input_details[0]['quantization']
if input_scale > 0:
quantized_input = np.round(
test_input / input_scale + input_zero_point
).astype(np.int8)
else:
quantized_input = test_input.astype(np.float32)

# 预热
interpreter.set_tensor(input_details[0]['index'], quantized_input)
interpreter.invoke()

# 计时推理
latencies = []
for _ in range(num_runs):
start = tf.timestamp()
interpreter.set_tensor(input_details[0]['index'], quantized_input)
interpreter.invoke()
latencies.append((tf.timestamp() – start) * 1000)

# 估算内存占用(张量内存)
tensor_memory = sum(
t['bytes'] for t in interpreter.get_tensor_details()
)

return {
'avg_latency_ms': np.mean(latencies),
'p99_latency_ms': np.percentile(latencies, 99),
'tensor_memory_kb': tensor_memory / 1024,
'model_size_kb': len(tflite_model) / 1024,
}

3.2 MCU 端 C++ 推理代码

// tflite_micro_detector.h — MCU 端目标检测推理接口
#ifndef TFLITE_MICRO_DETECTOR_H_
#define TFLITE_MICRO_DETECTOR_H_

#include "tensorflow/lite/micro/micro_interpreter.h"
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
#include "tensorflow/lite/schema/schema_generated.h"

// 检测结果结构体
typedef struct {
float x; // 中心点 x 坐标(归一化 0-1)
float y; // 中心点 y 坐标(归一化 0-1)
float width; // 宽度(归一化 0-1)
float height; // 高度(归一化 0-1)
float confidence; // 置信度
int8_t class_id; // 类别 ID
} Detection;

class TFLiteMicroDetector {
public:
// 初始化推理引擎,arena_size 为张量内存池大小
static TFLiteMicroDetector* Create(
const uint8_t* model_data,
size_t model_size,
uint8_t* tensor_arena,
size_t arena_size,
float confidence_threshold = 0.5f
);

// 执行推理:输入 RGB 图像数据,输出检测结果
int Detect(
const int8_t* input_data,
int input_width,
int input_height,
Detection* detections,
int max_detections
);

// 获取推理延迟(微秒)
uint32_t GetLastInferenceTimeUs() const { return last_inference_time_us_; }

private:
TFLiteMicroDetector() = default;
tflite::MicroInterpreter* interpreter_ = nullptr;
float confidence_threshold_ = 0.5f;
float input_scale_ = 1.0f;
int input_zero_point_ = 0;
float output_scale_ = 1.0f;
int output_zero_point_ = 0;
uint32_t last_inference_time_us_ = 0;
};

#endif // TFLITE_MICRO_DETECTOR_H_

sequenceDiagram
participant CAM as 摄像头
participant PRE as 预处理<br/>(缩放+量化)
participant TFL as TFLite Micro<br/>推理引擎
participant POST as 后处理<br/>(NMS+反量化)
participant APP as 应用层

CAM->>PRE: 原始帧 (320×240 RGB)
PRE->>PRE: 缩放到 96×96
PRE->>PRE: 量化为 INT8
PRE->>TFL: 输入张量 (1×96×96×3)
TFL->>TFL: INT8 推理
TFL->>POST: 输出张量 (检测框+类别)
POST->>POST: 反量化为 FP32
POST->>POST: NMS 去重
POST->>APP: Detection[] 结果数组
Note over TFL: 推理延迟: 50-100ms<br/>RAM 峰值: ~200KB

四、MCU 目标检测的边界与权衡

4.1 精度与资源的天平

96×96 的输入分辨率意味着模型无法识别小目标。在工业质检场景中,如果缺陷像素占比低于 5%,FOMO 架构几乎无法检出。提高输入分辨率可以改善小目标检测,但 RAM 需求呈平方增长——从 96×96 提升到 192×192,RAM 峰值增加约 4 倍。

4.2 算子兼容性限制

TFLite Micro 支持的算子集合远小于 TFLite 标准版。某些检测头中的自定义算子(如 Deformable Convolution)无法在 MCU 上运行。模型设计阶段必须确认所有算子都在 TFLite Micro 的支持列表中,否则需要手动实现自定义算子——这在 MCU 上是极其昂贵的工程投入。

4.3 推理延迟与功耗的矛盾

提高推理帧率意味着更频繁地唤醒 MCU,增加功耗。电池供电的 IoT 设备通常需要在检测性能和续航之间做取舍。一种务实策略是使用低功耗传感器触发(如 PIR 人体感应),只在有事件时才启动推理,待机功耗可降至微安级。

4.4 模型更新困难

MCU 的模型存储在 Flash 中,OTA 更新需要完整的固件刷写流程。频繁更新模型不现实,模型必须在部署前经过充分验证。这与云端模型"快速迭代"的理念相悖,要求 MCU 模型在精度和鲁棒性上有更高的基线要求。

五、总结

MCU 上的目标检测不是把云端模型缩小那么简单,而是从模型架构、量化策略到推理引擎的全链路优化。FOMO 和 MobileNet-SSDLite 是当前 MCU 检测的主流选择,配合 INT8 全量化可将模型压缩到 60-400KB,RAM 峰值控制在 200KB-1.5MB。

工程落地的关键决策:模型选型先确定 MCU 的 RAM/Flash 预算,再倒推输入分辨率和架构;量化优先尝试 PTQ,精度不足时再投入 QAT 的训练成本;TFLite Micro 的算子兼容性必须在模型设计阶段验证,不要等到部署时才发现不支持;功耗敏感场景采用传感器触发推理,避免持续运行。

MCU 目标检测的精度天花板远低于云端,但在延迟、隐私和成本上具有不可替代的优势。选择 MCU 部署的前提是:应用场景对精度的容忍度高于对实时性和隐私性的要求。

赞(0)
未经允许不得转载:171主机测评 » AI 边缘部署:MCU 上的轻量级目标检测,从 YOLO 到 TFLite Micro 的全链路优化
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址