大家好,我是賀老師,嵌入式 AI工程師,《嵌入式AI:讓單片機學會思考》主理人,專注AI在MCU上的落地實踐。
做 TinyML + STM32,不要一上來就糾結“用哪個模型最先進”。在 MCU 上,先進不等于能部署,能部署不等于能穩定運行,能穩定運行也不等于能放進產品。
真正可交付的路線是:先確定任務和板子,再確定模型格式和推理框架,隨后用工具鏈把模型分析清楚,再生成代碼接入工程,最后用真實數據在板子上驗證。少走一步,后面通常要用幾倍時間補回來。
模型格式
決定能不能被 STM32 工具鏈導入,常見是 .tflite、.onnx、.h5。
量化方式
決定模型尺寸、推理速度、RAM 占用和精度損失。
內存報告
決定模型是否能放進 Flash,運行時是否能放進 RAM。
板上驗證
決定 PC 端結果和 MCU 端結果是否一致。
TinyML + STM32 不是只有一條路。選錯路線,后面會在工程接入、算子支持、性能分析和調試上反復折騰。下面這張表可以直接作為選型參考。
工程建議:原型驗證階段,可以優先用 Edge Impulse 或 ST Edge AI Developer Cloud 快速跑通閉環;產品化階段,要回到 STM32Cube.AI / STM32Cube AI Studio / CubeIDE,把內存、功耗、實時性、傳感器和異常處理納入完整工程。

推薦順序:
1. 定義任務:輸入是什么,輸出是什么,推理周期是多少
2. 準備數據:采樣頻率、窗口長度、標簽規則先固定
3. 訓練或選模型:優先選小模型,不要盲目堆層數
4. 導出模型:優先準備 int8 TFLite 或 ONNX
5. 工具鏈分析:看 Flash、RAM、MACC、算子支持
6. 生成代碼:接入 STM32CubeIDE 工程
7. 板上驗證:串口打印結果、延遲、內存、錯誤碼
8. 回到模型:根據真實瓶頸裁剪、量化、換結構STM32 工具鏈能導入模型,還不能代表這個模型適合 MCU。模型導出階段要同時檢查三件事:格式、算子、量化。只要有一項不合適,后面很可能卡在分析或生成階段。
在 MCU 上,int8 通常比 float32 更現實。它能明顯減小權重體積,也更容易利用 CMSIS-NN、廠商優化庫或硬件加速能力。視覺模型、音頻模型、IMU 分類模型,如果目標是普通 Cortex-M MCU,優先按 int8 路線設計。
典型 TensorFlow Lite int8 量化寫法:
converter = tf.lite.TFLiteConverter.from_saved_model("saved_model")
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_dataset
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()
open("model_int8.tflite", "wb").write(tflite_model)很多量化后精度掉得厲害,不是量化方法本身不行,而是代表性數據集太干凈、太少、分布不對。做振動檢測,就要放真實電機、不同轉速、不同負載、不同安裝位置的數據;做語音喚醒,就要放不同距離、噪聲、音量和人聲。代表性數據集越接近現場,int8 模型越不容易在板子上翻車。
模型訓練時用的是 NHWC 還是 NCHW,輸入是 float32 歸一化還是 int8 量化值,音頻特征是 MFCC 還是 Mel filterbank,這些都要寫進工程約定。部署階段最怕一句“訓練時好像是這么處理的”。
常見錯誤:Python 訓練時輸入是 x / 255.0,MCU 端直接把原始 uint8 像素喂給模型;訓練時特征做了均值方差歸一化,MCU 端只做了截斷;訓練時窗口長度是 1 秒,板上采樣只湊了 0.8 秒。這類問題不會報編譯錯誤,但推理結果會很難看。
把模型導入 STM32Cube.AI 或 STM32Cube AI Studio 之后,不要急著點生成代碼。先看分析報告。報告里的數字比模型準確率更接近工程現實。
判斷標準可以這樣定:如果業務要求每 100 ms 給出一次判斷,單次推理最好不要貼著 100 ms 跑。傳感器采樣、預處理、后處理、通信、RTOS 調度都要時間,模型推理盡量控制在周期的 30% 到 50% 以內,后續才有優化余量。
很多 TinyML 示例看起來很簡單,是因為它把輸入數據寫死在數組里。真正項目里,模型前面還有一整條數據鏈路:采樣、濾波、分幀、特征提取、歸一化、量化、緩存管理。模型后面還要做閾值判斷、狀態機、防抖、報警、通信和日志。
用 STM32Cube.AI 生成的 API,函數名會隨網絡名稱變化。典型調用結構大致如下,實際工程以生成代碼為準。
/* 偽代碼:函數名以 Cube.AI 生成結果為準 */
ai_handle network = AI_HANDLE_NULL;
ai_network_create(&network, AI_NETWORK_DATA_CONFIG);
ai_network_init(network, &ai_network_params);
/* input_data 必須已經按訓練時的預處理和量化規則準備好 */
ai_input[0].data = AI_HANDLE_PTR(input_data);
ai_output[0].data = AI_HANDLE_PTR(output_data);
ai_i32 batch = ai_network_run(network, ai_input, ai_output);
if (batch != 1) {
ai_error err = ai_network_get_error(network);
/* 記錄 err.type 和 err.code,別只打印一句 run failed */
}工程習慣:把模型推理封裝成一個很薄的模塊,例如 ai_app_init()、ai_app_run()、ai_app_get_result()。不要讓傳感器驅動、模型 API、業務狀態機混在一個大循環里。后面換模型、換板子、換采樣頻率時,會省很多時間。
適合已經熟悉 STM32CubeMX / STM32CubeIDE 的人。先用 Python 訓練并導出 .tflite、.onnx 或 .h5,再在 STM32CubeMX 中啟用 AI 軟件包,導入模型,完成 Analyze、Validate、Generate。生成工程后,在 USER CODE 區域接入采樣和業務邏輯。
路線 A 重點:
模型文件 -> CubeMX / Cube.AI 導入 -> Analyze -> Validate -> Generate
-> CubeIDE 編譯下載 -> 串口查看推理時間和結果 -> 接入真實傳感器適合先判斷模型能不能跑、該選哪塊板、RAM 和 Flash 大概夠不夠。Developer Cloud 可以上傳模型或選擇 STM32 Model Zoo 里的模型,按流程做量化、優化、遠程 benchmark 和代碼生成。AI Studio 則更適合在本地 GUI 里評估、優化和編譯模型。
這條路線特別適合做選型。比如同一個音頻模型,先在云端比較 STM32U5、STM32H7、STM32N6 的推理時間和內存占用,再決定項目演示板或項目原型板。
不要偷懶:云端 benchmark 是篩選依據,不是最終驗收。自己的板子上時鐘、供電、外設、緩存、RTOS、編譯優化等級都可能不同,最終數據必須回到目標硬件上測。
適合傳感器類項目,尤其是動作識別、聲音分類、異常檢測。Edge Impulse 把采集、特征、訓練、測試和部署串得比較緊,導出 Cube.MX CMSIS-Pack 后,可以直接在 STM32CubeMX 里添加軟件包。
這條路線有幾個硬要求要記?。汗こ套詈冒?C++ 處理;CubeMX 中需要啟用 CRC;串口日志要實現 ei_printf();導入 pack 后要確認 Middleware 目錄和 Edge Impulse SDK 是否生成完整。
Edge Impulse 接入檢查:
1. Deployment 選擇 Cube.MX CMSIS-Pack
2. CubeMX 安裝本地 .pack 文件
3. Software Packs 中啟用對應組件
4. 啟用 CRC
5. 工程轉成 C++,處理 main.c / main.cpp
6. 實現 ei_printf 串口輸出
7. 用 Live classification 的 raw features 做本地一致性驗證