• 正文
    • 關(guān)于?uTensor 模型
    • uTensor 工作原理
    • uTensor 構(gòu)建、運(yùn)行和測(cè)試
  • 相關(guān)推薦
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

2K內(nèi)存單片機(jī)就能跑的嵌入式AI模型

03/06 14:11
1341
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

這兩年隨著ChatGPT、DeepSeek的火爆,AI已經(jīng)遍布工作和生活的各個(gè)角落,嵌入式端側(cè)AI也逐漸發(fā)展起來(lái)了。

今天就來(lái)分享一個(gè)可用于2KB內(nèi)存單片機(jī)的嵌入式AI模型:uTensor。

關(guān)于?uTensor 模型

uTensor 是一個(gè)基于 Tensorflow 構(gòu)建的極其輕量級(jí)的機(jī)器學(xué)習(xí)推理框架,并針對(duì) Arm 處理器進(jìn)行了優(yōu)化。它由一個(gè)運(yùn)行時(shí)庫(kù)和一個(gè)處理大部分模型轉(zhuǎn)換工作的離線工具組成。

模型地址:https://github.com/uTensor/uTensor

此存儲(chǔ)庫(kù)包含核心運(yùn)行時(shí)和運(yùn)算符、內(nèi)存管理器、調(diào)度器等的一些示例實(shí)現(xiàn),核心運(yùn)行時(shí)的大小僅為:2KB!

uTensor只需要2KB內(nèi)存的輕量化設(shè)計(jì)特點(diǎn),就是實(shí)現(xiàn)了極致壓縮:將TensorFlow模型轉(zhuǎn)換為.cpp、.hpp源代碼,消除冗余依賴。同時(shí),預(yù)分配內(nèi)存區(qū)域,杜絕運(yùn)行時(shí)內(nèi)存的泄漏。

實(shí)測(cè)核心運(yùn)行時(shí)和基礎(chǔ)算子的總代碼量?jī)H2KB,相當(dāng)于一張圖片的1/1000.

uTensor 工作原理

uTensor 工作原理大致如下圖所示:

在 Tensorflow 中構(gòu)建和訓(xùn)練模型,uTensor 獲取模型并生成 .cpp 和 .hpp 源文件。這些文件包含生成的推理所需的 C++代碼,只需要把生成的源文件復(fù)制到你的嵌入式項(xiàng)目中即可,實(shí)現(xiàn)過(guò)程非常簡(jiǎn)單。

uTensor 運(yùn)行時(shí)由兩個(gè)主要組件組成:

uTensor Core:其中包含滿足 uTensor 性能運(yùn)行時(shí)契約所需的基本數(shù)據(jù)結(jié)構(gòu)、接口和類型等。

uTensor 庫(kù):作為一系列基于 uTensor Core 構(gòu)建的默認(rèn)實(shí)現(xiàn)。

構(gòu)建系統(tǒng)分別編譯這兩個(gè)組件,使用戶能夠輕松擴(kuò)展和覆蓋構(gòu)建在 uTensor 核心之上的實(shí)現(xiàn),例如自定義內(nèi)存管理器、張量、運(yùn)算符和錯(cuò)誤處理程序。

錯(cuò)誤處理程序:

SimpleErrorHandler errH(50); // Maintain a history of 50 eventsContext::get_default_context()->set_ErrorHandler(&errH);...// A bunch of allocations...
// Check to make sure a rebalance has occurred inside our allocatorbool has_rebalanced = std::find(errH.begin(), errH.end(), localCircularArenaAllocatorRebalancingEvent()) != errH.end();

Tensor 讀寫(xiě)接口:

uint8_t myBuffer[4] = { 0xde, 0xad, 0xbe, 0xef };Tensor mTensor = new BufferTensor({2,2}, u8, myBuffer); // define a 2x2 tensor of uint8_ts
uint8_t a1 = mTensor(0,0);  // implicitly casts the memory referenced at this index to a uint8_tprintf("0x%hhxn", a1);     // prints 0xde
uint16_t a2 = mTensor(0,0); // implicitly casts the memory referenced at this index to a uint16_tprintf("0x%hxn", a2);      // prints 0xdead
uint32_t a3 = mTensor(0,0); // implicitly casts the memory referenced at this index to a uint32_tprintf("0x%xn", a3);      // prints 0xdeadbeef
// You can also write and read values with explicit casting and get similar behaviormTensor(0,0) = static_cast<uint8_t>(0xFF);printf("0xhhxn", static_cast<uint8_t>(mTensor(0,0)));

出于性能原因,各種 Tensor 讀/寫(xiě)接口更像緩沖區(qū),而不是成熟的 C++ 類型化對(duì)象,盡管高級(jí)接口本質(zhì)上看起來(lái)非常 Pythonic 。實(shí)際的讀取和寫(xiě)入取決于用戶如何轉(zhuǎn)換此緩沖區(qū)。

uTensor 構(gòu)建、運(yùn)行和測(cè)試

官方給出了 uTensor 構(gòu)建、運(yùn)行和測(cè)試的一些方法。

比如在本地構(gòu)建和測(cè)試:

git clone git@github.com:uTensor/uTensor.gitcd uTensor/git checkout proposal/rearchgit submodule initgit submodule updatemkdir buildcd build/cmake -DPACKAGE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug ..makemake test

在 Arm Mbed OS 上構(gòu)建和運(yùn)行:

mbed new my_projectcd my_projectmbed import https://github.com/uTensor/uTensor.git# Create main file# Run uTensor-cli workflow and copy model directory herembed compile # as normal

還有在在Arm 系統(tǒng)上構(gòu)建和運(yùn)行:

mkdir build && cd buildcmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=../extern/CMSIS_5/CMSIS/DSP/gcc.cmake  ..
//使用?CMSIS?優(yōu)化內(nèi)核mkdir build && cd buildcmake -DARM_PROJECT=1 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=../extern/CMSIS_5/CMSIS/DSP/gcc.cmake  ..

以上只是提供了一些參考和思路,實(shí)現(xiàn)的具體細(xì)節(jié),需要大家進(jìn)一步結(jié)合 uTensor 模型進(jìn)行優(yōu)化。

相關(guān)推薦

登錄即可解鎖
  • 海量技術(shù)文章
  • 設(shè)計(jì)資源下載
  • 產(chǎn)業(yè)鏈客戶資源
  • 寫(xiě)文章/發(fā)需求
立即登錄

作者黃工,從事嵌入式軟件開(kāi)發(fā)工作8年有余,高級(jí)嵌入式軟件工程師,業(yè)余維護(hù)公眾號(hào)『strongerHuang』,分享嵌入式軟硬件、單片機(jī)、物聯(lián)網(wǎng)等內(nèi)容。