換到性能調(diào)優(yōu))
最近后臺一直有人在問“atlas部署yolo”和“atlas 300v 24g 是運算加速卡嗎”這兩個問題我猜不少人是在選型階段或者是已經(jīng)把卡拿到手了結(jié)果卡在環(huán)境搭建和模型轉(zhuǎn)換上。這類問題我這一年里碰到太多次了干脆把整個思路、步驟和踩過的坑完整寫出來給準備入坑昇騰Atlas的兄弟們一份能直接照著做的參考。先說結(jié)論Atlas 300V 24G是一張標準的AI推理加速卡不是訓(xùn)練卡它基于昇騰310P處理器24GB顯存專門用來跑深度學習推理任務(wù)。把YOLO這類檢測模型部署上去核心流程就是“模型轉(zhuǎn)換 推理代碼 業(yè)務(wù)接入”沒有想象中復(fù)雜但細節(jié)確實多尤其是第一次接觸CANN和OM格式的時候容易一頭霧水。這篇文章不整虛的從硬件定位、部署方案設(shè)計、模型轉(zhuǎn)換到最終調(diào)優(yōu)全部按實操順序?qū)懨總€參數(shù)都給到可直接使用的程度。1. 先搞清楚Atlas 300V 24G到底是什么1.1 它確實是運算加速卡但“加速”和“訓(xùn)練”是兩碼事很多人看到“運算加速卡”這幾個字下意識會拿它跟NVIDIA的A100、RTX 4090去做對比然后問為什么不能直接跑PyTorch訓(xùn)練。這就是對產(chǎn)品定位理解偏差了。Atlas 300V 24G屬于昇騰推理卡做的是“已訓(xùn)練好的模型的推理計算”。什么叫推理計算就是模型權(quán)重已經(jīng)訓(xùn)練完畢你給它一張圖片或者一段視頻流它在前向傳播里算出目標框和類別。這個過程計算量比訓(xùn)練小很多但對時延、吞吐、功耗的要求更極端。正因為專注推理這類卡的能效比通常比訓(xùn)練卡高不少尤其適合視頻流分析、工業(yè)質(zhì)檢、智慧園區(qū)這些場景。官方標稱參數(shù)我在這里給個參考Atlas 300V 24G基于昇騰310P處理器內(nèi)存24GB典型功耗70到80瓦區(qū)間INT8算力大致在140 TOPS左右。這個算力水平跑YOLOv5s、YOLOv8s這一檔的模型處理多路視頻流基本沒有壓力。注意如果你需要的是“訓(xùn)練模型”的算力那300V 24G不合適應(yīng)該看Atlas 800訓(xùn)練卡或者昇騰910系列。300V的定位是“跑模型”不是“練模型”。1.2 Atlas系列型號命名太像了選型前先排雷Atlas產(chǎn)品線密密麻麻200、300I、300V、500、800、900單看數(shù)字很難判斷差異。我挑幾個常見的說一下免得買錯。Atlas 200系列是開發(fā)板形態(tài)適合嵌入式原型驗證適合學生和算法工程師做前期demo。Atlas 300I系列是單槽位半高半長的推理卡主打低功耗緊湊型服務(wù)器。Atlas 300V系列跟300I最大的區(qū)別是整卡性能更高、顯存更大像300V 24G這種就是雙槽位全高全長設(shè)計散熱條件要求更高。Atlas 500系列通常是盒子形態(tài)的智能小站更適合戶外邊緣場景。網(wǎng)上還有一個常見誤區(qū)Atlas 300V 24G能不能插普通臺式機答案是可以但有條件。它走PCIe 3.0 x16接口物理形態(tài)上跟普通顯卡一樣但驅(qū)動只支持Ubuntu、CentOS、openEuler等Linux系統(tǒng)Windows直接放棄。另外對主板BIOS里Above 4G Decoding選項有要求不開啟的話設(shè)備可能識別不到。我在選型時給團隊的建議很簡單先確認你的業(yè)務(wù)是訓(xùn)練還是推理推理場景再確認算法模型的大小和對視頻路數(shù)的要求。如果只是單路攝像頭做檢測300I Duo就夠如果是幾十路視頻并發(fā)直接上300V 24G顯存和算力冗余更充足。2. 為什么值得把YOLO部署到Atlas上部署鏈路怎么搭2.1 先算筆賬性能、功耗和成本到底劃不劃算之前有個做智慧養(yǎng)殖的客戶原來用一臺帶RTX 3080的服務(wù)器跑YOLOv5s處理8路1080p視頻流GPU占用率天天拉滿電源功耗動不動三四百瓦機房夏天熱得不行。后來換了兩張Atlas 300V 24G每張卡功耗不到80瓦8路視頻流分攤到兩張卡上單卡占用率不到70%整機功耗降了一大截。這筆賬怎么算以YOLOv5s、輸入分辨率640x640為例一張Atlas 300V 24G在INT8精度下跑批量大小為1的推理實測單幀處理時間大概在幾毫秒到十幾毫秒之間換算過來每秒能處理幾十幀。這個幀率看起來沒有高端GPU那么夸張但推理卡強就強在批量處理和并發(fā)路數(shù)。視頻流場景下通常把4到8路視頻流拼成一個batch輸入卡上計算單元利用率會明顯提升整體吞吐遠遠高于單路逐幀處理。如果是CPU跑YOLOv5s640x640輸入下純CPU推理單幀可能要去到一兩百毫秒這還不算前后處理。把這筆賬攤開看用300V 24G跑推理性能提升通常在十倍以上而且功耗只有CPU服務(wù)器的零頭。2.2 部署方案的總體架構(gòu)CANN是繞不開的底座昇騰平臺不像CUDA那樣可以直接用PyTorch或者TensorRT跑模型它有一套自己的軟件棧底層是驅(qū)動和固件中間層是CANNCompute Architecture for Neural Networks上層再封裝出各種推理框架。CANN里最核心的兩塊是ATC模型轉(zhuǎn)換工具和AscendCL推理接口。整個部署鏈路我理出來大概是這個樣子用PyTorch訓(xùn)練或者從開源倉庫拿到Y(jié)OLO權(quán)重。把模型導(dǎo)出為ONNX通用格式。在服務(wù)器上安裝好昇騰驅(qū)動、固件和CANN工具包。用CANN自帶的ATC工具把ONNX轉(zhuǎn)換成昇騰專用的OM格式。編寫AscendCL推理代碼加載OM模型做數(shù)據(jù)預(yù)處理、推理計算、后處理。把推理結(jié)果封裝成業(yè)務(wù)接口往上拋。很多第一次接觸的朋友最不理解的一點是為什么不能直接加載PyTorch權(quán)重文件原因是昇騰芯片不認PyTorch的權(quán)重格式芯片上執(zhí)行的是經(jīng)過融合、量化、圖優(yōu)化的OM模型。OM模型里不光是網(wǎng)絡(luò)結(jié)構(gòu)還包含了算子在芯片上的映射關(guān)系、數(shù)據(jù)排布格式、內(nèi)存分配方案。這種靜態(tài)優(yōu)化好處是推理時省掉了框架調(diào)度開銷缺點是模型結(jié)構(gòu)一變就得重新轉(zhuǎn)換。整個架構(gòu)里我建議把力氣花在兩步上一是ONNX導(dǎo)出的質(zhì)量二是ATC轉(zhuǎn)換參數(shù)的設(shè)置。這兩個環(huán)節(jié)出問題后面推理階段各種奇怪報錯都會冒出來。3. 實操把YOLO模型搬到Atlas 300V 24G上3.1 環(huán)境準備驅(qū)動和CANN的安裝順序不能亂先說硬件環(huán)境。我這邊測試用的服務(wù)器是雙路x86平臺128GB內(nèi)存系統(tǒng)Ubuntu 20.04內(nèi)核版本5.4。Atlas 300V 24G插在PCIe 3.0 x16槽位上電源至少750W因為官方建議整機供電冗余要留足。安裝之前先去昇騰官網(wǎng)下載三個東西驅(qū)動包、固件包、CANN Toolkit包。版本對照關(guān)系在官網(wǎng)文檔里都有每一版CANN對應(yīng)哪個版本的驅(qū)動和固件一定要看仔細不然裝完算子加載直接報版本不匹配。推薦的安裝順序# 1. 先裝驅(qū)動 ./Ascend-hdk-*.run --install # 2. 再裝固件注意固件跟驅(qū)動版本必須對應(yīng) ./Ascend-hdk-*.run --upgrade # 3. 最后裝CANN toolkit ./Ascend-cann-toolkit_*.run --install驅(qū)動裝完用下面命令確認設(shè)備有沒有正常識別npu-smi info如果能看到類似下面的輸出說明卡已經(jīng)識別成功-------------------------------------------------------------------------------------- | NPU Name | Health | Power(W) Temp(C) HugepagesUsage | | 300V | OK | 32.0 45 0 | --------------------------------------------------------------------------------------接下來配置CANN環(huán)境變量source /usr/local/Ascend/ascend-toolkit/set_env.sh這個環(huán)境變量文件里會設(shè)置好CANN路徑、頭文件路徑和庫文件路徑后面編譯運行都需要它。建議直接寫到~/.bashrc里避免每次重新source。提示如果是在容器里用還要確認設(shè)備節(jié)點映射和權(quán)限。宿主機上執(zhí)行l(wèi)s /dev/davinci*容器啟動時要把這些設(shè)備節(jié)點掛載進去否則aclrtSetDevice會報“device not found”。3.2 模型轉(zhuǎn)換ONNX轉(zhuǎn)OM是關(guān)鍵中的關(guān)鍵拿一個典型的YOLOv5s模型舉例假設(shè)已經(jīng)通過torch.onnx.export拿到了yolov5s.onnx。ATC轉(zhuǎn)換命令長這樣atc --modelyolov5s.onnx --framework5 --outputyolov5s_om \ --input_shapeimages:1,3,640,640 \ --soc_versionAscend310P3 \ --insert_op_confaipp.cfg逐個解釋一下參數(shù)--model輸入的ONNX模型文件。--framework5固定值5表示ONNX因為ATC支持諸多框架格式。--output輸出的OM文件名。--input_shape這里必須跟ONNX模型輸入節(jié)點的名字和維度完全匹配YOLOv5輸入節(jié)點名一般是images維度是[batch, channel, height, width]。batch固定為1容易理解如果要做多路視頻可以在推理時通過動態(tài)batch處理。--soc_versionAscend310P3這坑很多人踩過。Atlas 300V 24G用的310P芯片ATC轉(zhuǎn)換時soc_version要填對填錯會直接報“unsupported soc version”。具體是Ascend310P3還是Ascend310P1要看你的芯片型號運行npu-smi info能查出來保險起見可以在官網(wǎng)產(chǎn)品規(guī)格里確認一下。--insert_op_confaipp.cfgAIPP是昇騰的像素預(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 crop: false mean: 0.0 0.0 0.0 min: 0.0 0.0 0.0 max: 255.0 255.0 255.0 }這里mean和min/max的組合意思是把像素值從0到255歸一化到0到1。如果你的訓(xùn)練代碼里用的是ImageNet的mean和std需要換算成對應(yīng)數(shù)值或者干脆關(guān)閉AIPP的歸一化在推理代碼里用算子完成。我當時為了圖省事直接在AIPP里做了歸一化省一步是一步。轉(zhuǎn)換完成后會生成一個.om文件可以用atc自帶的工具做離線驗證但通常沒必要直接跑一次推理腳本就能發(fā)現(xiàn)問題。3.3 編寫推理腳本AscendCL的這些接口必須會用CANN安裝好之后推薦用Python版的pyACL做原型驗證開發(fā)效率比C高很多性能損失在單路視頻流場景下幾乎可以忽略。下面的示例代碼摘了核心部分不是完整代碼但主流程是清晰的。import acl import numpy as np # 初始化 acl.init() ret acl.rt.set_device(0) context, ret acl.rt.create_context(0) # 加載模型 model_path byolov5s_om.om model_id, ret acl.mdl.load_from_file(model_path) # 獲取模型輸入輸出信息 input_desc acl.mdl.create_desc() output_desc acl.mdl.create_desc() acl.mdl.get_input_desc(input_desc, model_id, 0) acl.mdl.get_output_desc(output_desc, model_id, 0) input_size acl.mdl.get_desc_size(input_desc) output_size acl.mdl.get_desc_size(output_desc) # 分配device內(nèi)存 input_data, ret acl.rt.malloc(input_size, 2) output_data, ret acl.rt.malloc(output_size, 2) # 構(gòu)造輸入數(shù)據(jù)假設(shè)image是已經(jīng)預(yù)處理好、shape為(1,3,640,640)的numpy數(shù)組 image_nd np.ascontiguousarray(image) acl.rt.memcpy(input_data, input_size, image_nd.ctypes.data, image_nd.nbytes, acl.rt.MEMCPY_HOST_TO_DEVICE) # 創(chuàng)建輸入輸出數(shù)據(jù)集 dataset_input acl.mdl.create_dataset() dataset_output acl.mdl.create_dataset() acl.mdl.add_dataset_buffer(dataset_input, input_data, input_size) acl.mdl.add_dataset_buffer(dataset_output, output_data, output_size) # 推理 ret acl.mdl.execute(model_id, dataset_input, dataset_output) # 把結(jié)果拷回主機端 output_np np.zeros(output_size, dtypenp.uint8) acl.rt.memcpy(output_np.ctypes.data, output_size, output_data, output_size, acl.rt.MEMCPY_DEVICE_TO_HOST)這段代碼走通了你就已經(jīng)跑通昇騰推理全流程。不過這里有一個非常容易踩的坑YOLO的模型輸出通常有三個尺度的特征圖OM模型在AscendCL下可能把它們拆分成了多個輸出節(jié)點你需要根據(jù)模型導(dǎo)出時定義的輸出數(shù)量來遍歷所有輸出desc。別只處理第0個輸出不然檢測框全部丟失。后處理邏輯里decoding和NMS我建議先在CPU上用numpy跑通因為前期排查問題最怕的就是不知道結(jié)果是模型錯了還是后處理錯了。等整個流程正確了再考慮把NMS搬到卡上或者用C實現(xiàn)來提性能。還有數(shù)據(jù)預(yù)處理建議把letterbox縮放、顏色通道轉(zhuǎn)換這些步驟封裝成獨立函數(shù)。YOLOv5訓(xùn)練時用的是RGB輸入推理階段如果圖像是BGR通道順序不調(diào)整檢測結(jié)果會非常稀疏框的位置也會偏差很大這是一個極易忽略的細節(jié)。3.4 跑通后的效果驗證用npu-smi和日志雙重確認推理腳本跑通后不要急著接業(yè)務(wù)先做兩件事第一觀察NPU占用。執(zhí)行npu-smi info重點看AI Core的占用率和顯存使用量。如果占用率一直很低說明模型優(yōu)化還不到位可能卡在數(shù)據(jù)在Host和Device之間的拷貝上。300V 24G的PCIe帶寬有限每次推理都做H2D和D2H拷貝時間損耗非常大。解決思路是批量推理比如一次把4張圖放進一個batch讓拷貝次數(shù)減少為原來的四分之一。第二用日志定位耗時。CANN環(huán)境變量里可以開啟profilingexport PROFILING_MODEtrue export PROFILING_OPTIONSoutput/tmp/profiling, task_timeon跑一次推理后去/tmp/profiling目錄看耗時分析能直觀看到數(shù)據(jù)預(yù)處理、模型執(zhí)行、后處理三部分各自的耗時占比。我調(diào)試過很多次最終結(jié)論基本都是模型執(zhí)行時間只占一半不到前后處理和拷貝反而成為瓶頸。4. 常見問題與排查技巧實錄4.1 模型轉(zhuǎn)換階段的報錯離了soc_version和input_shape就沒法玩我在多個項目里遇到過得最多的報錯是ATC轉(zhuǎn)換時報E40000錯誤信息里面大概率會包含“input shape mismatch”或者“Unsupported op type”。前者好解決檢查一下ONNX的輸入名和維度用onnx.load看一眼模型結(jié)構(gòu)就行。后者就比較麻煩說明模型里有算子還沒被CANN適配。YOLOv5s和YOLOv8s這種主流模型一般都能直接轉(zhuǎn)換真正要擔心的是自己魔改過的模型結(jié)構(gòu)。比如有人為了提精度在backbone里加了一些YOLO官方?jīng)]有的模塊比如自定義的注意力機制ATC不認的話就卡住了。我的建議是要么把自定義算子改回官方實現(xiàn)要么用C寫自定義算子插件注冊進CANN。后者門檻較高能夠在模型設(shè)計階段盡量規(guī)避就規(guī)避。另一個在轉(zhuǎn)換階段的坑是AIPP配置。我記得有一次改了歸一化參數(shù)結(jié)果檢測結(jié)果空白排查了半天最后發(fā)現(xiàn)是AIPP的src_image_size_w沒改圖像在預(yù)處理階段被強行縮放到錯誤尺寸模型輸出自然全亂。AIPP配置里的每個字段都值得仔細對一遍特別是輸入圖片尺寸必須跟模型輸入一致。4.2 推理階段的報錯先分清是環(huán)境問題還是代碼問題推理階段常見報錯及快速排查方案我做了一個速查表報錯現(xiàn)象大概率原因處理辦法aclrtSetDevice返回507設(shè)備節(jié)點未映射或驅(qū)動異常查/dev/davinci*是否存在容器場景檢查掛載模型加載失敗提示model load failedOM文件與當前芯片型號不匹配確認轉(zhuǎn)換時--soc_version是否填對推理結(jié)果全0輸入數(shù)據(jù)未成功拷貝到Device端檢查acl.rt.memcpy的H2D方向打印返回值確認推理輸出shape異常輸出節(jié)點遍歷不全遍歷所有output描述打印每個輸出維度檢測框偏移嚴重輸入通道順序不對或預(yù)處理參數(shù)與訓(xùn)練不一致確認RGB/BGR、letterbox參數(shù)與訓(xùn)練一致還有一類問題很難排查就是“推理偶發(fā)抖動”。如果單幀推理時間平時10毫秒偶爾跳到30毫秒通常是PCIe帶寬爭搶或者顯存碎片化導(dǎo)致的。解決辦法有幾個一是推理線程和拷貝線程分開用流水線方式掩蓋H2D耗時二是固定batch大小預(yù)分配好Device內(nèi)存不要在推理過程中反復(fù)malloc和free。顯存碎片在長時間運行的服務(wù)里非常要命我見過跑了一天后推理直接報out of memory的情況重啟進程就好根源就是內(nèi)存反復(fù)分配導(dǎo)致碎片化。4.3 性能調(diào)優(yōu)的一些獨家心得性能調(diào)優(yōu)是個很大的話題這里我結(jié)合經(jīng)驗給幾條對300V 24G特別有效的建議。第一能批量就批量。多路視頻流場景下一定不要把每幀圖像單獨推理正確做法是同一時刻收集多路圖像拼成batch。batch為4時的總耗時通常只有batch為1時的一倍多但吞吐翻了四倍。第二后處理盡量晚一點做。YOLO輸出的原始tensor在Device端如果先把所有檢測框坐標拷回Host再做NMS一次性拷貝量太大。可以先在Device端做置信度過濾只把少數(shù)高置信度框結(jié)果拷出來再做NMS。CANN有些版本支持自定義后處理算子但最快的方式是先用acl.rt.memcpy只拷貝過濾后的數(shù)組減少主機側(cè)處理壓力。第三功耗散熱一定不能忽略。Atlas 300V 24G滿載功耗也不低機箱風道太差的話卡容易觸發(fā)降頻跑一段時間后性能明顯下滑。建議在服務(wù)器里給GPU/加速卡區(qū)域加裝機箱風扇npu-smi info里能看到溫度超過85度基本就是散熱出問題了。第四留意CANN版本升級。昇騰的軟件迭代很快同型號卡在不同版本的CANN下算子性能和穩(wěn)定性差異還挺明顯。如果項目不趕時間建議每個大版本推出后先在測試環(huán)境把模型轉(zhuǎn)換和性能測試跑一遍確認沒問題再上生產(chǎn)。我踩過一次CANN 5.x升級到6.x的坑之前正常跑的OM模型直接加載不了重新用新版本轉(zhuǎn)換后才恢復(fù)。4.4 一個容易忽略的小細節(jié)鏡像與離線環(huán)境的適配有時候生產(chǎn)環(huán)境不具備直接聯(lián)網(wǎng)下載依賴包的條件昇騰的安裝包和依賴庫都是離線rpm或者run包這塊還好辦。但Python側(cè)依賴比如numpy、opencv-python如果服務(wù)器不能聯(lián)網(wǎng)建議提前用pip download把對應(yīng)Python版本的包拉到本地。別小看這些預(yù)處理庫YOLO部署真正麻煩的往往不是模型本身而是整個運行環(huán)境里各種依賴的版本匹配問題。我在一個ARM服務(wù)器上裝CANN時就遇到過一個很刁鉆的坑numpy的版本跟pyACL模塊不兼容導(dǎo)致import acl直接core dump。最后是查了CANN官方文檔中Python版本支持矩陣把numpy降級到指定版本才解決。所以不要盲目追求新版本官方文檔里寫的適配版本就是最穩(wěn)的。5. 給準備入坑的朋友幾句掏心窩的話Atlas 300V 24G這張卡到底值不值得用我的答案是如果業(yè)務(wù)場景是明確的推理應(yīng)用尤其是視頻流和批量檢測它性價比很高功耗和單路成本都明顯優(yōu)于同價位的GPU。但如果你的團隊完全沒有Linux系統(tǒng)和C/Debug經(jīng)驗純指望開箱即用那我建議先花兩周時間把CANN基礎(chǔ)過一遍再決定是否全量遷過來。我個人在實際項目中最大的體會是昇騰部署最大的成本不是硬件是所有文檔和技術(shù)社區(qū)沉淀加起來仍然偏少遇到問題多數(shù)時候得自己一點點試。但換個角度想正因為這樣現(xiàn)在愿意花時間把流程跑通的團隊反而能積累出真正的技術(shù)壁壘后面遷移到其他同類型加速卡上也會輕松很多。最后再分享一個小技巧剛開始做模型轉(zhuǎn)換的時候不要一上來就轉(zhuǎn)換自己的大模型。拿一個官方提供的resnet50或者yolov5s demo完整跑通整個鏈路再逐步替換成自己的模型。這樣能把“環(huán)境問題”和“模型問題”拆開排查能少走很多彎路。