基于Keras构建模型并部署到STM32F4的完整指南
2026/9/24 17:17:21 网站建设 项目流程

基于 Keras 构建模型并部署到 STM32F4 的完整指南

概述

将基于 Keras 构建的模型部署到 STM32F4 微控制器上,属于典型的 TinyML(微型机器学习)应用。由于 STM32F4 的硬件资源(如 Flash 和 RAM)相对有限,无法直接运行完整的深度学习模型,必须经过模型转换、量化压缩以及 C 代码生成等一系列步骤。

本文档涵盖以下三个阶段:

  • 阶段一:PC 端使用 Keras 构建与训练模型(Python + 正弦函数模拟数据)
  • 阶段二:模型压缩为 INT8 并转换为 C 代码
  • 阶段三:不使用 STM32CubeMX,手工搭建 STM32F4 工程并部署

下面是整个部署流程的概览图:

PC 端:Keras 构建与训练模型

模型保存为 .h5 文件

NNoM 量化压缩为 INT8

生成 C 代码(net.c / weights.h)

手工搭建 STM32F4 工程

编写业务逻辑(main.c)

部署到 STM32F4 并推理

阶段一:PC 端生成数据与 Keras 模型训练

1.1 环境准备

在 Python 环境中安装以下依赖:

  • numpy
  • tensorflow(包含 Keras)

1.2 生成带噪声的正弦数据

使用正弦函数加高斯噪声模拟真实传感器数据:

importnumpyasnp np.random.seed(42)X=np.linspace(0,2*np.pi,1000)y=np.sin(X)+np.random.normal(0,0.05,X.shape)# 加入高斯噪声

1.3 构建轻量级模型

为了适应 MCU 的低资源特性,精简隐藏层神经元数量,选择轻量级架构:

fromtensorflowimportkerasfromtensorflow.keras.modelsimportSequentialfromtensorflow.keras.layersimportDense model=Sequential([Dense(16,activation='relu',input_shape=(1,)),# 隐藏层16个节点Dense(1)# 输出层])model.compile(optimizer='adam',loss='mse')model.fit(X,y,epochs=100,batch_size=32,verbose=1)

1.4 模型保存

训练完成后,将模型保存为 Keras 原生格式:

model.save('sine_model.h5')

阶段一的完整流程如下:

生成带噪声的正弦数据

构建轻量级 Keras 模型

训练模型

保存为 sine_model.h5

阶段二:模型 INT8 量化与 C 代码转换

2.1 量化原理

STM32F4 的 FPU 处理浮点较慢,且 Flash/RAM 有限,必须将模型量化为 INT8 并转为 C 代码。

INT8 量化:将模型权重和激活值从 32 位浮点数(FP32)转换为 8 位整数(INT8)。这通常可使模型体积减小 75% 以上,并大幅降低内存占用和功耗。

量化感知训练:在训练或转换过程中模拟量化操作,以尽量保持模型在低精度下的准确率。

2.2 使用 NNoM 进行量化与代码生成

推荐使用轻量级开源框架NNoM,它专为 MCU 设计,支持 Keras 模型一键转 C 代码。

安装 NNoM:

pipinstallnnom

量化与导出代码:

importnnomimporttensorflowastf# 加载模型model=tf.keras.models.load_model('sine_model.h5')# 使用 NNoM 进行 INT8 量化并导出 C 代码nnom_model=nnom.NNoM(model)nnom_model.build(representative_data=X[:100])# 传入部分真实数据用于校准量化参数nnom_model.save('nnom_sine_model')# 生成 weights.h, net.h, net.c 等文件

说明:生成的weights.h包含了量化后的权重数组,net.c包含了推理逻辑。


阶段二的量化与代码生成流程如下:

加载 Keras 模型(.h5)

NNoM 构建模型

传入校准数据(X[:100])

INT8 量化

导出 C 代码(weights.h / net.c)

阶段三:STM32F4 端手工搭建工程与部署

不使用 STM32CubeMX,采用“古法”纯手工搭建工程,可以让你完全掌控代码的每一个细节。以 STM32F407 为例。

3.1 规划工程目录结构

在电脑上新建一个无中文、无空格的文件夹,创建以下目录:

STM32F4_Sine_AI/ ├── 01_MDK-ARM/ # Keil工程文件(.uvprojx) ├── 02_User/ # main.c 等用户业务代码 ├── 03_CMSIS/ # Cortex-M4内核文件 (core_cm4.h 等) ├── 04_Device/ # STM32F4专属文件 (启动文件, system_stm32f4xx.c) ├── 05_NNoM_Lib/ # 放入 NNoM 生成的 net.c, net.h, weights.h 及 NNoM 核心源码 └── 06_HAL_Driver/ # (可选) 如果不用寄存器,可放入标准外设库/HAL库

3.2 提取底层核心文件

从 ST 官方的STM32CubeF4固件包中提取以下文件到对应目录:

文件用途存放目录
startup_stm32f407xx.s启动文件04_Device
system_stm32f4xx.c.h系统时钟文件04_Device
core_cm4.hcmsis_compiler.hCMSIS 核心03_CMSIS
stm32f4xx.h,stm32f407xx.h设备头文件04_Device

3.3 Keil 工程配置(魔术棒设置)

Target 选项卡:

  • 选择芯片型号(如 STM32F407ZGT6)
  • 勾选Use MicroLIB(NNoM 依赖标准 C 库的内存分配)

C/C++ 选项卡:

  • Define 中添加宏定义:STM32F407xx, USE_STDPERIPH_DRIVER(若使用了标准库)
  • Include Paths 添加所有头文件所在的路径
  • 优化等级选择-O2-O3,并勾选C99 Mode

添加文件到工程:

在 Keil 左侧 Project 树中建立对应的 Group,将上述提取的.c文件、启动文件以及 NNoM 生成的net.c全部添加进去。

3.4 编写业务逻辑(main.c)

main.c中初始化系统时钟,并调用 NNoM 的推理接口:

#include"stm32f4xx.h"#include"net.h"// NNoM 生成的头文件#include"weights.h"// NNoM 生成的权重头文件#include<stdio.h>intmain(void){// 1. 初始化系统时钟 (可调用 SystemInit() 或手动配置 RCC 寄存器)SystemInit();// 2. 初始化 NNoM 模型nnom_model_t*model=nnom_model_create();// 3. 准备输入数据 (例如输入 PI/2,期望输出接近 1.0)floatinput_val=1.57f;int8_tq_input;// 注意:需要根据 NNoM 生成的量化参数将 float 转为 int8q_input=(int8_t)(input_val/model->in->tensor->q_scale)+model->in->tensor->q_zero_point;// 4. 执行推理memcpy(model->in->tensor->p_data,&q_input,sizeof(int8_t));nnom_predict(model);// 5. 获取并反量化输出结果int8_tq_output=((int8_t*)model->out->tensor->p_data)[0];floatresult=(q_output-model->out->tensor->q_zero_point)*model->out->tensor->q_scale;// result 即为模型预测的 sin(PI/2) 的值while(1){// 可以在这里通过串口打印 result,或控制 LED}}

阶段三的工程搭建与部署流程如下:

规划工程目录结构

提取底层核心文件

Keil 工程配置(魔术棒设置)

添加文件到工程

编写业务逻辑(main.c)

编译、烧录并验证推理结果

核心注意事项

4.1 内存分配

神经网络推理需要大量临时内存,务必在启动文件(.s)中将 Stack 和 Heap 调大(例如 Stack0x1000,Heap0x2000),否则极易发生 HardFault。

4.2 量化对齐

NNoM 在导出时会生成量化参数(Scale 和 Zero-point),在 C 端喂入数据和读取数据时,必须严格按照这些参数进行浮点与定点的转换。


总结与建议

对于 STM32F4,建议采用Keras 训练 + INT8 量化 + NNoM 生成代码的工作流。这条路径不仅避开了复杂的底层算子移植,还能充分利用开源框架的轻量化优势,是落地稳定且开发效率较高的选择。

扩展方向:可根据具体应用场景(如语音唤醒、手势识别、传感器分类等)设计更合适的轻量级模型结构,并进一步优化量化策略与推理性能。

整体工作流总结如下:

STM32F4 端

PC 端

Keras 训练

INT8 量化

NNoM 生成 C 代码

手工搭建工程

编写 main.c

部署与推理

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询