首頁 > 評測 > 【APM32F407IG Tiny Board測評】移植輕量級AI推理框架TinyMaix實現(xiàn)手寫數(shù)字識別

【APM32F407IG Tiny Board測評】移植輕量級AI推理框架TinyMaix實現(xiàn)手寫數(shù)字識別

  
  • 作者:
  • 來源:
  • [導(dǎo)讀]
  • 本文將介紹如何為APM32F407IG芯片移植輕量級AI推理框架TinyMaix,并在開發(fā)板上運行TinyMaix的手寫數(shù)字識別示例。本文將首先介紹TinyMaix是什么,以及APM32F407IG芯片的主要參數(shù)。然后,介紹如何為APM32F407IG芯片創(chuàng)建
本文將介紹如何為APM32F407IG芯片移植輕量級AI推理框架TinyMaix,并在開發(fā)板上運行TinyMaix的手寫數(shù)字識別示例。本文將首先介紹TinyMaix是什么,以及APM32F407IG芯片的主要參數(shù)。然后,介紹如何為APM32F407IG芯片創(chuàng)建一個支持基于SysTick計時,以及printf輸出到UART的Keil項目。接著,介紹如何將TinyMaix項目核心框架和手寫數(shù)字識別示例源碼添加到支持SysTick計時和printf輸出的Keil項目中。最后,介紹如何將編譯好的二進制程序下載到APM32F407IG Tiny開發(fā)板上,并運行手寫數(shù)字識別示例程序。

一、背景介紹

開始之前,首先介紹一下輕量級AI推理框架TinyMaix,以及本次使用活動的APM32F407IG Tiny Board的主控芯片APM32F407IGT6。

1.1 TinyMaix框架簡介

TinyMaix是國內(nèi)sipeed團隊開發(fā)一個輕量級AI推理框架,官方介紹如下:
TinyMaix 是面向單片機的超輕量級的神經(jīng)網(wǎng)絡(luò)推理庫,即 TinyML 推理庫,可以讓你在任意單片機上運行輕量級深度學(xué)習(xí)模型。
根據(jù)官方介紹,在僅有2K RAM的 Arduino UNO(ATmega328, 32KB Flash, 2KB RAM) 上,都可以基于 TinyMaix 進行手寫數(shù)字識別。對,你沒有看錯,2K RAM + 32K Flash的設(shè)備上都可以使用TinyMaix進行手寫數(shù)字識別!TinyMaix官網(wǎng)提供了詳細(xì)介紹,可以在本文末尾的參考鏈接中找到。
TinyMaix項目源碼時以 Apache-2.0協(xié)議開源的,
GitHub代碼倉:https://github.com/sipeed/tinymaix
TinyMaix項目源代碼倉中,包含了TinyMaix核心框架代碼、示例程序、常用模型、測試圖片、文檔等內(nèi)容。

1.2 TinyMaix上層API

TinyMaix框架對上層應(yīng)用程序提供的核心API主要位于代碼倉的tinymaix.h文件中,核心API如下:

/******************************* MODEL FUNCTION ************************************/
tm_err_t tm_load  (tm_mdl_t* mdl, const uint8_t* bin, uint8_t*buf, tm_cb_t cb, tm_mat_t* in);   //load model
void     tm_unload(tm_mdl_t* mdl);                                      //remove model
tm_err_t tm_preprocess(tm_mdl_t* mdl, tm_pp_t pp_type, tm_mat_t* in, tm_mat_t* out);            //preprocess input data
tm_err_t tm_run   (tm_mdl_t* mdl, tm_mat_t* in, tm_mat_t* out);         //run model

/******************************* UTILS FUNCTION ************************************/
uint8_t TM_WEAK tm_fp32to8(float fp32);
float TM_WEAK tm_fp8to32(uint8_t fp8);

/******************************* STAT FUNCTION ************************************/
#if TM_ENABLE_STAT
tm_err_t tm_stat(tm_mdlbin_t* mdl);                    //stat model
#endif

主要分為三類:
  • 模型函數(shù),包括模型加載、卸載、預(yù)處理、推理;
  • 工具函數(shù),包含F(xiàn)P32和uint8的互轉(zhuǎn);
  • 統(tǒng)計函數(shù),用于輸出模型中間層信息;
這里的模型,通常是預(yù)訓(xùn)練模型經(jīng)過腳本轉(zhuǎn)換生成的TinyMaix格式的模型;

1.3 TinyMaix底層依賴

TinyMaix可以簡單理解為一個矩陣和向量計算庫,目前已支持如下幾種計算硬件:

#define TM_ARCH_CPU         (0) //default, pure cpu compute
#define TM_ARCH_ARM_SIMD    (1) //ARM Cortex M4/M7, etc.
#define TM_ARCH_ARM_NEON    (2) //ARM Cortex A7, etc.
#define TM_ARCH_ARM_MVEI    (3) //ARMv8.1: M55, etc.
#define TM_ARCH_RV32P       (4) //T-head E907, etc.
#define TM_ARCH_RV64V       (5) //T-head C906,C910, etc.
#define TM_ARCH_CSKYV2      (6) //cskyv2 with dsp core
#define TM_ARCH_X86_SSE2    (7) //x86 sse2

對于ARM-Cortex系列MCU,可以支持純CPU計算和SIMD計算。其中CPU計算部分無特殊依賴(計算代碼均使用標(biāo)準(zhǔn)C實現(xiàn))。SIMD部分,部分計算代碼使用了C語言內(nèi)嵌匯編實現(xiàn),需要CPU支持相應(yīng)的匯編指令,才可以正常編譯、運行。
TinyMaix的示例代碼依賴于精準(zhǔn)計時打印輸出能力,具體是項目的tm_port.h中的幾個宏定義:

#define  TM_GET_US()       ((uint32_t)((uint64_t)clock()*1000000/CLOCKS_PER_SEC))

#define TM_DBGT_INIT()     uint32_t _start,_finish;float _time;_start=TM_GET_US();
#define TM_DBGT_START()    _start=TM_GET_US();
#define TM_DBGT(x)         {_finish=TM_GET_US();\
                            _time = (float)(_finish-_start)/1000.0;\
                            TM_PRINTF("===%s use %.3f ms\n", (x), _time);\
                            _start=TM_GET_US();}1.4 APM32F407IGT6芯片簡介

本次試用的APM32F407IG Tiny Board,主控芯片是APM32F407IGT6,它的主要參數(shù)為:
  • CPU: Cortex-M4F內(nèi)核,168 MHz
  • Flash: 1 MB
  • RAM: 192 KB
TinyMaix的手寫數(shù)字識別示例,在32KB Flash 2KB RAM的Arduino UNO R3上都可以運行。
在我們這次試用的主角APM32F407IG Tiny Board上運行是完全沒有任何壓力的。
開發(fā)板正面特寫,可以看到主控芯片型號為APM32F407IGT6:

二、開發(fā)環(huán)境搭建2.1 下載APM32F407資料

極海官網(wǎng)APM32F07資料下載頁: APM32F405/407 (geehy.com)
必須下載的文件包括:
  • APM32F405xG 407xExG數(shù)據(jù)手冊
  • APM32F4xxx用戶手冊
  • APM32F407IG Tiny 原理圖
  • APM32F4xx_SDK
  • APM32F4xx_DFP Pack
具體下載鏈接,參見本文末尾的參考鏈接部分。

2.2 安裝Keil MDK

ARM官網(wǎng)Keil MDK安裝包下載頁面(需要填寫問卷):
https://www.keil.com/download/product/
填寫完問卷之后,可以看到,最新版本5.38a安裝包文件下載頁面:
這里的安裝包文件的鏈接可以直接復(fù)制:
https://www.keil.com/fid/g6daezwlgtwj1wzt54w1lz01v1lvsy2w9vmud1/files/eval/mdk538a.exe
MD5: 6792e5e0c0b5207b4db8339e043d7461
PS: 使用下載工具下載完成后,記得驗證一下MD5值。
Keil本身的安裝沒啥難度,一路下一步就好了,這里不再詳細(xì)介紹。

2.3 安裝ARM Compiler 5

APM32F4xx_SDK需要ARM Compiler 5才可以順利編譯,用Keil MDK較新版本默認(rèn)附帶ARM Compiler 6無法正常編譯。因此,需要下載ARM Compiler 5。
ARM Compiler下載頁面為: https://developer.arm.com/documentation/ka005198/latest
可以看到ARM Compiler 5最后一個版本是:5.06 update 7 (build 960)
點擊中間的ACOMP5藍(lán)色鏈接,可以跳轉(zhuǎn)到該版本編譯器的下載頁面(需要注冊登錄):
這里下載下方的Win32版本即可。
ARM Compiler下載頁面的文件鏈接是動態(tài)生成的,無法直接復(fù)制出來。
我用某雷下載之后,轉(zhuǎn)存了一個云盤鏈接,方便國內(nèi)用戶下載:
鏈接:https://pan.xunlei.com/s/VN_A6-Wskfwt4IYWpJLHgsGkA1?pwd=h23k#MD5: 56a3c52585e7ce4d95fc75ae6ff6b9df

2.4 安裝APM32F4xx支持包

Keil MDK APM32F4系列MCU支持包: https://www.geehy.com/uploads/tool/Geehy.APM32F4xx_DFP.1.0.3.pack
下載完成后,雙擊安裝即可(PS:成功安裝Keil MDK之后,.pack文件會自動關(guān)聯(lián)到Keil)。
到這里,基礎(chǔ)開發(fā)環(huán)境已經(jīng)搭建完成了。

三、運行SysTick示例程序

現(xiàn)在,我們需要為APM32F407IGT6芯片創(chuàng)建一個同時支持SysTick計時和printf輸出的Keil項目。

3.1 下載APM32F4xx_SDK

首先,從極海官網(wǎng)上下載APM32F4xx_SDK,解壓后可以在它的 Examples 子目錄下找到 SysTick和USART示例,如下圖所示:

3.2 編譯SysTick示例程序

接著,打開SysTick目錄下,SysTick_TimeBase\Project\MDK 子目錄中的 SysTick_TimeBase.uvprojx 文件,可以看到該示例參與編譯的源代碼文件:
按F7鍵,進行編譯,編譯成功可以看到Build Output輸出如下:

3.3 修改調(diào)試器設(shè)置

接下來,將APM32F407 Tiny開發(fā)板通過USB Type-C線連接到電腦。注意,開發(fā)板注意接在調(diào)試的USB口上。
按照如下步驟修改調(diào)試器設(shè)置:
  • 在Project視圖中,鼠標(biāo)右鍵APMFF407,彈出懸浮菜單,如下圖所示:
  • 單擊”Options for Target ‘APM32FF407’“,將會彈出,如下圖所示:
  • 點擊Debug標(biāo)簽頁,界面如下圖所示:
  • 下來”ULINK2/ME Cortex Debugger“菜單,選中CMSIS-DAP,如下圖所示:
  • 繼續(xù)點擊剛剛的調(diào)試器下拉菜單右側(cè)的”Settings“按鈕,彈出CMSIS-DAP Cortex-M Target Driver Setup窗口,如下圖所示:
PS:這里SW Device中已經(jīng)成功識別到了ARM CoreSight SW-DP,說明調(diào)試和MCU之間通信正常。
  • 點Flash Download標(biāo)簽頁,界面顯示如下圖所示:
查閱數(shù)據(jù)手冊,這里參數(shù)都是正確的,不需要修改。
為了方便調(diào)試,建議將這里的Rest and Run勾選上,如下圖所示:
勾選之后,記得點OK保存。

3.4 下載和運行SysTick示例程序

完成上述調(diào)試設(shè)置之后,就可以按F8或Download按鈕開始下載成了。Download按鈕,位置如下圖所示:
開始下載后,Build Output窗口將會顯示下載進度,下載成功后可以看到:
其中,Application running … 是勾選了Reset and Run才會有的。
如果沒有意外,將會看到開發(fā)板上的LED燈已經(jīng)開始閃爍了:

3.5 分析SysTick示例程序主要代碼

我們繼續(xù)看Project視圖下的文件:
其中,各源碼目錄中的對應(yīng)作用分別為:
  • CMSIS目錄,啟動(.s)和初始化(.c)
  • StdPeriphDriver目錄,外設(shè)驅(qū)動庫
  • Boards目錄,APM32F407系列開發(fā)板條件編譯
  • Application目錄,中斷處理(apm32f4xx_int.c)和應(yīng)用代碼(main.c)
接下來,看下main.c中的主要代碼:
可以看到這里是一個點燈的代碼,其中while循環(huán)調(diào)用了另外兩個函數(shù):
  • APM_MINI_LEDToggle,用于實現(xiàn)LED3燈狀態(tài)翻轉(zhuǎn);
  • SysTick_Delay_ms,用于實現(xiàn)延時,單位毫秒;
這個while循環(huán),就是閃燈不斷LED2和LED,再延時一秒。
另外,還可以看到上面的截圖中:
  • 75行有一行對COM1的初始化,查看實現(xiàn)代碼可以知道就是USART1,串口參數(shù)為8n1;
  • 80行有一行printf打印語句,打印了一行文本,前后各有一個換行;
除此之外,main.c文件中還有如下代碼:
通過注釋,可以知道,這個函數(shù)實現(xiàn)了printf到串口的重定向。

3.6 查看SysTick示例程序的串口輸出

前面分析知道,SysTick示例程序的main函數(shù)中初始化了USART1,并且有一行字符串打印,另外還實現(xiàn)了printf到串口的重定向。因此,如果沒有什么意外的話,我們應(yīng)該可以通過USART1看到這一行打印的輸出。
接下來,查閱原理圖的APM32-Link部分:
可以看到,APM32-Link預(yù)留了USART1的跳線。
然而不幸的是:
  • 開箱之后發(fā)現(xiàn),APM32F407-Tiny開發(fā)板的J3、J5并沒有附帶跳線帽;
  • 通過USB線將APM32-Link連接到PC之后,并沒有在設(shè)備管理器中看到串口設(shè)備;
沒有跳線帽簡單,從其他板子上扣下來一對就行了。而APM32-Link連接到PC之后沒有識別到串口設(shè)備,可能原因有兩個:
  • APM32-Link固件不支持USB轉(zhuǎn)UART;
  • APM32-Link的主控芯片APM32F103C8T6不支持USB功能;
通過極海官網(wǎng)查閱APM32F103C8T6參數(shù)發(fā)現(xiàn),它是支持USBD功能的,理論上可以實現(xiàn)USB轉(zhuǎn)UART功能。那這里PC沒有識別到串口設(shè)備的原因就是APM32-Link固件暫時還不支持USB轉(zhuǎn)UART。
查閱極海官網(wǎng)APM32-Link介紹信息,發(fā)現(xiàn)確實如此,沒有找到對USB轉(zhuǎn)UART功能的說明。
所以,需要外接一個USB轉(zhuǎn)UART用來查看串口輸出,連接如下圖:
其中,
  • 開發(fā)板的U2TX,連接到USB轉(zhuǎn)串口的RX
  • 開發(fā)板的U2RX,連接到USB轉(zhuǎn)串口的TX
接著,USB轉(zhuǎn)串口和調(diào)試器插上PC,打開MobaXterm,設(shè)置如下參數(shù):
打開新的會話之后,按下開發(fā)板的RESET按鍵,將會看到:
成功接收到了printf打印的字符串!
繼續(xù)查閱原理圖的USART1_TX和USART1_RX標(biāo)號部分:
可以看到,
  • USART1_TX,對應(yīng)PA9
  • USART1_RX,對應(yīng)PA10
這也項目代碼能夠?qū)?yīng)起來:
在Keil中一路查看:
  • APM_MINI_COMInit函數(shù)定義;
  • COM_TX_PORT、COM_TX_PIN_SOURCE數(shù)組定義;
  • MINI_COM1_TX_GPIO_PORT、MINI_COM1_TX_PIN_SOURCE宏定義;
找到的Board_APM32F407_MINI.h文件,在Keil的Project視圖也可以看到:
該文件的完整路徑為:APM32F407\APM32F4xx_SDK_v1.3\Boards\Board_APM32F407_MINI\inc\Board_APM32F407_MINI.h
我們試用的是APM32F407_Tiny開發(fā)板,實際上不應(yīng)該用這個文件。但因為兩個板子的串口配置代碼是一樣的,所以只使用串口輸出的話,不修改也并不會影響串口輸出。
兩個開發(fā)板對應(yīng)的頭文件的主要差異在于,按鍵相關(guān)的宏定義不一樣:
如果想要修改為方法是,在Options for Target ‘APM32F407’窗口的C/C++標(biāo)簽頁中:
將APM32F407_MINI宏修改為APM32F407_TINY。
修改之后,main.c中的也要響應(yīng)修改:
  • APM_MINI_COMInit 替換為 APM_TINY_COMInit
  • APM_MINI_LEDInit 替換為 APM_TINY_LEDInit
  • APM_MINI_LEDToggle 替換為 APM_TINY_LEDToggle
四、移植TinyMaix核心庫和手寫數(shù)字識別示例
簡單起見,接下來我們不再新建Keil項目,而是直接將TinyMaix核心庫和手寫數(shù)字識別示例代碼拷貝到SysTick示例目錄中(雖然這么做不太規(guī)范)。
4.1 下載TinyMaix源碼到本地
首先,使用 git 命令下載TinyMaix最新源碼:
git clone https://github.com/sipeed/tinymaix.git4.2 拷貝TinyMaix源碼到Keil項目目錄
接著,在SysTick示例的SysTick_TimeBase目錄下,創(chuàng)建TinyMaix目錄:
將TinyMaix源碼的examples、include、src目錄,拷貝到剛剛創(chuàng)建的TinyMaix目錄中:
另外,創(chuàng)建tools目錄,并將tools目錄下的tmdl目錄拷貝過去;拷貝的exmaples中包含了多個示例,可以把不需要的刪除掉,只保留mnist目錄,即手寫數(shù)字識別示例。
4.3 將TinyMaix源文件添加到Keil項目中
首先,在Keil的Project視圖右擊APM32F407,選擇Manage Project Items:
接著,在彈出的Manage Project Items窗口中,進行如下兩步驟操作:
然后,點擊Add Files,在彈出的文件添加界面中,依次添加剛剛拷貝過來的TinyMaix目錄src目錄和examples/mnist目錄下的.c文件到項目中:
添加完成后,點擊OK確認(rèn)。
4.4 解決Keil項目的編譯問題
完成上述修改后,直接編譯,將會報錯:
首先,按照如下步驟,添加必要的include搜索路徑:
  • 在Project視圖右鍵APM32F407,選擇”Options for Target ‘APM32F407’“,如下圖所示:
  • 在彈出的Options for Target ‘APM32F407’窗口中,點擊C/C++標(biāo)簽頁,如圖下圖所示:
  • 在C/C++標(biāo)簽頁,點擊Include Paths右側(cè)的”…”按鈕,會彈出Folder Setup界面,如下圖所示:
  • 在Folder Setup界面中,分別點擊如下兩處,選擇目錄進行添加:
  • 在彈出的文件夾選擇界面中,選擇拷貝的TinyMaix的include目錄,選擇之后,如下圖所示:
此時,再次編譯項目,報錯已經(jīng)不一樣了:
這里報錯說,找不到”sys/time.h“文件。
直接雙擊error信息行,主編輯器區(qū)可以看到tm_port.h文件對應(yīng)位置:
回顧開頭1.4節(jié),這里就是TinyMaix依賴的幾個計時宏。
將其修改為:
接下來編譯,遇到如下錯誤:
需要打開GNU擴展選項:
再次編譯,報鏈接錯誤:
這兩個連接錯誤說有兩個main函數(shù)定義。
找到手寫數(shù)字識別的main.c,將其中的main函數(shù)重命名為mnist_main:
再次編譯,報錯如下:
這次說,SysTick_Get沒有定義。
打開Application下的main.c,Ctrl+F搜索TimingDelay:
找到如下引用:
將其全部替換掉為SysTickCount:
然后,修改main.c中的SysTick_Delay_ms和TimingDelay_Decrement函數(shù),并新增SysTick_Get函數(shù):
再次編譯,終于成功了:
4.5 調(diào)用mnist示例程序
接下來,在main.c文件的main函數(shù)中添加兩行代碼:
記得保存Ctrl+S。
然后重新編譯、下載,下載完成后,自動開始運行,可以看到串口輸出:
運行報錯了。
這里是因為,TinyMaix需要試用malloc申請內(nèi)存,APM32F407的SysTick示例程序默認(rèn)的堆大小配置不夠。
需要修改 startup_apm32f40x.s 文件:
將其中的Heap_Size修改為0x1000(4096),默認(rèn)的是0x200(512)
再次重新編譯、下載、運行,串口可以看到:
這次成功運行了,耗時4毫秒,識別了手寫數(shù)字2。
原始圖片數(shù)據(jù)為:
可以看出來,識別結(jié)果是正確的。
PS:看了一下字?jǐn)?shù)統(tǒng)計四千多字了,有點肝。
好了,本文就到這里了,感謝閱讀。
五、參考鏈接
  • APM32F405xG 407xExG數(shù)據(jù)手冊: https://www.geehy.com/uploads/tool/APM32F405xG 407xExG數(shù)據(jù)手冊 V1.5.pdf
  • APM32F4xxx用戶手冊: https://www.geehy.com/uploads/tool/APM32F4xxx用戶手冊 V2.0.pdf
  • APM32F407IG Tiny 原理圖: https://www.geehy.com/uploads/tool/APM32F407IG TinyBoard.zip
  • APM32F4xx_SDK: https://www.geehy.com/uploads/tool/APM32F4xx_SDK_v1.3.zip
  • APM32F4xx_DFP Pack: https://www.geehy.com/uploads/tool/Geehy.APM32F4xx_DFP.1.0.3.pack





  • 本文系21ic原創(chuàng),未經(jīng)許可禁止轉(zhuǎn)載!

網(wǎng)友評論

  • 聯(lián)系人:巧克力娃娃
  • 郵箱:board@21ic.com
  • 我要投稿
  • 歡迎入駐,開放投稿

熱門標(biāo)簽
項目外包 more+