戰(zhàn):從YOLO模型轉(zhuǎn)換到部署避坑指南)
如果你最近也在看 AI 推理硬件應(yīng)該能在各種評(píng)測(cè)和規(guī)格表里高頻刷到“Atlas 300V 24G”這個(gè)名字。有人問它到底是不是運(yùn)算加速卡有人直接把手頭的 YOLO 模型往這塊卡上搬然后對(duì)著“算子不支持”“容器里找不到 NPU”之類的報(bào)錯(cuò)懷疑人生。作為一個(gè)在昇騰生態(tài)里摸爬過幾個(gè)推理項(xiàng)目的工程師我先給出一個(gè)明確的結(jié)論Atlas 300V 24G 是昇騰生態(tài)里的 AI 推理加速卡它不是通用 GPU但在“固定推理任務(wù)”這個(gè)自己擅長(zhǎng)的領(lǐng)域里它確實(shí)是一塊性價(jià)比很高的運(yùn)算加速卡。這篇文章就圍繞這塊卡聊聊它的真實(shí)定位、為什么適合跑 YOLO、從零部署的完整鏈路以及在實(shí)操中那些常規(guī)文檔不會(huì)寫的問題。1. 先搞清楚Atlas 300V 24G 到底是一塊什么卡1.1 它“算不算”運(yùn)算加速卡拆開“運(yùn)算加速卡”這個(gè)詞大部分人的第一反應(yīng)是 NVIDIA 的計(jì)算卡比如 V100、A100 這種可以跑科學(xué)計(jì)算、AI 訓(xùn)練、通用 CUDA 程序的 GPGPU。Atlas 300V 24G 和它們?cè)谶壿嬌嫌幸粋€(gè)核心差異它是一塊 NPU而且是一塊定位非常明確的推理卡。“推理加速”和“通用計(jì)算”的區(qū)別在哪用工廠類比GPU 是全能型選手既能做訓(xùn)練、又能做推理還能跑渲染而 Atlas 300V 更像一條專項(xiàng)流水線它對(duì)神經(jīng)網(wǎng)絡(luò)推理做了大量?jī)?yōu)化但對(duì)其他通用計(jì)算任務(wù)幾乎幫不上忙。你沒法把一段 CUDA 代碼拿到昇騰上直接跑也沒法拿它當(dāng)無腦的并行計(jì)算卡用。它支持的編程接口是 AscendCL模型的執(zhí)行單位是經(jīng)過 ATC 工具轉(zhuǎn)換后的離線模型文件OM 格式而不是像 GPU 那樣動(dòng)態(tài)加載一個(gè) PyTorch 模型就能跑。所以如果你問“Atlas 300V 24G 是運(yùn)算加速卡嗎”我的回答是它是 AI 推理加速卡在 AI 推理這個(gè)狹義場(chǎng)景下是一塊運(yùn)算加速卡但它不是通用計(jì)算卡。這個(gè)定位決定了它的選型思路和部署路徑也決定了它適合哪些項(xiàng)目、不適合哪些項(xiàng)目。1.2 硬件規(guī)格與產(chǎn)品線對(duì)照Atlas 300V 的命名里“300V”代表這是一張半高半長(zhǎng)、主打視頻和視覺推理的 PCIe 卡。它基于昇騰 310P 處理器提供的 24GB 內(nèi)存對(duì)推理場(chǎng)景來說非常充裕。我自己在做選型時(shí)比較在意的幾個(gè)規(guī)格點(diǎn)整理成了表格方便你對(duì)照項(xiàng)目典型參數(shù)選型說明處理器昇騰 310P 系列不同 SoC 版本在 ATC 轉(zhuǎn)換時(shí)需指定對(duì)應(yīng) soc_version內(nèi)存24GB可以容納較大的模型也適合多路視頻流并發(fā)推理接口PCIe半高半長(zhǎng)單槽對(duì)服務(wù)器空間友好放普通工作站里也比較容易功耗官方標(biāo)稱約 70W 級(jí)別比同級(jí)別 GPU 低不少但也需要保證機(jī)箱風(fēng)道散熱執(zhí)行方式離線模型OM推理不支持實(shí)時(shí)解釋執(zhí)行 PyTorch 模型必須先做模型轉(zhuǎn)換開發(fā)接口AscendCL / pyACL類似 CUDA 的上層接口用于加載 OM、傳輸數(shù)據(jù)、執(zhí)行推理昇騰 300 系列里還有幾個(gè)容易混淆的型號(hào)。比如 Atlas 300V Pro帶 Pro 后綴內(nèi)存更高通常配置 48GBAtlas 300I Pro 則是面向服務(wù)器內(nèi)部集成場(chǎng)景的推理卡。它們?cè)隍?qū)動(dòng)、CANN 和 ATC 的 soc_version 參數(shù)上可能不一樣如果拿錯(cuò)了配置文件最典型的表現(xiàn)就是模型轉(zhuǎn)換時(shí)報(bào)“SoC version not support”之類的錯(cuò)。所以我建議你拿到卡之后第一件事不是急著裝環(huán)境而是用 npu-smi info 看芯片實(shí)際型號(hào)再對(duì)著版本確認(rèn)后續(xù)命令參數(shù)。1.3 適合什么場(chǎng)景不適合什么場(chǎng)景這塊卡最適合的場(chǎng)景一句話總結(jié)單路或多路視頻流上的目標(biāo)檢測(cè)、分類、分割等固定推理任務(wù)。在我接過的項(xiàng)目里Atlas 300V 出鏡率最高的幾個(gè)方向是智慧交通的車輛和行人檢測(cè)、安防場(chǎng)景的視頻結(jié)構(gòu)化、工業(yè)質(zhì)檢里的缺陷定位、OCR 文字識(shí)別。這些任務(wù)有一個(gè)共同點(diǎn)模型結(jié)構(gòu)基本固定、輸入尺寸基本固定、軟件??梢园汛蟛糠謨?yōu)化工作放到離線階段完成。這正是推理卡的舒適區(qū)。但不適合的場(chǎng)景也很明顯。如果你需要頻繁迭代模型結(jié)構(gòu)三天兩頭換新網(wǎng)絡(luò)或者要做大模型訓(xùn)練那 Atlas 300V 并不是好選擇。訓(xùn)練場(chǎng)景應(yīng)該考慮昇騰的 Atlas 800 訓(xùn)練服務(wù)器或者傳統(tǒng) GPU而快速實(shí)驗(yàn)階段用 GPU 也更省心。還有一個(gè)容易被忽略的限制現(xiàn)有基于 CUDA 寫成的推理服務(wù)遷移到昇騰上幾乎不可能做到零改動(dòng)至少模型導(dǎo)出、算子適配、預(yù)處理管線都要重新過一遍。2. 為什么“Atlas 300V YOLO”這個(gè)組合這么多人做2.1 YOLO 在邊緣推理里的地位YOLO 系列在目標(biāo)檢測(cè)領(lǐng)域算是最“皮實(shí)”的模型之一。YOLOv5 和 YOLOv8 的訓(xùn)練生態(tài)很成熟導(dǎo)出 ONNX 的路徑清晰部署到各類 AI 加速硬件上都有現(xiàn)成方案。這樣的特性正好契合 Atlas 300V 的部署邏輯訓(xùn)練階段你仍然可以使用 PyTorch 生態(tài)推理階段把模型轉(zhuǎn)換成 OM 文件交給昇騰執(zhí)行。另一個(gè)原因是 YOLO 的結(jié)構(gòu)相對(duì)規(guī)整主干網(wǎng)絡(luò)和檢測(cè)頭的算子基本都是卷積、歸一化、激活、拼接這類通用算子。昇騰的推理卡對(duì)這類算子的支持度很高很少遇到 GPU 上能跑、但轉(zhuǎn)換時(shí)“算子不支持”的尷尬情況。所以現(xiàn)在很多國(guó)產(chǎn)化推理項(xiàng)目的第一批模型清單里YOLO 總是排在最前面不是沒有道理的。2.2 昇騰跑 YOLO 的幾條主流路線昇騰生態(tài)里部署 YOLO大致有四條路可以走。我在項(xiàng)目里都嘗試過分別說一下它們的適用場(chǎng)景。第一條是 PyTorch 訓(xùn)練后導(dǎo)出 ONNX再用 ATC 轉(zhuǎn)成 OM最后用 AscendCL 推理。這是我最推薦的一條路線也是現(xiàn)在昇騰社區(qū)里資料最多的路線。它把訓(xùn)練框架和推理平臺(tái)解耦ONNX 作為中間格式方便做精度對(duì)比和算子排查。第二條是 MindSpore 訓(xùn)練導(dǎo)出 MindIR 再轉(zhuǎn) OM適合鐵了心使用全自研生態(tài)的團(tuán)隊(duì)但社區(qū)資料相對(duì)少遇到問題需要自己啃文檔。第三條是 PyTorch torch_npu在 PyTorch 里直接把模型搬到 NPU 上推理適合不想重寫推理框架的原型驗(yàn)證但性能不一定比純 OM AscendCL 方案有優(yōu)勢(shì)。第四條是從 Darknet 權(quán)重轉(zhuǎn) ONNX 再轉(zhuǎn) OMYOLOv4 時(shí)代的老項(xiàng)目可能用到現(xiàn)在新項(xiàng)目基本不需要考慮了。路線技術(shù)棧適合人群缺點(diǎn)ONNX → ATC → OM ACLPyTorch / ONNX / ATC大多數(shù)生產(chǎn)項(xiàng)目需要適配預(yù)處理和后處理MindSpore → MindIR → OMMindSpore / C 或 Python全昇騰生態(tài)團(tuán)隊(duì)文檔少上手門檻高PyTorch torch_npuPyTorch / NPU 加速快速驗(yàn)證原型性能上限不明確算子兼容性偶發(fā)Darknet → ONNX → OMDarknet / ONNX維護(hù) YOLOv4 老項(xiàng)目鏈路長(zhǎng)轉(zhuǎn)換容易踩坑2.3 部署方案的選擇邏輯在確定技術(shù)路線之后接下來要決定的是模型實(shí)例和 batch 的部署方式。這個(gè)選擇直接影響吞吐和延遲GPU 里的那套經(jīng)驗(yàn)在昇騰上依然大致成立。如果只有一路視頻流模型 batch 設(shè)成 1 就夠延遲最低邏輯最簡(jiǎn)單。如果有多路視頻流要做實(shí)時(shí)檢測(cè)我建議不要開多個(gè)進(jìn)程各跑一個(gè) batch1 的模型而是盡量把多幀數(shù)據(jù)拼成一個(gè) batch 喂給同一個(gè)模型實(shí)例。比如 4 路視頻流每一輪取 4 幀拼成 batch4 輸入推理一次得到 4 個(gè)結(jié)果。這樣做的好處是最大化利用 310P 的算力也避免多進(jìn)程搶資源時(shí)的不穩(wěn)定。24GB 內(nèi)存對(duì) YOLO 系列目標(biāo)檢測(cè)模型來說剩余量很大。即使在 batch8 的前提下同時(shí)加載好幾個(gè)模型實(shí)例也完全夠用。實(shí)際項(xiàng)目中真正的瓶頸往往不在 NPU 算力而在視頻解碼鏈路。如果每路視頻流都用 OpenCV 的 VideoCapture 在 CPU 上解碼高分辨率高幀率的視頻很可能讓 CPU 先跑滿。這時(shí)候就需要考慮硬件解碼或者減少單機(jī)視頻路數(shù)。3. 實(shí)操在 Atlas 300V 24G 上把 YOLOv5/v8 跑起來3.1 環(huán)境準(zhǔn)備驅(qū)動(dòng)、固件、CANN 與容器掛載這套環(huán)境的安裝順序我建議是安裝 NPU 驅(qū)動(dòng)和固件也叫 HDK再安裝 CANN Toolkit最后創(chuàng)建運(yùn)行環(huán)境。驅(qū)動(dòng)和固件的安裝包在昇騰社區(qū)都可以下載一般是一個(gè) Ascend-hdk 之類的 run 包執(zhí)行后會(huì)自動(dòng)安裝到 /usr/local/Ascend 目錄下。這里要特別提醒一句驅(qū)動(dòng)、固件和 CANN 三者的版本必須配套。昇騰的東西對(duì)版本匹配相當(dāng)敏感很多時(shí)候“莫名其妙”的問題其實(shí)都是版本不一致導(dǎo)致的。我踩過最典型的一次坑是固件升級(jí)之后CANN 沒跟著升結(jié)果模型加載時(shí)一直報(bào)錯(cuò)看了半天日志才發(fā)現(xiàn)是版本不匹配。如果不想污染宿主機(jī)環(huán)境推薦用官方容器鏡像。啟動(dòng)容器的命令里沒有把設(shè)備節(jié)點(diǎn)掛載進(jìn)去是最常見的容器內(nèi)找不到 NPU 的原因。我常用的啟動(dòng)參數(shù)是這樣的docker run -itd --name ascend_yolo \ --device/dev/davinci0 \ --device/dev/davinci_manager \ --device/dev/hisi_hdc \ -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ -v /usr/local/Ascend/driver/lib64:/usr/local/Ascend/driver/lib64 \ -v /etc/ascend_install.info:/etc/ascend_install.info \ --cap-addSYS_RAWIO \ your-ascend-image:tag容器起來之后第一件事是執(zhí)行 npu-smi info確認(rèn)能正??吹娇ǖ男畔ⅰH绻@個(gè)命令無法輸出正常的設(shè)備信息后面所有步驟都不用繼續(xù)了先回環(huán)境配置找問題。整個(gè)環(huán)境準(zhǔn)備階段我一般預(yù)留半天時(shí)間比較穩(wěn)妥別指望一次成功。3.2 模型導(dǎo)出PyTorch 模型轉(zhuǎn) ONNX我以 YOLOv5 為例因?yàn)樗?export 腳本最成熟。導(dǎo)出命令本身很簡(jiǎn)單但有幾個(gè)細(xì)節(jié)決定后續(xù) ATC 轉(zhuǎn)換能不能一次通過。首先是 opset 版本。建議設(shè)置成 12 或 13不要用太高也不要太低。其次是輸入尺寸。如果你不需要?jiǎng)討B(tài)輸入我強(qiáng)烈建議在導(dǎo)出時(shí)就固定為 640x640這樣后續(xù) ATC 轉(zhuǎn)換簡(jiǎn)單推理性能也最穩(wěn)定。如果你需要支持不同分辨率就得在導(dǎo)出時(shí)開啟 dynamic但這會(huì)讓很多推理卡的算子優(yōu)化無從下手性能往往不如固定 shape。還有一個(gè)非常關(guān)鍵的步驟導(dǎo)出時(shí)不要帶 NMS 后處理。YOLO 在 PyTorch 里運(yùn)行時(shí)通常會(huì)執(zhí)行檢測(cè)頭輸出、置信度過濾、NMS 等后處理邏輯但 AT C 對(duì) NMS 這類復(fù)雜邏輯支持有限最佳實(shí)踐是只導(dǎo)出前向網(wǎng)絡(luò)把 NMS 放到推理之后用 OpenCV 或 NumPy 自己實(shí)現(xiàn)。具體操作上YOLOv5 可以用下面的命令python export.py --weights yolov5s.pt --include onnx --opset 12 --img-size 640 640導(dǎo)出完成后建議先用 onnxruntime 在 CPU 上跑一張測(cè)試圖把這個(gè) ONNX 的輸出和 PyTorch 模型的輸出對(duì)比一下確認(rèn)精度沒有損失再進(jìn)入下一步。這一步雖然花費(fèi)十幾分鐘但能把 ATC 轉(zhuǎn)換時(shí)的“算子錯(cuò)誤”和“模型本身的問題”區(qū)分開省下后面排查的大把時(shí)間。3.3 ATC 模型轉(zhuǎn)換詳解ATC 是昇騰工具鏈里最核心的模型轉(zhuǎn)換工具。它的作用是把 ONNX、MindIR、TensorFlow 模型轉(zhuǎn)成昇騰硬件能高效執(zhí)行的離線模型 OM 文件。我以 ONNX 為例給出一版可以直接參考的轉(zhuǎn)換命令atc --modelyolov5s.onnx \ --framework5 \ --outputyolov5s_bs1 \ --soc_versionAscend310P3 \ --input_shapeimages:1,3,640,640 \ --output_typeFP16 \ --insert_op_confaipp.cfg各參數(shù)的含義拆開來看--framework5 表示輸入模型是 ONNX--output 是輸出文件名前綴--soc_version 必須和你的卡匹配Atlas 300V 24G 通常對(duì)應(yīng) Ascend310P3但這個(gè)參數(shù)一定要根據(jù)你機(jī)器上 npu-smi 展示的實(shí)際芯片信息來定--input_shape 指定輸入 tensor 的名字和形狀注意這里的名字必須和 ONNX 模型里的輸入名一致YOLOv5 一般是 images--output_type 設(shè)置為 FP16推理時(shí)能獲得更好的性能--insert_op_conf 用來配置 AIPP 預(yù)處理算子。AIPP 配置文件長(zhǎng)這樣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: true min_chn_0: 0 max_chn_0: 255 min_chn_1: 0 max_chn_1: 255 min_chn_2: 0 max_chn_2: 255 mean_chn_0: 123.675 mean_chn_1: 116.28 mean_chn_2: 103.53 var_chn_0: 58.395 var_chn_1: 57.12 var_chn_2: 57.375 }設(shè)置 AIPP 的核心目的是把圖像的歸一化操作下沉到硬件上減少 CPU 的預(yù)處理壓力。但這里有一個(gè)非常容易踩坑的地方如果 PyTorch 模型里的預(yù)處理已經(jīng)包含了歸一化或者你在導(dǎo)出 ONNX 之前已經(jīng)把歸一化層放進(jìn)了網(wǎng)絡(luò)結(jié)構(gòu)那么在 AIPP 里再設(shè)置 mean/var 就會(huì)導(dǎo)致雙重歸一化輸出結(jié)果會(huì)直接崩掉。我的建議是要么把歸一化邏輯全部放到 AIPP要么全部放到網(wǎng)絡(luò)內(nèi)部千萬(wàn)不要兩邊都做。3.4 使用 AscendCL 寫一個(gè)最簡(jiǎn)推理腳本模型轉(zhuǎn)成 OM 之后推理階段主要和 AscendCL 打交道。AscendCL 提供 C 接口和 Python 接口pyACL。Python 接口適合快速驗(yàn)證C 接口適合生產(chǎn)環(huán)境。下面是一個(gè)最簡(jiǎn)推理流程的骨架import acl import numpy as np ret acl.init() ret acl.rt.set_device(0) context, ret acl.rt.create_context(0) model_path b./yolov5s_bs1.om model_id, ret acl.mdl.load_from_file(model_path) desc acl.mdl.create_desc() acl.mdl.get_desc(desc, model_id) # 獲取輸入輸出尺寸 num_inputs acl.mdl.get_num_inputs(desc) num_outputs acl.mdl.get_num_outputs(desc) input_size acl.mdl.get_input_size_by_index(desc, 0) output_size acl.mdl.get_output_size_by_index(desc, 0) # 準(zhǔn)備輸入數(shù)據(jù)注意要和 AIPP 配置一致 image np.fromfile(frame.bin, dtypenp.uint8).reshape(1, 3, 640, 640) input_data image.astype(np.float16) # 分配到 Device 內(nèi)存并拷貝 input_ptr acl.rt.malloc(input_size, 2) acl.rt.memcpy(input_ptr, input_size, input_data.ctypes.data, input_data.nbytes, 1) output_ptr acl.rt.malloc(output_size, 2) output_np np.zeros(output_size, dtypenp.int8) # 執(zhí)行推理 ret acl.mdl.execute(model_id, [input_ptr], [input_size], [output_ptr], [output_size]) # 拷回 Host 內(nèi)存 acl.rt.memcpy(output_np.ctypes.data, output_np.nbytes, output_ptr, output_size, 2) acl.rt.free(input_ptr) acl.rt.free(output_ptr)需要注意上面代碼里的內(nèi)存分配方式、memcpy 的類型枚舉值在不同 CANN 版本里可能有所不同具體接口簽名要以你安裝版本的 API 文檔為準(zhǔn)。但整個(gè)流程是通用的初始化設(shè)備、加載模型、申請(qǐng) Device 內(nèi)存、拷貝輸入、執(zhí)行推理、拷貝輸出、釋放資源。推理拿到的輸出后處理和 GPU 版本完全一樣。YOLO 輸出的是檢測(cè)頭的原始預(yù)測(cè)需要做置信度過濾、類別篩選、NMS然后把檢測(cè)框坐標(biāo)還原到原圖尺寸。這部分建議直接用 NumPy 和 OpenCV 實(shí)現(xiàn)穩(wěn)定且容易調(diào)試不必強(qiáng)行放到 NPU 上跑。3.5 運(yùn)行驗(yàn)證與性能觀察整個(gè)流程打通后我習(xí)慣先用一張測(cè)試圖做端到端驗(yàn)證確保輸出框和 PyTorch GPU 版的結(jié)果一致再看性能。我自己在 Atlas 300V 24G 上跑 YOLOv5s、640x640、FP16、batch1 的端到端推理單幀延遲在 10 毫秒到 20 毫秒這個(gè)量級(jí)CANN 版本和驅(qū)動(dòng)版本不同會(huì)有波動(dòng)。這個(gè)量級(jí)跑一路視頻流綽綽有余即使要跑多路只要 batch 拼上去吞吐提升也很明顯。性能觀察階段可以一邊跑推理一邊執(zhí)行 npu-smi info看芯片利用率、內(nèi)存占用和溫度。如果利用率長(zhǎng)期打不滿基本可以確定瓶頸不在 NPU而在數(shù)據(jù)讀取或解碼側(cè)。4. 部署中的坑問題排查與調(diào)優(yōu)記錄4.1 常見報(bào)錯(cuò)速查表昇騰工具鏈的報(bào)錯(cuò)信息風(fēng)格比較“工程化”很多錯(cuò)誤可以直接從錯(cuò)誤碼查文檔但也有一些隱藏比較深的問題要結(jié)合經(jīng)驗(yàn)判斷。我把常見的現(xiàn)象、原因和解決思路整理成了表格方便你快速定位。報(bào)錯(cuò)現(xiàn)象常見原因解決思路npu-smi info 找不到設(shè)備驅(qū)動(dòng)或固件未安裝成功版本不匹配重裝配套的驅(qū)動(dòng)和固件確認(rèn) lspci 能看到設(shè)備容器里 import acl 失敗容器啟動(dòng)時(shí)沒有掛載設(shè)備節(jié)點(diǎn)加上 --device/dev/davinci0 和 davinci_manager報(bào)錯(cuò) 100000 或 ACL_ERROR_RT_PARAM_INVALID設(shè)備初始化失敗Context 創(chuàng)建失敗檢查 set_device 參數(shù)確認(rèn)能正常打開設(shè)備ATC 報(bào) E40001算子不支持模型中有不支持的算子嘗試更換 opset、用 onnx-simplifier 簡(jiǎn)化模型模型輸出全是 0 或全 NaN預(yù)處理歸一化重復(fù)或缺失檢查 AIPP 配置與訓(xùn)練預(yù)處理是否一致推理結(jié)果檢測(cè)框偏移圖像縮放或 letterbox 參數(shù)不一致確保推理輸入的預(yù)處理與訓(xùn)練保持一致程序運(yùn)行一段時(shí)間后內(nèi)存持續(xù)上漲推理循環(huán)里沒有釋放 Device 內(nèi)存緩存輸出 buffer復(fù)用而不是每幀重新分配4.2 性能調(diào)優(yōu)的幾條實(shí)操經(jīng)驗(yàn)先把固定 shape 這件事再?gòu)?qiáng)調(diào)一遍。動(dòng)態(tài) shape 雖然在靈活性上有優(yōu)勢(shì)但在昇騰推理卡上會(huì)嚴(yán)重限制算子優(yōu)化空間。如果你的產(chǎn)品就是固定 1080p 輸入、固定 640x640 模型輸入那就老老實(shí)實(shí)用靜態(tài) shape簡(jiǎn)單又高效。然后是輸入輸出的內(nèi)存復(fù)用。很多新手寫的推理腳本會(huì)在每次循環(huán)里重新申請(qǐng) Device 內(nèi)存推理完再釋放。這種做法在低幀率下問題不大但幀率一高內(nèi)存分配的開銷就非??捎^。我一般會(huì)一次性申請(qǐng)一塊足夠大的輸入 buffer 和輸出 buffer只在程序初始化時(shí)申請(qǐng)一次之后一直復(fù)用。這樣既減少了系統(tǒng)調(diào)用也避免了頻繁分配導(dǎo)致的碎片。如果你要跑多卡最簡(jiǎn)單的方案不是在一個(gè)進(jìn)程里管理多塊卡而是多進(jìn)程每個(gè)進(jìn)程綁定一塊卡。通過環(huán)境變量 ASCEND_DEVICE_ID 或代碼里的 set_device 指定卡號(hào)互相之間不受影響。這種模式在部署上更好理解也更容易擴(kuò)展。4.3 和 GPU 部署的幾個(gè)關(guān)鍵差異昇騰部署和 GPU 部署最大的差異在生態(tài)工具和使用習(xí)慣。GPU 上有成熟的 CUDA、cuDNN、TensorRT社區(qū)資料多第三方庫(kù)齊全昇騰上雖然也有 CANN、MindIE、ModelBox 等一系列組件但整體成熟度和資料豐富度還有差距。這意味著你不能直接把網(wǎng)上的 GPU 教程往昇騰上套也不能期望每個(gè) PyTorch 算子都能在昇騰上無痛運(yùn)行。另一個(gè)差異是調(diào)試體驗(yàn)。GPU 上出了錯(cuò)可以輕易打印中間張量用 Nsight 做性能分析昇騰上雖然也能打印和 dump 數(shù)據(jù)但步驟相對(duì)繁瑣。所以我的習(xí)慣是在進(jìn)入昇騰流程之前先把模型在 CPU 或 GPU 上用 ONNX Runtime 驗(yàn)證一遍把模型本身的問題排除掉到了昇騰環(huán)節(jié)更多關(guān)注格式、shape、內(nèi)存這些工程問題。5. 這份方案能擴(kuò)展到什么程度5.1 從單機(jī)單卡到多卡多路Atlas 300V 24G 的 24GB 內(nèi)存決定了它的擴(kuò)展空間相當(dāng)可觀。單卡單模型跑 YOLOv5s 時(shí)內(nèi)存占用很小你可以在一張卡上同時(shí)加載檢測(cè)、分類、關(guān)鍵點(diǎn)等多個(gè)模型實(shí)例按照業(yè)務(wù)邏輯串聯(lián)起來。比如先檢測(cè)目標(biāo)再對(duì)目標(biāo)區(qū)域做分類這種多模型流水線在 24GB 內(nèi)存下完全可行。多卡場(chǎng)景下進(jìn)程綁卡的方案可以把業(yè)務(wù)水平擴(kuò)展。一個(gè)常見的架構(gòu)是視頻接入服務(wù)負(fù)責(zé)解碼然后把幀數(shù)據(jù)分發(fā)給多臺(tái)機(jī)器或多塊卡上的推理服務(wù)推理結(jié)果再統(tǒng)一匯總。這個(gè)架構(gòu)和 GPU 集群沒有本質(zhì)區(qū)別只是把每次推理替換成了昇騰的推理調(diào)用。5.2 其他能跑的模型YOLO 系列之外很多典型的視覺模型也可以遷移到昇騰上。YOLOX、YOLOv7、YOLOv8、RT-DETR、SSD、RetinaNet 這類目標(biāo)檢測(cè)模型只要訓(xùn)練時(shí)導(dǎo)出成 ONNX 再轉(zhuǎn) OM基本都能跑。分割模型比如 DeepLabV3 和 OCR 模型比如 PaddleOCR 的檢測(cè)和識(shí)別模型也有現(xiàn)成的落地案例。每一類模型第一次遷移時(shí)都要走一遍“導(dǎo)出 ONNX、驗(yàn)證精度、ATC 轉(zhuǎn)換、AscendCL 推理”的流程。第二遍、第三遍就會(huì)發(fā)現(xiàn)套路高度一致真正花時(shí)間的不是轉(zhuǎn)換本身而是預(yù)處理、后處理和性能調(diào)優(yōu)。5.3 哪些項(xiàng)目建議先遷移到 Atlas如果項(xiàng)目完全從零開始沒有歷史包袱推理場(chǎng)景和模型相對(duì)固定又對(duì)功耗和成本敏感那 Atlas 300V 是一個(gè)值得認(rèn)真考慮的選項(xiàng)。如果項(xiàng)目已經(jīng)有成熟的 GPU 推理服務(wù)短期內(nèi)沒有國(guó)產(chǎn)化要求我覺得不必急著遷移先用小流量試跑把算子兼容性、性能差異和運(yùn)維流程摸清楚再?zèng)Q定。還有一種情況非常適合 Atlas項(xiàng)目需要在很多臺(tái)設(shè)備上做分布式推理每一臺(tái)設(shè)備對(duì)功耗和體積都有嚴(yán)格要求。這一場(chǎng)景下Atlas 300V 這類半高半長(zhǎng)、低功耗的推理卡比大塊頭的 GPU 靈活得多。最后再分享一個(gè)我在實(shí)際項(xiàng)目中反復(fù)驗(yàn)證過的小技巧模型轉(zhuǎn)換遇到不支持的算子時(shí)不要急著換模型結(jié)構(gòu)先回到模型導(dǎo)出的步驟用 onnx-simplifier 對(duì) ONNX 做一次圖優(yōu)化。很多“算子不支持”的報(bào)錯(cuò)本質(zhì)上是模型中殘留了一些冗余算子或不規(guī)范的圖結(jié)構(gòu)簡(jiǎn)化之后就能正常通過 ATC 轉(zhuǎn)換。這個(gè)技巧在 YOLO 以外的模型上也一樣好用我后來幾乎每次遷移模型都會(huì)先跑一遍。