大家好,這期測評一款國產(chǎn)芯片(龍鷹一號siengine SE1000)。 主要側(cè)重其中的AI能力部分,圍繞著“如何在開發(fā)板上跑一個完整AI應(yīng)用”這一主題來寫,前期根據(jù)官方提供的信息編譯簡單app,跟大家一起熟悉流程,知道如何配置開發(fā)環(huán)境、要用到哪些工具、操作流程是啥。后面接著就跑復(fù)雜一點的AI模型,講解軟件SDK中每個模塊(parser,quant,Gbuilder,simulator,profiler)的作用,逐代碼進行講解,以及如何DIY適配自己的需求等,so, let’s go!
1.硬件信息
龍鷹一號是一顆國產(chǎn) 7nm 智能座艙芯片,擁有 8 核 CPU 和 14 核 GPU,CPU算力能夠達到90~100K DMIPS,GPU算力900+GFLOPS,NPU算力達到8TOPS,對標(biāo)的是高通的8155,從安兔兔跑分來看確實數(shù)據(jù)差不多,目前已知是搭載在吉利汽車旗下領(lǐng)克08(23年9月發(fā)布)車型上
定位是座艙芯片的“龍鷹一號”不僅會負責(zé)中控屏幕的計算與顯示,還會負責(zé)汽車儀表、功能屏幕甚至HUD的顯示。“龍鷹一號”支持輸入11路相機數(shù)據(jù)(遺憾的是截至目前,我仍然無法購買適配好的攝像頭進行應(yīng)用開發(fā)),最高可支持7塊高清顯示屏顯示。 “龍鷹一號”會同時運行三個操作系統(tǒng),分別是儀表的RTOS操作系統(tǒng)、HUD的Linux系統(tǒng)以及中控屏幕的安卓系統(tǒng)(目前提供的SDK默認是使用linux系統(tǒng)的);開發(fā)板是交給第三方的RADXA設(shè)計的,型號為SiRider S1,具體鏈接在這:https://docs.radxa.com/sirider/s1
雖然BOM中的車規(guī)級物料改成了普通物料,但是憑借其扎實的配置(16GB LPDDR5, 128G UFS)還是使得成本達到了千元+級別,比同類的開發(fā)板(RK3588、樹莓派)是要貴上三五百塊的,其實也合理,畢竟RK3588 4核A76,6TopsNPU,450Gops都稍弱于SiRider S1; 由于我們關(guān)注的是AI這一部分,因此固件編譯部分我們就不細說了,因為板子默認就刷了ubuntu的固件,開箱后插上HDMI顯示器,插入鼠標(biāo)鍵盤就可直接開干了!
可以看到,ubuntu分配了4個大核A76+兩個小核A55;內(nèi)容用了12GB,剩下的都分配給FreeRTos了。 如下圖SOC框架圖所示,主要的算力擔(dān)當(dāng)以及視頻編解碼部分我認為足夠驚艷了,用來做NAS,軟路由,平板,電視盒子等應(yīng)用都分分鐘ok的呀!外設(shè)部分同樣如此,接口最多的是UART,IIC跟SPI口,這些都是低速通用接口,因此想要做外設(shè)控制相關(guān)的應(yīng)用的話,指定不是直接去快速控制了(比如FOC無刷電機,一般是需要3PWM接口/電機來進行控制, 而外設(shè)這里只提供了2個),而是通過低速接口間接驅(qū)動外設(shè)模塊了,比如開啟車門,開啟后備箱,開啟雨刮等非實時性要求高的應(yīng)用,嗯,定位非常準(zhǔn)確,所以我們做應(yīng)用的時候盡量去選這三種接口(uart/iic/spi)的封裝較好的獨立模塊就好了。
2. AI知識小科普
好的,背景介紹完畢,那我們現(xiàn)在開始進入AI部分的內(nèi)容吧!在這個大模型百家爭鳴的時代,我相信大家對AI都有一定的了解吧!
“AI就是人工智能呀!” “AI就是像人一樣跟你對話!” “AI就能將你的口頭描述轉(zhuǎn)化成實際的圖片!”
其實除了這些高大上的AI之外,你每天使用的打卡器(打工人必備)、刷臉機、以及監(jiān)控攝像頭、麥克風(fēng)等都含有AI技術(shù)在里面,你肯定好奇:
AI到底是怎么跑在具體的硬件設(shè)備上的呢?
假如我自己有個idea想要實現(xiàn)跑在具體硬件上,而不是通用PC上,我又該怎么做呢? 接下來我將為你一一解答。 類似于如何將大象塞入一個冰箱的問題,如何做一個AI應(yīng)用的頂層流程是這樣的,
第一步,你得有個天才般或者腦殘般的想法,針對這個想法提出需求;
第二步,基于需求訓(xùn)練一個模型出來;
第三步,將模型部署到具體的硬件上面去。
第一步跟第二步不是我們這次的主要學(xué)習(xí)內(nèi)容,接下來簡單帶過。 AI模型是由智力絕頂?shù)?a target="_blank">算法工程師們訓(xùn)練出來的,俗稱煉丹。煉丹的丹爐各式各樣,煉丹界主流的就是Tensorflow跟Pytorch;
這顆丹內(nèi)部由一堆的節(jié)點組成,節(jié)點本質(zhì)就是一堆數(shù)據(jù)加處理這堆數(shù)據(jù)的計算方法,如下圖所示:
在個人PC上或者服務(wù)器上,想要讓整個模型跑起來是非常簡單的,因為,整個基建部分都被各大廠商(主要是英偉達)給搭建好了,我們直接使用就好了,這就好比我們要找個地方住一晚,最方便且安全的選擇就是去找現(xiàn)成的五星級酒店(缺點顯然是*),而不是去自己建房子然后住進去。而且,這些AI部署的相關(guān)服務(wù)是被全球開發(fā)者多年驗證過的,好用、方便。但是,一旦你想部署到某個具體的、特定的、不通用的硬件上時,之前那一套就完全沒用了,得“入鄉(xiāng)隨俗”,用與特定硬件相匹配的軟件棧。具體到我們這里,就是周易SDK這一套軟件棧,想把AI模型跑到板子上我們就得學(xué)習(xí)這一套SDK的使用、開發(fā)方法。
3. 周易SDK介紹
老規(guī)矩,還是先看下整體流程:首先,假設(shè)現(xiàn)在已經(jīng)拿到一個訓(xùn)練好的模型model了,比如model.onnx,
這個模型只能是tensoflow/pytorch/caffe/mxnet/onnx格式的
然后我們用SDK中的工具鏈對模型model.onnx進行編譯得到aipu.bin,就像這樣aipubuild build.cfg 最后將這個aipu.bin封裝到應(yīng)用程序APP中, 放到到板子上運行即可;
簡單來說,流程跟你gcc編譯c代碼是一樣的,只是參數(shù)格式不一樣而已,這里的輸入是模型,輸出的是NPU支持的bin可執(zhí)行文件; 此外,調(diào)bug有debugger可用,性能問題可以用profiler,沒有具體硬件可以用simulator模擬硬件來跑,當(dāng)然了IDE圖形化操作界面也是有的。 后續(xù)的課程中我將就每一個模塊結(jié)合SDK文檔進行詳細講解+逐代碼分析。這章回,我們先跟著教程走一遍流程,認識認識代碼框架。
4. 操作流程+代碼框架初識
第一步是搭建開發(fā)環(huán)境,跟著這個教程:https://docs.radxa.com/sirider/s1/app-development/zhouyi\\\_npu一步一步來,就能把整個環(huán)境搭建流程跑通(windows直接用WSL2即可)。 第二步是編譯模型,在x86 PC段進行模型編譯,還是上面鏈接(看編譯部分)
看到有如上文件,第一步是生成量化校準(zhǔn)集,因為我們的原始模型是fp32的,但NPU是不支持fp32的,因此我們需要將其量化到int8/int16。 一個fp32的值量化到int8,在量化領(lǐng)域有非常多的算法來實現(xiàn),我們這里使用的是PTQ(假設(shè)不理解也不要緊,后面我會專門講解一下量化相關(guān)的內(nèi)容,因為這部分代碼開源了,因此甚至對著開源的代碼進行code級講解的)進行量化。 量化需要準(zhǔn)備一個數(shù)據(jù)集進行數(shù)據(jù)范圍分布的采集過程,假如不理解為什么要這一步也不要緊,知道有這個流程就行了,后面講量化算法的時候就明白了。
python3generate_calibration_data.py
我們看下代碼的實現(xiàn)
可知就是從原訓(xùn)練代碼里面摳出來的初始化代碼,處理的就是當(dāng)前目錄下的images圖集,得到的是對應(yīng)的npy格式對應(yīng)數(shù)據(jù); 緊接著產(chǎn)生輸入數(shù)據(jù):
python3 generate\_input\_binary.py
這里稍微解釋下,首先我們需要拿到一個量化參數(shù),也就是scale,這個值是從量化階段拿到的,量化產(chǎn)生文件之一就是*.json文件,從中尋找即可。 然后將輸入圖像量化成uint8格式的數(shù)據(jù),然后轉(zhuǎn)置一下得到NHWC格式的輸入,此時即可用作模型的輸入了(因為NPU支持的外部輸入layout就是NHWC),
vim ./resnet50/build.cfg
第二行的編譯mode有兩種,第一種是build,即編譯完后輸出aipu.bin給板子跑的,第二種是run,即編譯完后可以直接在服務(wù)器上、本地電腦上模擬硬件跑(simulator)。 編譯的流程有三大步驟:
解析模型;
量化
編譯執(zhí)行
Parser的作用是將標(biāo)準(zhǔn)的通用模型(ONNX、TF、pytorch等)轉(zhuǎn)換為內(nèi)部專用的IR;Input\_data\_format 指的是輸入的data\_layout,我們在前面的構(gòu)造輸入數(shù)據(jù)時選的就是NHWC,所以這里填NHWC;模型名字model\_name,標(biāo)準(zhǔn)填就好了;Detection\_postprocess填后處理的算子名,像檢測模型都是有后處理部分的,我們對應(yīng)填,當(dāng)然也可以選擇不填,直接在CPU端做后處理;其他都是所見即所得,除了注意input的配置即可,這是輸入tensor的名字,用netron打開onnx model即可得到; Optimizer中dataset字段就是指定數(shù)據(jù)集的格式,前面我們構(gòu)造的是numpy格式的,所以這里填NumpyDataset;主要注意下bits部分的設(shè)置,因為一般的玩法只有這里有可調(diào),來粗粒度的調(diào)整精度/性能的權(quán)衡,當(dāng)然了,后期大家想玩的話我就帶大家進行代碼級的玩法。 Gbuilder部分就是直接編譯的,profile就是輸出perf性能數(shù)據(jù)的,會一定程度上影響性能,因此在debug階段使用即可;target指的是硬件的版本號,這里是固定的填Z2\_1104即可,這一塊沒有什么需要額外配置的,當(dāng)然具體的每一個參數(shù)我們可以到后面的Gbuilder章節(jié)進行詳細解說,這里堪堪帶過。 按照官方教程直接編譯:
可以看到Gbuilder的版本是5.3.2194,開始進行解析模型了,這里由于我使用的是WSL2沒有cuda,所以會比較慢
解析完后輸出如上,此時就得到了我們NPU所需的中間表達格式(IR)了
得到IR后,我們會先做一個檢查,看解析出來的IR格式以及graph的連接關(guān)系是否合理,再初步做一個float graph級的圖優(yōu)化,可以看到這里優(yōu)化掉了一個Transpose層;
緊接著就進入量化階段了,可以看到整個流程里面有非常多的階段,每個階段都有在做特定的事,這里涉及的內(nèi)容比較多,我們暫且按下不表,后面我們將會對照源碼進行一一解說(有機會的話,還會跟業(yè)界做的比較好的ppq框架進行相關(guān)的對比)。 這里主要關(guān)注下最后的輸出scale,用來在后處理階段使用的;以及輸出tensor的cosine值,這個值是反應(yīng)模型精度的。 總之,經(jīng)過量化后,我們就得到了定點格式的IR,此IR經(jīng)過編譯后,可以直接在NPU硬件上跑起來的。
由于量化過程中也會有圖結(jié)構(gòu)的改變,因此這里做完量化后也需要執(zhí)行圖檢查以及圖優(yōu)化步驟的。
到這里后,終于開始編譯模型了,這個部分主要內(nèi)容包括給graph中的node進行算子匹配,整網(wǎng)內(nèi)存分配及優(yōu)化,多核調(diào)度,硬件底層圖優(yōu)化等。比如上圖中的aipu\_plugin就是算子,每個標(biāo)準(zhǔn)算子都有好幾種底層硬件實現(xiàn)(opencl、asm),根據(jù)特定機制進行整網(wǎng)全局匹配。
這里是layout的調(diào)度部分,目標(biāo)就是盡可能減少途中l(wèi)ayoutconvert的個數(shù),這個部分也是個最優(yōu)化的問題,細講下去也就停不下來了,將來有機會我們詳細說說。
最后就是內(nèi)存部分的內(nèi)容了,整網(wǎng)所需的內(nèi)存是26.547MB,代碼段、RO段、desc段(這個不常見,這是底層算子的特定格式),DataBss都是標(biāo)準(zhǔn)格式。最后可以看到是有個SRAM的優(yōu)化的,這個是NPU內(nèi)部的一個快速靜態(tài)存儲區(qū)域,用來緩存node間的featuemap的,不僅能降低footprint還能提升性能。 好了,到這里,模型終于編好了,我們看下編出了些啥:
第一個文件就是我們NPU需要的可執(zhí)行文件,也就是在build.cfg指定的輸出文件;
第二個文件就是build配置腳本;
第三個時量化校準(zhǔn)數(shù)據(jù)集;
第四個時輸入數(shù)據(jù),第五個是輸入數(shù)據(jù)對應(yīng)的圖片;
第六個、第七個就是parser后得到的浮點IR文件(圖結(jié)構(gòu)文件以及權(quán)重文件);
第八個是量化產(chǎn)生的文件,有啥量化的問題你去這個文件內(nèi)查查即可;
第九個、第十個是量化后產(chǎn)生的定點IR;
第十一個、第十二個文件是定點IR經(jīng)過圖優(yōu)化后的精簡IR;
第十三個、第十四個是浮點IR經(jīng)過圖優(yōu)化后產(chǎn)生的IR;
第十五個文件是驗證集的統(tǒng)計信息,有這個文件后,下次編譯就不用繼續(xù)跑耗時的校準(zhǔn)過程了;
第十六個文件是原始的resnet50.onnx模型;
第十七個文件是 run的時候(不是跑在NPU上而是在PC上跑simulator用的)用的cfg配置文件;
可以看到除了紅框內(nèi)的東西外,其余都是差不多的。 現(xiàn)在我們生成了模型的bin文件,但還不是最終應(yīng)用的可執(zhí)行文件,最終的應(yīng)用是調(diào)用我們剛剛生成的模型,這部分的代碼在這:
Aiputest就是應(yīng)用程序的邏輯部分,umd里面就是一堆面向用戶的庫函數(shù),庫函數(shù)里面是直接調(diào)用驅(qū)動,以及環(huán)境構(gòu)建的(待會我們直接進去看下代碼結(jié)構(gòu))。 按照軟件工程的結(jié)構(gòu),我們先查看頂層的CMakeLists.txt文件,獲取到的信息如下:
Cmake版本要搞對噢,UMDSRC變量要仔細檢查對路徑哈!設(shè)置好交叉編譯器的路徑,設(shè)置好最終的輸出路徑; 頂層配置好參數(shù),然后直接add\_subdirectory讓子目錄自己去根據(jù)參數(shù)執(zhí)行具體的編譯任務(wù)。 我們先看umd文件夾,里面直接Linux-driver/driver/umd的源碼拉進來編成動態(tài)庫,給后面的應(yīng)用aiputest來動態(tài)鏈接。
Aiputest是個非常簡單的應(yīng)用,因此我們只需要將umd頭文件引進來,umd動態(tài)庫鏈接進來,直接編譯即可。
我們看下main.cpp文件中的內(nèi)容結(jié)構(gòu):
其中UMD相關(guān)的功能全都封裝到standard\_api.h接口文件中了,接下來的代碼無非就是初始化環(huán)境,開啟NPU任務(wù),接受返回數(shù)據(jù),清理“戰(zhàn)場”(環(huán)境)等標(biāo)準(zhǔn)步驟,沒啥特殊的,具體參數(shù)解析可以查文檔或者等我后續(xù)的文章逐代碼解析。 (ps. 其中可以看到雖然是c++環(huán)境,但是用的都是非常標(biāo)準(zhǔn)的c代碼風(fēng)格,挺好的,非常適合用來直觀理解執(zhí)行流程。)
研究代碼發(fā)現(xiàn)這里有dump profiler的邏輯;
應(yīng)用中也是有profiler的程序的,其中result\_bin\_path就是上面代碼中輸出的PerfData.bin文件,因此我們可以留個坑,將來講講如何用這個來分析模型的性能優(yōu)化。 好了,視角拉回,我們直接編譯得到了對應(yīng)的文件,
按照官方教程的步驟將文件scp到板子后,直接就可以跑啦~
-
芯片
+關(guān)注
關(guān)注
454文章
50451瀏覽量
421943 -
開發(fā)板
+關(guān)注
關(guān)注
25文章
4956瀏覽量
97213 -
SDK
+關(guān)注
關(guān)注
3文章
1028瀏覽量
45782
原文標(biāo)題:開發(fā)板測評|芯擎SiRider S1初探流程·流暢
文章出處:【微信號:Ithingedu,微信公眾號:安芯教育科技】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論