境配置到INT8量化調(diào)優(yōu))
做一個(gè)項(xiàng)目名字就叫atlas。這不是什么新框架也不是什么花哨的中間件而是一塊實(shí)打?qū)嵉乃懔Φ鬃獣N騰Atlas 300V 24G推理加速卡外加在這張卡上從零把YOLO系列模型部署起來(lái)的一整套流程。最近總有朋友問(wèn)atlas部署yolo是不是特別麻煩atlas 300v 24g是運(yùn)算加速卡嗎到底能不能當(dāng)GPU用今天就把我踩過(guò)的坑、驗(yàn)證過(guò)的方案一次說(shuō)清楚。先回答那個(gè)高頻問(wèn)題Atlas 300V 24G確實(shí)是運(yùn)算加速卡但它不是通用計(jì)算卡而是專(zhuān)門(mén)為AI推理設(shè)計(jì)的加速卡。它和GPU最大的區(qū)別在于你不能直接拿它跑CUDA代碼也不能指望它像訓(xùn)練卡那樣做大規(guī)模反向傳播。它的主戰(zhàn)場(chǎng)是訓(xùn)練好的模型上線之后把圖片、視頻、文本這些輸入快速算出結(jié)果吞吐量高、功耗低、性價(jià)比突出。我之所以選它來(lái)部署YOLO正是因?yàn)轫?xiàng)目里需要在一臺(tái)普通的x86服務(wù)器上掛多路視頻流做實(shí)時(shí)目標(biāo)檢測(cè)用GPU資源太貴用純CPU又扛不住Atlas 300V 24G這種推理卡反而成了最合適的中間解。1. 認(rèn)識(shí)Atlas 300V 24G它到底是一張什么卡很多人第一次拿到Atlas 300V系列板卡時(shí)第一反應(yīng)是拿它和NVIDIA的顯卡去對(duì)標(biāo)我剛開(kāi)始也這樣。但實(shí)際用起來(lái)就會(huì)發(fā)現(xiàn)它的設(shè)計(jì)邏輯和GPU完全不同理解這一點(diǎn)是后面所有部署工作不跑偏的前提。1.1 硬件規(guī)格與定位Atlas 300V 24G是基于昇騰AI處理器的推理加速卡板載24GB顯存主打大模型和較高并發(fā)場(chǎng)景的推理加速。和訓(xùn)練卡不同這張卡在設(shè)計(jì)上舍棄了大量訓(xùn)練所需的計(jì)算單元換來(lái)的是更低的功耗和更高的推理能效比。整卡功耗通常在70W左右甚至可以做到無(wú)風(fēng)扇被動(dòng)散熱這在機(jī)房部署時(shí)非常友好。從軟件角度看它支持FP16、INT8等低精度推理其中INT8推理吞吐量是FP16的數(shù)倍。如果你部署的YOLO模型經(jīng)過(guò)量化校準(zhǔn)單卡跑出來(lái)的幀率會(huì)非??捎^。我實(shí)測(cè)過(guò)YOLOv5s在640x640輸入下的表現(xiàn)INT8模式下單路推理延遲可以做到個(gè)位數(shù)毫秒級(jí)別多路并發(fā)時(shí)吞吐量還能繼續(xù)往上走。1.2 為什么不能把它當(dāng)普通GPU用這是新手最容易踩的坑。Atlas 300V 24G不兼容CUDA它的軟件棧是華為自家的CANNCompute Architecture for Neural Networks。也就是說(shuō)你寫(xiě)好的PyTorch模型不能直接塞進(jìn)去跑必須經(jīng)過(guò)模型轉(zhuǎn)換把PyTorch的權(quán)重文件轉(zhuǎn)成昇騰專(zhuān)屬的OM格式。轉(zhuǎn)換鏈路通常是這樣PyTorch模型導(dǎo)出為ONNX再用CANN自帶的ATC工具把ONNX轉(zhuǎn)成OM最后通過(guò)ACLAscend Computing Language運(yùn)行時(shí)接口加載OM文件執(zhí)行推理。這個(gè)流程看著不復(fù)雜但里面藏著大量細(xì)節(jié)。ONNX算子版本不匹配會(huì)導(dǎo)致轉(zhuǎn)換失敗輸入張量的shape寫(xiě)錯(cuò)會(huì)導(dǎo)致推理結(jié)果全是0甚至AIPP配置里少寫(xiě)一個(gè)像素格式轉(zhuǎn)換參數(shù)都可能讓模型輸出的檢測(cè)框全部跑到角落里去。后面我會(huì)針對(duì)這些逐個(gè)拆解。2. CANN工具鏈安裝與部署環(huán)境準(zhǔn)備工欲善其事必先利其器。在Atlas 300V 24G上跑YOLO第一步不是寫(xiě)代碼而是先把CANN環(huán)境裝好。這塊內(nèi)容比較瑣碎但每一條都是我自己實(shí)際敲過(guò)命令驗(yàn)證過(guò)的照著做能省掉大半天的排查時(shí)間。2.1 宿主機(jī)環(huán)境要求Atlas 300V 24G是一張PCIe卡插在普通的x86服務(wù)器上就能用但這不代表隨便什么Linux發(fā)行版都行。官方明確支持的包括Ubuntu 20.04/22.04、CentOS 7.6等建議優(yōu)先用Ubuntu 20.04 x86_64生態(tài)兼容性最省心。內(nèi)核版本、gcc版本、Python版本都有對(duì)應(yīng)關(guān)系CANN 6.x版本下Python 3.7到3.10都可以但推薦3.8或3.9后面裝pyACL時(shí)不容易出幺蛾子。安裝前先檢查硬件是否被系統(tǒng)識(shí)別。用lspci | grep -i ascend能看到一張PCIe設(shè)備說(shuō)明物理鏈路沒(méi)問(wèn)題。接著裝驅(qū)動(dòng)。驅(qū)動(dòng)包的安裝方式比較簡(jiǎn)單解壓后以root身份執(zhí)行./install.sh它會(huì)自動(dòng)把內(nèi)核模塊、用戶態(tài)驅(qū)動(dòng)、npu-smi工具一起裝好。裝完執(zhí)行npu-smi info如果能列出板卡的芯片型號(hào)、顯存大小、溫度等信息就說(shuō)明驅(qū)動(dòng)OK了。2.2 安裝CANN Toolkit有了驅(qū)動(dòng)之后再裝CANN Toolkit。到昇騰社區(qū)下載對(duì)應(yīng)版本的Ascend-cann-toolkit安裝包這個(gè)包本質(zhì)上是一個(gè)龐大但組織良好的Python包集合和C動(dòng)態(tài)庫(kù)集合負(fù)責(zé)把模型編譯、運(yùn)行時(shí)調(diào)度、算子執(zhí)行這些能力暴露給你。安裝步驟也不復(fù)雜chmod x Ascend-cann-toolkit_7.0.0_linux-x86_64.run ./Ascend-cann-toolkit_7.0.0_linux-x86_64.run --install安裝完成后需要把CANN的環(huán)境變量寫(xiě)進(jìn)~/.bashrcsource /usr/local/Ascend/ascend-toolkit/set_env.sh這里有個(gè)細(xì)節(jié)建議養(yǎng)成習(xí)慣正因?yàn)檫@個(gè)環(huán)境變量要生效所以每次開(kāi)新終端跑推理程序之前都必須先source一下。我一開(kāi)始沒(méi)注意換了終端直接跑Python結(jié)果報(bào)ModuleNotFoundError: No module named acl后來(lái)才發(fā)現(xiàn)是pyACL的路徑?jīng)]加載進(jìn)來(lái)。2.3 驗(yàn)證環(huán)境是否可用環(huán)境配好之后強(qiáng)烈建議跑一個(gè)官方自帶的樣例來(lái)驗(yàn)證整條鏈路。CANN Toolkit里通常帶resnet50推理示例路徑在/usr/local/Ascend/ascend-toolkit/latest/tools下面或者在昇騰社區(qū)的sample倉(cāng)庫(kù)里。跑通一個(gè)resnet50分類(lèi)至少能證明驅(qū)動(dòng)、固件、CANN Toolkit、pyACL這一整套都正常工作之后再切到Y(jié)OLO就會(huì)順很多。如果跑樣例時(shí)報(bào)E50001 upgrade firmware這類(lèi)錯(cuò)誤通常是固件和驅(qū)動(dòng)版本不匹配。解決辦法是到昇騰社區(qū)下載和CANN版本配套的Ascend-hdk固件包重新刷一遍順序是先驅(qū)動(dòng)后固件。別問(wèn)我為什么知道問(wèn)就是經(jīng)歷過(guò)。3. YOLO模型從PyTorch到OM的完整轉(zhuǎn)換鏈路環(huán)境就緒后核心步驟來(lái)了把PyTorch訓(xùn)練好的YOLO模型轉(zhuǎn)換成Atlas 300V 24G能跑的OM模型。這部分是整個(gè)部署流程中報(bào)錯(cuò)率最高的地方但搞清楚原理之后其實(shí)非常機(jī)械。3.1 導(dǎo)出ONNX時(shí)要注意的算子陷阱無(wú)論你用YOLOv5還是YOLOv8第一步都是把.pt權(quán)重導(dǎo)出為ONNX。以YOLOv5為例python export.py --weights yolov5s.pt --include onnx --opset 11這里有兩個(gè)關(guān)鍵點(diǎn)。第一opset版本最好指定11CANN對(duì)opset 11的支持最穩(wěn)定用太高版本容易碰到不支持的算子。第二注意導(dǎo)出時(shí)是否帶detect層。很多教程建議--no-det也就是把后處理非極大值抑制、解碼錨框等留在應(yīng)用代碼里做。我強(qiáng)烈建議這么干因?yàn)镺NNX里的NMS算子在ATC工具轉(zhuǎn)換時(shí)經(jīng)常出幺蛾子而且把所有后處理放出去之后OM模型更簡(jiǎn)潔后續(xù)調(diào)試也容易定位問(wèn)題。導(dǎo)出的ONNX可以用Netron打開(kāi)看看輸入節(jié)點(diǎn)是images輸出節(jié)點(diǎn)是三個(gè)檢測(cè)頭的原始特征圖shape通常是[1, 255, 80, 80]、[1, 255, 40, 40]、[1, 255, 20, 20]255 3 * (5 80)對(duì)應(yīng)3個(gè)錨框、4個(gè)坐標(biāo)、1個(gè)目標(biāo)置信度、80個(gè)類(lèi)別。3.2 使用ATC工具完成模型轉(zhuǎn)換拿到ONNX之后用ATC把它轉(zhuǎn)成OM。ATC是CANN里負(fù)責(zé)模型編譯的集大成者它會(huì)做算子調(diào)度優(yōu)化、內(nèi)存復(fù)用和指令生成。下面是YOLOv5s的轉(zhuǎn)換命令我實(shí)際用過(guò)且穩(wěn)定的版本atc --modelyolov5s.onnx \ --framework5 \ --outputyolov5s_bs1 \ --input_shapeimages:1,3,640,640 \ --soc_versionAscend310P3 \ --insert_op_confaipp.cfg逐個(gè)參數(shù)解釋一下--framework5表示輸入模型是ONNX--output指定輸出文件前綴--input_shape需要和ONNX里的輸入節(jié)點(diǎn)完全一致模型如果是在別的尺寸下訓(xùn)練的這里寫(xiě)錯(cuò)會(huì)導(dǎo)致轉(zhuǎn)換出來(lái)的模型推理結(jié)果完全不對(duì)--soc_version要根據(jù)你板卡的實(shí)際芯片型號(hào)填寫(xiě)Atlas 300V 24G常見(jiàn)的芯片版本是Ascend310P系列可以通過(guò)npu-smi info查到具體版本號(hào)填錯(cuò)會(huì)直接報(bào)unsupported soc version。重點(diǎn)是aipp.cfg這是昇騰特有的AI預(yù)處理配置用來(lái)把圖像歸一化、減均值、縮放這些操作直接交給NPU硬件做省去CPU側(cè)開(kāi)銷(xiāo)。以YOLOv5為例標(biāo)準(zhǔn)配置如下aipp_op { aipp_mode: static input_format: RGB888_U8 src_image_size_w: 640 src_image_size_h: 640 csc_switch: true rbuv_swap_switch: false c_matrix { r0c0: 0.003921569 r1c0: 0 r2c0: 0 r0c1: 0 r1c1: 0.003921569 r2c1: 0 r0c2: 0 r1c2: 0 r2c2: 0.003921569 } }這段配置的作用是把輸入圖片從RGB888格式轉(zhuǎn)換到浮點(diǎn)并乘以1/255完成歸一化。注意YOLOv5的預(yù)處理邏輯還包括letterbox縮放這個(gè)不建議在AIPP里做而是應(yīng)該在CPU側(cè)先把圖像縮放并填充到640x640再把結(jié)果交給NPU。原因很簡(jiǎn)單AIPP的縮放算法和你在訓(xùn)練時(shí)用的letterbox不完全一致落到精度上就是mAP下降那么一兩個(gè)點(diǎn)肉眼看不出來(lái)但就是膈應(yīng)人。轉(zhuǎn)換成功后會(huì)生成yolov5s_bs1.om同時(shí)終端會(huì)打印出ATC run success。如果中途報(bào)錯(cuò)十有八九是ONNX里的算子在昇騰上沒(méi)有對(duì)應(yīng)實(shí)現(xiàn)。此時(shí)有兩個(gè)方向一是換更標(biāo)準(zhǔn)的YOLO導(dǎo)出方式二是用--op_type_list嘗試打開(kāi)自定義算子映射。我個(gè)人的經(jīng)驗(yàn)是官方Y(jié)OLOv5 7.0版本導(dǎo)出的ONNX在opset 11下基本都能直接轉(zhuǎn)換成功很少需要碰自定義算子。3.3 動(dòng)態(tài)Batch與AIPP的取舍之前說(shuō)過(guò)輸入shape要固定但在真實(shí)業(yè)務(wù)里推理請(qǐng)求往往是動(dòng)態(tài)變化的白天視頻流并發(fā)高后半夜請(qǐng)求少。如果把模型固定成batch1高峰期吞吐不夠固定成batch8低峰期白白占用內(nèi)存。解決辦法是使用ATC的動(dòng)態(tài)Batch能力atc --modelyolov5s.onnx \ --framework5 \ --outputyolov5s_dynamic \ --input_shapeimages:-1,3,640,640 \ --dynamic_batch_size1,2,4,8 \ --soc_versionAscend310P3 \ --insert_op_confaipp.cfg轉(zhuǎn)換后OM模型支持在推理時(shí)動(dòng)態(tài)指定batch為1、2、4或8。代價(jià)是轉(zhuǎn)換后的模型會(huì)比固定batch版本大一些占用的顯存也會(huì)按最大batch預(yù)留這是可接受的。我實(shí)際在Atlas 300V 24G上同時(shí)跑8路高清視頻流就是用的動(dòng)態(tài)batch配合應(yīng)用層做請(qǐng)求排隊(duì)效果比開(kāi)8個(gè)batch1的獨(dú)立進(jìn)程好得多。4. 基于ACL的推理代碼實(shí)現(xiàn)與內(nèi)存細(xì)節(jié)模型弄好了下一步就是寫(xiě)推理代碼。昇騰的推理接口叫ACLAscend Computing Language有C和Python兩套綁定。我下面以Python為例因?yàn)榈俣瓤斐隽藛?wèn)題也好調(diào)試。但要提醒一句如果對(duì)性能有極致要求生產(chǎn)環(huán)境建議用C省掉Python解釋器的開(kāi)銷(xiāo)。4.1 pyACL推理最小閉環(huán)一個(gè)完整的pyACL推理流程是這樣的初始化 - 設(shè)置設(shè)備 - 加載模型 - 準(zhǔn)備輸入輸出內(nèi)存 - 執(zhí)行推理 - 取回結(jié)果 - 銷(xiāo)毀資源。核心代碼如下import acl # 1. 初始化 acl.init() ret acl.rt.set_device(0) # 2. 加載OM模型 model_path byolov5s_bs1.om model_id 100 ret acl.mdl.load_from_file(model_path, model_id) # 3. 獲取模型輸入輸出描述 desc acl.mdl.create_desc() ret acl.mdl.get_desc(desc, model_id) input_size acl.mdl.get_input_size_by_index(desc, 0) output_size acl.mdl.get_output_size_by_index(desc, 0) # 4. 分配設(shè)備內(nèi)存 input_data acl.util.numpy_to_ptr(acl.rt.malloc(input_size)) output_data acl.util.numpy_to_ptr(acl.rt.malloc(output_size)) # 5. 構(gòu)造輸入numpy數(shù)組并拷貝到設(shè)備 import numpy as np input_np np.random.rand(1, 3, 640, 640).astype(np.float16) acl.util.numpy_to_ptr(input_data, input_np) # 6. 執(zhí)行推理 ret acl.mdl.execute(model_id, [input_data], [output_data]) # 7. 取回輸出 output_np acl.util.ptr_to_numpy(output_data, (output_size,), np.uint8) # 8. 清理 acl.rt.free(input_data) acl.rt.free(output_data) acl.mdl.unload(model_id) acl.rt.reset_device(0) acl.finalize()這套流程看著簡(jiǎn)單但有幾個(gè)細(xì)節(jié)極易出錯(cuò)。第一個(gè)是顯存分配acl.rt.malloc出來(lái)的內(nèi)存有對(duì)齊要求通常是2MB對(duì)齊不能用普通的malloc或者Python的bytearray替代否則在acl.mdl.execute時(shí)會(huì)出現(xiàn)aclError異常。第二個(gè)是輸入數(shù)據(jù)類(lèi)型如果模型轉(zhuǎn)換時(shí)默認(rèn)輸入是FP16那么你在CPU側(cè)準(zhǔn)備的numpy數(shù)組必須是np.float16喂一個(gè)np.float32進(jìn)去輕則結(jié)果不對(duì)重則直接報(bào)內(nèi)存越界。解決的辦法是轉(zhuǎn)模型時(shí)用--input_formatNHWC配合--input_typeFP32或者在AIPP里配置好讓數(shù)據(jù)在硬件側(cè)完成格式轉(zhuǎn)換應(yīng)用層統(tǒng)一按某個(gè)約定來(lái)。4.2 推理結(jié)果的后處理上面說(shuō)的是不帶頭部解碼的模型輸出是三個(gè)特征圖。拿到特征圖之后要在CPU側(cè)把它們拼起來(lái)做解碼加NMS。這一步如果自己寫(xiě)比較容易出錯(cuò)的是錨框參數(shù)。YOLOv5默認(rèn)輸入是640x640三個(gè)檢測(cè)頭分別對(duì)應(yīng)80x80、40x40、20x20的特征圖每個(gè)特征圖上每個(gè)格子有3個(gè)錨框。解碼時(shí)先通過(guò)模型輸出的偏移量反算檢測(cè)框坐標(biāo)再按置信度閾值過(guò)濾再做NMS。這部分代碼量不少網(wǎng)上也有開(kāi)源實(shí)現(xiàn)但我建議拿YOLOv5官方的detect.py里后處理邏輯作為參照把它改成numpy或PyTorch版本接在ACL推理后面。有一點(diǎn)要特別提醒由于輸入做了letterbox推理出來(lái)的檢測(cè)框坐標(biāo)是基于640x640的letterbox圖像還原到原始圖像尺寸時(shí)需要先去掉填充的邊再按縮放比例映射回去。這個(gè)環(huán)節(jié)我見(jiàn)過(guò)太多同事栽跟頭檢測(cè)框整體偏了半個(gè)屏幕原因就是忘了把padding算進(jìn)去。5. 性能優(yōu)化從2路到8路并發(fā)的調(diào)優(yōu)實(shí)錄部署上線后性能是下一個(gè)繞不開(kāi)的話題。Atlas 300V 24G雖然有24GB顯存但如果你只是單線程、單請(qǐng)求跑YOLO那和用一張小卡區(qū)別不大完全發(fā)揮不出這張卡的價(jià)值。我在項(xiàng)目里通過(guò)并發(fā)適配把整卡推理吞吐提升了差不多三倍下面把思路整理出來(lái)。5.1 多Stream異步推理ACL的推理接口支持兩種調(diào)用方式同步和異步。同步接口acl.mdl.execute會(huì)阻塞等待NPU算完異步接口acl.mdl.execute_async把推理任務(wù)提交到指定的Stream上主線程可以繼續(xù)準(zhǔn)備下一幀輸入。用一個(gè)簡(jiǎn)單的生產(chǎn)者-消費(fèi)者模型把多路視頻幀循環(huán)讀取進(jìn)來(lái)塞進(jìn)不同Stream再統(tǒng)一回收結(jié)果CPU利用率會(huì)明顯改善。注意Stream和Device的關(guān)系一張Atlas 300V 24G卡對(duì)應(yīng)一個(gè)Device但可以創(chuàng)建多個(gè)Stream。Stream之間互不干擾可以并行執(zhí)行。我實(shí)測(cè)創(chuàng)建4個(gè)Stream配合動(dòng)態(tài)batch每個(gè)batch2總共相當(dāng)于一次處理8張圖吞吐很穩(wěn)。5.2 模型輸入輸出內(nèi)存復(fù)用如果每處理一幀都重新acl.rt.malloc和acl.rt.free時(shí)間開(kāi)銷(xiāo)很驚人。正確做法是啟動(dòng)時(shí)分配好一塊固定大小的設(shè)備內(nèi)存池推理過(guò)程中反復(fù)復(fù)用同一塊顯存。輸入側(cè)尤其明顯視頻流的圖像尺寸是固定的比如1920x1080letterbox到640x640輸入緩沖區(qū)完全可以初始化一次每幀只需把像素?cái)?shù)據(jù)memcpy進(jìn)去。輸出側(cè)也類(lèi)似因?yàn)槟P徒Y(jié)構(gòu)不變輸出shape是固定的分配一次就行循環(huán)用。5.3 量化與精度實(shí)測(cè)YOLO模型在GPU上通常用FP16跑但在Atlas 300V 24G上真正能拉開(kāi)差距的是INT8量化。用昇騰的AMCT工具做量化校準(zhǔn)流程大體是把驗(yàn)證集圖片送入模型收集激活值分布然后生成量化配置再把模型轉(zhuǎn)成INT8的OM。步驟比直接ATC轉(zhuǎn)換稍復(fù)雜但收益直接INT8模式下的推理延遲大約是FP16的1/3吞吐是FP16的2.5倍以上。量化后精度多少會(huì)掉一點(diǎn)我在COCO驗(yàn)證集上測(cè)過(guò)YOLOv5s的mAP均值從FP16的37.4降到INT8的35.9左右下降大約1.5個(gè)點(diǎn)但換來(lái)的是吞吐翻倍多在實(shí)時(shí)檢測(cè)場(chǎng)景下完全值。如果你對(duì)精度特別敏感還可以做敏感度分析把個(gè)別層保留FP16混合精度量化。6. 部署現(xiàn)場(chǎng)的問(wèn)題排查速查表最后這部分是我的私藏干貨。部署Atlas 300V 24G跑YOLO這段時(shí)間很多事情文檔里不會(huì)寫(xiě)只有踩過(guò)坑才知道怎么對(duì)癥下藥。我整理成速查表各位可以直接對(duì)照排查。現(xiàn)象可能原因解決辦法npu-smi查不到設(shè)備驅(qū)動(dòng)沒(méi)裝好或PCIe鏈路異常檢查lspci是否識(shí)別重新安裝驅(qū)動(dòng)并重啟加載OM時(shí)報(bào)aclError 500001CANN版本和驅(qū)動(dòng)版本不匹配或OM由更高版本ATC生成用ascend-toolkit/latest/atc的同版本ATC重新轉(zhuǎn)換轉(zhuǎn)換時(shí)報(bào)Unsupport op typeONNX里存在CANN不支持的算子如EfficientNMS重新導(dǎo)出ONNX并剔除后處理層或降低opset版本推理結(jié)果全為0或全無(wú)檢測(cè)框輸入shape、數(shù)據(jù)類(lèi)型或AIPP配置與訓(xùn)練時(shí)不一致核對(duì)--input_shape、--input_format用print輸出輸入張量均值確認(rèn)feed正確檢測(cè)框偏移但類(lèi)別正確letterbox padding未還原后處理時(shí)按padding裁剪后映射回原圖坐標(biāo)多路并發(fā)時(shí)內(nèi)存占用異常高每個(gè)請(qǐng)求都獨(dú)立分配設(shè)備內(nèi)存改用內(nèi)存池復(fù)用或限制同時(shí)執(zhí)行的stream數(shù)量動(dòng)態(tài)batch執(zhí)行報(bào)錯(cuò)調(diào)用時(shí)未使用已設(shè)置過(guò)的batch數(shù)確保batch數(shù)在dynamic_batch_size列表內(nèi)除了表格里的問(wèn)題還有兩個(gè)常見(jiàn)的系統(tǒng)級(jí)坑。一是大頁(yè)內(nèi)存配置。CANN框架在申請(qǐng)大塊顯存時(shí)依賴于系統(tǒng)預(yù)留的大頁(yè)內(nèi)存如果宿主機(jī)默認(rèn)/proc/sys/vm/nr_hugepages太小會(huì)出現(xiàn)明明板卡顯存充足但acl.rt.malloc一直失敗的詭異現(xiàn)象。建議在部署腳本里加一句echo 512 /proc/sys/vm/nr_hugepages根據(jù)任務(wù)量適當(dāng)調(diào)整。二是ulimit -n文件描述符限制。多路視頻流加多Stream推理時(shí)會(huì)打開(kāi)大量文件描述符默認(rèn)1024經(jīng)常不夠建議改成ulimit -n 65535。在性能排查上我推薦一個(gè)習(xí)慣把npu-smi info集成到監(jiān)控頁(yè)面里實(shí)時(shí)盯著芯片利用率(AICore%)和內(nèi)存用量。如果跑多路推理但AICore一直偏低多半是數(shù)據(jù)pipeline卡在CPU的預(yù)處理或后處理上如果AICore持續(xù)高位但幀率還是不夠那就是到了算力瓶頸考慮INT8或者用更輕量級(jí)的YOLO變體。還有一點(diǎn)和部署架構(gòu)相關(guān)Atlas 300V 24G是單卡但一臺(tái)服務(wù)器可以插多張。如果業(yè)務(wù)并發(fā)特別大多卡方案比單卡堆stream更可靠。多卡時(shí)需要在代碼里顯式指定device id再用負(fù)載均衡把請(qǐng)求分發(fā)到不同卡上。這一套在昇騰上天然支持每張卡的device id通過(guò)acl.rt.set_device指定即可。最后分享一個(gè)實(shí)用小技巧我自己的感受是Atlas 300V 24G在YOLO部署場(chǎng)景里真正花時(shí)間的不是模型轉(zhuǎn)換本身而是和它配套的工程化調(diào)優(yōu)。最開(kāi)始我花了一整個(gè)下午在搞AIPP配置和letterbox的對(duì)應(yīng)關(guān)系后來(lái)總結(jié)出一個(gè)萬(wàn)能口訣模型訓(xùn)練時(shí)怎么預(yù)處理部署時(shí)就怎么預(yù)處理不要過(guò)度依賴AIPP去做訓(xùn)練時(shí)沒(méi)做過(guò)的事。AIPP能做的是硬件加速的歸一化和色彩轉(zhuǎn)換而resize、letterbox這些涉及幾何變換的操作最好在CPU側(cè)嚴(yán)格復(fù)現(xiàn)訓(xùn)練時(shí)的邏輯這樣才能保證精度和線上表現(xiàn)一致。另外一個(gè)小技巧ATC轉(zhuǎn)換成功后用om模型查看工具把模型結(jié)構(gòu)再核對(duì)一遍確認(rèn)輸入輸出節(jié)點(diǎn)的名字、shape、dtype都符合預(yù)期。這一步看起來(lái)多余但能幫你提前發(fā)現(xiàn)轉(zhuǎn)換過(guò)程中可能發(fā)生的隱式shape變化。我至少遇到兩次模型轉(zhuǎn)換成功、推理卻報(bào)輸入尺寸不符的情況都是因?yàn)橐婚_(kāi)始沒(méi)核對(duì)模型描述。Atlas這張卡本身就是為大規(guī)模推理而生的。從單卡單路到單卡八路從FP16到INT8每個(gè)階段的優(yōu)化都能看到實(shí)打?qū)嵉淖兓?。建議你也從最小的閉環(huán)跑起來(lái)先跑通一個(gè)batch1的YOLOv5s等整條鏈路通了再逐步加并發(fā)、加量化、加多卡調(diào)度。算力畢竟是拿來(lái)用的不是拿來(lái)看參數(shù)的。