
STM32 X-CUBE-AI生成框架源码解析:AI模型部署模板详解
在STM32上部署AI模型时,X-CUBE-AI框架提供了两个核心函数:MX_X_CUBE_AI_Init()和MX_X_CUBE_AI_Process()。本文将详细分析这两个函数的每一行代码,解释所有参数、变量和嵌套函数,帮助初学者彻底理解X-CUBE-AI的工作流程。//负责AI模型的初始化//负责AI模型的推理过程让我们深入分析这两个函数的实现细节。ai_error:结构体类型,包含两个字
·
一、概述
在STM32上部署AI模型时,X-CUBE-AI框架提供了两个核心函数:MX_X_CUBE_AI_Init()和MX_X_CUBE_AI_Process()。本文将详细分析这两个函数的每一行代码,解释所有参数、变量和嵌套函数,帮助初学者彻底理解X-CUBE-AI的工作流程。
X-CUBE-AI框架主要通过两个核心函数实现AI模型的部署:
void MX_X_CUBE_AI_Init(void);//负责AI模型的初始化
void MX_X_CUBE_AI_Process(void);//负责AI模型的推理过程
让我们深入分析这两个函数的实现细节。
二、初始化函数分析
1. MX_X_CUBE_AI_Init()
void MX_X_CUBE_AI_Init(void)
{
printf("\r\nTEMPLATE - initialization\r\n");
ai_boostrap(data_activations0);
}
2. 调用AI引导初始化函数
ai_boostrap(data_activations0);
- 调用ai_boostrap函数初始化AI模型
- 参数data_activations0:预分配的激活缓冲区,用于存储神经网络中间计算结果
- 在文件顶部通常定义为:AI_ALIGNED(32) ai_u8 data_activations0[AI_MPU6050_AI_DATA_ACTIVATIONS_SIZE];
AI_ALIGNED(32)
static uint8_t pool0[AI_MPU6050_AI_DATA_ACTIVATION_1_SIZE];
ai_handle data_activations0[] = {pool0};
- AI_ALIGNED(32):确保内存32字节对齐,优化访问速度
- ai_u8:无符号8位整数类型
- AI_MPU6050_AI_DATA_ACTIVATIONS_SIZE:激活缓冲区大小(例如384字节)
3. ai_boostrap函数详解
static int ai_boostrap(ai_handle *act_addr)
{
ai_error err;
/* Create and initialize an instance of the model */
err = ai_mpu6050_ai_create_and_init(&mpu6050_ai, act_addr, NULL);
if (err.type != AI_ERROR_NONE) {
ai_log_err(err, "ai_mpu6050_ai_create_and_init");
return -1;
}
ai_input = ai_mpu6050_ai_inputs_get(mpu6050_ai, NULL);
ai_output = ai_mpu6050_ai_outputs_get(mpu6050_ai, NULL);
#if defined(AI_MPU6050_AI_INPUTS_IN_ACTIVATIONS)
/* In the case where "--allocate-inputs" option is used, memory buffer can be
* used from the activations buffer. This is not mandatory.
*/
for (int idx=0; idx < AI_MPU6050_AI_IN_NUM; idx++) {
data_ins[idx] = ai_input[idx].data;
}
#else
for (int idx=0; idx < AI_MPU6050_AI_IN_NUM; idx++) {
ai_input[idx].data = data_ins[idx];
}
#endif
#if defined(AI_MPU6050_AI_OUTPUTS_IN_ACTIVATIONS)
/* In the case where "--allocate-outputs" option is used, memory buffer can be
* used from the activations buffer. This is no mandatory.
*/
for (int idx=0; idx < AI_MPU6050_AI_OUT_NUM; idx++) {
data_outs[idx] = ai_output[idx].data;
}
#else
for (int idx=0; idx < AI_MPU6050_AI_OUT_NUM; idx++) {
ai_output[idx].data = data_outs[idx];
}
#endif
return 0;
}
3.1 定义错误变量
ai_error err;
- ai_error:结构体类型,包含两个字段
- type:错误类型,如AI_ERROR_NONE(无错误)
- code:具体错误码
3.2 创建并初始化AI模型
err = ai_mpu6050_ai_create_and_init(&mpu6050_ai, act_addr, NULL);
- 函数作用:创建神经网络实例并初始化
- 参数1 &mpu6050_ai:
- 指向全局变量mpu6050_ai的指针(类型为ai_handle,本质是void*)
- 函数执行后,该变量将存储已初始化的AI模型实例
- 参数2 act_addr:
- 上一步传入的激活缓冲区指针(data_activations0)
- 用于存储网络运行时的中间结果
- 参数3 NULL:
- 权重缓冲区指针,为NULL表示使用内置权重
- 权重通常编译到固件中(见s_mpu6050_ai_weights_array_u64)
3.3 错误处理
if (err.type != AI_ERROR_NONE) {
ai_log_err(err, "ai_mpu6050_ai_create_and_init");
return -1;
}
- 检查创建是否成功
- AI_ERROR_NONE:表示无错误(值为0)
- ai_log_err:错误日志函数,打印详细错误信息
- return -1:返回错误代码
3.4 获取输入输出缓冲区
ai_input = ai_mpu6050_ai_inputs_get(mpu6050_ai, NULL);
ai_output = ai_mpu6050_ai_outputs_get(mpu6050_ai, NULL);
- 获取AI模型的输入输出缓冲区
- ai_input和ai_output:全局变量,类型为ai_buffer*
- 参数1 mpu6050_ai:前面初始化的AI模型句柄
- 参数2 NULL:用于返回缓冲区数量,不需要时设为NULL
3.5 ai_mpu6050_ai_inputs_get函数分析
ai_buffer* ai_mpu6050_ai_inputs_get(ai_handle network, ai_u16 *n_buffer)
{
if (network == AI_HANDLE_NULL) {
network = (ai_handle)&AI_NET_OBJ_INSTANCE;
AI_NETWORK_OBJ(network)->magic = AI_MAGIC_CONTEXT_TOKEN;
}
return ai_platform_inputs_get(network, n_buffer);
}
- 作用:获取网络输入缓冲区
- 参数1:网络句柄,如果为NULL则使用默认实例
- 参数2:可选的输出参数,存储缓冲区数量
- 返回:指向ai_buffer结构体数组的指针
3.6 ai_buffer结构体详解
typedef struct ai_buffer_ {
ai_buffer_format format; // 数据格式,如AI_BUFFER_FORMAT_FLOAT
ai_handle data; // 指向数据的指针
ai_buffer_meta_info* meta_info; // 元数据信息
ai_flags flags; // 标志位
ai_size size; // 数据大小
ai_buffer_shape shape; // 数据维度
} ai_buffer;
3.7 配置输入缓冲区
#if defined(AI_MPU6050_AI_INPUTS_IN_ACTIVATIONS)
for (int idx=0; idx < AI_MPU6050_AI_IN_NUM; idx++) {
data_ins[idx] = ai_input[idx].data;
}
#else
for (int idx=0; idx < AI_MPU6050_AI_IN_NUM; idx++) {
ai_input[idx].data = data_ins[idx];
}
#endif
- AI_MPU6050_AI_INPUTS_IN_ACTIVATIONS:定义时,输入数据使用激活缓冲区
- 未定义时:输入数据使用单独分配的缓冲区
- AI_MPU6050_AI_IN_NUM:输入节点数量,通常为1
- data_ins:全局数组,用于存储输入数据
- ai_input[idx].data:输入缓冲区的数据指针
3.8 配置输出缓冲区
#if defined(AI_MPU6050_AI_OUTPUTS_IN_ACTIVATIONS)
for (int idx=0; idx < AI_MPU6050_AI_OUT_NUM; idx++) {
data_outs[idx] = ai_output[idx].data;
}
#else
for (int idx=0; idx < AI_MPU6050_AI_OUT_NUM; idx++) {
ai_output[idx].data = data_outs[idx];
}
#endif
与输入缓冲区配置类似,但针对输出数据
- AI_MPU6050_AI_OUT_NUM:输出节点数量,通常为1
- data_outs:全局数组,用于存储输出数据
3.9 返回初始化结果
return 0;
三、推理执行函数分析:MX_X_CUBE_AI_Process()
void MX_X_CUBE_AI_Process(void)
{
int res = -1;
printf("TEMPLATE - run - main loop\r\n");
if (mpu6050_ai) {
do {
/* 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);
} while (res==0);
}
if (res) {
ai_error err = {AI_ERROR_INVALID_STATE, AI_ERROR_CODE_NETWORK};
ai_log_err(err, "Process has FAILED");
}
}
1. 初始化结果变量
int res = -1;
res:函数结果变量,初始值为-1(表示错误)
- 该变量将在执行过程中更新,0表示成功
2. 打印运行提示
printf("TEMPLATE - run - main loop\r\n");
3. 检查AI模型是否初始化
if (mpu6050_ai) {
// ...
}
4. 主处理循环
do {
/* 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);
} while (res==0);
- 循环执行三个主要步骤,直到某一步骤返回非零值
- 注意:这里设计成循环是为了支持连续处理多帧数据
5. 数据采集和预处理
res = acquire_and_process_data(data_ins);
- 调用用户自定义的acquire_and_process_data函数
- 参数data_ins:全局数组,用于存储输入数据
- 返回值res:0表示成功,非0表示错误
5.1 acquire_and_process_data函数模板
int acquire_and_process_data(ai_i8* data[])
{
/* fill the inputs of the c-model
for (int idx=0; idx < AI_MPU6050_AI_IN_NUM; idx++ )
{
data[idx] = ....
}
*/
return 0;
}
- 用户需要实现此函数:
- 从传感器(如MPU6050)读取数据
- 进行数据预处理(如归一化)
- 将处理后的数据存入data数组
- 参数data:指向输入数据缓冲区的指针数组
- 返回值:0表示成功,非0表示错误
6. 执行AI推理
if (res == 0)
res = ai_run();
仅当前一步成功时执行AI推理
- 调用ai_run()函数,执行实际推理计算
6.1 ai_run函数分析
static int ai_run(void)
{
ai_i32 batch;
batch = ai_mpu6050_ai_run(mpu6050_ai, ai_input, ai_output);
if (batch != 1) {
ai_log_err(ai_mpu6050_ai_get_error(mpu6050_ai),
"ai_mpu6050_ai_run");
return -1;
}
return 0;
}
- 作用:执行神经网络推理
- 流程:调用底层API、检查结果、处理错误
6.1.1 变量定义
ai_i32 batch;
ai_i32:32位有符号整数类型
- batch:将存储处理的批次数量,通常为1
6.1.2 执行推理计算
batch = ai_mpu6050_ai_run(mpu6050_ai, ai_input, ai_output);
- 调用实际执行推理的底层函数
- 参数1 mpu6050_ai:AI模型句柄
- 参数2 ai_input:输入数据缓冲区
- 参数3 ai_output:输出数据缓冲区
- 返回值:处理的批次数量,成功时为1
6.1.3 错误检查
if (batch != 1) {
ai_log_err(ai_mpu6050_ai_get_error(mpu6050_ai),
"ai_mpu6050_ai_run");
return -1;
}
检查处理批次是否为1
- 如果不是1,获取详细错误信息并打印
- ai_mpu6050_ai_get_error:获取错误信息的函数
- return -1:返回错误标志
6.1.4 返回成功标志
return 0;
7. 后处理结果
int post_process(ai_i8* data[])
{
/* process the predictions
for (int idx=0; idx < AI_MPU6050_AI_OUT_NUM; idx++ )
{
data[idx] = ....
}
*/
return 0;
}
仅当前一步成功时执行后处理
- 调用用户自定义的post_process函数处理推理结果
7.1 post_process函数模板
int post_process(ai_i8* data[])
{
/* process the predictions
for (int idx=0; idx < AI_MPU6050_AI_OUT_NUM; idx++ )
{
data[idx] = ....
}
*/
return 0;
}
- 用户需要实现此函数:
- 处理AI模型的输出结果
- 可以进行结果解释、阈值判断等
- 参数data:包含输出数据的指针数组
- 返回值:0表示成功,非0表示停止循环
8. 错误处理
if (res) {
ai_error err = {AI_ERROR_INVALID_STATE, AI_ERROR_CODE_NETWORK};
ai_log_err(err, "Process has FAILED");
}
检查是否有错误发生(res非0)
- 创建错误信息结构体:
- AI_ERROR_INVALID_STATE:错误类型,表示无效状态
- AI_ERROR_CODE_NETWORK:错误码,表示网络错误
- 打印错误信息到日志
四、用户自定义函数详解
在使用X-CUBE-AI框架时,用户需要自己实现以下两个关键函数:
1. 数据采集函数
int acquire_and_process_data(ai_i8* data[])
{
// 例如:从MPU6050读取数据
float acc_x, acc_y, acc_z;
float gyro_x, gyro_y, gyro_z;
// 读取传感器数据
MPU6050_ReadAccelerometer(&acc_x, &acc_y, &acc_z);
MPU6050_ReadGyroscope(&gyro_x, &gyro_y, &gyro_z);
// 数据归一化
acc_x = acc_x / 16384.0f;
acc_y = acc_y / 16384.0f;
acc_z = acc_z / 16384.0f;
gyro_x = gyro_x / 131.0f;
gyro_y = gyro_y / 131.0f;
gyro_z = gyro_z / 131.0f;
// 填充数据到AI输入缓冲区
float* input_data = (float*)data[0];
input_data[0] = acc_x;
input_data[1] = acc_y;
input_data[2] = acc_z;
input_data[3] = gyro_x;
input_data[4] = gyro_y;
input_data[5] = gyro_z;
return 0;
}
2. 结果处理函数
int post_process(ai_i8* data[])
{
float* output_data = (float*)data[0];
// 获取四种姿态的概率
float prob_standing = output_data[0];
float prob_walking = output_data[1];
float prob_running = output_data[2];
float prob_falling = output_data[3];
// 找出最大概率对应的姿态
float max_prob = prob_standing;
int max_idx = 0;
if (prob_walking > max_prob) {
max_prob = prob_walking;
max_idx = 1;
}
if (prob_running > max_prob) {
max_prob = prob_running;
max_idx = 2;
}
if (prob_falling > max_prob) {
max_prob = prob_falling;
max_idx = 3;
}
// 打印结果
printf("检测到的姿态: ");
switch (max_idx) {
case 0: printf("站立 (%.2f%%)\n", max_prob * 100); break;
case 1: printf("行走 (%.2f%%)\n", max_prob * 100); break;
case 2: printf("跑步 (%.2f%%)\n", max_prob * 100); break;
case 3: printf("跌倒 (%.2f%%)\n", max_prob * 100); break;
}
// 检测到跌倒时触发警报
if (max_idx == 3 && max_prob > 0.8f) {
printf("警报:检测到跌倒事件!\n");
// 可以在这里添加蜂鸣器或其他提醒
}
return 0; // 返回0继续循环,返回非0停止
}
五、完整使用示例
int main(void)
{
// 系统初始化
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
// 初始化MPU6050
MPU6050_Init();
// 初始化AI模型
MX_X_CUBE_AI_Init();
printf("系统初始化完成,开始姿态检测...\n");
// 主循环
while (1) {
// 执行AI处理
MX_X_CUBE_AI_Process();
// 延时100ms
HAL_Delay(100);
}
}
六、总结
STM32 X-CUBE-AI框架通过两个核心函数实现了AI模型从初始化到运行的全过程:
- MX_X_CUBE_AI_Init():
- 创建并初始化AI模型实例
- 配置输入输出缓冲区
- 准备模型运行环境
- MX_X_CUBE_AI_Process():
- 执行数据采集和预处理
- 调用神经网络推理引擎
- 处理AI模型的输出结果
用户只需要关注实现自己的数据采集和结果处理函数,而不必深入了解神经网络的底层实现细节,大大简化了在STM32上部署AI模型的难度。
更多推荐
所有评论(0)