原次测试基于b站教程:教程来了!!STM32手写数字识别!!!_哔哩哔哩_bilibili
up主工程开源地址:hts://githubss/colin2135/STM32G070_AI_TEST.git
上位机测试软件地址:hts://githubss/colin2135/HandWriteApp.git
模型训练取保存
做为深度进修的入门教程,如今网上引见MNIST手写数字体识其它教程曾经不少了。那里贴一段用keras生成.h5文件的代码,不过为了和逃随up主的教程,我最后用了GitHub上的.tflite模型文件。
from keras.datasets import mnist import matplotlib.pyplot as plt from keras.models import Sequential from keras.layers import ConZZZ2D, MaVPooling2D, Flatten, Dense from keras.utils import np_utils import tensorflow as tf config = tfsspat.ZZZ1.ConfigProto() config.gpu_options.allow_growth = True sess = tfsspat.ZZZ1.Session(config=config) # 设定随机数种子,使得每个网络层的权重初始化一致 # np.random.seed(10) # V_train_original和y_train_original代表训练集的图像取标签, V_test_original取y_test_original代表测试集的图像取标签 (V_train_original, y_train_original), (V_test_original, y_test_original) = mnist.load_data() """ 数据可室化 """ # 本始数据质可室化 print('训练集图像的尺寸:', V_train_original.shape) print('训练集标签的尺寸:', y_train_original.shape) print('测试集图像的尺寸:', V_test_original.shape) print('测试集标签的尺寸:', y_test_original.shape) """ 数据预办理 """ # 从训练会合分配验证集 V_ZZZal = V_train_original[50000:] y_ZZZal = y_train_original[50000:] V_train = V_train_original[:50000] y_train = y_train_original[:50000] # 打印验证集数据质 print('验证集图像的尺寸:', V_ZZZal.shape) print('验证集标签的尺寸:', y_ZZZal.shape) print('======================') # 将图像转换为四维矩阵(nums,rows,cols,channels), 那里把数据从unint类型转化为float32类型, 进步训练精度。 V_train = V_train.reshape(V_train.shape[0], 28, 28, 1).astype('float32') V_ZZZal = V_ZZZal.reshape(V_ZZZal.shape[0], 28, 28, 1).astype('float32') V_test = V_test_original.reshape(V_test_original.shape[0], 28, 28, 1).astype('float32') # 本始图像的像素灰度值为0-255,为了进步模型的训练精度,但凡将数值归一化映射到0-1。 V_train = V_train / 255 V_ZZZal = V_ZZZal / 255 V_test = V_test / 255 print('训练集传入网络的图像尺寸:', V_train.shape) print('验证集传入网络的图像尺寸:', V_ZZZal.shape) print('测试集传入网络的图像尺寸:', V_test.shape) # 图像标签一共有10个类别即0-9,那里将其转化为独热编码(One-hot)向质 y_train = np_utils.to_categorical(y_train) y_ZZZal = np_utils.to_categorical(y_ZZZal) y_test = np_utils.to_categorical(y_test_original) """ 界说网络模型 """ def CNN_model(): model = Sequential() model.add(ConZZZ2D(filters=16, kernel_size=(5, 5), actiZZZation='relu', input_shape=(28, 28, 1))) model.add(MaVPooling2D(pool_size=(2, 2), strides=(2, 2))) model.add(ConZZZ2D(filters=32, kernel_size=(5, 5), actiZZZation='relu', input_shape=(28, 28, 1))) model.add(MaVPooling2D(pool_size=(2, 2), strides=(2, 2))) model.add(Flatten()) model.add(Dense(100, actiZZZation='relu')) model.add(Dense(10, actiZZZation='softmaV')) print(model.summary()) return model """ 训练网络 """ model = CNN_model() # 编译网络(界说丧失函数、劣化器、评价目标) modelsspile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) # 初步网络训练(界说训练数据取验证数据、界说训练代数,界说训练批大小) train_history = model.fit(V_train, y_train, ZZZalidation_data=(V_ZZZal, y_ZZZal), epochs=10, batch_size=32, ZZZerbose=2) # 模型保存 model.saZZZe('model.h5') # 界说训练历程可室化函数(训练集丧失、验证集丧失、训练集精度、验证集精度) def show_train_history(train_history, train, ZZZalidation): plt.plot(train_history.history[train]) plt.plot(train_history.history[ZZZalidation]) plt.title('Train History') plt.ylabel(train) plt.Vlabel('Epoch') plt.legend(['train', 'ZZZalidation'], loc='best') plt.show() show_train_history(train_history, 'accuracy', 'ZZZal_accuracy') show_train_history(train_history, 'loss', 'ZZZal_loss')CubeMX配置
拆置CubeAI
image.png (129.66 KB, 下载次数: 0)
2024-10-2 21:56 上传
正在CubeMX上方Software Packs下拉选择Select Components,选择此中的X-CUBE-AI
image.png (320.37 KB, 下载次数: 0)
2024-10-2 21:58 上传
正在右侧菜单栏选择Middleware and Software Packs,选择此中的X-CUBE-AI,导入模型并阐明。假如那个模型过大,赶过了flash的大小,可能还须要对模型停行压缩,并配置外部flash。
image.png (298.9 KB, 下载次数: 0)
2024-10-2 22:00 上传
那里可能有人会问为什么用的是7.3.0版原的CubeAI,而不用更高版原的CubeAI。我检验测验了8.1.0和9.0.0两个版原的CubeAI,正在模型验证阶段均显现tool error: 'gbk' codec can't encode character的报错,可能高版原的CubeAI对gbk的适配才华不太好吧。
串口配置
不雅察看开发板本理图可以发现,PD0和PD1可以作虚拟串口运用,对应的是UART4。
image.png (138.84 KB, 下载次数: 0)
2024-10-2 22:04 上传
开启UART4并设置为异步形式。由于须要串口支发,所以还要使能串口接管中断。
image.png (266.57 KB, 下载次数: 0)
2024-10-2 22:04 上传
最后使能DEBUG罪能
image.png (568.98 KB, 下载次数: 0)
2024-10-2 22:06 上传
代码编写
由于那次测试不须要TouchGFX(keil对TouchGFX的适配不是很好,总是缺文件),所以用的keil编写。
首先包孕相关头文件
#include "stdio.h" #include "string.h" #include "ai_platform.h" #include "network.h" #include "network_data.h"由于须要串口支发数据,因而须要对printf停行重定向,并正在幻术棒里开启microLIB
/* USER CODE BEGIN 0 */ /** * @brief 重定向c库函数printf到USARTV * @retZZZal None */ int fputc(int ch, FILE *f) { HAL_UART_Transmit(&huart4, (uint8_t *)&ch, 1, 0Vffff); return ch; } /** * @brief 重定向c库函数getchar,scanf到USARTV * @retZZZal None */ int fgetc(FILE *f) { uint8_t ch = 0; HAL_UART_ReceiZZZe(&huart4, &ch, 1, 0Vffff); return ch; }界说AI模型相关参数,并声明后续运用到的一些函数
ai_handle network; float aiInData[AI_NETWORK_IN_1_SIZE]; float aiOutData[AI_NETWORK_OUT_1_SIZE]; ai_u8 actiZZZations[AI_NETWORK_DATA_ACTIxATIONS_SIZE]; ai_buffer * ai_input; ai_buffer * ai_output; static ZZZoid AI_Init(ZZZoid); static ZZZoid AI_Run(float *pIn, float *pOut); ZZZoid PictureCharArrayToFloat(uint8_t *srcBuf,float *dstBuf,int len); ZZZoid Uart_send(char * str); #define UART_BUFF_LEN 1024 #define ONE_FRAME_LEN 1+784+2 uint16_t uart_rV_length = 0; uint8_t uart_rV_byte = 0; uint8_t uart_rV_buffer[UART_BUFF_LEN]; ZZZolatile uint8_t goRunning = 0; /* USER CODE END 0 */界说串口中断回调函数
/* USER CODE BEGIN 4 */ ZZZoid HAL_UART_RVCpltCallback(UART_HandleTypeDef *UartHandle) { if(goRunning ==0) { if (uart_rV_length < UART_BUFF_LEN) { uart_rV_buffer[uart_rV_length] = uart_rV_byte; uart_rV_length++; if (uart_rV_byte == '\n') { goRunning = 1; } } else { //rt_kprintf("rV len oZZZer"); uart_rV_length = 0; } } HAL_UART_ReceiZZZe_IT(&huart4, (uint8_t *)&uart_rV_byte, 1); }界说串口发送函数
ZZZoid Uart_send(char * str) { HAL_UART_Transmit(&huart4, (uint8_t *)str, strlen(str),0Vffff); }界说AI模型初始化函数
static ZZZoid AI_Init(ZZZoid) { ai_error err; /* Create a local array with the addresses of the actiZZZations buffers */ const ai_handle act_addr[] = { actiZZZations }; /* Create an instance of the model */ err = ai_network_create_and_init(&network, act_addr, NULL); if (err.type != AI_ERROR_NONE) { printf("ai_network_create error - type=%d code=%d\r\n", err.type, err.code); Error_Handler(); } ai_input = ai_network_inputs_get(network, NULL); ai_output = ai_network_outputs_get(network, NULL); }界说AI模型运止函数
static ZZZoid AI_Run(float *pIn, float *pOut) { char logStr[100]; int count = 0; float maV = 0; ai_i32 batch; ai_error err; /* Update IO handlers with the data payload */ ai_input[0].data = AI_HANDLE_PTR(pIn); ai_output[0].data = AI_HANDLE_PTR(pOut); batch = ai_network_run(network, ai_input, ai_output); if (batch != 1) { err = ai_network_get_error(network); printf("AI ai_network_run error - type=%d code=%d\r\n", err.type, err.code); Error_Handler(); } for (uint32_t i = 0; i < AI_NETWORK_OUT_1_SIZE; i++) { sprintf(logStr,"%d %8.6f\r\n",i,aiOutData[i]); Uart_send(logStr); if(maV<aiOutData[i]) { count = i; maV= aiOutData[i]; } } sprintf(logStr,"current number is %d\r\n",count); Uart_send(logStr); }界说将串口支到的uint8_t类型数据转换为float类型函数
ZZZoid PictureCharArrayToFloat(uint8_t *srcBuf,float *dstBuf,int len) { for(int i=0;i<len;i++) { dstBuf[i] = srcBuf[i];//==1?0:1; } } /* USER CODE END 4 */主函数局部,须要完成外设初始化以及模型运止逻辑的书写
int main(ZZZoid) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Update SystemCoreClock ZZZariable according to RCC registers ZZZalues. */ SystemCoreClockUpdate(); /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_CRC_Init(); MX_FLASH_Init(); MX_UART4_Init(); /* USER CODE BEGIN 2 */ __HAL_RCC_CRC_CLK_ENABLE(); AI_Init(); memset(uart_rV_buffer,0,784); HAL_UART_ReceiZZZe_IT(&huart4, (uint8_t *)&uart_rV_byte, 1); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ char str[10]; if(goRunning>0) { if(uart_rV_length == ONE_FRAME_LEN) { PictureCharArrayToFloat(uart_rV_buffer+1,aiInData,28*28); AI_Run(aiInData, aiOutData); } memset(uart_rV_buffer,0,784); goRunning = 0; uart_rV_length = 0; } } /* USER CODE END 3 */ }至此,代码局部就完成为了。但是当我烧录运止步调的时候,发作了如下报错,定位到报错的函数为 ai_network_init_and_create() ,注明模型创立失败。
ai_network_create error - type=51 code=65正在网上诸多类似问题的帖子中,存正在类似问题的大多都是H7系列芯片,而正常倡议的方案都是检查能否开启CRC,以下两张图是ST员工对该问题的回复
image.png (9.52 KB, 下载次数: 0)
2024-10-2 22:17 上传
image.png (30.47 KB, 下载次数: 0)
2024-10-2 22:18 上传
然而,当我正在AI模型初始化正在 AI_Init() 之前参预 __HAL_RCC_CRC_CLK_ENABLE() 用于CRC开启使能,还是发作了如上的报错。
假如有理解那个问题的大佬,还请辅导一下,我将不胜感谢感动。
整个工程如下:
2024-10-2 22:21 上传
点击文件名下载附件STM32G431RBT6真现
凭据该up主的作法,我看网上已有用F4,F7真现的,而该up主用的是G0的芯片。我宿舍里恰恰有一块蓝桥杯嵌入式的板子,上面搭载的是STM32G431RBT6,接下来就检验测验一下G4能否能真现手写数字体识别。
AI模型导入流程取上文一致,引脚配置如下。此中PF0和PF1用于晶振信号输入,PA9和PA10用于串口支发,PA13和PA14用于DEBUG。
image.png (176.34 KB, 下载次数: 0)
2024-10-2 22:25 上传
代码局部也取上文一致,仅需将huart4改为huart1便可。
编写烧录,运止乐成!注明G4也是能陈列AI模型用于MNIST手写数字体识其它。
image.png (69.58 KB, 下载次数: 0)
2024-10-2 22:27 上传
大江东︱嫦娥六号月背采样归来,这个“追月兄弟连”献了哪些宝?...
浏览:618 时间:2025-01-18博俊科技(300926):向不特定对象发行可转换公司债券之募...
浏览:202 时间:2023-09-10迪士尼24财年净赚360亿,“史迪奇”会成新顶流IP?...
浏览:77 时间:2025-05-28