一、前言
本文主要介紹如何基于ESP32的開發(fā)板通過microTVM進行一個卷積算子的調(diào)優(yōu)。
二、microTVM
microTVM是TVM 編譯器的擴展,它能夠使TVM應用于微控制器,提供了在設備上運行 TVM RPC 服務以完成自動調(diào)優(yōu)的方法,同時也提供了一套最小化 C 語言的runtime,使得裸機邊緣設備可以獨立完成模型推理。
基于TVM RPC服務
需要host端與設備端同時參與,由host端與設備端通過串口或USB等進行連接通信,host端將交叉編譯完的固件程序燒錄到設備端,該固件程序包括了TVM編譯完成的模型設備端代碼,TVM C runtime,設備的初始化操作以及TVM RPC server。而host端負責GrpahExecutor實例的創(chuàng)建,它會通過串口或USB等物理連接發(fā)送RPC命令到設備端進行模型推理。基于TVM RPC服務
獨立運行
只需要設備端參與,與基于RPC服務的區(qū)別是GraphExecutor實例是由設備自己獨立完成。獨立運行
三、在ESP32上運行microTVM進行autotune
1、Zephyr安裝與配置
1.1 配置zephyr sdk
Zephyr sdk的release地址在:https://github.com/zephyrproject-rtos/sdk-ng
需要下載最新的0.14.1版本,提供了esp相關(guān)的toolchain,如果使用west espressif進行安裝會遇到newlibc的編譯問題。
cd ~/
wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.14.1/zephyr-sdk-0.14.1_linux-x86_64.tar.gz
tar -xvf zephyr-sdk-0.14.1_linux-x86_64.tar.gz
cd zephyr-sdk-0.14.1
./setup.sh
. environment-setup-x86_64-pokysdk-linux
我們需要的toolchain目錄為 xtensa-espressif_esp32_zephyr-elf
1.2 安裝依賴
這個按照Zephyr官方文檔進行:
sudo apt install --no-install-recommends git cmake
ninja-build gperf ccache dfu-util device-tree-compiler wget
python3-dev python3-pip python3-setuptools python3-tk
python3-wheel xz-utils file make gcc gcc-multilib
g++-multilib libsdl2-dev
pip3 install -- user -U west
echo 'export PATH=~/.local/bin:'$PATH'' >> ~/.bashrc
source ~/.bashrc
zephyr對cmake版本有要求,如果需要升級,可以執(zhí)行:
wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | sudo apt-key add -sudo apt-add-repository 'deb https://apt.kitware.com/ubuntu/ focal main'sudo apt update
sudo apt install cmake
1.3 初始化zephyr工程
west init ~/zephyrproject
cd ~/zephyrproject
west update
west zephyr-export
1.4 ESP32 newlibc支持
cd ~/zephyrproject/zephyr
git remote add upstream https://github.com/sylvioalves/zephyr.git
git fetch upstream
git checkout upstream/feature/newlibc_cpp_support
west update
雖然這個feature還沒有入到主分支,但是不加這個支持的話,不出意外應該會遇到的錯誤應該是這樣的:
In file included from ~/zephyrproject/zephyr/lib/posix/pthread_common.c:10:
~/zephyrproject/zephyr/include/posix/time.h:90:15: error: static declaration of 'clock_gettime' follows non-static declaration
__syscall int clock_gettime(clockid_t clock_id, struct timespec *ts);
^~~~~~~~~~~~~
In file included from ~/zephyrproject/zephyr/include/posix/time.h:12,
from ~/zephyrproject/zephyr/lib/posix/pthread_common.c:10:
/home/zgs/.espressif/tools/zephyr/xtensa-esp32-elf/xtensa-esp32-elf/sys-include/time.h:187:5: note: previous declaration of 'clock_gettime' was here
int clock_gettime (clockid_t clock_id, struct timespec *tp);
^~~~~~~~~~~~~
In file included from ~/zephyrproject/zephyr/lib/posix/pthread_common.c:10:
~/zephyrproject/zephyr/include/posix/time.h:94:5: error: conflicting types for 'timer_create'
int timer_create(clockid_t clockId, struct sigevent *evp, timer_t *timerid);
....
make[2]: *** [zephyr/lib/posix/CMakeFiles/lib__posix.dir/build.make:76: zephyr/lib/posix/CMakeFiles/lib__posix.dir/pthread_common.c.obj] Error 1
make[1]: *** [CMakeFiles/Makefile2:2950: zephyr/lib/posix/CMakeFiles/lib__posix.dir/all] Error 2
make[1]: *** Waiting for unfinished jobs....
1.5 導出環(huán)境變量
export ZEPHYR_BASE='${HOME}/zephyrproject/zephyr'
export ZEPHYR_TOOLCHAIN_VARIANT='espressif'
export ESPRESSIF_TOOLCHAIN_PATH='${HOME}/zephyr-sdk-0.14.1/xtensa-espressif_esp32_zephyr-elf'
export PATH=$PATH:$ESPRESSIF_TOOLCHAIN_PATH/bin
1.6 修改toolchain名稱
下載的zephyr-sdk 0.14.1中的toolchain名稱跟esp32所使用的默認名稱不一致,需要修改編譯腳本的默認值:
diff --git a/cmake/toolchain/espressif/target.cmake b/cmake/toolchain/espressif/target.cmake
index 5245bf9d08..f677bc9024 100644
--- a/cmake/toolchain/espressif/target.cmake
+++ b/cmake/toolchain/espressif/target.cmake
@@ -8,7 +8,7 @@ set(COMPILER gcc)
set(LINKER ld)
set(BINTOOLS gnu)
-set(CROSS_COMPILE_TARGET_xtensa_esp32 xtensa-esp32-elf)
+set(CROSS_COMPILE_TARGET_xtensa_esp32 xtensa-espressif_esp32_zephyr-elf)
set(CROSS_COMPILE_TARGET_xtensa_esp32s2 xtensa-esp32s2-elf)
set(CROSS_COMPILE_TARGET_riscv_esp32c3 riscv32-esp-elf)
2、TVM配置
2.1 使能 microTVM 編譯
修改 config.cmake
set(USE_MICRO ON)
重新編譯tvm。
2.2 增加esp32支持
在 ~/github/tvm/apps/microtvm/zephyr/template_project/boards.json 增加:
diff --git a/apps/microtvm/zephyr/template_project/boards.json b/apps/microtvm/zephyr/template_project/boards.json
index aae764a82..19a80397a 100644
--- a/apps/microtvm/zephyr/template_project/boards.json
+++ b/apps/microtvm/zephyr/template_project/boards.json
@@ -95,5 +95,13 @@
'fpu': true,
'vid_hex': '0483',
'pid_hex': '374b'
+ },
+ 'esp32': {
+ 'board': 'esp32',
+ 'model': 'esp32',
+ 'is_qemu': false,
+ 'fpu': true,
+ 'vid_hex': '',
+ 'pid_hex': ''
}
}
2.3 增加esp32 flash runner串口獲取方式
在~/github/tvm/apps/microtvm/zephyr/template_project/microtvm_api_server.py增加:
diff --git a/apps/microtvm/zephyr/template_project/microtvm_api_server.py b/apps/microtvm/zephyr/template_project/microtvm_api_server.py
index 059e76048..7e7b6e888 100644--- a/apps/microtvm/zephyr/template_project/microtvm_api_server.py+++ b/apps/microtvm/zephyr/template_project/microtvm_api_server.py
@@ -669,6 +669,10 @@ class ZephyrSerialTransport:
def _find_stm32cubeprogrammer_serial_port(cls, options):
return generic_find_serial_port()
+ @classmethod+ def _find_esp32_serial_port(cls, options):+ return generic_find_serial_port()+
@classmethod
def _find_serial_port(cls, options):
flash_runner = _get_flash_runner()@@ -685,6 +689,9 @@ class ZephyrSerialTransport:
if flash_runner == 'stm32cubeprogrammer':
return cls._find_stm32cubeprogrammer_serial_port(options)
+ if flash_runner == 'esp32':+ return cls._find_esp32_serial_port(options)+
raise RuntimeError(f'Don't know how to deduce serial port for flash runner {flash_runner}')
def __init__(self, options):
2.4 修改host_driven內(nèi)存分配及頭文件依賴
主要修改兩個地方:
zephyr從2.6.0開始power/reboot.h改成了sys/reboot.h
縮小tvm_heap分配的內(nèi)存,否則最終的編譯會出現(xiàn)region `dram0_1_seg' overflowed by xxxxx bytes的錯誤。
diff --git a/apps/microtvm/zephyr/template_project/src/host_driven/main.c b/apps/microtvm/zephyr/template_project/src/host_driven/main.c
index 44d656028..463f7e0d1 100644--- a/apps/microtvm/zephyr/template_project/src/host_driven/main.c+++ b/apps/microtvm/zephyr/template_project/src/host_driven/main.c
@@ -33,7 +33,7 @@ #include #include #include #include #include #include #include #include #ifdef CONFIG_ARCH_POSIX #include 'posix_board_if.h'@@ -130,7 +131,7 @@ tvm_crt_error_t TVMPlatformGenerateRandom(uint8_t* buffer, size_t num_bytes) { } // Heap for use by TVMPlatformMemoryAllocate.-K_HEAP_DEFINE(tvm_heap, 216 * 1024);+K_HEAP_DEFINE(tvm_heap, 50 * 1024); // Called by TVM to allocate memory. tvm_crt_error_t TVMPlatformMemoryAllocate(size_t num_bytes, DLDevice dev, void** out_ptr) { 按這樣改完后,編譯最終得到的內(nèi)存區(qū)使用情況如下,可以看到dram0_1_seg的使用率已經(jīng)到了96.22%: 內(nèi)存區(qū)使用情況 3、算子調(diào)優(yōu) 3.1 按microtvm_autotune的例程編寫應用 import osimport jsonimport numpy as npimport pathlibimport shutilimport tvmfrom tvm.relay.backend import Runtime BOARD = os.getenv('TVM_MICRO_BOARD', default='esp32')def create_module(): data_shape = (1, 3, 10, 10) weight_shape = (6, 3, 5, 5) # 輸入數(shù)據(jù) data = tvm.relay.var('data', tvm.relay.TensorType(data_shape, 'float32')) weight = tvm.relay.var('weight', tvm.relay.TensorType(weight_shape, 'float32')) # relay卷積算子 y = tvm.relay.nn.conv2d( data, weight, padding=(2,2), kernel_size=(5, 5), kernel_layout='OIHW', out_dtype='float32', ) # 定義relay Function表達式 f = tvm.relay.Function([data, weight], y) # 用卷積算子表達式構(gòu)建一個module relay_mod = tvm.IRModule.from_expr(f) # 表達式類型推理 relay_mod = tvm.relay.transform.InferType()(relay_mod) # weight隨機值 weight_sample = np.random.rand( weight_shape[0], weight_shape[1], weight_shape[2], weight_shape[3] ).astype('float32') params = {'weight': weight_sample} return relay_mod, paramsdef config_target(): runtime = Runtime('crt', {'system-lib': True}) boards_file = pathlib.Path(tvm.micro.get_microtvm_template_projects('zephyr')) / 'boards.json' with open(boards_file) as fp: boards = json.load(fp) target = tvm.target.target.micro(boards[BOARD]['model']) return runtime, target relay_mod, params = create_module()runtime, target = config_target()# 配置優(yōu)化passpass_context = tvm.transform.PassContext(opt_level=3, config={'tir.disable_vectorize': True})with pass_context: tasks = tvm.autotvm.task.extract_from_program(relay_mod['main'], {}, target)assert len(tasks) > 0zephyr_base = os.getenv('HOME') + '/zephyrproject/zephyr'module_loader = tvm.micro.AutoTvmModuleLoader( template_project_dir=pathlib.Path(tvm.micro.get_microtvm_template_projects('zephyr')),
上一篇:Zephyr 環(huán)境搭建 - ESP32 篇
下一篇:最后一頁
推薦閱讀最新更新時間:2025-06-06 13:39

設計資源 培訓 開發(fā)板 精華推薦
- ZSR800GTA 8 伏正電流調(diào)節(jié)器的典型應用
- #第七屆立創(chuàng)電賽#電流電壓表
- 5050LED驅(qū)動
- 具有串行控制功能的 LTC4556 智能卡接口的典型應用
- LTC2946IMS 雙電源、電荷和能量監(jiān)視器的典型應用,使用單個光耦合器進行電流隔離,并在任一電源出現(xiàn)故障時使用阻塞二極管來保持數(shù)據(jù)
- 征集令 |物聯(lián)網(wǎng)之光——學習陪伴小夜燈
- lm3886-singel
- AM3GW-2405DZ ±5V 3 瓦 DC-DC 轉(zhuǎn)換器的典型應用
- 使用 LT1054IN8 數(shù)字可編程負電源的典型應用
- TRK-KEA8、Kinetis KEA8 StarterTRAK 用于低端汽車應用
- uboot 替代 eboot 燒寫、啟動 wince
- 賽微電子:北京FAB3正推進多款MEMS芯片工藝開發(fā)
- Vishay推出高溫下連續(xù)工作的7575封裝尺寸汽車級IHLP?電感器
- 華潤微專家委員會主任暨核心技術(shù)人員王國平離職了
- 不起火/不爆炸的挑戰(zhàn)和意義,解析長城大禹電池
- 倪光南:可適當聚焦RISC-V架構(gòu),掌握芯片產(chǎn)業(yè)發(fā)展主動權(quán)
- 德國: 3D打印技術(shù)批量生產(chǎn)電池
- 工業(yè)機器人更加準確的方位
- e絡盟供貨Analog Devices雙路降壓轉(zhuǎn)換器, 具有多相功能且符合ASIL B標準
- “自動泊車”原理是什么?AVP落地該如何解決?
- 面壁智能端側(cè)大模型首日上線,英特爾工程師聯(lián)合優(yōu)化實現(xiàn)2.2倍推理效率躍升
- 瞄準車規(guī)級碳化硅,理想發(fā)表重要成果
- 車規(guī)級MCU國內(nèi)替代提速
- 博世新獲國內(nèi)頭部車企座艙域控項目定點
- 首款測量電動汽車電機溫度的傳感器問世,提升對磁鐵的保護以減少稀土的使用
- Arm開發(fā)出計算子系統(tǒng) 以加速汽車設計的下一代AI芯片的開發(fā)
- 福特汽車申請新專利 或?qū)崿F(xiàn)車庫定向音樂播放
- 泊車場景一定需要超聲波嗎?
- 同星新一代TC1055 Pro開啟車載網(wǎng)絡測試新時代
- 福特汽車申請新專利 或?qū)⑴鋫浒踩ㄗ粉櫹到y(tǒng)
- 智能機器人行業(yè)的主要動向
- 華為員工反思公司十大內(nèi)耗,“大公司病”不可避免?
- 博世德累斯頓300mm晶圓廠量產(chǎn),成為博世第一家AIoT工廠
- 阿里推出的自動送貨機器人,進行了哪些技術(shù)創(chuàng)新?
- 是德科技推出高速以太網(wǎng)媒體訪問控制安全測試解決方案
- D字型掃地機—格蘭博CH350D-G的評測:各項性能都挺好!
- 智能音箱品牌戰(zhàn)一觸即發(fā),未來的市場是怎樣的?
- 要想將VR/AR普及和流行,還需要哪些推動力?
- 初生牛犢不怕虎 造車新勢力的硬核移動互聯(lián)科技盤點
- 用它給家里來一場清潔革命!創(chuàng)新洗地機器人,深度清潔污漬