Skip to content

想要自行体验使用STM32进行超级轻量级模型的部署,需要具备以下的知识:

  • 编程语言:熟悉C和python
  • 基础知识:熟悉基础的机器学习的框架,例如TensorFlow等

0.什么是神经网络

神经网络的基础知识可以看这一篇CSDN博客:https://blog.csdn.net/illikang/article/details/82019945

作为使用方,你可以把神经网络理解为一个黑箱,给定输入,然后给你输出~

1.搭建一个神经网络

1.1.模型搭建

首先我们需要从最最简单的例子说起,​这里是我们的目标是预测正弦函数。给定一个输入,范围(0, 180),输出其对应的正弦值范围(0, 1)。我们搭建的简单的网络结构如下图所示:

当然你可以自行试着随便搭建尝试。

1.2.生成sin(x)的数据,进行模型的训练

​在仓库中的2.software/2.Advanced/1.CubeAI./python_code文件夹中已经给出所有的文件,请自行查看。其中test为模型的效果测试,train为模型训练, sine_gen为sin的数据生成,生成的csv内容可以自行查看。

在这里生成sin(x)的一系列数据后,使用keras框架搭建模型进行训练,激活函数使用tanh,没有使用sigmod是因为其不能表达负数的部分。学习率设置为0.001,epoch设置为2000。最后生成.h5.tflite文件。

python
#导入工具包
import tensorflow as tf
import pandas as pd
import numpy as np

#读取数据
data = pd.read_csv('./Embedded_things/sin_values.csv', sep=',', header=None)
raw_x = data.iloc[:,0].astype(float)
sinex = data.iloc[:,1].astype(float)
print(sinex.shape)

#建立模型
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(units=10, activation='tanh', input_shape=(1,)))
model.add(tf.keras.layers.Dense(units=5, activation='tanh'))
model.add(tf.keras.layers.Dense(units=1))
model.summary()

model.compile(optimizer=tf.keras.optimizers.AdamW(0.001),
             loss=tf.keras.losses.mse,                      #loss使用均方差,刚才的分类用的交叉熵
             metrics=[tf.keras.metrics.mse])
history = model.fit(x=raw_x, y=sinex, epochs=2000)

print(model.evaluate(raw_x, sinex))

#保存模型
model.save('./Embedded_things/sine_calcu.h5')

#转换模型为tf lite格式 不量化
load_model = tf.keras.models.load_model('./Embedded_things/sine_calcu.h5')
converter = tf.lite.TFLiteConverter.from_keras_model(load_model)
tflite_model = converter.convert()
open("./Embedded_things/sine_calcu.tflite", "wb").write(tflite_model)

2.STM32工程创建

2.1.打开CubeMX,把常规的设置都设置好,打开串口等

2.2.打开select components,选上X-CUBE-AI

在上面这个device applicantion选项中,分别意义如下:

  • Not selected:不生成设备侧应用示例。只保留网络相关文件,你需要自己写初始化、喂数据、推理、打印。
  • ApplicationTemplate:最精简模板。初始化 + 一次推理流程框架,方便你自己改业务逻辑。优点是干净、好改;缺点是默认不带完整性能统计。
  • SystemPerformance:专门做性能评测。会生成用于测推理耗时/周期/吞吐等的测试流程,并打印报告。
  • Validation:专门做结果校验。用测试样本跑网络,和参考输出对比,打印误差指标(如 max error、均方误差等),用于验证部署正确性。

我们选最方便简单的 ApplicationTemplate 就行,其他的基本是性能测试的。

2.3.添加网络,选择你的模型(.h5或.tflite),再进行验证

2.4.生成工程,代码功能

  • app_x-cube-ai.c: 负责业务侧调用流程。初始化模型、准备输入、调用推理、后处理输出。
  • sin_calcu.c: 模型执行引擎的“网络定义文件”。里面定义了张量、层、权重映射、激活内存映射,以及公开 API(create/init/run 等)
  • sin_calcu_data.c: 模型数据映射层。把“权重区/激活区”组织成 ai_buffer,并提供 ai_sin_calcu_data_params_get 供初始化阶段绑定。
  • sin_calcu_data_params.c: 模型常量参数文件。核心是权重常量数组 s_sin_calcu_weights_array_u64,以及权重/激活表句柄。

2.5.修改代码

​在main中,找到MX_X_CUBE_AI_Process()函数,里面有前处理,run推理,还有后处理。具体详见仓库代码,我们这节课要用模型预测sine的值。

c
void MX_X_CUBE_AI_Process(void)
{
    /* USER CODE BEGIN 6 */
  int res = -1;

  if (sin_calcu) {
    /* 1 - acquire and pre-process input data */
    res = acquire_and_process_data(data_ins);
    /* 2 - process the data - call inference engine */
    if (res == 0)
      res = ai_run();
    /* 3 - post-process the predictions */
    if (res == 0)
      res = post_process(data_outs);
    if (res == 0)
      HAL_Delay(100);
  }

  if (res) {
    ai_error err = {AI_ERROR_INVALID_STATE, AI_ERROR_CODE_NETWORK};
    ai_log_err(err, "Process has FAILED");
  }
    /* USER CODE END 6 */
}

前处理中,主要我们做数据的生产,我们吧sin的角度值生成到input数组。大致是设定输入为0~180。

c
int acquire_and_process_data(ai_i8* data[])
{
  float* input = (float*)data[0];

  s_input_deg = s_deg;
  s_y_true = sinf(s_input_deg * APP_PI / 180.0f);
  input[0] = s_input_deg;

  s_deg += APP_INPUT_STEP_DEG;
  if (s_deg > APP_INPUT_MAX_DEG) {
    s_deg = 0.0f;
  }

  return 0;
}

run推理,通过我们的网络推理后,得到输出y到数组中

c
static int ai_run(void)
{
  ai_i32 batch;

  batch = ai_sin_calcu_run(sin_calcu, ai_input, ai_output);
  if (batch != 1) {
    ai_log_err(ai_sin_calcu_get_error(sin_calcu),
        "ai_sin_calcu_run");
    return -1;
  }

  return 0;
}

后处理,我们将数组的结果输出出来,然后去vofa看看输出的y与真实的sin(x)是否拟合比较好。

c
int post_process(ai_i8* data[])
{
  const float* output = (const float*)data[0];

  /* FireWater text frame for VOFA+: input(deg), prediction, ground truth */
  printf("input, y_pre, y_ture: %.2f, %.2f, %.2f\r\n", s_input_deg, output[0], s_y_true);

  return 0;
}

各个函数其具体含义读者可以阅读手册或看API深入了解,这里不过多阐述。

2.5.验证

​通过串口传输出的数据到上位机VAFA,其中蓝色的线为准确的sin(x)的值,绿色的为模型输出的值,可以看到拟合的比较好,但是在接近sin(x)=0的附近,拟合的比较不好。

本站访客数 人次 本站总访问量