天工開(kāi)物|征程 6 啟航新章:仿真篇
1.1 什么仿真?
仿真是使用其它相似的系統(tǒng)來(lái)模仿真實(shí)的需要研究或使用的系統(tǒng),其所遵循的基本原則是相似性原理。仿真從框架上涉及到兩個(gè)系統(tǒng):1)被仿的系統(tǒng):需要研究或使用的系統(tǒng);2)仿真出來(lái)的系統(tǒng):在用戶側(cè)視角與被仿的系統(tǒng)有一定相似性。 注意:這里的系統(tǒng)是個(gè)抽象的概念,可以是軟件,也可以是硬件,還可以是復(fù)雜的綜合事件。在 征程6 開(kāi)發(fā)平臺(tái)中,仿真的對(duì)象為“開(kāi)發(fā)板及其上的系統(tǒng)”。
1.2 為什么要仿真?
仿真在不同行業(yè)不同背景下的的目的是不同的,這些目的包括但不限于:
設(shè)計(jì)組裝自動(dòng)控制系統(tǒng)。
評(píng)價(jià)目標(biāo)系統(tǒng)性能和功能。
為目標(biāo)系統(tǒng)設(shè)計(jì)擴(kuò)展功能和組件。
在 征程6 開(kāi)發(fā)平臺(tái)中,仿真系統(tǒng)可以為我們提供下列便捷:
緩解開(kāi)發(fā)工作對(duì)開(kāi)發(fā)板硬件的依賴 物理開(kāi)發(fā)板的 CPU 是 ARM 的,其系統(tǒng)指令也是 ARM 平臺(tái)的,其上應(yīng)用程序的代碼需要經(jīng)過(guò) arm 編譯器的處理。在缺少物理開(kāi)發(fā)板的情況下,經(jīng)過(guò)接口仿真在開(kāi)發(fā)服務(wù)器(X86平臺(tái))上實(shí)現(xiàn)了與 ARM 平臺(tái)側(cè)相似(因?yàn)橄到y(tǒng)及計(jì)算架構(gòu)有異存在些許差異的情況是可能的,但差距一般很小)的功能。因?yàn)榉抡娼涌诤虯RM平臺(tái)側(cè)接口在設(shè)計(jì)上保持了完全一致性,所以所開(kāi)發(fā)的應(yīng)用程序在經(jīng)過(guò)不同編譯器處理后即可生成的平臺(tái)適用的目標(biāo)程序并加以運(yùn)行。對(duì)于開(kāi)發(fā)而言,開(kāi)發(fā)者在沒(méi)有獲得物理開(kāi)發(fā)板前提前開(kāi)始功能開(kāi)發(fā)和驗(yàn)證工作,從仿真的 X86 平臺(tái)切換真實(shí)的 ARM 平臺(tái)時(shí),只需要對(duì)所開(kāi)發(fā)的代碼修改編譯器和運(yùn)行時(shí)庫(kù)便可以快速完成從仿真到真實(shí)平臺(tái)的轉(zhuǎn)換過(guò)程;對(duì)于用戶學(xué)習(xí)而言,OE 所提供的 ARM 側(cè)程序也可以通過(guò)改編譯器和運(yùn)行時(shí)庫(kù)在開(kāi)發(fā)服務(wù)器上加以使用。
避免多人共享同一物理開(kāi)發(fā)板時(shí)帶來(lái)的環(huán)境沖突問(wèn)題 物理開(kāi)發(fā)板屬于臨界資源,其上的系統(tǒng)版本在某一時(shí)刻是確定而且是唯一的。如果不同人在開(kāi)發(fā)時(shí)所依賴的系統(tǒng)版本不同,那么得不到系統(tǒng)版本滿足的開(kāi)發(fā)人員便無(wú)法進(jìn)行開(kāi)發(fā)工作。而仿真環(huán)境是通對(duì)通過(guò) docker image 的版本加以區(qū)分的,其獨(dú)立且可以通過(guò) DOCKER 容器構(gòu)建多個(gè)相同或不同的仿真環(huán)境,如此一來(lái),不同開(kāi)發(fā)者對(duì)系統(tǒng)版本的依賴便可得到解決。
數(shù)據(jù)回灌仿真
為代碼調(diào)試提供便利 在開(kāi)發(fā)環(huán)境中同時(shí)存在了業(yè)務(wù)源代碼、編譯的目標(biāo)程序以及 X86 平臺(tái)調(diào)試工具 gdb??梢詫?duì)業(yè)務(wù)代碼逐行進(jìn)行襠部調(diào)試,加速功能 bug 的排查。
1.3 仿真系統(tǒng)的優(yōu)缺點(diǎn)
仿真系統(tǒng)包括方便快捷、成本低廉、工作效率高等諸多優(yōu)點(diǎn),但是每一個(gè)事物都有其兩面性,仿真系統(tǒng)也存在一定缺點(diǎn)。在 征程6 開(kāi)發(fā)平臺(tái)中,仿真系統(tǒng)的缺點(diǎn)包括:
性能一致性 因?yàn)樘囟I(yè)務(wù)場(chǎng)景需要,真實(shí)開(kāi)發(fā)板在設(shè)計(jì)時(shí)引入了特定加速硬件以加速計(jì)算過(guò)程,而仿真所依賴的開(kāi)發(fā)機(jī)一般是為通用計(jì)算而設(shè)計(jì)的普通 PC 機(jī),并不包含真實(shí)開(kāi)發(fā)板所具備的加速硬件。所以這里的仿真更多是功能上的仿真。當(dāng)然,顯卡作為普通計(jì)算機(jī)組件在很多 PC 機(jī)上是配備了的,同時(shí)顯卡也是AI加速的主要器件之一,在接口仿真實(shí)現(xiàn)時(shí)可以通過(guò)顯卡加速。然而這里仍然有兩個(gè)方面需要考慮:1)顯卡的加速效果與顯卡配置相關(guān),同時(shí)即使配置上去了是否可以達(dá)到真實(shí)的開(kāi)發(fā)板上特別設(shè)計(jì)過(guò)的加速硬件也很難說(shuō)。2)仿真有很多個(gè),其加速代碼的質(zhì)量和開(kāi)發(fā)時(shí)間也是逐步進(jìn)行的,所以同樣硬件條件下隨著工具鏈版本迭代加速效果也可能是不同的。
功能一致性 因?yàn)榉抡嫦到y(tǒng)和被仿真系統(tǒng)在計(jì)算架構(gòu)、操作系統(tǒng)等方面存在差異,同樣的數(shù)據(jù)輸入在經(jīng)過(guò)處理后得到的輸出結(jié)果可能存在些許差異,但差距一般很小。
開(kāi)發(fā)投入 因?yàn)闃I(yè)務(wù)代碼的最終運(yùn)行環(huán)境(arm架構(gòu))和 仿真環(huán)境間的差異,需要在開(kāi)發(fā)階段構(gòu)建兩套編譯腳本: X86 平臺(tái)編譯腳本 For 仿真; arm 平臺(tái)編譯腳本 For 最終的板端部署。
系統(tǒng)特性約束 仿真的本質(zhì)是 X86 平臺(tái)上“模仿”出接口以實(shí)現(xiàn)在 ARM 平臺(tái)上的功能。在 X86 仿真平臺(tái)下無(wú)法使用 ARM 平臺(tái)下特有的功能和指令,如 Neon。因此,功能仿真過(guò)后在最后的實(shí)車(chē)部署階段,還是需要依賴工程的深度優(yōu)化(Neon 加速等),還會(huì)涉及對(duì)齊等工作。
2. 仿真在 征程6 計(jì)算平臺(tái)的實(shí)現(xiàn)2.1 仿真框架概述
在 征程6 開(kāi)發(fā)平臺(tái)中,仿真功能是通過(guò)地平線統(tǒng)一異構(gòu)計(jì)算框架 HUCP(Horizon Unified Computing Platform)來(lái)實(shí)現(xiàn)的。相對(duì)于 征程5 的 DNN 預(yù)測(cè)庫(kù),HUCP 支持自定義算子(Plugin)并 新增了數(shù)學(xué)計(jì)算庫(kù)(FFT、BLAS等)、CV 庫(kù)等的封裝, 進(jìn)行了功能和邊界的擴(kuò)展以提供計(jì)算圖全圖(視頻通路 + 前/后處理 + 多模型串街 + 自定義計(jì)算)表達(dá)的能力,支持將全圖一起送入下游編譯。
注:為支持全圖表達(dá)能力,在 Torch 開(kāi)發(fā)環(huán)境新增 FLAP 和 LEAP 兩套自定義計(jì)算組件,支持通過(guò) DSL、Numba、Triton 等算法友好的 Python 編程方式,添加模型前/中/后的自定義計(jì)算,包括:
在 Pyramid、GDC 等硬件 IP 功能上拆分封裝出的各種 OP(LEAP)
CPU/ VPU 上實(shí)現(xiàn)的自定義計(jì)算(前/后處理,自定義算子等)(FLAP)
2.2 仿真實(shí)現(xiàn)原理
上圖 是 征程6 開(kāi)發(fā)平臺(tái)感知部署框架的構(gòu)成,可以看出 HUCP 介于應(yīng)用程序和運(yùn)行平臺(tái)之間,是應(yīng)用程序和運(yùn)行平臺(tái)之間的“中間件”。對(duì)上,HUCP 為上層應(yīng)用開(kāi)發(fā)設(shè)計(jì)和提供了一套統(tǒng)一的應(yīng)用程序編程接口(API);對(duì)下,隱蔽不同 CPU 架構(gòu)在接口實(shí)現(xiàn)上帶來(lái)的差異,不同架構(gòu)的運(yùn)算平臺(tái)調(diào)用各自的系統(tǒng)接口對(duì) HUCP 提供的編程接口進(jìn)行實(shí)現(xiàn)和編譯以生成不同架構(gòu)的動(dòng)態(tài)鏈接庫(kù)供編譯器連接時(shí)調(diào)用。
3. 仿真哪些東西
仿真功能依賴于統(tǒng)一異構(gòu)計(jì)算框架 HUCP,而 HUCP 所提供的應(yīng)用程序編程接口在實(shí)現(xiàn)時(shí)不僅調(diào)用了 BPU、CPU、DSP 等常規(guī)硬件資源,同時(shí)也包含對(duì) Pyramid、GDC、Stitch、Codec 等視頻通路上的硬件 IP(不包含非計(jì)算的 camera 接入部分)資源的利用。在 征程6 SoC 上這些硬件是真實(shí)存在的,在 X86 平臺(tái)下,通過(guò)接口的 X86 平臺(tái)實(shí)現(xiàn)對(duì)這些硬件進(jìn)行了仿真,從而透明化了不同平臺(tái)間接口調(diào)用的差異。對(duì)于應(yīng)用程序開(kāi)發(fā)者而言,在面向接口編程的思想指導(dǎo)下僅需在編譯階段選擇對(duì)應(yīng)平臺(tái)的編譯工具和編譯庫(kù)即可。
4. 功能如何使用4.1 基礎(chǔ)使用環(huán)境準(zhǔn)備
仿真功能作為算法工具鏈發(fā)布套件的一部分,其所依賴的環(huán)境已經(jīng)集成在工具鏈發(fā)布(v3.0.12之后)的 docker 鏡像中,仿真功能基礎(chǔ)示例(horizon_j6_open_explorer_xxx-py38_20240430/samples/ucp_tutorial/dnn/basic_samples/code/00_quick_start)也包含在工具鏈每次發(fā)版的 OE 包中。因此跟使用AI工具鏈其他功能一樣,在開(kāi)始使用仿真功能之前,需要先參考工具鏈?zhǔn)褂檬謨?cè) load 算法工具鏈的 docker 鏡像,然后根據(jù)鏡像構(gòu)建映射了 OE 包的用戶容器。 用戶容器啟動(dòng)后便可參考基礎(chǔ)示例體驗(yàn)仿真功能了.
注:詳細(xì)的工具鏈?zhǔn)褂檬謨?cè) docker 基礎(chǔ)環(huán)境準(zhǔn)備和 docker 使用,請(qǐng)參考。
4.2 業(yè)務(wù)代碼編寫(xiě)
UCP 為應(yīng)用程序開(kāi)發(fā)者提供了統(tǒng)一的業(yè)務(wù)編程接口,在面向接口編程的思想指導(dǎo)下透明化了不同平臺(tái)間接口調(diào)用的差異。因此,在業(yè)務(wù)代碼構(gòu)建上,不同運(yùn)行平臺(tái)的業(yè)務(wù)代碼并無(wú)差別,開(kāi)發(fā)者可將注意力集中在業(yè)務(wù)邏輯之上,待業(yè)務(wù)代碼構(gòu)建完成后開(kāi)發(fā)者僅需在編譯時(shí)選擇對(duì)應(yīng)平臺(tái)的編譯工具和編譯庫(kù)即可完成編譯進(jìn)行業(yè)務(wù)測(cè)試。 注:如果想在基于 ARM 架構(gòu)的開(kāi)發(fā)板平臺(tái)上通過(guò) ARM 平臺(tái)下特有的功能和指令(如 Neon)加速業(yè)務(wù)處理過(guò)程,同時(shí)基于仿真調(diào)試業(yè)務(wù)邏輯,可通過(guò)編譯宏區(qū)別平臺(tái)分別進(jìn)行編程,由此帶來(lái)的工作量和兩個(gè)環(huán)境下數(shù)據(jù)對(duì)齊問(wèn)題需要用戶自己評(píng)估。
4.3 編譯腳本構(gòu)成
仿真平臺(tái)和被仿真平臺(tái)的 CPU 架構(gòu)和指令集是不同的,所以說(shuō)使用的編譯器和運(yùn)行時(shí)庫(kù)也會(huì)存在差異。業(yè)務(wù)代碼構(gòu)建完成后,進(jìn)行編譯時(shí),需要針對(duì)不同的目標(biāo)運(yùn)行平臺(tái)選擇正確的編譯器和運(yùn)行時(shí)庫(kù),下下述為X86 仿真平臺(tái)和 ARM 目標(biāo)開(kāi)發(fā)板平臺(tái)在部署工程實(shí)現(xiàn)時(shí)依賴庫(kù)和腳本間的差異(來(lái)自 OE 包基礎(chǔ)實(shí)例程序horizon_j6_open_explorer_xxx-py38_20240430/samples/ucp_tutorial/dnn/basic_samples/code/00_quick_start)。
依賴庫(kù)差異
SHELL 編譯腳本差異
CMakeLists.txt 腳本中 ARM&X86 差異
5. 仿真案例5.1 快速入門(mén)
該示例代碼展示了 x86 仿真平臺(tái)和 arm 開(kāi)發(fā)板平臺(tái)的基本腳本邏輯和編譯邏輯,用戶可以以此參照為自己的工程添加仿真構(gòu)建邏輯。
5.2 擴(kuò)展工程案例
OE 包原 ai_benchmark 示例為方便向開(kāi)發(fā)者提供參考模型后處理邏輯,構(gòu)建了插件式“數(shù)據(jù)處理+模型推理+推理結(jié)果處理與展示”業(yè)務(wù)流框架。為方便開(kāi)發(fā)者使用仿真功能進(jìn)行自有模型的后處理代碼調(diào)試,最大限度復(fù)用已有的插件式雨霧流程框架,我們對(duì)原有的 ai_benchmark 工程進(jìn)行了部分修改并添加了仿真編譯腳本,開(kāi)發(fā)者可以參考擴(kuò)展工程中 fcos 的后處理代碼邏輯(類(lèi)繼承關(guān)系)構(gòu)建適配自己模型的后處理文件并在配置中加以引用。因擴(kuò)展工程中編譯腳本是自動(dòng)進(jìn)行新增文件索引和編譯的,用戶只需要將自己擴(kuò)展的后處理代碼文件保存至與 fcos 的后處理代碼文件統(tǒng)計(jì)的 method 目錄(注意頭文件和源文件分別存放)下進(jìn)行編譯即可,無(wú)需進(jìn)行他們腳本代碼的開(kāi)發(fā)。
擴(kuò)展工程相對(duì)于 OE 包中原 ai_benchmark 示例代碼有如下差異:
保留了原 ai_benchmark 示例代碼中所有的插件式框架代碼,包括推理數(shù)據(jù)準(zhǔn)備、模型推理代碼以及與后處理、輸出四者間的調(diào)度邏輯。
刪除了源代碼中大部分模型的后處理邏輯,僅保留了 fcos 的部分以作示例。
添加仿真編譯腳本并對(duì)原有的 CMakeLists.txt 進(jìn)行變動(dòng)同時(shí)對(duì)測(cè)試運(yùn)行腳本 env.sh 微調(diào)以適應(yīng)仿真場(chǎng)景需要。
用戶可以參考 fcos 的后處理邏輯可針對(duì)自己的模型構(gòu)建后處理進(jìn)行功能仿真驗(yàn)證。
6. 其他說(shuō)明6.1 與 征程5 仿真對(duì)比
J征程5 仿真功能提供的是一套基于 GPU 環(huán)境的 QAT 定點(diǎn)模型(紅框1)推理方式,但因?yàn)樵撃P臀挥诰幾g之前,所以端側(cè) runtime 數(shù)據(jù)類(lèi)型的變化并不能同步體現(xiàn)在 x86 端。而相同的場(chǎng)景下,征程6 使用新一代 HBDK4 工具鏈對(duì)其進(jìn)行了標(biāo)準(zhǔn)化,如下圖所示,編譯環(huán)節(jié)會(huì)同時(shí)產(chǎn)出一個(gè)上板模型和一個(gè)可 GPU 推理的仿真模型(紅框2),SoC 和 x86 端可以使用完全相同的 API 無(wú)感地加載和推理這兩個(gè)模型。因此,在 征程6 工具鏈中,算法同學(xué)能夠在 x86 環(huán)境下快速、便捷地完成原型驗(yàn)證、回灌仿真等工作,節(jié)約大量算法/工程對(duì)齊的開(kāi)銷(xiāo),后續(xù)也能絲滑地遷移至 SoC 環(huán)境(只需替換模型文件,基于交叉編譯工具重新編譯工程即可),從而極大地提升了生產(chǎn)開(kāi)發(fā)效率。
*博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請(qǐng)聯(lián)系工作人員刪除。