:從環(huán)境到調(diào)優(yōu)全攻略)
Atlas 300V 24G這塊卡最近在安防視頻分析和邊緣計算圈子里討論度很高。我搜了下后臺數(shù)據(jù)atlas部署yolo和atlas 300v 24g 是運算加速卡嗎這兩組詞被問得最多說明不少人拿到卡之后第一件事就是想跑目標(biāo)檢測卻又對這塊卡的定位和部署鏈路一知半解。這篇文章我不講虛的就圍繞我實際把YOLOv5部署到Atlas 300V 24G上的完整經(jīng)歷來寫從硬件選型到模型轉(zhuǎn)換再到性能調(diào)優(yōu)把能復(fù)現(xiàn)的步驟和踩過的坑一并交代清楚。先回答那個被問了無數(shù)次的問題Atlas 300V 24G確實是運算加速卡但它是推理加速卡不是訓(xùn)練卡更不是用來跑CUDA的GPU。搞清楚這一點后面所有部署思路都不會走偏。1. Atlas 300V 24G到底是一張什么卡1.1 先搞懂Atlas家族的定位華為Atlas產(chǎn)品線特別容易把人繞暈300I、300V、300T、200 DK、500 A2名字長得像用途差很多。我拿手里這批卡梳理一下一張表就能看明白型號芯片定位典型場景Atlas 300I昇騰310P純推理加速卡通用深度學(xué)習(xí)推理、OCR、分類Atlas 300V昇騰310P視頻推理加速卡視頻結(jié)構(gòu)化、智能安防、目標(biāo)檢測跟蹤Atlas 300T昇騰910訓(xùn)練加速卡模型訓(xùn)練、大規(guī)模并行計算Atlas 200 DK昇騰310開發(fā)者套件學(xué)習(xí)、原型驗證、嵌入式開發(fā)Atlas 500 A2昇騰310P智能邊緣小站邊緣盒子、一體機方案我第一次拿到Atlas 300V 24G的時候第一反應(yīng)是找它的CUDA核心數(shù)找了一圈發(fā)現(xiàn)這思路本身就有問題。昇騰芯片用的是達芬奇架構(gòu)根本不存在CUDA的概念算力單位是TOPS衡量的是INT8整數(shù)運算能力。300V Pro這顆310P芯片的INT8算力大約在140 TOPS相當(dāng)于什么概念呢一張中高端GPU能跑的推理負載它基本都能接得住但功耗只有幾十瓦。1.2 它確實是運算加速卡但跟GPU玩法完全不一樣回到搜索熱詞的問題本身Atlas 300V 24G是運算加速卡這一點沒有任何疑問。它專門干的就是矩陣運算、卷積運算、神經(jīng)網(wǎng)絡(luò)推理這些重計算的活。24G這個顯存容量在推理卡里屬于大塊頭我記得第一次用npu-smi看顯存占用時還愣了一下——一張推理卡給到24G意味著你可以同時塞進去好幾個模型或者跑那種吃顯存的超大batch推理這在純推理場景里是很奢侈的配置。但要注意它和GPU有本質(zhì)區(qū)別。GPU是通用并行計算架構(gòu)什么都能跑靈活但功耗大Atlas 300V是專用推理架構(gòu)只能跑CANN生態(tài)里的模型格式好處是能效比高、單位成本低壞處是你得適應(yīng)它的工具鏈。很多從GPU平臺遷移過來的朋友上來就習(xí)慣性想用PyTorch直接推理這是最大的認知誤區(qū)。1.3 300V和300I、300T別買錯300V和300I都用310P芯片算力基本一致但300V多了一個殺手锏——硬件視頻編解碼能力。DVPP硬件單元可以硬解H.264/H.265視頻流直接輸出YUV數(shù)據(jù)給AI處理器做分析全程不占CPU。這一點決定了300V特別適合接攝像頭視頻流做實時分析而300I更適合以圖片為輸入的通用推理場景。我做視頻結(jié)構(gòu)化項目的時候一路1080P視頻流在GPU平臺上需要額外吃不少CPU去做解碼換上300V之后解碼直接被硬件接管CPU占用肉眼可見地降了下來。如果你的核心業(yè)務(wù)是讀視頻幀→做檢測→輸出結(jié)果300V就是那個專門為你優(yōu)化的答案。至于300T那是面向訓(xùn)練場景的四卡八卡互聯(lián)做分布式訓(xùn)練用的單張插在PCIE槽上跑推理屬于暴殄天物。選型的時候把訓(xùn)練和推理這兩條線分開想基本不會買錯。2. 為什么YOLO部署選Atlas的人越來越多2.1 視頻流處理是300V的甜點區(qū)YOLO系列模型在安防和工業(yè)質(zhì)檢領(lǐng)域處于絕對統(tǒng)治地位而這些場景里絕大部分輸入都是視頻流。前端攝像頭不斷產(chǎn)生H.264/H.265碼流傳統(tǒng)做法是拉流后在CPU上解碼成幀再用GPU逐幀推理。這種方式有個隱性問題多路視頻并發(fā)時CPU解碼會成為瓶頸解碼速度跟不上推理速度GPU在那里空轉(zhuǎn)等數(shù)據(jù)。Atlas 300V的設(shè)計思路是直接把解碼和推理放進同一張卡里。DVPP硬件解碼出來的YUV數(shù)據(jù)可以在顯存內(nèi)直接作為AI計算的輸入不走PCIe回傳省掉了大量數(shù)據(jù)搬移開銷。我在實際測試中單卡接8路1080P視頻流做YOLOv5s實時檢測CPU占用率能控制在10%以內(nèi)這是GPU方案很難做到的。2.2 能效比和單路成本優(yōu)勢明顯數(shù)據(jù)中心和機房對功耗有硬性指標(biāo)。一張GPU推理卡動輒兩三百瓦配套的散熱、電源、機柜空間都得跟著升級。Atlas 300V的最大功耗大概在72W左右一張GPU的功耗能供電給三四張300V單路視頻流的硬件成本攤薄下來很有吸引力。還有個容易被忽略的點AI推理芯片的TCO不僅看硬件采購價還要看TDP和部署密度。同樣的4U機箱裝GPU可能只能塞4張卡裝300V這種低功耗卡可以塞滿整體算力密度翻倍。對于做安防平臺或者智慧園區(qū)的集成商來說這個賬很好算。2.3 從GPU遷移到Ascend要面對的現(xiàn)實既然有這么多優(yōu)勢為啥大家還是習(xí)慣用GPU因為遷移成本是真實的。CUDA生態(tài)成熟到近乎無腦PyTorch寫完了直接跑昇騰這邊你要面對的是ONNX導(dǎo)出、ATC模型轉(zhuǎn)換、AscendCL接口調(diào)用、算子兼容性排查每一步都可能出問題。所以理性看待這件事很重要。如果你的業(yè)務(wù)是快速原型驗證、模型頻繁迭代、算法團隊沒有專門做部署優(yōu)化的人GPU依然是最省心的選擇。但如果你的業(yè)務(wù)是相對固定的推理負載比如就那幾個YOLO模型版本場景明確、并發(fā)量大、對功耗和成本敏感那花一兩周時間把CANN這套工具鏈吃透長期回報非??捎^。我自己的判斷標(biāo)準(zhǔn)是單模型持續(xù)運行時長超過三個月就值得遷移到Atlas。3. 部署第一步環(huán)境準(zhǔn)備與工具鏈安裝3.1 硬件連接與固件驅(qū)動確認先說硬件安裝。Atlas 300V是標(biāo)準(zhǔn)PCIe全高卡外形尺寸和GPU差不多插到服務(wù)器的PCIe x16槽位上即可。需要注意供電我用的服務(wù)器是雙電源冗余配置單卡功耗雖然低但多卡滿載時還是建議確認電源余量充足。裝好卡之后第一件事是確認系統(tǒng)能識別到設(shè)備。在Ubuntu服務(wù)器上執(zhí)行l(wèi)spci | grep -i ascend npu-smi infonpu-smi是昇騰的設(shè)備管理工具類似于NVIDIA的nvidia-smi能看到芯片溫度、功耗、顯存占用、算力利用率。我當(dāng)時新卡插上去執(zhí)行npu-smi info報了Driver not initialized不用慌說明驅(qū)動還沒裝。驅(qū)動和固件的安裝包在昇騰社區(qū)下載中心記得要匹配操作系統(tǒng)的內(nèi)核版本。3.2 CANN工具鏈怎么裝才不踩坑CANN是昇騰的計算架構(gòu)相當(dāng)于CUDA在GPU生態(tài)里的位置。必須裝沒有它什么模型都跑不起來。安裝的核心邏輯是先驅(qū)動后固件再CANN工具包順序不能亂。我建議用root權(quán)限裝完所有基礎(chǔ)依賴后再切換到普通用戶跑推理避免各種權(quán)限引發(fā)的玄學(xué)問題。安裝命令大致如下# 安裝驅(qū)動注意包名要與內(nèi)核版本匹配 ./Ascend-hdk-310p-npu-driver_xxx_linux-aarch64.run --full # 安裝固件 ./Ascend-hdk-310p-npu-firmware_xxx.run --full # 安裝CANN toolkit ./Ascend-cann-toolkit_xxx_linux-aarch64.run --install安裝完成后配置環(huán)境變量把以下內(nèi)容加到~/.bashrcsource /usr/local/Ascend/ascend-toolkit/set_env.sh source /usr/local/Ascend/driver/tools/version.info然后重新執(zhí)行npu-smi info能看到卡的狀態(tài)變成OK芯片溫度、顯存總?cè)萘?4G這些都正常顯示環(huán)境就算通了。3.3 模型文件的翻譯思路Atlas只能跑.om格式的離線模型而我們訓(xùn)練出來的PyTorch模型是.pt或.onnx格式。這就需要一個翻譯官把通用模型轉(zhuǎn)成昇騰能認的格式這個工具叫ATCAscend Tensor Compiler。轉(zhuǎn)換邏輯是.pt→.onnx→.om。為什么中間要過一道ONNX因為PyTorch模型格式跟昇騰芯片綁定的計算圖規(guī)范差得太遠ONNX作為一個開放的中間表示是生態(tài)之間最通用的橋梁。這一步在GPU平臺上完全不需要但在昇騰上它是必經(jīng)之路。理解了這個鏈路后面每一步出錯你都知道問題出在哪個環(huán)節(jié)。4. 實操YOLOv5在Atlas 300V上的完整部署4.1 從PyTorch導(dǎo)出干凈的ONNX模型我用的是YOLOv5 v6.0版本的官方權(quán)重這個版本在工業(yè)界用得最多、資料也最全。導(dǎo)出ONNX這一步最容易埋雷很多人后面轉(zhuǎn)換失敗都是因為這里沒處理好。首先確保模型文件完整然后執(zhí)行導(dǎo)出命令python export.py --weights yolov5s.pt --include onnx --opset 11 --batch-size 1這里有兩個關(guān)鍵參數(shù)要解釋。--opset 11是ONNX算子集版本昇騰的ATC工具對opset 11的支持最成熟用太新的版本容易遇到算子不兼容--batch-size 1是固定batch為1如果后面要做動態(tài)batch這里可以先固定1等基礎(chǔ)流程跑通再優(yōu)化。導(dǎo)出后用onnxsim做一次圖優(yōu)化把冗余節(jié)點清理掉python -m onnxsim yolov5s.onnx yolov5s_sim.onnx這一步不是必須的但我實測做了圖簡化之后ATC轉(zhuǎn)換的成功率和推理性能都有提升因為刪掉了大量無效的Shape和Identity節(jié)點。4.2 ATC離線轉(zhuǎn)換把ONNX變成OM拿到干凈的ONNX文件后開始轉(zhuǎn)換。我用的ATC命令是這樣atc --modelyolov5s_sim.onnx \ --framework5 \ --soc_versionAscend310P3 \ --input_shapeimages:1,3,640,640 \ --outputyolov5s_bs1 \ --insert_op_confaipp.cfg \ --output_typeFP32 \ --logerror逐個參數(shù)解釋一下--framework5表示輸入是ONNX格式這個數(shù)字是固定的別改。--soc_versionAscend310P3對應(yīng)310P芯片的版本一定要跟你的實際芯片型號匹配可以用npu-smi info查看具體型號后確認。我之前在這上面吃過虧填錯版本直接報E10001: soc version invalid。--input_shape必須跟導(dǎo)出ONNX時的輸入尺寸一致。YOLOv5默認輸入是1,3,640,640即1張3通道640×640的圖。--insert_op_confaipp.cfg是圖像預(yù)處理配置這是昇騰的一大特色。AIPP硬件模塊可以在推理前自動完成resize、歸一化、顏色空間轉(zhuǎn)換等于把圖像預(yù)處理從CPU上搬到了硬件上。aipp.cfg的內(nèi)容長這樣aipp_op { aipp_mode: static input_format: RGB888_U8 src_image_size_w: 640 src_image_size_h: 640 csc_switch: false rbuv_swap_switch: false min_chn_0: 0 min_chn_1: 0 min_chn_2: 0 var_reci_chn_0: 0.003921569 var_reci_chn_1: 0.003921569 var_reci_chn_2: 0.003921569 }這里的0.003921569是1/255也就是把像素從0~255歸一化到0~1。關(guān)鍵是這個配置里的預(yù)處理要和訓(xùn)練時保持一致YOLOv5訓(xùn)練時用到的歸一化就是除以255所以這里配置的歸一化是匹配的。轉(zhuǎn)換成功后會在當(dāng)前目錄生成yolov5s_bs1.om文件這個就是能在Atlas 300V上跑的最終模型文件。4.3 Python推理代碼的骨架模型轉(zhuǎn)換好了接下來就是寫推理程序。昇騰提供了AscendCLACL底層接口類似CUDA Runtime API也提供了更上層的MindX SDK封裝得更徹底。我習(xí)慣先用ACL把底層鏈路打通這樣出了問題好排查。核心推理代碼的邏輯很簡單先初始化設(shè)備再加載模型然后準(zhǔn)備輸入輸出內(nèi)存執(zhí)行推理最后取回結(jié)果import numpy as np from acl import acl # 初始化 ret acl.init() ret acl.rt.set_device(0) context, ret acl.rt.create_context(0) # 加載模型 model_id, ret acl.mdl.load_from_file(yolov5s_bs1.om) model_desc acl.mdl.create_desc() ret acl.mdl.get_desc(model_desc, model_id) # 獲取模型輸入輸出信息 input_size acl.mdl.get_input_size_by_index(model_desc, 0) output_num acl.mdl.get_num_outputs(model_desc) output_size acl.mdl.get_output_size_by_index(model_desc, 0) # 分配設(shè)備內(nèi)存 input_data np.random.randn(1, 3, 640, 640).astype(np.float32) input_buffer, ret acl.rt.malloc(input_size, 2) acl.rt.memcpy(input_buffer, input_size, input_data.tobytes(), input_size, 2) output_buffer, ret acl.rt.malloc(output_size, 2) # 執(zhí)行推理 stream, ret acl.rt.create_stream() ret acl.mdl.execute_async(model_id, [input_buffer], [output_buffer], stream) ret acl.rt.synchronize_stream(stream) # 取回結(jié)果 output np.zeros(output_size, dtypenp.uint8) acl.rt.memcpy(output.tobytes(), output_size, output_buffer, output_size, 3) # 清理資源 acl.rt.free(input_buffer) acl.rt.free(output_buffer) acl.mdl.unload(model_id) acl.rt.destroy_context(context) acl.finalize()這段代碼是最小可用版本實際項目中你要把輸入數(shù)據(jù)的獲取改成讀視頻幀或讀圖片用cv2.imread讀進來的圖像是HWC格式要先轉(zhuǎn)成CHW再根據(jù)aipp.cfg的配置做resize到640×640然后轉(zhuǎn)成float32。要注意的是如果用了AIPP歸一化輸入到模型的原始數(shù)據(jù)就是0~255的uint8而不是歸一化后的float這個細節(jié)搞錯了推理結(jié)果會全亂。4.4 輸出解析從張量到檢測框推理拿到的那一堆原始輸出不是直接能用的檢測框。YOLOv5的輸出是一個1×25200×85的張量25200是三種不同尺度特征圖80×80、40×40、20×20預(yù)測框的總數(shù)85是4個坐標(biāo)1個置信度80個類別概率。后處理流程包括置信度過濾、非極大值抑制NMS、坐標(biāo)映射。這部分代碼量不小但邏輯固定。我自己是把Ultralytics官方倉庫里的后處理邏輯移植過來改了一下坐標(biāo)縮放因為Atlas上做預(yù)處理時已經(jīng)把圖resize到640了輸出坐標(biāo)要映射回原始圖像尺寸才能畫框。如果你不想從零寫后處理可以看看MindX SDK里自帶的YOLOv5后處理插件或者參考昇騰社區(qū)開源的mxVision推理樣例那里面的輸出解析模塊是現(xiàn)成的稍微改改就能用。4.5 性能壓測與關(guān)鍵參數(shù)調(diào)優(yōu)基礎(chǔ)流程通了之后下一步就是壓性能。我用一段1920×1080的視頻做了測試記錄推理耗時和端到端吞吐。先說結(jié)論YOLOv5s、640×640輸入、batch1的情況下單卡純推理時延實測在2~5毫秒?yún)^(qū)間加上解碼、縮放、后處理的全流程時延控制在15毫秒以內(nèi)處理單路1080P視頻做到實時25幀以上綽綽有余。如果發(fā)現(xiàn)性能沒達到預(yù)期按以下優(yōu)先級排查調(diào)優(yōu)優(yōu)化項操作方式收益開啟AIPP硬件預(yù)處理在ATC轉(zhuǎn)換時配置aipp.cfg釋放CPU降低端到端時延使用動態(tài)batch--dynamic_batch_size1,2,4多路請求合并推理提升吞吐多Stream并行AC L里創(chuàng)建多個stream并發(fā)推理充分利用多核AI Core減少CPU拷貝輸入數(shù)據(jù)盡量直接在Device側(cè)準(zhǔn)備減少PCIe傳輸開銷模型低精度量化使用INT8量化后的OM模型推理速度成倍提升我最推薦的還是模型量化。昇騰對INT8的支持很成熟YOLOv5s量化成INT8之后在保證mAP損失可控通常下降不到1%的前提下推理速度能再翻一倍。量化工具在CANN自帶用amct_onnx工具先做校準(zhǔn)數(shù)據(jù)集的統(tǒng)計再重新走一遍ATC轉(zhuǎn)換鏈路清晰。5. 部署中踩過的坑一次說完5.1 常見錯誤速查表這一路部署下來我整理了一份高頻問題對照表遇到報錯直接對著查報錯信息或現(xiàn)象根因解決辦法E10001: soc version invalidATC的--soc_version填錯npu-smi info查看芯片型號后修改Driver not initialized驅(qū)動沒裝好或內(nèi)核模塊沖突重新安裝驅(qū)動確認內(nèi)核版本匹配model not exist or occupy failed顯存不足或模型路徑錯誤確認24G顯存剩余檢查文件權(quán)限推理輸出全是0AIPP歸一化與模型輸入不符核對是否重復(fù)歸一化檢查輸入數(shù)據(jù)格式轉(zhuǎn)換時報op not supportONNX算子不被ATC支持檢查opset版本用onnxsim簡化圖多路視頻CPU占用高沒用DVPP硬解碼在CPU上軟解改用MindX SDK的VideoDecoder模塊推理結(jié)果框的位置偏移后處理坐標(biāo)沒映射回原圖尺寸用縮放比例還原坐標(biāo)最陰間的要算推理輸出全是0這個問題表面上看模型加載成功、推理執(zhí)行成功但結(jié)果就是不對。我排查了兩天才發(fā)現(xiàn)是輸入數(shù)據(jù)的數(shù)值范圍問題——AIPP里已經(jīng)配置了除以255的歸一化我還在代碼里手動做了一遍歸一化等于歸一化了兩次數(shù)據(jù)被壓到了接近0模型自然什么都識別不出來。5.2 一些值得記住的實操心得關(guān)于顯存管理我發(fā)現(xiàn)分配Device內(nèi)存時最好用acl.rt.malloc而不是依賴框架自動管理雖然底層代碼會多幾行但長時間運行不會出現(xiàn)內(nèi)存碎片越積越多的問題。有一次我的程序跑了三天三夜之后突然報顯存不夠重啟進程又好了后來定位到是反復(fù)創(chuàng)建銷毀Context導(dǎo)致的設(shè)備內(nèi)存泄漏。CANN這套接口和CUDA一樣資源用完必須手動釋放這個習(xí)慣要養(yǎng)成。關(guān)于多模型部署24G大顯存有個特別實用的玩法把YOLOv5檢測模型、一個ReID模型、一個人臉特征提取模型同時加載到一個Context里用同一路視頻流做級聯(lián)推理。這樣一張卡就頂一個多模型流水線極大簡化了系統(tǒng)架構(gòu)。我實測同時加載三個模型只占了大概8G顯存還很寬裕。關(guān)于調(diào)試手段CANN提供了msprof性能分析工具能導(dǎo)出算子級的時間消耗分析瓶頸非常有用。我第一次用的時候發(fā)現(xiàn)圖像縮放算子占了很大比例后來把縮放從CPU手寫改到AIPP硬件處理性能立刻上了一個臺階。遇到性能問題別瞎猜拿profiling數(shù)據(jù)說話這是最有效率的排查方式。6. 結(jié)個尾說點實在的Atlas 300V 24G是一塊被低估的推理加速卡。它確實是運算加速卡而且是專門為視頻分析場景優(yōu)化過的運算加速卡配合YOLO系列模型在安防、交通、工業(yè)質(zhì)檢這些需要大規(guī)模處理視頻流的業(yè)務(wù)里能效比優(yōu)勢非常明顯。心理預(yù)期要放對它不是CUDA的平替是一套獨立的推理生態(tài)一旦把CANN的工具鏈跑通了這套東西的穩(wěn)定性和性價比都能超出預(yù)期。最后分享一個我個人的習(xí)慣做昇騰項目部署永遠先跑通最小的端到端鏈路——一張圖進去、一個檢測框出來再想并行優(yōu)化、多路接入的事。每次試錯就改一個變量不要同時動模型版本、ATC參數(shù)和推理代碼。我見過太多同事一次性改了七八個地方出了錯根本定位不了是哪一步的問題。耐住性子一步步驗證Atlas這套東西其實比想象中要老實得多。