首頁>技術>

開心的程式猿@NXP

2021-02-04 Thursday

  讀過之前兩篇的童鞋們,想來已經開始著手開發屬於自己的AI視覺應用了,當然,手中還沒有OpenART套件的朋友們,也不用著急,可以先參照"智慧車大賽AI視覺組參考答案"在PC上先試訓一下AI模型,然後結合AI視覺組仙人一步之模型量化,熟悉一下模型部署流程。

  但是,想必高階玩家已經不滿足止步於只使用python了吧。

  瞭解我們的OpenART套件的童鞋們肯定知道,套件本身是集成了RT-Thread這款RTOS的,何不嘗試點新玩法?挑戰點高難度,嘗試下用C來直接寫code,在小夥伴面前炫耀一下?

  也正式因為有了RTOS的加持,每一個任務本身在RTOS中都作為一個獨立執行緒存在,想要為專案新增新功能的話,只需要為其建立一個新的執行緒即可,無需更改已有裸機程式碼。

  本文的目的就是展示給大家,如何以執行緒的方式在工程中新增一個新的功能,以實現對於tflite micro推理引擎的直接呼叫。

  那麼,話不多說,直接開整。

  首先介紹一下如何在OpenART中建立一個新的執行緒(OpenART中集成了RT-Thread作業系統,因此如下操作都是以RT-Thread為基礎的):

  下面開始編寫執行緒主函式,主要包括以下內容:

一、初始化攝像頭:

  因為我們需要透過攝像頭讀取指令,由於我們已經不再使用python指令碼,攝像頭初始化部分需要手動進行,到了這裡,是不是要勸退一些小夥伴了呢?別急,還有更厲害的在後面,感受C語言的魅力吧!

  初始化流程和python呼叫流程類似,只不過我們這次要直接進行函式呼叫,來實現攝像頭模組的初始化,這裡要感謝RT-Thread所提供的裝置管理框架,能夠讓我們能夠方便的實現這一功能:

二、讀取影象:

  大家可能注意到了這個fb_alloc,可能有同學會問,這個不是Micropython中的嗎?這裡還能用嗎,當然,大家可以把它理解成一個記憶體管理器,是可以用C來直接進行函式呼叫的:

  這個image_t結構體,實際上它包含了影象的所有資訊,就可以直接進行處理了。

三、模型推理:

  至此,程式碼中所涉及到的影象採集部分就到此為止了,下面開始介紹模型推理部分。

  不過,要提前說明的是,在這裡我們沒有保留python API所實現的影象輸入部分,即可以透過設定視窗滑動步長和視窗放縮比,來實現多尺度下的影象識別,我們假設要識別的物體充滿整個螢幕,即識別區域為整副攝像頭採集的影象,而這就喪失了多目標識別能力,有興趣的玩家可以自行實現。

  那麼如何利用tflite micro進行模型推斷呢?

  ⊙ 首先第一步是讀取模型,model_data就是以二進位制方式讀取的tflite模型,在OpenART中,我們採用DFS檔案系統來進行模型檔案的讀取,full_path根據:

  ⊙ 之後是例項化操作解析器和模型直譯器,其中,解析器用來訪問Tensorflow的操作,可以擴充套件此類以向專案中新增自定義操作。直譯器是用來對模型進行結構上的解析,以進行模型求解。

  ⊙ 運算之前,我們需要預先為輸入、輸出以及中間陣列分配一定的記憶體。因此,使用者需要預分配一個大小為tensor_arena_size的uint8_t的陣列,傳遞給模型解析器。

  ⊙ 隨後還需要呼叫函式對預分配的tensor arena進行分配:

  ⊙ 至此,萬事俱備,只欠東風了,而我們的東風就是待識別的影象,tflite模型的輸入,是透過對input tensor進行賦值實現的,實現方法也很簡單,我們只需要將第二步讀取到的影象資料,按照模型輸入的要求進行處理後,直接對其賦值即可:

  這裡我們假設image是已經按照模型出入要求處理好的影象資料,size是其大小,實際情況下,可以隨機應變,宗旨就是要對model_input->data.data這個變數進行遍歷賦值。

  讓我們的模型直譯器開始幹活,還需要最後一步:

  ⊙ 最後,怎樣獲取結果呢?和設定input tensor大同小異,我們這次要獲取output tensor, 需要注意的是這裡的model_output->data.data是個void*型別,需要根據model_output->type進行指標的強制型別轉化:

  ⊙ 這裡面比較重要的是兩個callback函式,要注意的是,這兩個函式會在函式內部自動呼叫,使用者需要傳入input_callback_data和output_callback_data,下面進行一一說明。

首先是input_callback,其定義如下,使用者需要自行實現其函式體,其作用是,根據傳入的input_height,input_width, input_channels對採集的影象進行放縮處理,is_float表示資料是否轉換為浮點數表示,最後對model_input進行賦值:與其對應的是output_callback, 其定義如下,其作用是,根據傳入的output_height,output_width, output_channels對採集的影象進行放縮處理,is_float表示結果是否為浮點數表示,最後將model_ouput的值賦值到callback_data中:四、匯出:

  最後一步是匯出到msh命令列,這樣才可以在系統啟動後,在RT-Thread的命令視窗中進行呼叫,這裡我們透過EXPORT_MSH_CMD()這個特殊的宏進行命令的宣告:

  這裡包含兩部分的內容,以逗號進行分割,第一部分既代表命令列中所對應的命令,又代表當輸入tflite_micro這一命令時所呼叫的函式名,沒錯,我們就是要把我們建立tflite執行緒的函式tflite_micro_main放到這裡面,這樣,我們就匯出了一個叫做tflite_micro的命令,當我們執行這一命令時,所建立的tflite micro執行緒就會被呼叫。第二部分,是對於指令的描述。

  至此,我們的菜就全部備齊了,這裡略過1萬字的程式碼除錯以及下載過程,在出現的msh命令列視窗中輸入tflite_micro,將待識別的影象對準攝像頭,即可進行物體的識別:

msh /> tflite_micro

  執行結果:

  不過,由於我們是直接以執行緒的形式呼叫tflite micro的推理引擎,因此沒有辦法在使用openmv ide進行影象的預覽了,不過,如果擁有一塊LCD的小夥伴,就可以不用慌張了,可以顯示在LCD螢幕上一睹芳容。

  本期,小編為大家帶來了如何在底層以新建執行緒的方式直接呼叫tflite micro推理引擎,參考程式碼位於https://gitee.com/crist_xu/tflite_thread_call.git,不過,程式碼並不包含OpenART程式碼包,同學們可以參考下實現,等到OpenART軟體包正式和大家見面之後再進行動手。

15
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • Kotlin - 類成員