戰(zhàn))
有人拿著一張Atlas 300V 24G的卡用命令一查nvidia-smi沒有任何輸出第一反應(yīng)是“這卡是不是壞了”。其實(shí)它壓根不是GPU。最近后臺(tái)被問得最頻繁的一句話就是“Atlas 300V 24G是運(yùn)算加速卡嗎”。我給個(gè)直接回答它是AI推理加速卡核心是昇騰自研NPU不是用來跑CUDA訓(xùn)練的那類GPU但它的24G內(nèi)存和百級(jí)TOPS算力正好用來干部署YOLO這種推理活。這篇文章我會(huì)拿一張真實(shí)跑過YOLOv5的Atlas 300V 24G說事把硬件識(shí)別、環(huán)境搭建、模型轉(zhuǎn)換、Python推理代碼、以及一堆報(bào)錯(cuò)坑完整過一遍。無論你是剛拿到卡的小白還是已經(jīng)在別的推理卡上調(diào)過模型的老手都能從中找到能直接照抄的東西。1. 先弄清楚Atlas 300V 24G在硬件里的準(zhǔn)確角色1.1 它為什么叫“運(yùn)算加速卡”又為什么不是“GPU”很多剛接觸Atlas的人會(huì)有一個(gè)“慣性認(rèn)知”只要是一塊插在PCIe槽里帶散熱片的加速卡那就是GPU。這個(gè)認(rèn)知在Atlas 300V 24G上行不通。它的芯片是昇騰310P屬于NPU架構(gòu)設(shè)計(jì)目標(biāo)非常聚焦高效執(zhí)行神經(jīng)網(wǎng)絡(luò)中的算子尤其是卷積、矩陣乘、激活函數(shù)這些推理密集操作。它不是通用并行計(jì)算設(shè)備不能跑渲染也不支持CUDA。判斷一塊卡是什么類型別只看外形要看系統(tǒng)怎么識(shí)別。Atlas 300V 24G插到服務(wù)器之后執(zhí)行l(wèi)spci一般會(huì)顯示Processing accelerators這一類設(shè)備。用nvidia-smi必然看不到因?yàn)樗鼪]有NVIDIA芯片這時(shí)候需要用的是npu-smi info類似GPU場景里的nvidia-smi。我第一次拿到這塊卡時(shí)第一眼看到24G心里想的是“這HDMI接口在哪”后來才意識(shí)到自己完全搞錯(cuò)了方向——它連視頻輸出接口都沒有純粹是計(jì)算用的。還有一個(gè)更關(guān)鍵的區(qū)別訓(xùn)練卡和推理卡不能混為一談。拿T4這種卡做推理沒問題但它同時(shí)也能訓(xùn)練模型因?yàn)橛?xùn)練需要反向傳播、自動(dòng)求導(dǎo)需要高精度的FP16甚至FP32還依賴大容量顯存和高速互連。Atlas 300V 24G的定位則偏“專用推理”它不做反向傳播也不需要支持各種奇怪的浮點(diǎn)指令集它只需要把訓(xùn)練好的權(quán)重在低精度下反復(fù)做前向推理把算力利用率拉滿。這也是為什么它在功耗和性價(jià)比上能比同級(jí)別GPU更有優(yōu)勢。1.2 關(guān)鍵規(guī)格24G內(nèi)存、INT8算力、功耗與接口從拿到手的這塊卡硬件信息來看參數(shù)大概是這樣的不同批次可能有細(xì)微差別以官方規(guī)格為準(zhǔn)維度參數(shù)芯片昇騰310PAtlas 300V Pro 對應(yīng)版本內(nèi)存24GBINT8算力約140 TOPSFP16算力約70 TFLOPS卡功耗約72W具體看負(fù)載和型號(hào)接口PCIe 4.0 x16散熱方式無風(fēng)扇被動(dòng)散熱需要服務(wù)器風(fēng)道配合24G這個(gè)容量非常有意思。YOLOv5s的權(quán)重文件才十幾MB你可能會(huì)想“24G是不是浪費(fèi)了”其實(shí)不浪費(fèi)。推理時(shí)吃內(nèi)存的不是權(quán)重而是中間特征圖和批量處理產(chǎn)生的輸出。比如你想跑一個(gè)batch size為16的YOLOv5m每幀1080P分辨率經(jīng)過letterbox后縮到640×640中間特征圖占用會(huì)隨著batch線性增長再加上多路視頻流并行24G能讓你從容地安排多batch任務(wù)而不用擔(dān)心內(nèi)存溢出。INT8的算力才是這塊卡的“殺手锏”。140 TOPS是在INT8精度下測出來的前提是模型要做量化把FP32或FP16的權(quán)重和激活值壓到8位整數(shù)。實(shí)際部署的時(shí)候大多數(shù)YOLO模型都能在精度損失極小的情況下轉(zhuǎn)成INT8從而吃滿這個(gè)算力。如果你堅(jiān)持用FP16跑那算力會(huì)縮水一半但仍然可用。1.3 適合什么場景、不適合什么場景基于上面這些參數(shù)我對這塊卡的使用邊界做了一個(gè)很主觀的劃分。適合的場景有三類AI視頻分析比如工廠質(zhì)檢、安防監(jiān)控、交通流量統(tǒng)計(jì)。這類場景通常是多路RTSP視頻流接進(jìn)來每一路都跑一個(gè)YOLO目標(biāo)檢測24G內(nèi)存和較高的INT8算力可以支撐比較大的并發(fā)路數(shù)。私有化推理服務(wù)客戶要求數(shù)據(jù)不出內(nèi)網(wǎng)或者不讓用公有云GPU。Atlas 300V 24G可以作為獨(dú)立PCIe卡插入通用服務(wù)器部署成內(nèi)網(wǎng)推理節(jié)點(diǎn)。低功耗邊緣一體機(jī)整機(jī)功耗受限制的機(jī)箱里一塊72W的卡比一塊250W的GPU好交代得多。不適合的場景也很明確訓(xùn)練新模型沒有高精度浮點(diǎn)回傳能力也沒有多卡高速互聯(lián)強(qiáng)行訓(xùn)練就是折磨自己。通用GPU計(jì)算比如CUDA生態(tài)里的RAPIDS數(shù)據(jù)處理、Blender渲染這些不是AI算子NPU完全幫不上忙該上NVIDIA就上NVIDIA。2. 為什么拿它跑YOLO以及整體流程怎么走2.1 推理成本對比一張300V能頂多少路視頻我拿一張Atlas 300V 24G跑YOLOv5s輸入分辨率640×640batch size設(shè)為1實(shí)測單幀推理耗時(shí)大約在6-10毫秒之間不同CANN版本和量化精度有波動(dòng)。這個(gè)數(shù)據(jù)意味著什么如果按每路視頻25FPS計(jì)算一幀處理周期是40毫秒單卡串行處理的話理想情況下能扛住4-6路實(shí)時(shí)視頻。但如果你把batch size調(diào)大或者用多個(gè)stream并行一張卡可以同時(shí)處理更多路畫面。這正好是它競爭力最強(qiáng)的地方。同樣跑YOLOv5s推理一張圖形卡動(dòng)輒200W以上功耗性能確實(shí)更強(qiáng)但很多時(shí)候你在生產(chǎn)環(huán)境里根本不需要訓(xùn)練級(jí)算力需要的只是“穩(wěn)定、低功耗、能吃滿多路視頻流”。Atlas 300V 24G用72W功耗做到這個(gè)量級(jí)機(jī)房散熱、電費(fèi)成本都會(huì)友好很多。當(dāng)然我不是說它比GPU快。單看絕對算力GPU仍然有優(yōu)勢。但推理卡有一個(gè)隱藏優(yōu)勢模型轉(zhuǎn)換后算子與硬件綁定更緊實(shí)際推理效率往往很高而且不存在“顯卡驅(qū)動(dòng)頻繁更新導(dǎo)致推理庫不兼容”這種問題。生產(chǎn)部署圖的是一個(gè)穩(wěn)定Atlas恰恰抓中了這個(gè)點(diǎn)。2.2 跑通YOLO的全鏈路五步從PyTorch權(quán)重到OM模型在開始敲命令之前你腦子里一定要有全鏈路圖。我畫個(gè)簡單的流程PyTorch權(quán)重(.pt) - ONNX(.onnx) - OM(.om) - ACL推理 - 后處理輸出這個(gè)鏈路里每一步都有坑。比如ONNX導(dǎo)出時(shí)某個(gè)算子版本不對ATC轉(zhuǎn)換時(shí)就報(bào)錯(cuò)OM模型轉(zhuǎn)換成功后推理代碼里數(shù)據(jù)排布不對檢測框就會(huì)“漂移”。所以建議按順序分階段驗(yàn)證不要一口氣從PyTorch直接跳到部署腳本。具體拆解成五步環(huán)境準(zhǔn)備裝驅(qū)動(dòng)、固件、CANN工具包。模型導(dǎo)出用PyTorch導(dǎo)出ONNX設(shè)置固定shape和算子版本。格式轉(zhuǎn)換用ATC把ONNX轉(zhuǎn)成OM按需配置AIPP預(yù)處理。推理編碼用Python/C調(diào)用AscendCL接口加載OM并執(zhí)行推理。服務(wù)封裝把前四步封裝成HTTP接口或RTSP流處理供業(yè)務(wù)調(diào)用。后兩步通常由項(xiàng)目開發(fā)完成但前四步才是決定項(xiàng)目能否跑通的關(guān)鍵。2.3 硬件部署的形態(tài)服務(wù)器還是工控機(jī)Atlas 300V 24G是一張標(biāo)準(zhǔn)PCIe卡物理尺寸比我預(yù)想的小一些但被動(dòng)散熱意味著你必須把它裝在有風(fēng)道的機(jī)器里。我見過有人在開放式礦機(jī)架上插這塊卡結(jié)果負(fù)載一高就過熱降頻檢測速度直接掉一半。建議至少保證從機(jī)箱前方到顯卡位置有持續(xù)氣流。插卡位置優(yōu)先選PCIe x16全長插槽如果主板只有x8通道理論上也能運(yùn)行但帶寬減半。對于單路YOLO推理PCIe帶寬并不是明顯瓶頸真正吃帶寬的是多路視頻數(shù)據(jù)不停往卡上拷貝所以有條件還是上x16。供電方面這張卡整體功耗不高通過PCIe插槽供電基本就夠不需要額外接8pin供電線。3. 環(huán)境搭建驅(qū)動(dòng)、固件、CANN一個(gè)都不能少3.1 驅(qū)動(dòng)和固件安裝順序先固件后驅(qū)動(dòng)Atlas環(huán)境的安裝順序有講究我第一次安裝的時(shí)候先裝了驅(qū)動(dòng)后來跑模型一加載就報(bào)錯(cuò)排查半天發(fā)現(xiàn)是固件版本不對。正確的順序是先裝固件firmware再裝驅(qū)動(dòng)driver。因?yàn)轵?qū)動(dòng)在加裝時(shí)會(huì)校驗(yàn)芯片固件版本版本不匹配直接會(huì)導(dǎo)致NPU設(shè)備狀態(tài)變成“abnormal”。以x86架構(gòu)的Ubuntu 20.04系統(tǒng)為例。拿到驅(qū)動(dòng)安裝包Ascend-hdk-310P-npu-driver_23.0.rc1_linux-x86_64.run后先不要急著雙擊安裝。執(zhí)行chmod x Ascend-hdk-310P-npu-driver_23.0.rc1_linux-x86_64.run ./Ascend-hdk-310P-npu-driver_23.0.rc1_linux-x86_64.run --full安裝完成后立刻驗(yàn)證固件npu-smi info -t board -i 0能看到固件版本號(hào)說明設(shè)備已經(jīng)被系統(tǒng)識(shí)別。如果報(bào)錯(cuò)“No device found”先檢查卡是否插緊然后確認(rèn)PCIe插槽在BIOS里是否被識(shí)別。驅(qū)動(dòng)安裝完成后重啟服務(wù)器再用npu-smi info查看所有NPU芯片。正常狀態(tài)應(yīng)該是health: OK芯片溫度、內(nèi)存占用都列得清清楚楚。如果顯示abnormal多半就是固件和驅(qū)動(dòng)匹配問題老老實(shí)實(shí)按版本配套表重新裝。3.2 CANN工具包安裝與環(huán)境變量驅(qū)動(dòng)裝好只是第一步CANN昇騰計(jì)算語言才是真正讓你能跑模型的東西。CANN版本很多我用的是7.0.RC1搭配Python 3.8。下載Ascend-cann-toolkit_7.0.RC1_linux-x86_64.run后同樣賦予執(zhí)行權(quán)限并安裝./Ascend-cann-toolkit_7.0.RC1_linux-x86_64.run --install裝完之后環(huán)境變量不會(huì)自動(dòng)全局生效需要手動(dòng)source腳本。每次開終端都要執(zhí)行或者直接把它寫進(jìn)~/.bashrcsource /usr/local/Ascend/ascend-toolkit/set_env.sh這一步經(jīng)常被忽略。有人在Python腳本里import acl結(jié)果報(bào)ModuleNotFoundError其實(shí)不是包沒裝而是環(huán)境變量沒指到ascend-toolkit的Python庫路徑。如果acl模塊找不到先執(zhí)行print(os.environ[ASCEND_HOME_PATH])確認(rèn)路徑是否正常。3.3 安裝后的自檢方法基礎(chǔ)環(huán)境搭完后不要急著轉(zhuǎn)模型先確認(rèn)三個(gè)指標(biāo)npu-smi info能看到芯片且溫度正常。ldconfig -p | grep ascend能看到相關(guān)so庫。Python環(huán)境下執(zhí)行import acl然后調(diào)用acl.init()返回成功。我一般寫一個(gè)最簡單的測試腳本import acl ret acl.init() print(acl init:, ret)如果打印結(jié)果為acl init: 0說明ACL API調(diào)用鏈沒問題。這一步過了再走模型轉(zhuǎn)換能排除80%的底層環(huán)境問題。4. YOLO模型轉(zhuǎn)換從PyTorch到OM的最佳實(shí)踐4.1 從YOLOv5導(dǎo)出ONNX時(shí)參數(shù)怎么設(shè)YOLOv5導(dǎo)出ONNX原本在GPU平臺(tái)上很簡單但為了Atlas轉(zhuǎn)換順利有幾個(gè)參數(shù)必須提前控制好。最省事的方式是固定輸入尺寸和batch size。我用的命令是python export.py --weights yolov5s.pt --include onnx --opset 11 --batch-size 1 --img 640 640--opset 11很關(guān)鍵。ATCA工具對高版本ONNX算子支持可能不夠完備如果導(dǎo)出時(shí)用的opset 17之后ATC轉(zhuǎn)換大概率會(huì)碰到不支持的算子報(bào)錯(cuò)。固定shape是為了避免動(dòng)態(tài)維度在ATC轉(zhuǎn)換時(shí)產(chǎn)生額外復(fù)雜度。如果實(shí)際部署時(shí)必須支持不同分辨率建議在推理外層做縮放而不是模型內(nèi)部搞動(dòng)態(tài)shape。導(dǎo)出后用onnx.checker驗(yàn)證一下模型結(jié)構(gòu)import onnx m onnx.load(yolov5s.onnx) onnx.checker.check_model(m) print(onnx.helper.printable_graph(m.graph)[:500])如果結(jié)構(gòu)正常接著做ATC轉(zhuǎn)換。4.2 使用ATC工具轉(zhuǎn)換ONNX到OMATC是模型轉(zhuǎn)換的核心工具命令格式source /usr/local/Ascend/ascend-toolkit/set_env.sh atc --modelyolov5s.onnx --framework5 \ --outputyolov5s_bs1 \ --input_formatNCHW \ --input_shapeimages:1,3,640,640 \ --soc_versionAscend310P3 \ --output_typeFP32逐個(gè)參數(shù)說明--framework5表示輸入格式是ONNX。--input_shape里images名稱要和ONNX輸入節(jié)點(diǎn)名一致用onnx.load看graph.input[0].name就能拿到。--soc_version是目標(biāo)芯片版本我的卡識(shí)別出來的芯片是Ascend310P3。如果不知道直接查npu-smi info -t board -i 0輸出里有芯片型號(hào)。--output_type建議設(shè)為FP32這是輸出的數(shù)據(jù)精度不要和模型量化搞混。推理時(shí)輸入和輸出通常用FP32中間計(jì)算會(huì)降精度。如果希望在Atlas芯片上做AIPP預(yù)處理可以額外加一個(gè)配置文件。AIPP可以在卡上完成圖片縮放、減均值、除以標(biāo)準(zhǔn)差等操作這樣CPU端就不用重復(fù)做預(yù)處理能省不少CPU占用。但為了調(diào)試方便我第一次做的時(shí)候沒有用AIPP而是在代碼里用OpenCV做縮放和歸一化。這個(gè)選擇因人而異后面我會(huì)給建議。轉(zhuǎn)換成功后會(huì)生成yolov5s_bs1.om文件。用ls -lh看看文件大小一般幾十MB。如果只有幾KB那基本是轉(zhuǎn)換出錯(cuò)了。4.3 轉(zhuǎn)換過程中的常見報(bào)錯(cuò)與對策ATC轉(zhuǎn)換報(bào)錯(cuò)是最勸退的一環(huán)。我把高頻報(bào)錯(cuò)整理一下報(bào)錯(cuò)信息原因?qū)Σ逧10001版本不匹配檢查soc_version與當(dāng)前驅(qū)動(dòng)匹配E40000 unsupported op算子不支持多出現(xiàn)在高版本ONNX中降低opset再導(dǎo)ONNXCheckInputShape輸入shape的名稱或尺寸不對查看ONNX輸入節(jié)點(diǎn)調(diào)整input_shapeSet aipp相關(guān)錯(cuò)誤AIPP配置寫錯(cuò)先不使用AIPP跑通后再加上我的經(jīng)驗(yàn)總結(jié)就是先用最樸素的配置不要加任何高級(jí)優(yōu)化參數(shù)跑通一個(gè)最簡單OM模型然后再逐步加AIpp、多batch、動(dòng)態(tài)分辨率。5. 用Python調(diào)用AscendCL跑YOLO推理5.1 Python ACL接口的核心概念拿到OM模型之后需要寫推理代碼。Atlas上模型推理的編程接口叫AscendCLACLPython接口風(fēng)格和C很像但是因?yàn)橛蠫IL限制高性能場景建議最終用C或者多進(jìn)程純Python適合快速驗(yàn)證。ACL的核心概念包括Device物理NPU設(shè)備用acl.rt.set_device(0)選擇。Context設(shè)備上的上下文類似CPU進(jìn)程里的程序計(jì)數(shù)器用于管理資源。Stream執(zhí)行隊(duì)列同一個(gè)stream里的算子和推理任務(wù)是串行的不同stream可以并行。Model加載的OM模型。DataBuffer輸入輸出數(shù)據(jù)的內(nèi)存封裝。整體流程是初始化ACL - 設(shè)置Device - 創(chuàng)建Context - 創(chuàng)建Stream - 加載模型 - 準(zhǔn)備輸入輸出內(nèi)存 - 執(zhí)行推理 - 解析結(jié)果 - 釋放資源。5.2 一段能跑的推理代碼骨架下面這段代碼是我實(shí)際調(diào)試用的簡化版完整處理了單張圖片并做了解析。YOLOv5的OM輸入和輸出的內(nèi)存分配都需要對齊到32字節(jié)所以我用acl.rt.malloc而不是普通的numpy數(shù)組。import cv2 import numpy as np import acl def letterbox(img, new_shape(640, 640), color(114, 114, 114)): shape img.shape[:2] r min(new_shape[0] / shape[0], new_shape[1] / shape[1]) new_unpad (int(round(shape[1] * r)), int(round(shape[0] * r))) dw (new_shape[1] - new_unpad[0]) / 2 dh (new_shape[0] - new_unpad[1]) / 2 if shape[::-1] ! new_unpad: img cv2.resize(img, new_unpad, interpolationcv2.INTER_LINEAR) top, bottom int(round(dh - 0.1)), int(round(dh 0.1)) left, right int(round(dw - 0.1)), int(round(dw 0.1)) img cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, valuecolor) return img def init(): acl.init() acl.rt.set_device(0) context, ret acl.rt.create_context(0) stream, ret acl.rt.create_stream() return context, stream def run_inference(model_id, input_data): desc acl.mdl.create_desc() 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) input_data np.ascontiguousarray(input_data) input_ptr acl.util.numpy_to_ptr(input_data) output_np np.zeros((output_size,), dtypenp.uint8) output_ptr acl.util.numpy_to_ptr(output_np) ret acl.mdl.execute(model_id, [input_ptr], [input_size], [output_ptr], [output_size]) if ret ! 0: raise RuntimeError(facl.mdl.execute failed: {ret}) return output_np context, stream init() model_path byolov5s_bs1.om model_id, ret acl.mdl.load_from_file(model_path) img cv2.imread(test.jpg) img letterbox(img) blob cv2.cvtColor(img, cv2.COLOR_BGR2RGB) blob blob.astype(np.float32) / 255.0 blob blob.transpose(2, 0, 1) blob np.expand_dims(blob, 0) blob np.ascontiguousarray(blob) output_data run_inference(model_id, blob) # output_data 后續(xù)需要解析成檢測框、置信度、類別 print(output_data.shape)注意代碼里output_size是OM模型輸出數(shù)據(jù)的總字節(jié)數(shù)。因?yàn)閅OLOv5的detect頭有多個(gè)輸出直接解析時(shí)要把輸出buffer按輸出維度切分。更規(guī)范的做法是創(chuàng)建多個(gè)輸出buffer一 一對應(yīng)acl.mdl.get_output_size_by_index這里為了簡潔我沒寫完整。5.3 性能調(diào)優(yōu)多batch、并發(fā)Stream單張圖片推理速度測試沒問題后再考慮性能優(yōu)化。我實(shí)踐的優(yōu)先級(jí)是先上多batch把多張圖拼成一個(gè)batch一次推理。比如batch size4推理時(shí)間可能只比單張多50%但總吞吐翻倍??梢孕薷膶?dǎo)出和轉(zhuǎn)換時(shí)的batch size為4再在代碼里把4張圖拼接成[4, 3, 640, 640]。再用多線程/多進(jìn)程每個(gè)線程創(chuàng)建獨(dú)立的stream和context避免互相阻塞。Python多線程受GIL限制CPU預(yù)處理部分會(huì)拖后腿可以用多進(jìn)程但要注意模型加載是否需要在每個(gè)進(jìn)程中單獨(dú)執(zhí)行。用AIPP替代CPU預(yù)處理把resize、歸一化搬進(jìn)卡內(nèi)減少host到device的拷貝量。這里提醒一個(gè)很多人忽略的問題不要在推理循環(huán)里每次都load_from_file加載模型。模型加載很耗時(shí)正確做法是服務(wù)啟動(dòng)時(shí)加載一次之后只執(zhí)行acl.mdl.execute。6. 我在部署中踩過的坑和針對性解決辦法6.1 npu-smi顯示abnormal驅(qū)動(dòng)與固件不一致第一次裝完重啟npu-smi info顯示芯片狀態(tài)是abnormal溫度顯示異常內(nèi)存大小為0。排查了一圈最后確認(rèn)是固件版本太舊而驅(qū)動(dòng)版本過新。解決方式是去官網(wǎng)下載與驅(qū)動(dòng)配套的固件包先卸載驅(qū)動(dòng)再升級(jí)固件最后重裝驅(qū)動(dòng)。這個(gè)順序千萬不能反過來。后來我把“先固件后驅(qū)動(dòng)”寫進(jìn)了團(tuán)隊(duì)部署手冊。6.2 模型轉(zhuǎn)換時(shí)unsupported op導(dǎo)致半途而廢YOLOv5 6.0版本導(dǎo)出的ONNX在opset 17下ATC會(huì)報(bào)Unsupported OpResize。我一開始以為要手寫自定義算子后來發(fā)現(xiàn)把opset降到11就能解決問題。原因是高版本ONNX的一些算子分支在ATC支持列表里確實(shí)沒有覆蓋到。如果確實(shí)需要使用高版本opset可以嘗試在ONNX模型里把Resize替換成ResizeV2部分CANN版本支持但最省力的還是降opset。6.3 推理輸出全0或檢測框偏移的根因分析有一類問題是“模型跑通了但結(jié)果不對”。我排查過兩個(gè)典型輸出全0大概率是輸入數(shù)據(jù)排列不對。Atlas對輸入內(nèi)存的對齊要求很高某些情況下輸入buffer需要按32字節(jié)對齊。用numpy_to_ptr時(shí)要把輸入numpy數(shù)組做np.ascontiguousarray確保內(nèi)存連續(xù)。另外歸一化方式要和訓(xùn)練時(shí)一致。YOLOv5官方源碼是除以255不是減均值除以標(biāo)準(zhǔn)差搞錯(cuò)了輸出當(dāng)然異常。檢測框偏移這是letterbox坑。如果訓(xùn)練時(shí)用640×640的letterbox推理時(shí)卻直接把原圖縮放到640×640沒有灰邊填充坐標(biāo)映射就對不上。推理后還原坐標(biāo)時(shí)要記得減去letterbox的padding再除以縮放比例。很多新手漏了這一步導(dǎo)致框偏到左上角。6.4 一張最終推薦的部署配置參考表為了方便你少走彎路我放一個(gè)經(jīng)過驗(yàn)證的參考配置配置項(xiàng)推薦值操作系統(tǒng)Ubuntu 20.04 x86_64NPU驅(qū)動(dòng)23.0.RC1CANN7.0.RC1Python3.8模型YOLOv5 6.0ONNX opset11輸入尺寸640×640batch size1調(diào)試 - 4上線輸出精度FP32量化可選INT8精度損失可控時(shí)使用這套配置在我本地跑YOLOv5s單路視頻實(shí)時(shí)檢測穩(wěn)定連續(xù)運(yùn)行一周沒有出現(xiàn)內(nèi)存泄漏或掉卡。最后再分享一個(gè)我自己的小體會(huì)拿到Atlas 300V 24G之后不用急著去調(diào)并行、調(diào)精度。先把“單batch單張圖”的OM推理鏈路跑通npu-smi里的利用率肉眼可見地動(dòng)起來再考慮多路并發(fā)。這個(gè)卡很有意思的地方在于你用好了它就是一塊低功耗的“視頻檢測發(fā)動(dòng)機(jī)”用不好它就會(huì)因?yàn)楦鞣N環(huán)境問題變成一塊總有報(bào)錯(cuò)的粉塵板。當(dāng)你把ATC、ACL、AIPP這些概念一點(diǎn)點(diǎn)理清之后再回頭看最初“這是不是運(yùn)算加速卡”的問題你自己就能給出一個(gè)很篤定的答案是而且是專門為AI推理而生那種。