戰(zhàn):目標(biāo)檢測與實(shí)例分割的訓(xùn)練部署全攻略)
簡介面向計(jì)算機(jī)視覺研究者、開發(fā)者及深度學(xué)習(xí)技術(shù)人員這份以Ultralytics YOLOv8為核心的實(shí)例分割與目標(biāo)檢測資源提供從模型訓(xùn)練到部署落地的完整鏈路。壓縮包內(nèi)置預(yù)訓(xùn)練pt權(quán)重、模型配置文件、數(shù)據(jù)集示例、訓(xùn)練與推理腳本及系統(tǒng)化文檔覆蓋物體識別、圖像分析、安全監(jiān)控、無人機(jī)視覺、自動(dòng)駕駛等典型應(yīng)用場景滿足科研實(shí)驗(yàn)、產(chǎn)品原型開發(fā)與實(shí)際部署的多層次需求。整包共788個(gè)文件以md說明文檔、py腳本、yaml配置為主體兼顧pyc編譯產(chǎn)物、ipynb交互式示例、pt權(quán)重、onnx導(dǎo)出模型及多平臺Dockerfile部署方案包體約26.63MB目錄結(jié)構(gòu)清晰支持本地訓(xùn)練、云端推理與邊緣端部署的快速切換。已有526人學(xué)習(xí)下載。借助其中詳細(xì)的環(huán)境配置說明、數(shù)據(jù)標(biāo)注格式梳理、訓(xùn)練參數(shù)調(diào)優(yōu)建議與驗(yàn)證部署指引開發(fā)者可快速掌握YOLOv8的模型微調(diào)、性能評估與工程化落地方案配合預(yù)訓(xùn)練權(quán)重與推理腳本可在數(shù)分鐘內(nèi)啟動(dòng)自定義數(shù)據(jù)集訓(xùn)練有效縮短項(xiàng)目迭代周期。 最近一直在折騰一個(gè)基于YOLOv8的視覺項(xiàng)目標(biāo)題寫著“目標(biāo)檢測實(shí)例分割模型訓(xùn)練與部署”看起來很常規(guī)但真正從零到一走完一遍還是會(huì)踩到不少文檔里沒寫明白的坑。特別是項(xiàng)目文件包里還出現(xiàn)了“ultralytics.rar”這說明大概率是需要離線安裝依賴庫或者在一臺沒有外網(wǎng)的環(huán)境里復(fù)現(xiàn)整套流程。這類場景在真實(shí)工程里太常見了所以我打算把整個(gè)項(xiàng)目的核心脈絡(luò)、訓(xùn)練細(xì)節(jié)、部署要點(diǎn)和常見坑整理出來給正在做類似選題的朋友一個(gè)參考。這個(gè)項(xiàng)目面向的讀者很明確已經(jīng)接觸過深度學(xué)習(xí)、跑過簡單分類模型但第一次接觸YOLO系列、搞不清楚實(shí)例分割和目標(biāo)檢測到底有什么區(qū)別或者卡在訓(xùn)練環(huán)境配置、數(shù)據(jù)集標(biāo)注、模型導(dǎo)出部署這些環(huán)節(jié)的人。我會(huì)盡量把每一個(gè)關(guān)鍵步驟背后的原因也講清楚方便你遇到問題能自己定位而不是只會(huì)復(fù)制粘貼命令。1. 項(xiàng)目定調(diào)與整體技術(shù)選型先把這個(gè)項(xiàng)目的技術(shù)輪廓捋一遍。YOLOv8在YOLO系列里算是一個(gè)分水嶺它把之前分散的Detect、Segment、Pose、Classify等任務(wù)統(tǒng)一到了同一個(gè)框架下也就是由Ultralytics團(tuán)隊(duì)維護(hù)的ultralytics庫。你做目標(biāo)檢測、實(shí)例分割、姿態(tài)估計(jì)甚至分類都可以用同一套API、同一個(gè)訓(xùn)練管線這是它現(xiàn)在成為工業(yè)落地主力方案的重要原因。標(biāo)題里同時(shí)出現(xiàn)了“目標(biāo)檢測”和“實(shí)例分割”這兩個(gè)任務(wù)有本質(zhì)區(qū)別。目標(biāo)檢測輸出的是“物體在哪 物體是什么”表現(xiàn)形式為矩形框bounding box適合抓取、計(jì)數(shù)、監(jiān)控這類只需要知道位置和類別的場景。而實(shí)例分割輸出的是“每個(gè)像素屬于哪個(gè)物體實(shí)例”表現(xiàn)形式為像素級掩膜mask適合精細(xì)操作、背景復(fù)雜需要摳出物體輪廓的場景。如果你之前只做過目標(biāo)檢測現(xiàn)在想切到實(shí)例分割最需要改變認(rèn)知的是數(shù)據(jù)標(biāo)注環(huán)節(jié)因?yàn)闃?biāo)注格式、標(biāo)簽文件、yaml配置、訓(xùn)練輸出都不一樣。這個(gè)項(xiàng)目里兩個(gè)任務(wù)大概率是需要單獨(dú)訓(xùn)練兩個(gè)模型的因?yàn)槟繕?biāo)檢測模型和實(shí)例分割模型共享了YOLOv8的backbone和neck結(jié)構(gòu)但head分支完全不同不能一個(gè)模型同時(shí)輸出兩種形式的結(jié)果。從工程上講這也是比較穩(wěn)妥的做法后面我會(huì)詳細(xì)講兩條線的差異。技術(shù)棧上ultralytics庫是絕對的核心它把訓(xùn)練、驗(yàn)證、導(dǎo)出、推理全部封裝好了。底層計(jì)算依賴PyTorchGPU加速依賴CUDA和cuDNN。整個(gè)項(xiàng)目跑下來涉及的關(guān)鍵組件包括Python環(huán)境、PyTorch、Ultralytics庫、OpenCV、NumPy、PyYAML以及后面部署時(shí)要用的ONNX Runtime或TensorRT。如果你拿到的是“ultralytics.rar”這種離線資源包里面一般會(huì)包含帶依賴的安裝包或wheel文件這種就是給內(nèi)網(wǎng)環(huán)境準(zhǔn)備的安裝思路和在線pip安裝不太一樣我會(huì)在環(huán)境搭建部分單獨(dú)展開。還有一個(gè)值得說的點(diǎn)是YOLOv8本身有三種規(guī)模選擇n、s、m、l、x分別對應(yīng)網(wǎng)絡(luò)寬度和深度從小到大。標(biāo)題里沒寫具體用哪種模型但從熱詞里出現(xiàn)了“gtx1660ti跑yolov8”和“rk3588部署yolov8”來看業(yè)務(wù)場景應(yīng)該偏向性價(jià)比路線的s或m版本。如果你用的是1660Ti這類6GB顯存的卡n和s版本訓(xùn)練起來比較從容m版本跑小數(shù)據(jù)集也行但批量大小別開太大。2. 環(huán)境搭建與ultralytics安裝的實(shí)操細(xì)節(jié)2.1 GPU方案1660Ti到底夠不夠用很多人第一次用YOLOv8都會(huì)糾結(jié)一個(gè)問題我的顯卡能不能跑這里直接給結(jié)論GTX 1660Ti 6GB顯存訓(xùn)練YOLOv8n和YOLOv8s完全沒問題YOLOv8m要看訓(xùn)練集圖片大小和batch size具體調(diào)。但CPU訓(xùn)練就別想了除非你的數(shù)據(jù)集特別小否則一次迭代可能要幾分鐘而且讓CPU去算卷積操作屬實(shí)是浪費(fèi)時(shí)間。1660Ti跑YOLOv8s實(shí)例分割的實(shí)際體驗(yàn)我做過一輪輸入尺寸默認(rèn)640x640batch size設(shè)8COCO預(yù)訓(xùn)練權(quán)重微調(diào)大概5500張訓(xùn)練圖單卡能跑顯存占用在85%到92%浮動(dòng)。這個(gè)數(shù)字說明6GB顯存是“能跑但不寬?!比绻阕鰯?shù)據(jù)增強(qiáng)或提高分辨率到1280大概率會(huì)爆顯存。如果你是學(xué)生黨或者個(gè)人開發(fā)者手上只有1660Ti我的建議是模型選yolov8sbatch size從8開始逐步往上加輸入尺寸暫時(shí)不改成1280訓(xùn)練時(shí)打開amp混合精度大概是現(xiàn)在性價(jià)比最好的組合方式。2.2 CUDA、PyTorch、ultralytics的版本搭配環(huán)境配置是新人最容易卡住的地方版本不匹配的問題比模型本身的問題還多。我這里給一套經(jīng)過驗(yàn)證的推薦版本組合這套組合在Windows、Linux下都用過穩(wěn)定不沖突組件推薦版本備注Python3.103.11、3.12也可以用但3.10的兼容性最省心CUDA11.812.1也行關(guān)鍵看PyTorch有沒有對應(yīng)的預(yù)編譯包c(diǎn)uDNN8.x與CUDA 11.8配套即可PyTorch2.0.1或2.1.0建議通過官方index安裝別用默認(rèn)源ultralytics8.x最新版直接pip安裝即可安裝PyTorch時(shí)建議用官方命令指定CUDA版本這個(gè)細(xì)節(jié)很關(guān)鍵。很多人后面報(bào)錯(cuò)label維度對不上、Aten算子缺失往根上查都是PyTorch編譯器對應(yīng)的CUDA版本和本機(jī)驅(qū)動(dòng)不匹配導(dǎo)致的。你在命令行執(zhí)行下面的代碼時(shí)torch和torchvision的版本號要對應(yīng)上pip install torch2.1.0 torchvision0.16.0 --index-url https://download.pytorch.org/whl/cu118安裝完成之后一定要驗(yàn)證一下GPU是否真的可用這一步很多人跳過后面訓(xùn)練時(shí)報(bào)“CUDA unavailable”又一頭霧水。驗(yàn)證代碼很簡單import torch print(torch.__version__) print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0))如果打印出來是True和你的顯卡型號說明環(huán)境OK。如果你的結(jié)果是False先查NVIDIA驅(qū)動(dòng)版本再看PyTorch是不是安裝成了CPU版本這兩個(gè)原因占到了九成以上。2.3 離線安裝“ultralytics.rar”的處理思路“ultralytics.rar”這個(gè)文件名其實(shí)暴露了一個(gè)很實(shí)際的場景你需要離線安裝。國內(nèi)很多項(xiàng)目環(huán)境是物理隔離的不能直接pip install所以在有網(wǎng)的機(jī)器上下載好安裝包再用U盤拷進(jìn)內(nèi)網(wǎng)環(huán)境是常規(guī)操作。如果你拿到的是一個(gè)壓縮包里面的結(jié)構(gòu)通常是wheel文件、依賴包和requirements.txt三部分。離線安裝的正確姿勢是先解壓rar然后在內(nèi)網(wǎng)機(jī)器上進(jìn)入解壓后的目錄依次執(zhí)行pip install --no-index --find-links./ deps/*.whl pip install --no-index --find-links./ ultralytics*.whl這里要注意依賴包的安裝順序很重要PyTorch和torchvision這類底層的包要優(yōu)先裝因?yàn)閡ltralytics在導(dǎo)入時(shí)會(huì)檢查torch是否可用。如果直接先裝ultralytics再裝torch中間過程可能出現(xiàn)反復(fù)報(bào)錯(cuò)的情況。另外某些激光雷達(dá)、機(jī)器人相關(guān)的依賴包可能與你的項(xiàng)目無關(guān)可以跳過裝多了反而容易產(chǎn)生包沖突。2.4 快速驗(yàn)證安裝是否成功裝完之后建議用一段極短的代碼驗(yàn)證ultralytics是否正常工作from ultralytics import YOLO # 加載一個(gè)預(yù)訓(xùn)練模型并做推理測試 model YOLO(yolov8s.pt) results model(https://ultralytics.com/images/bus.jpg) print(results[0].boxes.cls)如果你的網(wǎng)絡(luò)環(huán)境能訪問外網(wǎng)yolov8s.pt會(huì)直接自動(dòng)下載到當(dāng)前目錄如果不行你需要手動(dòng)下載這個(gè)權(quán)重文件放到目錄下。能正常輸出類別ID說明ultralytics庫的核心功能沒問題。這時(shí)候再跑一個(gè)快速訓(xùn)練測試yolo train datacoco8.yaml modelyolov8s.pt epochs1 imgsz640用coco8這個(gè)微型數(shù)據(jù)集做一輪訓(xùn)練能正常完成的話整個(gè)環(huán)境配置就算徹底通過了。這個(gè)操作看似簡單但在項(xiàng)目前期能幫你節(jié)省大量定位問題的時(shí)間。3. 數(shù)據(jù)準(zhǔn)備檢測和分割的數(shù)據(jù)處理差異3.1 數(shù)據(jù)集標(biāo)注是兩條分岔路目標(biāo)檢測和實(shí)例分割在數(shù)據(jù)準(zhǔn)備階段就走上了完全不同的路。目標(biāo)檢測用的是矩形框標(biāo)注每個(gè)對象一個(gè)“目標(biāo)類別左上角坐標(biāo)右下角坐標(biāo)”的三元組標(biāo)注工具用LabelImg就行。而實(shí)例分割用的是多邊形標(biāo)注Polygon標(biāo)注每個(gè)對象的輪廓標(biāo)注工具建議用Labelme或者X-AnyLabeling然后用腳本把標(biāo)注轉(zhuǎn)成YOLO格式的文本文件。YOLOv8目標(biāo)檢測的標(biāo)簽格式是class_id x_center y_center width height其中x_center、y_center、width、height都是歸一化到0~1之間的相對坐標(biāo)不是像素坐標(biāo)。實(shí)例分割的標(biāo)簽格式是class_id x1 y1 x2 y2 x3 y3 ...多邊形坐標(biāo)點(diǎn)對也要求歸一化。這個(gè)歸一化如果搞錯(cuò)訓(xùn)練時(shí)模型會(huì)發(fā)瘋損失降到NaN或者完全不收斂。3.2 數(shù)據(jù)集目錄結(jié)構(gòu)必須按規(guī)范來不管是檢測還是分割ultralytics都要求數(shù)據(jù)集目錄按固定結(jié)構(gòu)組織dataset/ ├── train/ │ ├── images/ │ └── labels/ ├── val/ │ ├── images/ │ └── labels/ └── data.yaml訓(xùn)練集和驗(yàn)證集一定要分開。有人貪方便把全部數(shù)據(jù)都放train里然后驗(yàn)證集也從train里隨機(jī)抽這會(huì)導(dǎo)致mAP虛高看起來模型很厲害實(shí)際部署后效果一塌糊涂。規(guī)規(guī)矩矩劃出一部分完全獨(dú)立的驗(yàn)證集才能準(zhǔn)確評估模型真實(shí)水平。3.3 data.yaml配置文件的完整寫法數(shù)據(jù)準(zhǔn)備好之后需要寫一個(gè)data.yaml文件告訴ultralytics訓(xùn)練時(shí)去哪讀數(shù)據(jù)、有幾個(gè)類別、類別名是什么。標(biāo)準(zhǔn)的寫法如下path: /your/absolute/path/to/dataset train: train/images val: val/images names: 0: person 1: car 2: dog有個(gè)容易踩的坑是path字段到底要不要寫絕對路徑。我的經(jīng)驗(yàn)是直接把數(shù)據(jù)集路徑寫到path字段里train和val用相對路徑即可這樣換機(jī)器時(shí)只需要改path一個(gè)地方。如果你用的相對路徑train/images那它是以當(dāng)前工作目錄為基準(zhǔn)的不同機(jī)器工作目錄不一樣很容易出問題。類別編號從0開始這個(gè)不要改。標(biāo)簽文件里的class_id必須和names的索引嚴(yán)格對應(yīng)類別順序一旦變了整個(gè)模型預(yù)測的類別就錯(cuò)位了。訓(xùn)練前我習(xí)慣寫個(gè)腳本掃描一遍所有標(biāo)簽txt檢查是否有超出類別總數(shù)的情況、是否有空的標(biāo)簽文件這類數(shù)據(jù)問題在深夜訓(xùn)練時(shí)最讓人崩潰。3.4 tiny object和樣本不平衡問題標(biāo)題熱詞里出現(xiàn)了“小目標(biāo)檢測”和“水下目標(biāo)檢測”這類場景對數(shù)據(jù)的要求更高。小目標(biāo)因?yàn)橄袼卣加锰倌J(rèn)的640x640輸入尺寸往往讓backbone學(xué)習(xí)不到有效的語義信息。實(shí)際項(xiàng)目里兩個(gè)最有效的方法一是把imgsz調(diào)到1280顯存占用會(huì)明顯上升網(wǎng)絡(luò)會(huì)看到更多小目標(biāo)的細(xì)節(jié)另一種是使用SAHISlicing Aided Hyper Inference切片推理把大圖切成小塊再逐個(gè)推理最后再拼回結(jié)果。樣本不平衡問題也很關(guān)鍵特別是工業(yè)缺陷檢測這類場景壞樣本天生就少。如果你直接拿原始比例去訓(xùn)練模型傾向于把什么都預(yù)測成“正?!?。我的做法是對少樣本類別做離線增強(qiáng)——旋轉(zhuǎn)、翻轉(zhuǎn)、馬賽克、HSV擾動(dòng)然后把多類別的圖像隨機(jī)丟棄一部分讓模型對每個(gè)類別的樣本量大體均衡。這一招比任何注意力機(jī)制都管用。4. 模型訓(xùn)練與評價(jià)體系拆解4.1 訓(xùn)練參數(shù)的選擇邏輯訓(xùn)練模型時(shí)ultralytics的YOLO類提供了大量參數(shù)但實(shí)際項(xiàng)目里大多數(shù)用默認(rèn)值就夠了。真正需要重點(diǎn)關(guān)注的只有幾個(gè)from ultralytics import YOLO # 加載模型 model YOLO(yolov8s-seg.pt) # 或者 yolov8s.pt # 訓(xùn)練 model.train( datadataset/data.yaml, epochs100, imgsz640, batch8, lr00.01, patience20, device0, workers4, ampTrue )epochs決定訓(xùn)練輪數(shù)100輪是起步數(shù)據(jù)量大時(shí)150到200輪也正常但沒必要一味堆輪數(shù)配合早停機(jī)制patience20如果連續(xù)20輪驗(yàn)證集指標(biāo)沒有提升就自動(dòng)停掉省時(shí)間又防過擬合。batch的大小受顯存約束設(shè)成8或16比較常見。lr0初始學(xué)習(xí)率用默認(rèn)0.01如果數(shù)據(jù)集很小比如幾千張建議調(diào)低到0.001否則網(wǎng)絡(luò)在剛開始就震蕩后面很難收斂。數(shù)據(jù)增強(qiáng)方面ultralytics默認(rèn)開啟了馬賽克增強(qiáng)、隨機(jī)平移、縮放、翻轉(zhuǎn)等這些對大多數(shù)場景都有效。但如果你做的是工業(yè)檢測這種相對固定的場景比如產(chǎn)品固定在某個(gè)角度拍照馬賽克增強(qiáng)反而會(huì)引入不真實(shí)的樣本建議把mosaic關(guān)掉或者調(diào)低概率。判斷依據(jù)很簡單訓(xùn)練集和驗(yàn)證集的loss能同時(shí)下降且不震蕩訓(xùn)練就屬于正常如果驗(yàn)證集出現(xiàn)大幅波動(dòng)優(yōu)先懷疑數(shù)據(jù)增強(qiáng)強(qiáng)度設(shè)錯(cuò)了。4.2 訓(xùn)練過程中的損失函數(shù)曲線怎么看訓(xùn)練過程會(huì)輸出損失值其中包括box_loss、cls_loss、dfl_loss實(shí)例分割還會(huì)多一個(gè)seg_loss。很多人看到訓(xùn)練早期loss很大就慌這完全不必要。YOLOv8的損失是從一個(gè)很高的初始值開始平滑下降的重點(diǎn)看訓(xùn)練后期是否收斂、驗(yàn)證集的loss是否有反彈趨勢。建議每輪訓(xùn)練完同時(shí)把訓(xùn)練損失和驗(yàn)證損失繪制到一張圖上。方法很簡單用ultralytics自動(dòng)保存的results.csv即可import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/segment/train/results.csv) plt.plot(df[epoch], df[train/box_loss], labeltrain box loss) plt.plot(df[epoch], df[val/box_loss], labelval box loss) plt.legend() plt.show()如果訓(xùn)練損失持續(xù)下降但驗(yàn)證損失開始上升說明過擬合了解決辦法是增加數(shù)據(jù)量或更強(qiáng)的正則化而不是繼續(xù)加輪數(shù)。如果兩者都維持在比較高的水平不下去優(yōu)先檢查學(xué)習(xí)率是否過大、自己的數(shù)據(jù)集標(biāo)簽是否噪點(diǎn)很多、類別是否和預(yù)訓(xùn)練權(quán)重的類別差異太大。4.3 評價(jià)指標(biāo)不能只知道m(xù)AP熱詞里有個(gè)高頻詞“目標(biāo)檢測評價(jià)標(biāo)準(zhǔn)”這里集中說清楚。目標(biāo)檢測和實(shí)例分割的通用評價(jià)指標(biāo)是mAP具體分為mAP50和mAP50-95。mAP50是預(yù)測框與真實(shí)框的IoU大于0.5時(shí)算作正確匹配的精確率-召回率曲線下面積它比較容易漲適合初判模型有沒有學(xué)會(huì)。mAP50-95則是從0.5到0.95每隔0.05計(jì)算一次再取平均它對框的定位精度要求極高漲得慢是正常的但實(shí)際部署時(shí)對定位精度要求高的場景比如機(jī)械臂抓取主要看這個(gè)指標(biāo)。分割任務(wù)還額外關(guān)注mask IoU它衡量的是分割掩膜和真實(shí)掩膜的重疊比例反映像素級準(zhǔn)確度。單看mAP不能完全說明問題特別是小目標(biāo)多的數(shù)據(jù)集mAP可能整體偏低但你實(shí)際業(yè)務(wù)里的目標(biāo)尺寸恰好是中等偏大的那模型其實(shí)是夠用的。所以我的習(xí)慣是訓(xùn)練完一定跑一次混淆矩陣confusion matrix看哪些類別之間互相混淆嚴(yán)重再針對性補(bǔ)數(shù)據(jù)這比盯著mAP調(diào)參效率高得多。4.4 小目標(biāo)檢測的專項(xiàng)技巧熱詞里多次出現(xiàn)小目標(biāo)檢測和“小目標(biāo)檢測頭”這塊值得一提。YOLOv8默認(rèn)有三個(gè)檢測頭分別對應(yīng)不同尺度的特征圖大目標(biāo)用淺層特征小目標(biāo)用更深但分辨率更高的特征圖。但默認(rèn)的P3層特征圖80x80對于特別小的目標(biāo)還是不夠所以有人會(huì)加一個(gè)P2檢測頭提高對小目標(biāo)的召回。具體的改進(jìn)做法屬于模型結(jié)構(gòu)改動(dòng)的范疇比如用GFPN替換PANet或者在頸部網(wǎng)絡(luò)里加入注意力模塊。這些改動(dòng)不是必須的如果你的數(shù)據(jù)里小目標(biāo)占比極高先試加大imgsz到1280。假如imgsz到1280SAHI切片推理還是不夠再去考慮改模型結(jié)構(gòu)、引入小目標(biāo)檢測頭。5. 模型應(yīng)用與工程化部署落地5.1 用訓(xùn)練好的權(quán)重做推理驗(yàn)證訓(xùn)練結(jié)束后模型權(quán)重會(huì)保存在runs/segment/train/weights/目錄下里面有兩個(gè)文件best.pt和last.pt。best.pt是驗(yàn)證集指標(biāo)最好的模型last.pt是最后一輪的模型。推理時(shí)就該用best.pt不要用last.pt這個(gè)區(qū)別容易忽略但很關(guān)鍵。from ultralytics import YOLO model YOLO(runs/segment/train/weights/best.pt) results model.predict(test.jpg, conf0.25, iou0.45, saveTrue)conf和iou的取值對結(jié)果影響很大。conf太低會(huì)輸出大量低置信度的誤檢框conf太高又會(huì)漏檢0.25是默認(rèn)值實(shí)際使用時(shí)要結(jié)合自己的誤檢和漏檢成本去調(diào)整。iou用于抑制重疊框檢測密集小目標(biāo)時(shí)可以調(diào)低到0.3目標(biāo)間距大時(shí)可以調(diào)高到0.7跟你的業(yè)務(wù)場景掛鉤。5.2 導(dǎo)出ONNX與TensorRT格式部署到端側(cè)設(shè)備一般不會(huì)直接跑.pt文件而是先導(dǎo)出成ONNX或TensorRT格式。ultralytics一行代碼就能完成導(dǎo)出yolo export modelruns/segment/train/weights/best.pt formatonnx opset12 simplifyTrueONNX是中間格式兼容性最好適合跨平臺推理。如果設(shè)備是NVIDIA平臺的可以進(jìn)一步轉(zhuǎn)成TensorRT推理速度能提升很多yolo export modelruns/segment/train/weights/best.pt formatengine device0轉(zhuǎn)化過程中容易遇到一個(gè)問題ONNX導(dǎo)出來之后用ONNX Runtime推理時(shí)結(jié)果和PyTorch的推理結(jié)果不一致。這個(gè)大概率是輸入預(yù)處理歸一化方式、通道順序、letterbox resize不一致導(dǎo)致的而不是模型本身的問題。跟用的部署腳本和模型文件放在一起的預(yù)處理代碼一定要和ultralytics的預(yù)處理邏輯保持一致這也是為什么我建議在部署前先用同一張圖分別跑PyTorch推理和ONNX推理來對比輸出。5.3 邊緣設(shè)備部署要點(diǎn)RK3588與樹莓派標(biāo)題熱詞里有“rk3588部署yolov8”和“樹莓派5上部署自己訓(xùn)練的yolov5模型”我簡單說一下邊緣設(shè)備部署的通用路徑。RK3588這類帶有NPU算力6TOPS的開發(fā)板一般不是直接跑ONNX而是通過RKNN-Toolkit2工具鏈把ONNX模型轉(zhuǎn)成.rknn格式再在板子上用RKNN Runtime加載推理。這里有一個(gè)關(guān)鍵點(diǎn)RKNN轉(zhuǎn)換工具對某些算子支持不完整比如一些高版本ONNX里新增的算子可能不支持所以轉(zhuǎn)換前最好把opset設(shè)低一些12或13simplifyTrue開啟報(bào)錯(cuò)時(shí)能省很多事。另外轉(zhuǎn)換時(shí)如果模型中間有動(dòng)態(tài)shape需要指定固定輸入尺寸RKNN通常只支持靜態(tài)輸入。樹莓派5的CPU性能比前代強(qiáng)了不少但沒有GPU跑YOLOv8s推理一般在1到3秒每幀之間看分辨率。如果想提速一般做兩個(gè)事情一是轉(zhuǎn)換成NCNN格式的模型這個(gè)專門為CPU做了優(yōu)化二是降低輸入尺寸。樹莓派上跑NCNN版的YOLOv5s這是我的一個(gè)實(shí)際經(jīng)驗(yàn)推理速度可以壓到一幀400毫秒左右雖然沒有達(dá)到實(shí)時(shí)但做普通的抓拍檢測夠用了。Jetson Orin Nano這類帶GPU的板子路徑會(huì)更順一些直接用TensorRT engine推理操作上和桌面端幾乎一樣重點(diǎn)是把GPU內(nèi)存的管理做好FP16精度在Orin Nano上能換來明顯性能收益精度損失肉眼幾乎看不出來推薦直接用FP16。5.4 部署時(shí)常見的性能瓶頸與優(yōu)化手段部署中最常見的性能瓶頸依次是預(yù)處理耗時(shí)過大、模型推理耗時(shí)、后處理NMS耗時(shí)。前兩者好理解后者往往被忽略。目標(biāo)檢測的后處理NMS部分是Python實(shí)現(xiàn)的純CPU計(jì)算當(dāng)畫面里目標(biāo)數(shù)量很多時(shí)耗時(shí)會(huì)從幾毫秒漲到幾十毫秒。優(yōu)化手段有兩個(gè)方向一是把NMS部分拿到GPU上計(jì)算ultralytics在TensorRT導(dǎo)出時(shí)已集成了一部分高性能NMS二是在部署腳本里改用批量矩陣操作或向量化操作來寫NMS。如果精度要求不高想在邊緣設(shè)備上換取速度可以考慮把IoU的閾值調(diào)大或直接做TopK截?cái)嘀槐A糁眯哦茸罡叩那皫资畟€(gè)框這對大部分業(yè)務(wù)影響不大但速度提升非常明顯。6. 常見問題與排查技巧實(shí)錄6.1 訓(xùn)練時(shí)loss為NaN或直接崩潰這個(gè)問題幾乎每個(gè)用YOLO訓(xùn)練過的人都會(huì)遇到絕大部分原因出在學(xué)習(xí)率過大或標(biāo)簽格式錯(cuò)誤。建議先按這個(gè)順序排查第一步調(diào)低lr0把它從0.01降到0.001如果不再NaN說明初始學(xué)習(xí)率太高第二步檢查標(biāo)簽文件里的坐標(biāo)是否有負(fù)數(shù)、超出圖像邊界、歸一化值大于1的異常數(shù)據(jù)第三步確認(rèn)類別ID是否超出data.yaml里的類別總數(shù)。6.2 運(yùn)動(dòng)物體只識別一次或漏檢熱詞里有個(gè)很具體的現(xiàn)象“運(yùn)動(dòng)的物體經(jīng)過攝像頭只識別一次yolov8 seg”。這通常不是因?yàn)槟P蜎]識別到而是視頻后處理時(shí)缺少“跟蹤關(guān)聯(lián)”導(dǎo)致的。如果你逐幀檢測物體在某一幀被檢測出來了但下一幀因?yàn)檫\(yùn)動(dòng)模糊或遮擋沒檢測出來視覺上就會(huì)呈現(xiàn)“只識別了一次”。正確解法是在檢測后加一個(gè)跟蹤器用ByteTrack或DeepSORT把相鄰幀的檢測框關(guān)聯(lián)起來。簡單來說先檢測出當(dāng)前幀的目標(biāo)框再用IOU匹配或ReID特征匹配把目標(biāo)和上一幀的目標(biāo)關(guān)聯(lián)起來即使某幾幀沒有檢測框也能通過卡爾曼濾波預(yù)測位置維持跟蹤ID。ultralytics內(nèi)部已經(jīng)集成了ByteTrack一行代碼就能啟用results model.track(video.mp4, persistTrue)設(shè)置persistTrue后幀與幀之間會(huì)保持同一目標(biāo)的ID不會(huì)閃斷。做實(shí)例分割的視頻跟蹤建議在mask掩膜層面加一個(gè)掩膜IoU匹配效果遠(yuǎn)好過純框級別的關(guān)聯(lián)因?yàn)檫\(yùn)動(dòng)物體形變時(shí)框體會(huì)大幅變化但掩膜的重疊程度比較穩(wěn)定。6.3 小目標(biāo)檢測效果差從哪里入手小目標(biāo)檢測是老大難問題。排在前面的優(yōu)化優(yōu)先級是提高輸入分辨率imgsz到1280使用SAHI切片推理訓(xùn)練時(shí)增強(qiáng)更多針對小目標(biāo)的裁剪和復(fù)制粘貼增強(qiáng)如果數(shù)據(jù)本身是大圖里的小目標(biāo)嘗試滑窗截成小圖訓(xùn)練。這四個(gè)手段做完還沒效果再去改網(wǎng)絡(luò)結(jié)構(gòu)或引入額外的小目標(biāo)檢測頭不要一上來就改模型結(jié)構(gòu)那通常是消息最慢且最容出問題的方式。6.4 部署時(shí)模型推理速度慢的通用排查順序部署時(shí)遇到推理速度達(dá)不到預(yù)期排查順序是先看模型輸入分辨率是否為640很多導(dǎo)出時(shí)默認(rèn)補(bǔ)到了648x640再看推理后端是否啟用FP16或INT8量化再看多線程和批處理是否充分利用最后看后處理代碼里是否存在不必要的循環(huán)和Python開銷。往往前面的環(huán)節(jié)優(yōu)化好速度已經(jīng)能提升一倍以上。6.5 數(shù)據(jù)處理中的隱藏雷區(qū)還有一個(gè)隱藏雷區(qū)是標(biāo)簽文件編碼統(tǒng)一性。不同標(biāo)注工具生成的txt文件可能存在編碼差異有些是UTF-8有些是ANSI基礎(chǔ)訓(xùn)練時(shí)可能沒問題但加上中文路徑或特殊字符后容易出錯(cuò)。最穩(wěn)妥的方式是用腳本將所有標(biāo)簽文件和圖片文件名統(tǒng)一轉(zhuǎn)成純英文小寫命名并確保每個(gè)標(biāo)簽文件的換行是LF而不是CRLF。7. 最后再分享一個(gè)訓(xùn)練和部署的小技巧這個(gè)項(xiàng)目前前后后折騰了大半個(gè)月如果只讓我說一條最值得提醒的經(jīng)驗(yàn)?zāi)蔷褪怯?xùn)練之前一定要跑一次最小化驗(yàn)證流程拿幾張圖像、幾十個(gè)標(biāo)注跑1個(gè)epoch確認(rèn)從數(shù)據(jù)讀取、標(biāo)簽匹配到前向傳播、反向傳播全都能正常完成后再放開用完整數(shù)據(jù)集訓(xùn)練。很多人一上來就直接全量數(shù)據(jù)開訓(xùn)結(jié)果跑了幾個(gè)小時(shí)才發(fā)現(xiàn)標(biāo)簽格式錯(cuò)了或者類別對不上白白浪費(fèi)時(shí)間。另一個(gè)實(shí)用的技巧是訓(xùn)練過程中每個(gè)epoch結(jié)束后把驗(yàn)證集的預(yù)測結(jié)果可視化輸出一次。方法是在train函數(shù)里設(shè)置model.train(datadataset/data.yaml, epochs100, valTrue, plotsTrue)開啟plots后ultralytics會(huì)自動(dòng)輸出包括混淆矩陣、PR曲線、驗(yàn)證集預(yù)測圖在內(nèi)的可視化結(jié)果。觀察驗(yàn)證集預(yù)測圖比自己等整輪訓(xùn)練結(jié)束再看mAP高效得多一旦發(fā)現(xiàn)漏檢、錯(cuò)檢能及時(shí)判斷是標(biāo)注問題還是模型學(xué)習(xí)不到位調(diào)整的方向也更準(zhǔn)確。最后說一下項(xiàng)目往后還能怎么擴(kuò)展。如果你已經(jīng)訓(xùn)練好了自己的檢測和分割模型下一步可以考慮接入ByteTrack做實(shí)時(shí)視頻流分析再把檢測結(jié)果通過MQTT或HTTP上報(bào)到服務(wù)端形成一個(gè)完整的端-邊-云應(yīng)用。YOLOv8本身只是視覺感知環(huán)節(jié)真正讓它發(fā)揮作用的一定是與你業(yè)務(wù)邏輯的深度綁定這一點(diǎn)在你把模型部署到真實(shí)場景后會(huì)有更切身的體會(huì)。本文還有配套的精品資源點(diǎn)擊獲取