在STM32H7上部署边缘AI模型

一、环境准备

1. 必需的软件包:

  • Python 3.7+
  • TensorFlow 2.x
  • STM32CubeMX 6.8.0+
  • X-CUBE-AI 8.0.0+ 扩展包
  • Keil MDK 5.x 或 STM32CubeIDE

2.Python依赖库:

pip install tensorflow==2.10.0
pip install numpy
pip install scikit-learn
pip install matplotlib

二、模型训练与转换流程

  • 训练模型

从代码可以看到模型结构(参考aitest.py):

    model = tf.keras.Sequential([
        # 使用最简单的输入定义方式
        tf.keras.layers.Dense(64, activation='relu', input_shape=(6,)),
        tf.keras.layers.Dense(32, activation='relu'),
        tf.keras.layers.Dense(4, activation='softmax')
    ])

  • 模型转换

转换为TFLite格式(参考aitest.py):

        input_shape = (1, 6)
        concrete_func = tf.function(model).get_concrete_function(
            tf.TensorSpec(input_shape, tf.float32)
        )
        
        converter = tf.lite.TFLiteConverter.from_concrete_functions([concrete_func])
        converter.optimizations = [tf.lite.Optimize.DEFAULT]
        converter.target_spec.supported_types = [tf.float32]
        
        print("正在执行转换...")
        tflite_model = converter.convert()

这篇文章是对stm32部署边缘AI的教程,不对模型创建做具体教程,我是用cursor生成的模型代码

以下是完整代码

import numpy as np
import tensorflow as tf
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
import os
import tempfile

# 1. 生成模拟数据
def generate_mock_data(n_samples=1000):
    """
    生成模拟的MPU6050数据
    n_samples: 每种状态的样本数量
    """
    # 创建空数组存储数据
    X = []
    y = []
    
    # 为四种不同状态生成数据
    for state in range(4):
        if state == 0:  # 正常状态
            # 加速度数据范围
            ax = np.random.normal(0, 0.1, n_samples)
            ay = np.random.normal(0, 0.1, n_samples)
            az = np.random.normal(9.8, 0.1, n_samples)  # 重力加速度
            # 角速度数据范围
            gx = np.random.normal(0, 0.1, n_samples)
            gy = np.random.normal(0, 0.1, n_samples)
            gz = np.random.normal(0, 0.1, n_samples)
            
        elif state == 1:  # 轻微倾斜
            ax = np.random.normal(1, 0.2, n_samples)
            ay = np.random.normal(1, 0.2, n_samples)
            az = np.random.normal(9.5, 0.2, n_samples)
            gx = np.random.normal(0.5, 0.2, n_samples)
            gy = np.random.normal(0.5, 0.2, n_samples)
            gz = np.random.normal(0.2, 0.1, n_samples)
            
        elif state == 2:  # 危险倾斜
            ax = np.random.normal(2, 0.3, n_samples)
            ay = np.random.normal(2, 0.3, n_samples)
            az = np.random.normal(9.0, 0.3, n_samples)
            gx = np.random.normal(1.0, 0.3, n_samples)
            gy = np.random.normal(1.0, 0.3, n_samples)
            gz = np.random.normal(0.5, 0.2, n_samples)
            
        else:  # 跌倒状态
            ax = np.random.normal(5, 0.5, n_samples)
            ay = np.random.normal(5, 0.5, n_samples)
            az = np.random.normal(3.0, 0.5, n_samples)
            gx = np.random.normal(2.0, 0.5, n_samples)
            gy = np.random.normal(2.0, 0.5, n_samples)
            gz = np.random.normal(1.0, 0.3, n_samples)
        
        # 组合数据
        for i in range(n_samples):
            X.append([ax[i], ay[i], az[i], gx[i], gy[i], gz[i]])
            y.append(state)
    
    return np.array(X), np.array(y)

# 2. 数据预处理
def preprocess_data(X, y):
    """
    对数据进行预处理
    """
    # 标准化数据
    scaler = StandardScaler()
    X_scaled = scaler.fit_transform(X)
    
    # 保存标准化参数(后面部署要用)
    np.save('scaler_params.npy', {
        'mean': scaler.mean_,
        'scale': scaler.scale_
    })
    
    # 分割训练集和测试集
    X_train, X_test, y_train, y_test = train_test_split(
        X_scaled, y, test_size=0.2, random_state=42
    )
    
    return X_train, X_test, y_train, y_test

# 3. 创建模型
def create_model():
    """
    创建姿态识别模型
    """
    model = tf.keras.Sequential([
        # 使用最简单的输入定义方式
        tf.keras.layers.Dense(64, activation='relu', input_shape=(6,)),
        tf.keras.layers.Dense(32, activation='relu'),
        tf.keras.layers.Dense(4, activation='softmax')
    ])
    
    return model

# 4. 训练模型
def train_model(X_train, y_train):
    """
    训练模型
    """
    # 创建模型
    model = create_model()
    
    # 编译模型
    model.compile(
        optimizer='adam',
        loss='sparse_categorical_crossentropy',
        metrics=['accuracy']
    )
    
    # 训练模型
    history = model.fit(
        X_train, y_train,
        epochs=20,
        batch_size=32,
        validation_split=0.2,
        verbose=1
    )
    
    return model, history

# 5. 评估模型
def evaluate_model(model, X_test, y_test, history):
    """
    评估模型性能
    """
    # 测试集评估
    test_loss, test_acc = model.evaluate(X_test, y_test)
    print(f'\nTest accuracy: {test_acc:.4f}')
    
    # 绘制训练历史
    plt.figure(figsize=(12, 4))
    
    # 损失曲线
    plt.subplot(1, 2, 1)
    plt.plot(history.history['loss'], label='Training Loss')
    plt.plot(history.history['val_loss'], label='Validation Loss')
    plt.title('Model Loss')
    plt.xlabel('Epoch')
    plt.ylabel('Loss')
    plt.legend()
    
    # 准确率曲线
    plt.subplot(1, 2, 2)
    plt.plot(history.history['accuracy'], label='Training Accuracy')
    plt.plot(history.history['val_accuracy'], label='Validation Accuracy')
    plt.title('Model Accuracy')
    plt.xlabel('Epoch')
    plt.ylabel('Accuracy')
    plt.legend()
    
    plt.tight_layout()
    plt.show()

# 6. 主函数
def main():
    # 生成模拟数据
    print("生成模拟数据...")
    X, y = generate_mock_data(n_samples=1000)
    
    # 数据预处理
    print("数据预处理...")
    X_train, X_test, y_train, y_test = preprocess_data(X, y)
    
    # 训练模型
    print("开始训练模型...")
    model, history = train_model(X_train, y_train)
    
    # 评估模型
    print("评估模型性能...")
    evaluate_model(model, X_test, y_test, history)
    
    print("开始保存和转换模型...")
    try:
        # 1. 设置路径并创建目录
        import os
        
        base_dir = "D:/STM32_AI"
        model_dir = f"{base_dir}/model"
        model_path = f"{model_dir}/model.tflite"
        
        print(f"\n正在创建目录...")
        print(f"基础目录: {base_dir}")
        print(f"模型目录: {model_dir}")
        
        # 确保目录存在
        try:
            os.makedirs(base_dir, exist_ok=True)
            print("√ 基础目录创建成功")
            
            os.makedirs(model_dir, exist_ok=True)
            print("√ 模型目录创建成功")
        except Exception as e:
            print(f"创建目录时出错: {str(e)}")
            raise
            
        # 2. 转换模型
        print("\n正在转换模型...")
        input_shape = (1, 6)
        concrete_func = tf.function(model).get_concrete_function(
            tf.TensorSpec(input_shape, tf.float32)
        )
        
        converter = tf.lite.TFLiteConverter.from_concrete_functions([concrete_func])
        converter.optimizations = [tf.lite.Optimize.DEFAULT]
        converter.target_spec.supported_types = [tf.float32]
        
        print("正在执行转换...")
        tflite_model = converter.convert()
        print("√ 模型转换成功")
        
        # 3. 保存模型
        print(f"\n正在保存模型到: {model_path}")
        with open(model_path, 'wb') as f:
            f.write(tflite_model)
            
        # 4. 验证文件
        if os.path.exists(model_path):
            file_size = os.path.getsize(model_path)
            print(f"√ 模型保存成功!")
            print(f"  - 位置:{model_path}")
            print(f"  - 大小:{file_size/1024:.2f} KB")
            
            # 显示完整的文件信息
            import time
            file_stat = os.stat(model_path)
            print(f"  - 创建时间:{time.ctime(file_stat.st_ctime)}")
            print(f"  - 修改时间:{time.ctime(file_stat.st_mtime)}")
        else:
            print(f"错误:文件未能保存到 {model_path}")
            
        print("\n=== 使用说明 ===")
        print("1. 请确认文件是否存在于以下位置:")
        print(f"   {model_path}")
        print("2. 在 STM32CubeMX 中使用此路径导入模型")
        
    except Exception as e:
        print(f"\n发生错误:")
        print(f"错误类型: {type(e).__name__}")
        print(f"错误信息: {str(e)}")
        import traceback
        traceback.print_exc()

if __name__ == "__main__":
    main()

程序运行

(这里的数据是使用python脚本生成的数据)

生成的文件

三、在STM32上部署边缘AI - X-CUBE-AI支持的模型格式

X-CUBE-AI支持导入以下几种主流深度学习框架的模型格式:

  • TensorFlow Lite (.tflite)
  • Keras (.h5, .keras)
  • ONNX (.onnx)

这里我导入的TFLIte格式的文件,脚本是先生成.h5文件在转换为TFLite的,直接导入.h5格式的文件也可以

四、STM32CubeMX配置

  • 安装X-CUBE-AI:

        打开cubemx,选择select  components 下载x_CUBE_AI

找到如图AI插件点击install

下载之后就可以选择芯片导入模型了​​​​

这里我选择的芯片是stm32H743VIT6(尽量选择内存大一些的芯片部署)

然后还是在select components中选择X_CUBE_AI

此处选择最后一项生成应用模板

导入模型:

配置时钟串口等外设(略)

点开middleware 。。。

点击addnetwork

点击browse导入刚刚那个生成的文件(.h5或者。tflite)

注意这里导入文件的路径不能太长否则会报错

完成后点击下面地analyze

注意电脑用户名不能有中文,否则会报错就会这样

提醒一句如果,如果你的电脑用户名是中文且你自己不会改,就尽量去淘宝上找人给你改一下否则(专业的事情还是交给专业的人):

改为中文名后就可以正常导入了

analyze勾上就表示成功了

导入之后就可以了

然后正常生成工程即可

具体地工程示例我会稍后更新,此文章仅演示如何导入

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值