境搭建到NPU推理實(shí)戰(zhàn))
把手里的RK3588開發(fā)板跑成OpenHarmony 4.0系統(tǒng)再把YOLOv8目標(biāo)檢測模型部署上去這件事我從立項(xiàng)到真正在板子上看到實(shí)時(shí)檢測畫面前后折騰了一個(gè)多月。核心問題不在AI模型本身而在環(huán)境搭建、系統(tǒng)適配、模型轉(zhuǎn)換這一條鏈路的碎片化信息太多。這篇就把我的完整路線寫出來適合正在或者準(zhǔn)備在RK3588上搞OpenHarmony并且想把AI應(yīng)用真正跑起來的開發(fā)者。先說一下我最后的成果OpenHarmony 4.0 Release系統(tǒng)跑在訊為RK3588平臺(tái)上攝像頭采集經(jīng)RGA硬件加速后送入RKNN NPU推理YOLOv8s模型1080p輸入下端到端大概25到30 FPS。這個(gè)結(jié)果不算頂尖但已經(jīng)把RK3588這塊板子的CPU、GPU、NPU、RGA都串起來了整個(gè)過程的坑和細(xì)節(jié)下面一條條說。1. 為什么是RK3588這塊芯片剛好卡在性能與生態(tài)的交匯點(diǎn)上1.1 8核CPU、Mali GPU和6TOPS NPU分別解決什么問題RK3588是瑞芯微推出的高性能SoC采用8nm制程4個(gè)A76大核加4個(gè)A55小核主頻能到2.4GHz左右。這個(gè)配置放到嵌入式板子里算很能打的跑OpenHarmony系統(tǒng)編譯出來的鏡像日常應(yīng)用開多個(gè)都不會(huì)明顯卡頓跑v4l2攝像頭采集、圖像縮放、模型推理、UI渲染全部壓在一個(gè)SoC上也基本能扛住。對AI部署來說RK3588最有價(jià)值的是那顆NPU官方標(biāo)稱6TOPS算力支持INT4/INT8/INT16/FP16混合量化。雖然和高端獨(dú)立NPU沒法比但在板級方案里這個(gè)算力對YOLOv8s這種參數(shù)量在千萬級別的模型來說跑30FPS以上完全夠用。GPU是ARM Mali-G610 MP4主要用于圖形渲染。實(shí)測跑OpenHarmony自帶的ArkUI應(yīng)用、視頻播放這些場景GPU和VPU硬件編解碼器能分擔(dān)掉大量CPU壓力。這顆芯片比較均衡不像某些開發(fā)板CPU很強(qiáng)但NPU是擺設(shè)也不像某些NPU芯片CPU太弱讓圖像預(yù)處理成為瓶頸。1.2 OpenHarmony 4.0對RK3588的支持到底到了什么程度OpenHarmony 4.0 Release版本發(fā)布后官方主干對RK3588的支持一直通過device/board/rockchip、device/soc/rockchip、vendor/rockchip這些倉庫來維護(hù)社區(qū)里也有Rockchip的SIG組在持續(xù)跟進(jìn)。實(shí)際體驗(yàn)下來OpenHarmony 4.0在RK3588上已經(jīng)有比較完整的啟動(dòng)鏈路U-Boot能正常起來、內(nèi)核能跑、圖形棧能起來、音視頻HAL基本可用。但要注意官方主干對RK3588的支持是能跑級別不是開箱即用產(chǎn)品化級別。你拿到一塊RK3588開發(fā)板先別急著直接編譯官方代碼。原因是不同廠家板子的DDR配置、PMIC、PHY、eMMC/存儲(chǔ)顆粒、顯示接口都不一樣這些差異在U-Boot和內(nèi)核設(shè)備樹里直接體現(xiàn)。我測試的板子基于訊為RK3588平臺(tái)廠家一般會(huì)提供適配好的OpenHarmony SDK補(bǔ)丁優(yōu)先用廠家的SDK比從開源主干直接開始省很多事。我最初從社區(qū)主干拉代碼編譯了兩次起來后攝像頭和顯示都有問題換廠家SDK后幾步就到UI界面了。所以給新手的第一個(gè)建議是先用廠商定制好的鏡像跑通再談自己改代碼。2. 宿主機(jī)環(huán)境把編譯OpenHarmony的機(jī)器一次搞定2.1 為什么我推薦Ubuntu 20.04 64GB內(nèi)存的x86_64物理機(jī)編譯OpenHarmony 4.0的官方文檔要求宿主機(jī)是Ubuntu 20.04x86_64我試過Ubuntu 22.04也能跑但編譯腳本里有些工具的版本和路徑是寫死的在22.04上會(huì)隨機(jī)踩到各種小坑。為了少浪費(fèi)一個(gè)通宵直接裝Ubuntu 20.04.6 LTS最穩(wěn)。內(nèi)存方面OpenHarmony 4.0全量編譯RK3588產(chǎn)品時(shí)內(nèi)存低于32GB很容易在中后期OOM因?yàn)閚inja和clang會(huì)同時(shí)起大量并行任務(wù)每個(gè)編譯單元的內(nèi)存疊加起來非??捎^。我用的機(jī)器是64GB內(nèi)存、16核CPU、1TB SSD。機(jī)械盤編譯會(huì)慢到懷疑人生不是能不能用的問題是單次全量編譯從30分鐘拉長到兩三小時(shí)的問題。一個(gè)容易忽略的點(diǎn)是磁盤空間。OpenHarmony 4.0源碼加編譯產(chǎn)物加中間緩存全量下來要超過200GBprebuilts和out目錄非常占空間。建議至少預(yù)留300GB并且用ext4文件系統(tǒng)。我第一次放在NTFS掛載的分區(qū)里repo同步到一半就因?yàn)槲募傩圆恢С謭?bào)錯(cuò)了后來單獨(dú)分了一個(gè)ext4盤符才順利通過。2.2 宿主機(jī)依賴清單與repo同步的完整命令我整理了一份實(shí)際用到的依賴清單按OpenHarmony 4.0文檔再細(xì)化了一些sudo apt-get update sudo apt-get install -y \ git git-lfs curl wget \ python3 python3-pip python3-setuptools python3-venv \ binutils build-essential bison flex \ libc6-dev libssl-dev libncurses5-dev libncursesw5-dev \ zlib1g-dev gcc g \ make cmake ninja-build \ openjdk-11-jdk \ dosfstools mtools mtd-utils \ device-tree-compiler u-boot-tools \ file treepython3默認(rèn)版本我固定到3.8。Ubuntu 20.04自帶Python 3.8不需要額外處理如果非要在22.04上試python3.10會(huì)有部分舊工具鏈不兼容需要手動(dòng)配置pyenv或者直接用官方容器。源代碼倉庫建議用Gitee鏡像同步全量代碼幾十GB倉庫非常多必須用repo工具管理。我的操作是mkdir -p ~/ohos cd ~/ohos repo init -u https://gitee.com/openharmony/manifest.git -b OpenHarmony-4.0-Release repo sync -c -j8 --no-tags注意repo sync時(shí)加上--no-tags能少拉不少tag數(shù)據(jù)。如果中途網(wǎng)絡(luò)斷掉不要直接重來再執(zhí)行一次repo sync -c -j8 --no-tags即可repo本身支持?jǐn)帱c(diǎn)續(xù)傳。整個(gè)源碼拉下來后prebuilts目錄里已經(jīng)帶了clang、gcc、llvm等全套工具鏈不需要再手工裝交叉編譯器。2.3 我第一次編譯就被環(huán)境坑了兩次第一次編譯失敗印象最深的是Python模塊問題。OpenHarmony 4.0的構(gòu)建系統(tǒng)依賴hb工具文檔里提示用pip3 install build/hb安裝但很多人的pip會(huì)先裝到用戶目錄導(dǎo)致hb命令找不到。后來我是用cd ~/ohos pip3 install --user build/hb export PATH$HOME/.local/bin:$PATH才把hb工具穩(wěn)定啟用。第二個(gè)坑是文件句柄限制。OpenHarmony的構(gòu)建系統(tǒng)會(huì)同時(shí)打開海量文件系統(tǒng)默認(rèn)的ulimit -n是1024編譯一定會(huì)在某個(gè)階段報(bào)Too many open files。必須在編譯前執(zhí)行ulimit -n 65535而且要注意每次重新登錄終端都要再設(shè)置一次不是寫進(jìn).bashrc就一定能生效有些環(huán)境的PAM配置會(huì)覆蓋。還有一個(gè)隱性問題如果在Windows上用WSL編譯磁盤是跨文件系統(tǒng)掛載的ninja的inotify會(huì)出各種詭異問題。群里好幾個(gè)人卡在WSL編譯到一半文件鎖沖突所以盡量用原生Linux或者虛擬機(jī)虛擬機(jī)也要給足CPU和內(nèi)存。編譯時(shí)如果報(bào)/bin/bash: line 1: 18769 Killed基本就是內(nèi)存不夠觸發(fā)了OOM killer屬于硬件瓶頸只能加內(nèi)存或者減少ninja并行度。3. 源碼獲取與RK3588適配層OpenHarmony 4.0到底改了哪些文件3.1 源碼目錄里與RK3588強(qiáng)相關(guān)的幾個(gè)倉庫拿到源碼后和RK3588直接相關(guān)的目錄主要分布在三個(gè)層次device/soc/rockchip芯片相關(guān)的BSP代碼包括內(nèi)核、HAL、媒體相關(guān)配置。device/board/rockchip具體板卡的適配比如設(shè)備樹、U-Boot配置、產(chǎn)品定義。RK3588對應(yīng)的板級目錄一般是device/board/rockchip/rk3588。vendor/rockchip廠商產(chǎn)品配置、鏡像打包腳本、預(yù)編譯的組件和Demo應(yīng)用。這三個(gè)目錄的關(guān)系我理解成芯片能力、板卡實(shí)現(xiàn)、產(chǎn)品形態(tài)三層芯片提供的是CPU/GPU/NPU的能力定義板卡決定這些能力如何連線到實(shí)際的硬件引腳上產(chǎn)品層決定做出來的系統(tǒng)長什么樣、帶哪些應(yīng)用、默認(rèn)什么分區(qū)。廠商SDK里拿到的大多數(shù)補(bǔ)丁最后都會(huì)落到這三個(gè)目錄下。特別是device/board/rockchip/rk3588里的dts文件基本決定了板子上的攝像頭、HDMI、MIPI屏能不能亮起來。我拿到訊為SDK后第一件事就是對比補(bǔ)丁和官方分支的差異發(fā)現(xiàn)差異集中在U-Boot的設(shè)備樹和內(nèi)核dts上其他部分改動(dòng)不大。3.2 版本選型社區(qū)主干 vs 廠商SDK vs OpenHarmony 4.0 ReleaseOpenHarmony的版本線其實(shí)挺多主干master分支更新最快OpenHarmony-4.0-Release是穩(wěn)定發(fā)布版還有4.1、5.0這些后續(xù)版本。我在RK3588上做產(chǎn)品選型時(shí)選了OpenHarmony 4.0 Release理由有三4.0是穩(wěn)定發(fā)布版API凍結(jié)社區(qū)討論多遇到問題搜一下就有答案。Rockchip的SDK對4.0的適配最成熟很多第三方開發(fā)板出廠就預(yù)裝4.0。5.0雖然API更豐富但RK3588適配還不夠完善尤其是GPU驅(qū)動(dòng)和攝像頭HAL社區(qū)里不少反饋提到啟動(dòng)黑屏、GPU渲染異常。如果你不是追新功能做工程就是求穩(wěn)4.0 Release是RK3588上最省心的選擇。如果是拿開發(fā)板做預(yù)研5.0的ArkTS新特性也很香但別把它當(dāng)生產(chǎn)環(huán)境的默認(rèn)選項(xiàng)。3.3 編譯前的產(chǎn)品配置hb set和產(chǎn)品名的選擇OpenHarmony的構(gòu)建工具鏈?zhǔn)莌bHarmonyOS Build使用方式可以理解為類似buildroot或yocto的配置加編譯。cd ~/ohos hb sethb set會(huì)列出當(dāng)前源碼樹里所有可編譯的產(chǎn)品選擇方式是按數(shù)字。我開發(fā)板上對應(yīng)的是帶rk3588字樣的產(chǎn)品配置每個(gè)廠商SDK命名不同我那個(gè)板子在SDK里叫rk3588_standard。選好后執(zhí)行hb build -f第一次全量構(gòu)建時(shí)間取決于機(jī)器配置我的機(jī)器上大約25到35分鐘。構(gòu)建產(chǎn)物默認(rèn)生成在out/rk3588/packages/phone/images/里面會(huì)有boot.img、system.img、vendor.img、userdata.img等鏡像文件還有打包好的update.img。注意不同產(chǎn)品配置輸出的目錄名字不一樣比如rk3568的板子產(chǎn)物目錄就完全不同不要拿A產(chǎn)品的產(chǎn)物目錄名去套B產(chǎn)品。內(nèi)核怎么改、dts怎么改這個(gè)階段先不需要?jiǎng)?。第一次編譯的目標(biāo)只是把官方或廠商配置原樣跑通驗(yàn)證宿主機(jī)環(huán)境沒問題。我見過很多人第一步就想著改內(nèi)核結(jié)果構(gòu)建出錯(cuò)也不知道是環(huán)境問題還是代碼問題排錯(cuò)成本翻倍。4. 編譯與燒錄第一次把系統(tǒng)點(diǎn)亮并連上adb4.1 燒錄前必須搞懂的信息不要用dd一把梭拿到編譯好的鏡像后最常見的錯(cuò)誤是把它當(dāng)成樹莓派直接用dd寫進(jìn)SD卡或用balenaEtcher刻錄。RK3588開發(fā)板不是樹莓派那種SD卡優(yōu)先的設(shè)備它的系統(tǒng)分布在固定的Flash分區(qū)上需要用瑞芯微官方的RKDevToolWindows或upgrade_toolLinux來燒錄。分區(qū)表對應(yīng)著OpenHarmony的鏡像劃分我的板子分區(qū)大致是這樣分區(qū)作用默認(rèn)大小參考ubootU-Boot引導(dǎo)程序8MBboot內(nèi)核和ramdisk64MBsystemOpenHarmony系統(tǒng)核心2GB~4GBvendor廠商定制HAL和庫1GB~2GBuserdata用戶數(shù)據(jù)和應(yīng)用剩余空間這個(gè)表格的具體大小會(huì)隨產(chǎn)品配置變化但分區(qū)分工明確這一點(diǎn)是一樣的。RKDevTool燒錄的底層邏輯是走Loader模式不是簡單地把鏡像平鋪到存儲(chǔ)里它會(huì)按分區(qū)表把不同鏡像寫到對應(yīng)分區(qū)所以千萬不要拿dd ifxxx.img of/dev/sdX來燒。輕則分區(qū)錯(cuò)亂重則Loader被破壞只能短接Maskrom來恢復(fù)。4.2 燒錄實(shí)操RKDevTool的步驟和常見坑第一次燒錄以Windows RKDevTool為例步驟是開發(fā)板按住Recovery或Maskrom按鍵再上電或者用Type-C線連接電腦后按住按鍵進(jìn)入Loader模式。打開RKDevTool確認(rèn)識(shí)別到設(shè)備一般在界面上方會(huì)顯示發(fā)現(xiàn)一個(gè)LOADER設(shè)備。在升級固件頁簽中選擇打包好的update.img。如果廠商給了單個(gè)img也可以用分區(qū)表分別指定鏡像。我推薦優(yōu)先用update.img整包省心分區(qū)表都配好了。點(diǎn)擊升級進(jìn)度條跑完會(huì)自動(dòng)重啟。如果RKDevTool一直識(shí)別不到設(shè)備十有八九是Type-C線的問題。必須是數(shù)據(jù)線不是那種只能充電的線而且優(yōu)先用主板上的Type-C口不要用轉(zhuǎn)接Hub。還有一個(gè)小細(xì)節(jié)有些板子要先在系統(tǒng)里開啟adb的USB調(diào)試模式才能在系統(tǒng)運(yùn)行狀態(tài)下連adb但刷Loader是不依賴系統(tǒng)的只看硬件Loader。燒錄完成后第一次啟動(dòng)建議同時(shí)接上串口UART看日志。串口一般通過開發(fā)板上的調(diào)試串口引腳轉(zhuǎn)USB出來在電腦上設(shè)置波特率1500000RK官方調(diào)試串口常用或者廠商文檔指定的波特率我用的是1500000。系統(tǒng)能不能起來、卡在哪個(gè)階段串口日志比什么調(diào)試工具都直觀。4.3 OpenHarmony 4.0里adb連接的排查思路系統(tǒng)正常啟動(dòng)到UI后想用adb做后續(xù)部署在OpenHarmony上通常需要打開開發(fā)者模式。具體路徑在設(shè)置-關(guān)于中連續(xù)點(diǎn)擊版本號(hào)幾次打開開發(fā)者選項(xiàng)然后開啟USB調(diào)試。連接后宿主機(jī)執(zhí)行adb devices如果識(shí)別到設(shè)備但顯示unauthorized去板子上的系統(tǒng)彈窗點(diǎn)授權(quán)如果完全看不到設(shè)備按這個(gè)順序排查數(shù)據(jù)線是否支持?jǐn)?shù)據(jù)傳輸換線是最高頻的解法。USB口是否接在開發(fā)板正確的Host口上。很多板子Type-C口用于燒錄另有Type-A口用于adb或者外設(shè)不能混用。系統(tǒng)是否真正進(jìn)入了開發(fā)者模式下的USB調(diào)試串口日志里會(huì)有usb相關(guān)的枚舉信息。重啟后是否又回到了默認(rèn)關(guān)閉狀態(tài)。OpenHarmony某些定制鏡像默認(rèn)沒有USB調(diào)試權(quán)限需要檢查vendor鏡像里的相關(guān)權(quán)限配置。adb能連上AI應(yīng)用部署就完成了最關(guān)鍵的一步因?yàn)楹竺嫱遄由贤瓶蓤?zhí)行文件、推模型、拉日志全靠它。5. AI應(yīng)用部署在OpenHarmony 4.0上跑通YOLOv8目標(biāo)檢測5.1 三條路線我最后選了RKNN NPU推理在OpenHarmony上跑YOLOv8我梳理下來有三條路線路線A直接編譯純CPU版本的推理程序用ONNX Runtime CPU或NCNN代碼最通用但1080p輸入下推理延遲很高基本在每秒幾幀級別跑實(shí)時(shí)檢測太勉強(qiáng)。路線B通過OpenHarmony的AI框架能力比如接入MindSpore Lite集成方式規(guī)范但模型轉(zhuǎn)換鏈路要適配MindSpore Lite的生態(tài)Python工具鏈支撐相對有限。路線C直接用瑞芯微的RKNN Runtime模型先用rknn-toolkit2從ONNX轉(zhuǎn)成.rknn格式再在板子上用C API加載推理。這條路性能和可控性最好也是RK3588平臺(tái)最正統(tǒng)的路線。我最后選了路線C理由不復(fù)雜RK3588的NPU就是給RKNN Runtime服務(wù)的廠商SDK里已經(jīng)帶了runtime庫和大量模型示例接口是C風(fēng)格的。特別提醒OpenHarmony的應(yīng)用運(yùn)行環(huán)境默認(rèn)不能直接訪問Linux的動(dòng)態(tài)庫和NPU設(shè)備節(jié)點(diǎn)。路線C更準(zhǔn)確的落地形態(tài)是Native C后端 可選的應(yīng)用層封裝先用C寫好推理服務(wù)通過OpenHarmony的NAPI橋接到ArkTS界面或者在前期驗(yàn)證階段干脆先用命令行原生程序跑通推理確認(rèn)NPU可用再考慮界面封裝。我實(shí)際是先做命令行驗(yàn)證一次成功后才封裝成帶UI的服務(wù)這樣出錯(cuò)時(shí)少一層干擾。5.2 宿主機(jī)上準(zhǔn)備模型轉(zhuǎn)換環(huán)境rknn-toolkit2和PyTorchrknn-toolkit2是瑞芯微提供的工具在x86宿主機(jī)上運(yùn)行負(fù)責(zé)把PyTorch/TensorFlow/ONNX模型轉(zhuǎn)換成.rknn格式并支持在模擬器上做精度仿真。我轉(zhuǎn)換YOLOv8模型時(shí)的環(huán)境如下Ubuntu 20.04 x86_64Python 3.8建議用venv單獨(dú)建一個(gè)環(huán)境避免和系統(tǒng)Python沖突PyTorch 2.0.1CPU版即可不需要CUDA因?yàn)槲覀冎挥糜趯?dǎo)出ONNXrknn-toolkit2版本我用的1.6.0不同版本API有差異后面會(huì)舉例安裝rknn-toolkit2時(shí)有一個(gè)大坑它依賴的protobuf、onnx、numpy版本比較老直接pip install最新版容易沖突。我新建venv后按官方對應(yīng)版本的requirements安裝依賴然后手動(dòng)先把numpy釘?shù)?.24.4、protobuf釘?shù)?.20.x最后再安裝rknn_toolkit2對應(yīng)的whl包這樣才順利裝上。如果后面導(dǎo)入rknn報(bào)protobuf或numpy相關(guān)錯(cuò)誤基本就是版本問題。5.3 YOLOv8模型從導(dǎo)出ONNX到轉(zhuǎn)成RKNN的完整配置我用的是YOLOv8s模型yolov8s.pt導(dǎo)出ONNX時(shí)在YOLOv8的工程目錄里執(zhí)行yolo export modelyolov8s.pt formatonnx opset12 simplifyTrue導(dǎo)出后拿到y(tǒng)olov8s.onnx。接著寫一個(gè)轉(zhuǎn)換腳本from rknn.api import RKNN rknn RKNN() rknn.config(mean_values[[0, 0, 0]], std_values[[255, 255, 255]], target_platformrk3588) rknn.load_onnx(modelyolov8s.onnx) rknn.build(do_quantizationTrue, datasetdataset.txt) rknn.export_rknn(yolov8s.rknn)這里target_platform必須是rk3588不同芯片的NPU指令集不完全通用我同事拿rk3568的模型直接跑在rk3588上runtime報(bào)錯(cuò)說模型和硬件不匹配。do_quantizationTrue表示做INT8量化量化后模型體積和推理速度都提升明顯但精度會(huì)有所損失。量化時(shí)需要提供一個(gè)dataset.txt文件里面是幾百張圖片的路徑每行一張這些圖片用來統(tǒng)計(jì)每層的數(shù)值范圍。建議盡量用你實(shí)際業(yè)務(wù)場景的圖片而不只是從網(wǎng)上隨便下點(diǎn)圖。我在測試中用過純COCO圖片做量化換到暗光攝像頭畫面后目標(biāo)框有概率漏檢改用業(yè)務(wù)圖片重新量化后明顯好轉(zhuǎn)。最后會(huì)生成yolov8s.rknnINT8量化后一般幾十MB大小比FP32小很多。5.4 在OpenHarmony板子上跑起第一幀NPU推理把rknn模型和推理程序推到板子上我用的是adbadb push yolov8s.rknn /data/local/tmp/ adb push rknn_yolov8_demo /data/local/tmp/ adb shell chmod x /data/local/tmp/rknn_yolov8_demo adb shell /data/local/tmp/rknn_yolov8_demo在程序里加載模型的核心C API大概長這樣#include rknn_api.h rknn_context ctx; rknn_init(ctx, model_path, 0, 0, NULL); rknn_input inputs[1]; inputs[0].index 0; inputs[0].type RKNN_TENSOR_UINT8; inputs[0].size 640 * 640 * 3; inputs[0].fmt RKNN_TENSOR_NHWC; inputs[0].buf img_data; rknn_inputs_set(ctx, 1, inputs); rknn_output outputs[3]; // YOLOv8后處理需要3個(gè)輸出分支 rknn_outputs_get(ctx, 3, outputs, NULL);第一次運(yùn)行如果能看到類似RKNN Driver Information的日志并且rknn_init返回0說明NPU驅(qū)動(dòng)和runtime都正常。接著在板子上接入攝像頭取一幀圖像縮放成640x640送入模型再對輸出做NMS后處理就能畫出檢測框。后續(xù)想要界面化可以在OpenHarmony側(cè)寫一個(gè)NAPI擴(kuò)展把rknn_init、rknn_inference這些C接口封裝成ArkTS可以調(diào)用的方法然后開發(fā)一個(gè)簡單的相機(jī)預(yù)覽頁面實(shí)時(shí)顯示檢測框。這部分是純OpenHarmony應(yīng)用開發(fā)的工作步驟多但不涉及底層調(diào)試跑通命令行推理后心里就有底了。6. 把AI應(yīng)用做扎實(shí)攝像頭適配、RGA加速與性能實(shí)測6.1 攝像頭怎么接v4l2到RGA到NPU的數(shù)據(jù)通路YOLOv8跑通了但實(shí)時(shí)視頻流檢測和單張圖片檢測完全是兩個(gè)難度。單圖檢測只要推一張圖片進(jìn)去就行實(shí)時(shí)檢測需要把攝像頭采集、格式轉(zhuǎn)換、縮放、推理、后處理、顯示全部串起來任何一個(gè)環(huán)節(jié)掉鏈子幀率就上不去。我實(shí)際使用的數(shù)據(jù)通路是v4l2從攝像頭采集原始幀。RK3588的MIPI CSI攝像頭在OpenHarmony下如果驅(qū)動(dòng)已經(jīng)適配好會(huì)生成/dev/video0節(jié)點(diǎn)。如果你用的是USB攝像頭不需要太多適配如果用的是MIPI屏和MIPI攝像頭必須先確認(rèn)設(shè)備樹下csi2_dphy、mipi_camera相關(guān)節(jié)點(diǎn)有沒有正確使能。將原始幀通過RK3588的RGA2D硬件加速器做縮放和像素格式轉(zhuǎn)換把YUV或BGR數(shù)據(jù)統(tǒng)一轉(zhuǎn)成640x640 RGB喂給NPU。RGA是RK芯片上很好用的硬件單元可以理解為圖形搬運(yùn)工做圖像縮放、旋轉(zhuǎn)、格式轉(zhuǎn)換時(shí)比CPU快得多而且不占GPU算力。網(wǎng)上關(guān)于rk3588 mpp rga的討論熱度很高就是因?yàn)檫@塊用得不好AI應(yīng)用的整體幀率直接被打回原形。推理輸出后后處理NMS在CPU上做。這一步按類別過濾即可。顯示環(huán)節(jié)可以先簡單地把檢測結(jié)果畫到一幀圖上再用RGA轉(zhuǎn)成顯示格式推給HDMI或屏幕。RGA的使用有現(xiàn)成的librga庫交叉編譯時(shí)鏈接-lrga頭文件是rga.h。我實(shí)際測試下來用RGA把1080p的YUV數(shù)據(jù)縮放到640x640的RGB大約1到2毫秒CPU去縮放同一幀數(shù)據(jù)要8到15毫秒。所以如果你想跑實(shí)時(shí)檢測RGA幾乎是必選項(xiàng)不然CPU耗在前處理上的時(shí)間比NPU推理時(shí)間還長。6.2 性能實(shí)測CPU、GPU、NPU三種方式的差異為了直觀我分別跑了三種方式純CPU推理ONNX Runtime CPU、NPU推理RKNNINT8量化、NPU推理RGA前處理優(yōu)化。測試設(shè)備是RK3588OpenHarmony 4.0YOLOv8s模型輸入640x640下面是參考數(shù)據(jù)運(yùn)行方式單幀推理延遲1080p攝像頭端到端幀率CPU占用備注CPU推理約700ms1~2 FPS接近滿載基本不可用NPU推理INT8約30ms8~12 FPS較高CPU前處理成為瓶頸NPU推理 RGA 多線程后處理約25ms25~30 FPS2~3個(gè)核可用性直接提升這里想表達(dá)的是NPU推理本身很快瓶頸往往在把圖像送進(jìn)NPU之前和從NPU輸出之后這兩個(gè)環(huán)節(jié)。很多人在開發(fā)板上跑AI只看模型推理延遲結(jié)果一上攝像頭實(shí)時(shí)流就崩就是這個(gè)原因。工程上真正跑好AI應(yīng)用要拿整條鏈路做優(yōu)化而不是只調(diào)模型參數(shù)。6.3 三個(gè)容易在部署階段栽跟頭的細(xì)節(jié)第一個(gè)細(xì)節(jié)是內(nèi)存泄漏。我最初調(diào)試時(shí)用rknn_outputs_get獲取輸出后用對應(yīng)接口釋放但漏了在循環(huán)里釋放inputs緩沖跑了十幾分鐘內(nèi)存就吃滿系統(tǒng)被OOM殺掉。NPU推理循環(huán)里一定要確保每個(gè)rknn API都有對應(yīng)的release調(diào)用建議每次循環(huán)測一下free養(yǎng)成習(xí)慣。第二個(gè)細(xì)節(jié)是靜態(tài)庫和動(dòng)態(tài)庫版本沖突。廠商SDK里通常提供librknnrt.so但OpenHarmony系統(tǒng)鏡像里的vendor鏡像可能已經(jīng)帶了一份runtime版本如果和你編譯時(shí)鏈接的不一致運(yùn)行時(shí)會(huì)報(bào)模型版本不匹配或API錯(cuò)誤。解決方法是程序運(yùn)行時(shí)優(yōu)先使用LD_LIBRARY_PATH指定你推上去的庫或者干脆用dlopen加載指定路徑的librknnrt.so。我的調(diào)試經(jīng)驗(yàn)是先用adb shell strings /usr/lib/librknnrt.so | grep version查看板載runtime版本再?zèng)Q定用哪個(gè)SDK版本編譯程序。第三個(gè)細(xì)節(jié)是模型輸出后處理。YOLOv8的輸出不是簡單的邊界框數(shù)組而是三個(gè)不同尺度的feature map需要在后處理里做anchor-free解碼、置信度閾值過濾、類別篩選、NMS。很多代碼倉庫直接把YOLOv5的后處理邏輯套到Y(jié)OLOv8上結(jié)果檢測框偏到離譜。建議后處理解碼時(shí)對照YOLOv8源碼里predict步驟的原始邏輯來寫特別是dist2bbox那段很容易寫錯(cuò)。這一步出錯(cuò)沒有任何報(bào)錯(cuò)表現(xiàn)出來就是模型加載正常但檢測結(jié)果不對排查起來最花時(shí)間。7. 從環(huán)境搭建到AI部署最值得記錄的踩坑匯總7.1 環(huán)境與編譯類大部分問題出在版本不是你想的那樣現(xiàn)象根因處理方式hb命令找不到pip安裝后未加到PATHexport PATH$HOME/.local/bin:$PATH編譯時(shí)Too many open files系統(tǒng)文件句柄限制ulimit -n 65535編譯被Killed內(nèi)存不足觸發(fā)OOM加內(nèi)存或降低并行度hb build -f --jobs 8repo sync卡住網(wǎng)絡(luò)不穩(wěn)定重復(fù)執(zhí)行repo sync斷點(diǎn)續(xù)傳生成的鏡像無法啟動(dòng)分區(qū)表不匹配優(yōu)先用update.img整包燒寫7.2 燒錄與啟動(dòng)類先分清Loader模式和系統(tǒng)模式現(xiàn)象根因處理方式RKDevTool識(shí)別不到設(shè)備Type-C線不支持?jǐn)?shù)據(jù) / 未進(jìn)入Loader換線按住按鍵上電燒錄后黑屏鏡像版本與板卡硬件不符確認(rèn)廠商板卡SDK與鏡像匹配adb devices無設(shè)備系統(tǒng)未開啟USB調(diào)試設(shè)置-開發(fā)者選項(xiàng)-USB調(diào)試啟動(dòng)卡在logoU-Boot或內(nèi)核dts問題接串口看日志定位7.3 模型與推理類問題從轉(zhuǎn)換階段就開始埋雷現(xiàn)象根因處理方式rknn.load_onnx報(bào)錯(cuò)onnx/protobuf版本沖突用venv按requirements安裝釘住版本模型加載成功但推理結(jié)果異常后處理解碼錯(cuò)誤對照YOLOv8源碼重寫dist2bbox和NMS板載runtime版本不一致系統(tǒng)自帶librknnrt與SDK不符用LD_LIBRARY_PATH指定庫或升級鏡像INT8量化后漏檢量化數(shù)據(jù)集與場景不符用業(yè)務(wù)圖片重新量化這是我把整個(gè)項(xiàng)目做下來的經(jīng)驗(yàn)不是說官方文檔有問題而是官方文檔太平整了根本不會(huì)告訴你RGA前處理、runtime版本、NMS后處理這些真實(shí)工程里的坑。如果你也正在折騰RK3588 OpenHarmony 4.0建議嚴(yán)格按先廠商鏡像匹配驗(yàn)證、再源碼編譯、再跑命令行AI、最后封裝UI的順序來別跳步每個(gè)階段都留好日志和驗(yàn)證手段。另外個(gè)人推薦一個(gè)小技巧在宿主機(jī)上寫一個(gè)簡單的腳本把編譯、打包、adb推送到板子、運(yùn)行幾個(gè)步驟做成一條命令循環(huán)開發(fā)的時(shí)候能省掉大量重復(fù)操作。我是做完這個(gè)腳本之后才把開發(fā)效率提上去的前期的重復(fù)性操作非常多沒有自動(dòng)化的日子簡直是在拿命換時(shí)間。OpenHarmony在RK3588上的生態(tài)還在快速成熟中但4.0這個(gè)版本配合RK3588的NPU做實(shí)時(shí)目標(biāo)檢測已經(jīng)具備了工程可用性。我后續(xù)計(jì)劃把YOLOv8換成更輕量級的版本同時(shí)把攝像頭美化和檢測框疊加做進(jìn)ArkUI界面里這個(gè)方向后續(xù)有機(jī)會(huì)再繼續(xù)分享。