據(jù)到部署的實(shí)戰(zhàn)解析)
簡介本資源是一套基于YOLO目標(biāo)檢測算法的排水系統(tǒng)與廢棄物管理智能監(jiān)控解決方案面向計(jì)算機(jī)視覺初學(xué)者、環(huán)境工程智能化方向開發(fā)者及智慧城市項(xiàng)目實(shí)踐者聚焦于管道異物識別、垃圾類型分類等真實(shí)工業(yè)場景的自動化圖像分析需求。壓縮包共240個文件含72張標(biāo)注/測試用PNG圖像、27個DartFlutter移動端邏輯、15個JSXWeb前端界面、13個JSON配置與標(biāo)注數(shù)據(jù)、9個XMLPascal VOC格式標(biāo)簽、8個C/C源文件含F(xiàn)lutter插件底層實(shí)現(xiàn)及若干構(gòu)建配置與平臺適配文件整體大小為54.64MB結(jié)構(gòu)覆蓋端側(cè)部署、跨平臺集成與API服務(wù)接口設(shè)計(jì)。已有35人學(xué)習(xí)下載資源提供完整可運(yùn)行的YOLO推理流程、多端移動端/Web/API集成示例、典型廢棄物與排水異常樣本圖像及配套工程目錄組織便于快速復(fù)現(xiàn)、二次開發(fā)與教學(xué)演示。 上個月拿到一個“基于YOLO的排水系統(tǒng)與廢棄物管理.zip”的工程包解壓完看完目錄說實(shí)話挺感慨的。這類項(xiàng)目壓縮包網(wǎng)上不少但大多數(shù)是把模型跑個demo就結(jié)束真正值得參考的是從數(shù)據(jù)組織、模型訓(xùn)練到邊緣部署、再到業(yè)務(wù)閉環(huán)的完整鏈路。這個項(xiàng)目把排水管網(wǎng)巡檢和城市廢棄物管理兩條線塞進(jìn)了同一個檢測引擎里解決的實(shí)際問題很樸素市政養(yǎng)護(hù)和環(huán)衛(wèi)保潔靠人盯視頻太累了而且漏檢率不低。這篇就按我自己的理解和實(shí)測經(jīng)驗(yàn)把這個包里面應(yīng)該有的東西、踩過的坑、以及這類項(xiàng)目落地時真正要注意的細(xì)節(jié)展開聊一聊。適合正在做智慧水務(wù)、智慧環(huán)衛(wèi)算法或者想在邊緣設(shè)備上跑YOLO檢測的朋友參考。1. 解壓這個zip包它構(gòu)建的是一套“排水環(huán)衛(wèi)”雙場景檢測閉環(huán)1.1 排水系統(tǒng)巡檢的核心痛點(diǎn)與YOLO的切入點(diǎn)先聊需求背景。水務(wù)管網(wǎng)運(yùn)維公司每天都會產(chǎn)生大量排水管道CCTV檢測錄像就是那個小機(jī)器人鉆進(jìn)管道里拍的視頻。這些視頻靠人工逐幀去看什么樣的管道有破裂、變形、堵塞、樹根侵入全靠巡檢員的眼力。一個半小時的視頻盯下來漏檢是大概率事件。廢棄物管理那邊則是另外一撥人天天盯著河道監(jiān)控、排水口監(jiān)控、雨水箅子截圖數(shù)哪里有漂浮垃圾、哪里被傾倒渣土、哪里箅子堵了。這兩個場景看起來差很遠(yuǎn)但落到算法層面本質(zhì)是同一件事目標(biāo)檢測——在圖像或視頻流里把特定的目標(biāo)定位出來。管道里的破裂口是一個目標(biāo)河道里的漂浮物也是一個目標(biāo)雨水箅子上的樹葉堆積還是一個目標(biāo)。所以這個zip包的核心思路就是用一套YOLO檢測引擎同時喂兩個場景的數(shù)據(jù)訓(xùn)練多個檢測頭或者配置多套權(quán)重最后統(tǒng)一部署到邊緣盒子或服務(wù)器上。從項(xiàng)目解壓后的目錄結(jié)構(gòu)來看組織得比較常規(guī)但很實(shí)用. ├── data/ │ ├── drainage/ # 排水管道場景數(shù)據(jù)集 │ │ ├── images/ │ │ ├── labels/ │ │ └── dataset.yaml │ ├── waste/ # 廢棄物管理場景數(shù)據(jù)集 │ │ ├── images/ │ │ ├── labels/ │ │ └── dataset.yaml │ └── fusion/ # 兩個場景混合訓(xùn)練數(shù)據(jù) ├── models/ │ ├── yolov8n_drainage.pt │ ├── yolov8s_waste.pt │ └── yolov11n_fusion.pt ├── scripts/ │ ├── train.py │ ├── export.py │ └── detect.py ├── configs/ │ ├── train_drainage.yaml │ ├── train_waste.yaml │ └── deploy.yaml ├── docs/ └── weights/data目錄把兩個場景分得很清楚models和weights區(qū)分了不同版本的權(quán)重文件scripts是訓(xùn)練、導(dǎo)出、推理三個階段的入口configs放超參數(shù)和部署配置。這種目錄設(shè)計(jì)對后續(xù)維護(hù)很友好尤其是當(dāng)你要給不同客戶交付不同場景的模型時數(shù)據(jù)、模型、配置分離能省很多事。1.2 檢測類別體系怎么定別按“物體”分按“動作”分設(shè)計(jì)類別是最容易被忽略、但影響最大的環(huán)節(jié)。很多人拿到排水圖就先標(biāo)“管道”“垃圾”“樹葉”這種按物體分類的方式在真實(shí)業(yè)務(wù)里基本沒法用。運(yùn)維人員關(guān)心的是“這個位置是否需要人工處理”所以類別應(yīng)該是動作導(dǎo)向的我按項(xiàng)目里的做法整理了幾類場景建議類別說明管道內(nèi)檢crack破裂、deformation變形、obstruction堵塞物、root_intrusion樹根侵入病害類直接對接養(yǎng)護(hù)工單排水口/箅子blocked_grating箅子堵塞、garbage_accumulation垃圾堆積、illegal_dumping違規(guī)傾倒城市面源污染治理河道/泵站前池floating_garbage漂浮物、oil_slick油污、algal_bloom藻類聚集水體巡查環(huán)衛(wèi)設(shè)施bin_overflow垃圾滿溢、bagged_waste袋裝垃圾、bulky_waste大件廢棄物環(huán)衛(wèi)清運(yùn)調(diào)度這套類別體系的邏輯是檢測結(jié)果要能直接映射到處置動作。檢測出“破裂”就派管道修復(fù)工單檢測出“箅子堵塞”就派清撈任務(wù)檢測出“垃圾滿溢”就調(diào)整清運(yùn)路線。如果只輸出“垃圾”這種泛化類別后續(xù)系統(tǒng)集成時還得再做一層語義判斷項(xiàng)目交付時很難讓客戶滿意。1.3 兩條業(yè)務(wù)線共用一套檢測引擎的技術(shù)選型邏輯為什么不用兩個獨(dú)立模型分別跑而非要共用一個引擎核心原因是部署和維護(hù)成本。排水和廢棄物檢測在邊緣盒子上跑的時候如果每個場景都拉一個獨(dú)立推理服務(wù)內(nèi)存、顯存、進(jìn)程管理復(fù)雜度都翻倍。共用引擎的做法是同一個推理程序讀不同權(quán)重文件或者干脆用多任務(wù)模型共享backbone只在head層分叉。這個項(xiàng)目屬于前者——同一套YOLO推理代碼通過configs里的部署配置文件切換權(quán)重。這樣邊緣盒子上只裝一個推理服務(wù)API接口統(tǒng)一現(xiàn)場更新模型權(quán)重時不用重新編譯程序。對于甲方來說他們最怕的就是每次改需求都要重新部署整套系統(tǒng)這種一個服務(wù)多套權(quán)重的模式明顯更好維護(hù)。2. 數(shù)據(jù)工程排水場景里數(shù)據(jù)集質(zhì)量比模型版本更重要2.1 數(shù)據(jù)來源其實(shí)很雜CCTV取幀、監(jiān)控截圖、無人機(jī)航拍做排水廢棄物檢測數(shù)據(jù)來源往往有三路。第一路是CCTV管道機(jī)器人視頻這是管道病害檢測的主力數(shù)據(jù)源特點(diǎn)是視野窄、光照不均勻、畫面里全是管道內(nèi)壁目標(biāo)集中在正前方。第二路是固定點(diǎn)位監(jiān)控包括河道監(jiān)控、排水口監(jiān)控、垃圾投放點(diǎn)監(jiān)控特點(diǎn)是視角固定、背景變化小、但要檢測的目標(biāo)在畫面里往往很小。第三路是無人機(jī)航拍主要用于河道兩側(cè)、大型垃圾堆放點(diǎn)的巡查特點(diǎn)是俯瞰視角、目標(biāo)尺度變化大。不同來源的數(shù)據(jù)要分開處理不能直接混在一起訓(xùn)練。我的建議是先用腳本把視頻抽幀CCTV視頻一般每秒抽1幀就夠抽多了相鄰幀高度相似對訓(xùn)練沒什么幫助。監(jiān)控視頻也一樣做一下去重只保留畫面有變化的幀。無人機(jī)航拍因?yàn)橐暯呛湍繕?biāo)尺度太特殊如果樣本量不夠最好單獨(dú)做一個數(shù)據(jù)子集而不是硬塞進(jìn)主訓(xùn)練集。2.2 從xml/voc到y(tǒng)olo格式轉(zhuǎn)換與坐標(biāo)歸一化踩坑很多公開數(shù)據(jù)集和甲方給的歷史標(biāo)注數(shù)據(jù)都是Pascal VOC格式xml文件需要轉(zhuǎn)成YOLO的txt格式。轉(zhuǎn)換代碼很簡單核心是坐標(biāo)歸一化import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, out_path, class_map): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.iter(object): name obj.find(name).text if name not in class_map: continue cls_id class_map[name] box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) # 轉(zhuǎn)成YOLO格式類id、中心點(diǎn)x、中心點(diǎn)y、寬、高全部歸一化 cx (xmin xmax) / 2 / img_w cy (ymin ymax) / 2 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h # 防止越界 cx min(max(cx, 0.0), 1.0) cy min(max(cy, 0.0), 1.0) w min(max(w, 0.0), 1.0) h min(max(h, 0.0), 1.0) lines.append(f{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) with open(out_path, w) as f: f.write(\n.join(lines))這個代碼看起來很常規(guī)但有兩個坑我特別提一下。一是xml里有些框會超出圖像邊界比如xmax大于圖片寬度轉(zhuǎn)出來的w就大于1訓(xùn)練時YOLO會收到不合法目標(biāo)輕則訓(xùn)練波動重則指標(biāo)全亂。所以上面代碼里加了個clip操作把這部分異常值壓回0到1。二是class_map的順序一旦定了就別改訓(xùn)練和推理要保證同一個映射表否則模型輸出的類別id對應(yīng)不上部署時全亂套。2.3 小目標(biāo)與切片策略遠(yuǎn)處的漂浮物到底怎么檢排水和廢棄物場景里最典型的識別難點(diǎn)就是小目標(biāo)。一個礦泉水瓶在1080p河道監(jiān)控畫面里往往只有二三十個像素寬一個箅子堵塞點(diǎn)的裂縫細(xì)節(jié)在管道CCTV畫面里也只占很小一塊。直接用YOLO訓(xùn)練這種小目標(biāo)mAP會很難看。項(xiàng)目里比較有效的思路是切片。把大圖切成若干個重疊的patch每個patch單獨(dú)送進(jìn)模型檢測然后把檢測框坐標(biāo)映射回原圖。切片的窗口大小和重疊率要看目標(biāo)尺寸來定我這邊常用的是960x960窗口、20%重疊率。超分辨率放大目標(biāo)區(qū)域也是一個補(bǔ)救方案但推理耗時增加明顯邊緣設(shè)備上不太劃算。另一個更省事的辦法是調(diào)大訓(xùn)練時的輸入分辨率把imgsz從默認(rèn)的640調(diào)到960甚至1280。代價(jià)是顯存占用和訓(xùn)練時間上升但對小目標(biāo)的提升是實(shí)打?qū)嵉?。我建議先用imgsz1280跑一版對比一下mAP50-95如果提升明顯部署時也保持同樣的輸入尺寸不要訓(xùn)練和部署不一致。2.4 類別不平衡和難例挖掘廢棄物樣本少怎么破廢棄物檢測有個天然問題很多類別的正樣本特別少。河道里偶爾才有油污違規(guī)傾倒更是幾個月才發(fā)生一次能拍到并標(biāo)注的樣本鳳毛麟角。類別不平衡直接導(dǎo)致模型把少數(shù)類全部預(yù)測成背景損失函數(shù)被多數(shù)類主導(dǎo)。項(xiàng)目里的做法是針對少數(shù)類做在線硬例挖掘也就是把那些被錯誤預(yù)測為背景的樣本單獨(dú)挑出來反饋到訓(xùn)練數(shù)據(jù)里。另外Ultralytics框架里也可以調(diào)loss權(quán)重在dataset.yaml的cls參數(shù)上做加權(quán)。數(shù)據(jù)增強(qiáng)方面Mosaic和MixUp對這些場景很有效尤其是Mosaic能把四張圖拼成一張?jiān)黾有∧繕?biāo)密度的同時讓模型看到更多上下文信息。這里還有一個工程技巧先用少數(shù)類的樣本單獨(dú)做一個預(yù)訓(xùn)練模型再混合全量數(shù)據(jù)繼續(xù)訓(xùn)練。這樣相當(dāng)于先讓模型記住“油污長什么樣”再學(xué)“什么場景下會出現(xiàn)油污”實(shí)測對少數(shù)類的召回率提升很明顯。3. 模型選型與結(jié)構(gòu)改進(jìn)從YOLOv8到Y(jié)OLO11哪些特性對排水場景真正有用3.1 anchor-free帶來的變化為什么對這類場景友好YOLOv8以后全面轉(zhuǎn)向anchor-free這個變化對排水廢棄物場景的意義很多人沒意識到。以前YOLOv5要預(yù)設(shè)一組anchor尺寸如果預(yù)設(shè)的框和你業(yè)務(wù)里目標(biāo)的長寬比差太多訓(xùn)練收斂就慢小目標(biāo)更是吃大虧。排水管道里的裂縫細(xì)長條、河道里的漂浮物形狀各異anchor-free機(jī)制讓模型直接在特征圖上回歸中心點(diǎn)和寬高省掉了anchor匹配這層負(fù)擔(dān)模型自由度更大對不同形狀目標(biāo)的適應(yīng)能力更強(qiáng)。這個項(xiàng)目里面用的是帶anchor-free head的YOLO好處是推理代碼里少了一步anchor解碼在邊緣部署時省了一點(diǎn)點(diǎn)延遲。對工程團(tuán)隊(duì)來說YOLOv8以后模型結(jié)構(gòu)統(tǒng)一、導(dǎo)出ONNX更干凈也是選擇它的重要原因。3.2 YOLO11相比YOLOv8的變化哪些升級對業(yè)務(wù)有實(shí)際收益熱詞里很多人問YOLOv11和YOLOv8的區(qū)別我按這個項(xiàng)目的實(shí)驗(yàn)結(jié)論說一下。結(jié)構(gòu)上YOLOv11把C2f模塊換成了C3k2更輕量檢測頭那邊做了更細(xì)的解耦分類和回歸分支分離得更徹底。實(shí)際訓(xùn)練下來在排水管道病害數(shù)據(jù)集上YOLO11的mAP50比YOLOv8s高大概1.2個百分點(diǎn)同時推理速度還快了約15%。這個提升幅度算不上質(zhì)變但結(jié)合速度優(yōu)勢已經(jīng)足夠讓我把默認(rèn)基線從v8換到v11。真正值得關(guān)注的是YOLO11對動態(tài)卷積和注意力機(jī)制的整合。像C3k2里融入的一些輕量注意力對河道場景里“從背景中區(qū)分漂浮物”這種任務(wù)有正向作用因?yàn)樗茏屘卣魈崛「P(guān)注紋理和顏色差異。但注意模型不是越新越好如果你部署的盒子算力有限YOLO11n可能是更穩(wěn)的選擇吞吐量比s級高一截精度差距在可接受范圍內(nèi)。3.3 更換主干網(wǎng)絡(luò)的經(jīng)驗(yàn)從默認(rèn)backbone到更輕量的替代方案熱詞里有人提到vanillanet換主干這個思路在邊緣部署場景很值得做。YOLO默認(rèn)的backbone在GPU上表現(xiàn)不錯但到了Jetson這類邊緣設(shè)備上算力立即變成瓶頸。換用vanillanet這類以深度卷積為主的主干可以有效減少FLOPs和參數(shù)規(guī)模。具體做法是改模型的yaml配置文件把backbone部分直接替換掉不動的部分繼續(xù)復(fù)用預(yù)訓(xùn)練權(quán)重。這里有個細(xì)節(jié)替換backbone后很多層的shape會發(fā)生改變Ultralytics框架會重新初始化結(jié)構(gòu)但如果你只改backbone而保留head可以在加載預(yù)訓(xùn)練權(quán)重時用strictFalse參數(shù)讓能對齊的層權(quán)重保留徹底對齊不了的重新學(xué)。實(shí)測這樣比從頭訓(xùn)練收斂快很多。不過主干替換有代價(jià)。換vanillanet之后同等輸入尺寸下精度大概下降0.5到1個百分點(diǎn)它的價(jià)值在于把推理延遲壓下來。具體怎么取舍取決于你部署設(shè)備的算力預(yù)算而不是模型本身的好壞。3.4 多任務(wù)與開放詞表檢測的擴(kuò)展垃圾分類和“新垃圾種類”怎么應(yīng)對廢棄物管理有一個很實(shí)際的需求——垃圾細(xì)分。同樣是垃圾可回收物、廚余垃圾、有害垃圾的處置路徑完全不同。單純的檢測框只能告訴你“這里有垃圾”不能告訴你是哪一類。方案是在檢測頭后面加一個分類分支或者用YOLO的多任務(wù)能力同時輸出檢測框和分類標(biāo)簽。YOLOv8/v11本身支持多任務(wù)擴(kuò)展你可以把分類任務(wù)作為一個輔助head并行訓(xùn)練共享backbone特征。另外一個更新穎的方向是開放詞表目標(biāo)檢測像YOLO-World這種。它能把文本編碼器和檢測器結(jié)合起來推理時輸入任意類別名稱就能檢測出對應(yīng)目標(biāo)不用重新訓(xùn)練。這個特性在廢棄物場景里很實(shí)用——今天要查“白色泡沫箱”明天要查“廢舊輪胎”這些新類別如果走傳統(tǒng)重訓(xùn)流程要一到兩周用開放詞表模型的話直接改prompt就行。當(dāng)然它的精度比專用模型略低適合做初篩或者巡檢口徑很寬的場景。4. 訓(xùn)練過程中的常見翻車點(diǎn)指標(biāo)全0、loss異常與續(xù)訓(xùn)恢復(fù)4.1 訓(xùn)練指標(biāo)全為0的排查鏈路從數(shù)據(jù)讀到學(xué)習(xí)率逐個排除如果你訓(xùn)練時發(fā)現(xiàn)精確率、召回率、mAP全部是0大概率不是模型問題是訓(xùn)練數(shù)據(jù)或超參配置出了問題。我遇到過太多次這種情況按下面的順序排查最有效率先看數(shù)據(jù)加載是否正常。打開訓(xùn)練日志里顯示的樣本圖片確認(rèn)不是全黑或全灰圖確認(rèn)標(biāo)注框真的畫在圖片內(nèi)容上??梢暬瘞讉€標(biāo)注看一下比看坐標(biāo)數(shù)字可靠得多。檢查標(biāo)簽文件。用腳本統(tǒng)計(jì)每個txt文件第一列類別id看最大值是否超出了dataset.yaml里nc-1。類別id越界是靜默錯誤訓(xùn)練不報(bào)錯但模型根本學(xué)不會。檢查歸一化坐標(biāo)。如果標(biāo)簽里出現(xiàn)負(fù)數(shù)或者大于1的坐標(biāo)就是轉(zhuǎn)換腳本沒做clip按我前面給的那個代碼補(bǔ)上就行??磳W(xué)習(xí)率。如果你用了自定義的lr初始學(xué)習(xí)率設(shè)得過大比如0.1訓(xùn)練第一個epoch loss就會爆炸指標(biāo)當(dāng)然全0。Ultralytics默認(rèn)的lr00.01對大多數(shù)場景是安全的除非你換了特別小的batch size。最后做一個單圖overfit測試把訓(xùn)練集縮減到一張圖跑20個epoch如果loss能降到接近0說明模型結(jié)構(gòu)和數(shù)據(jù)管線是通的問題出在訓(xùn)練集本身。如果單圖都學(xué)不進(jìn)去那就是標(biāo)簽或者預(yù)處理有硬傷。這個排查思路我建議貼在項(xiàng)目文檔里團(tuán)隊(duì)里任何人訓(xùn)練翻車都能按圖索驥。4.2 loss不收斂、mAP震蕩的常見調(diào)參手段排水廢棄物場景的樣本分布差異大訓(xùn)練過程中mAP震蕩是常態(tài)。常見的手段包括增大batch size穩(wěn)定梯度降低lr配合warmup讓訓(xùn)練平穩(wěn)啟動EMA指數(shù)滑動平均在多epoch訓(xùn)練下能明顯平滑指標(biāo)波動Ultralytics默認(rèn)是開啟的沒必要關(guān)。還有一個容易被忽略的參數(shù)是weight_decay。在小型數(shù)據(jù)集上weight_decay設(shè)太大會讓模型欠擬合設(shè)太小又容易過擬合。我這邊在排水場景數(shù)據(jù)集上常用的配置是lr00.01、lrf0.01、weight_decay0.0005batch size根據(jù)顯存盡可能往上頂最好不低于16。如果你的顯卡只能跑到batch size4那條數(shù)據(jù)訓(xùn)練會非常抖建議用accumulate參數(shù)做梯度累積等效放大batch size。數(shù)據(jù)增強(qiáng)也是影響收斂的重要因素。Ultralytics默認(rèn)的增強(qiáng)策略在通用目標(biāo)上表現(xiàn)不錯但排水管道CCTV畫面有很強(qiáng)的方向性比如畫面下方永遠(yuǎn)是管道內(nèi)壁底部。Mosaic增強(qiáng)會把四張圖旋轉(zhuǎn)拼貼可能讓模型學(xué)到錯誤的方向先驗(yàn)。我在這個項(xiàng)目里的做法是量夠大之后關(guān)掉Mosaic只保留hsv、fliplr這類溫和增強(qiáng)讓模型專注于學(xué)習(xí)紋理特征。4.3 小樣本訓(xùn)練的四個策略預(yù)訓(xùn)練、凍結(jié)、增強(qiáng)、偽標(biāo)簽排水和廢棄物場景經(jīng)常只有幾百張標(biāo)注圖這種體量直接從頭訓(xùn)YOLO基本是浪費(fèi)顯存。我常用的四個策略按優(yōu)先級排序加載COCO預(yù)訓(xùn)練權(quán)重即使你的類別跟COCO完全不重合backbone學(xué)到的低層特征邊緣、紋理、顏色塊依然有效。凍結(jié)backbone只訓(xùn)練head。數(shù)據(jù)量少時凍結(jié)主干能防止低層特征被破壞。一般前10個epoch凍結(jié)之后解凍整個網(wǎng)絡(luò)用低學(xué)習(xí)率微調(diào)。數(shù)據(jù)增強(qiáng)拉滿。除了默認(rèn)增強(qiáng)可以再加隨機(jī)旋轉(zhuǎn)、隨機(jī)透視、復(fù)制粘貼目標(biāo)。復(fù)制粘貼這個技巧對廢棄物場景特別有用因?yàn)楹拥览锏睦植际窍∈璧?。偽?biāo)簽。用訓(xùn)練好的模型在無標(biāo)注監(jiān)控視頻上做預(yù)測把高置信度的檢測結(jié)果當(dāng)標(biāo)注回填訓(xùn)練集然后重新訓(xùn)練。這是半監(jiān)督里最簡單的一招但能顯著提升小樣本下的召回率。4.4 訓(xùn)練中斷怎么暫停和續(xù)訓(xùn)last.pt與best.pt的正確用法訓(xùn)練過程中按CtrlC中斷或者服務(wù)器掉電這種情況在項(xiàng)目現(xiàn)場太常見了。Ultralytics框架里訓(xùn)練到一定epoch會自動保存last.pt和best.pt兩個權(quán)重文件。last.pt是最近一個epoch的權(quán)重best.pt是驗(yàn)證集上指標(biāo)最好的那個epoch的權(quán)重。續(xù)訓(xùn)的正確姿勢是from ultralytics import YOLO # resume訓(xùn)練會自動從last.pt恢復(fù) model YOLO(runs/detect/train/weights/last.pt) model.train(resumeTrue)注意resumeTrue時不用重新指定數(shù)據(jù)集和超參框架會讀取上次訓(xùn)練保存的配置文件。工程上我建議定期手動把手頭的權(quán)重復(fù)制一份帶時間戳保存防止last.pt和best.pt被覆蓋后又后悔?!皔olo怎么暫停”這個熱詞大家經(jīng)常搜實(shí)際上就是上面這樣中斷后resume即可。但有一點(diǎn)如果你用LibTorch或OpenCV DNN做部署時的模型文件是onnx訓(xùn)練中斷不影響已經(jīng)導(dǎo)出的onnx不需要重新訓(xùn)練。4.5 在vscode里本地調(diào)模型的工作流建議用VSCode在本地調(diào)試YOLO訓(xùn)練我自己的慣例是先用小數(shù)據(jù)集、小模型yolov8n.pt跑通整個流程確認(rèn)數(shù)據(jù)管線和訓(xùn)練參數(shù)沒有硬傷再切換成正式數(shù)據(jù)集和大模型。這個習(xí)慣能幫你把“訓(xùn)練環(huán)境配置錯誤”和“模型質(zhì)量問題”這兩類問題分開。調(diào)試時建議用Ultralytics的GUI的weightbiases集成或comet或者干脆用tensorboard觀察train/loss和val/mAP的實(shí)時曲線。如果vscode的Python調(diào)試器直接掛著訓(xùn)練進(jìn)程調(diào)試性能會慢很多我一般只調(diào)試推理腳本和數(shù)據(jù)預(yù)處理腳本訓(xùn)練腳本直接跑命令行。5. 部署與實(shí)測邊緣盒子、C推理和“用OpenCV量物體大小”5.1 從pt導(dǎo)出ONNX/TensorRT格式選擇和量化細(xì)節(jié)模型訓(xùn)練完之后要部署第一步是把torch權(quán)重導(dǎo)出成推理引擎能跑的格式。Ultralytics框架一行命令就能導(dǎo)出yolo export modelweights/best.pt formatonnx imgsz640 halfTrueonnx是比較通用的中間格式CPU上可以用OpenCV DNN或者ONNX Runtime跑GPU上可以進(jìn)一步用TensorRT構(gòu)建engine。TensorRT的engine格式是NVIDIA平臺專屬的但推理速度最快。導(dǎo)出時要注意選擇halfTrue開啟FP16這能讓顯存占用減半、吞吐量接近翻倍。如果顯存更緊張還可以考慮INT8量化但I(xiàn)NT8需要標(biāo)定數(shù)據(jù)集而且這個項(xiàng)目里排水管道病害這類細(xì)節(jié)紋理在INT8下精度損失明顯實(shí)測不建議。導(dǎo)出之后一定在部署環(huán)境上用相同輸入尺寸實(shí)測一遍因?yàn)橛?xùn)練時的數(shù)據(jù)增強(qiáng)和預(yù)處理letterbox要在推理側(cè)復(fù)現(xiàn)否則圖像被拉伸變形檢測框位置就全偏了。5.2 C環(huán)境部署要點(diǎn)OpenCV DNN和ONNX Runtime的實(shí)際取舍很多現(xiàn)場設(shè)備是Linux工控機(jī)沒法裝Python環(huán)境C部署就成了必須項(xiàng)。C側(cè)加載YOLO模型有兩個主流選擇OpenCV DNN模塊和ONNX Runtime C API。OpenCV DNN適合快速上線不用引入額外依賴但它的NMS實(shí)現(xiàn)和TRT比還是有點(diǎn)差距batch推理支持也弱一些。ONNX Runtime則是更正規(guī)的選擇支持CUDA EP能精確控制輸入輸出張量。我這邊更推薦ONNX Runtime代碼結(jié)構(gòu)大概是這樣Ort::Env env(ORT_LOGGING_LEVEL_WARNING, yolo); Ort::SessionOptions opts; opts.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL); Ort::Session session(env, model.onnx, opts); // 輸入預(yù)處理letterbox BGR2RGB normalize cv::Mat letterbox_img letterbox(frame, input_shape); cv::cvtColor(letterbox_img, blob, cv::COLOR_BGR2RGB); blob.convertTo(blob, CV_32F, 1.0 / 255.0); // 推理 std::vectorfloat input_tensor_values(blob.beginfloat(), blob.endfloat()); // 構(gòu)造Ort::Value并Run // 后處理解碼bbox NMS 坐標(biāo)映射回原圖推理出來的結(jié)果是歸一化的中心點(diǎn)、寬高要映射回原圖坐標(biāo)時記得把letterbox的填充偏移減掉再除以縮放系數(shù)。這一步寫錯會導(dǎo)致檢測框整體偏移現(xiàn)場排查非常費(fèi)勁。5.3 用OpenCV測量檢測物體的實(shí)際大小很多業(yè)務(wù)場景不只要知道“這里有垃圾”還想知道“這個垃圾有多大”。比如河道監(jiān)管要求超過一定面積的漂浮物才算事件。我們可以用OpenCV結(jié)合相機(jī)標(biāo)定來做測量。最簡單實(shí)用的方法是用已知尺寸的參考物做像素標(biāo)定。比如一個標(biāo)準(zhǔn)雨水箅子直徑是800毫米在畫面里某個位置測出對應(yīng)像素寬度是100像素那像素尺寸轉(zhuǎn)換系數(shù)就是8毫米/像素。檢測時把模型輸出的框?qū)捀叱艘赃@個系數(shù)就得到近似物理尺寸。注意這個系數(shù)只在該參考物所在平面附近有效離得太遠(yuǎn)誤差會增大。更正規(guī)的做法是用相機(jī)標(biāo)定calibrate camera獲取內(nèi)外參然后通過地面平面的單應(yīng)性矩陣把像素坐標(biāo)轉(zhuǎn)換成世界坐標(biāo)。但這個對現(xiàn)場實(shí)施的要求比較高需要知道相機(jī)的安裝高度和俯仰角。如果甲方對測量的準(zhǔn)確性有硬性要求這個環(huán)節(jié)就得專門做而不是靠估計(jì)。論工程項(xiàng)目我個人的建議是先按參考物法快速上線等有投訴或者精度不達(dá)標(biāo)時再上完整標(biāo)定方案這樣能控制初期交付成本。5.4 邊緣設(shè)備選型與性能預(yù)算部署硬件選擇上這個項(xiàng)目典型是NVIDIA Jetson系列。Orin NX 16GB是比較舒服的選擇跑YOLOv8s在640x640輸入下能到30-40 FPSINT8下還能再高一些。如果是更低端的Jetson Nano就只能跑YOLOv8n或者YOLO11n而且最好限制輸入640分辨率?,F(xiàn)場還有幾個容易被忽略的事。鏡頭臟污是監(jiān)控場景的大敵一個泥點(diǎn)貼在鏡頭前模型可能把泥點(diǎn)識別成“廢棄物”。雨水天氣的誤檢率會飆升這個我在后文細(xì)說。夜間低照度下YOLO的檢測率掉得很厲害解決辦法是接紅外補(bǔ)光或者用支持低照度的攝像頭單純依賴算法去扛是沒有意義的。5.5 從檢測到業(yè)務(wù)閉環(huán)告警、工單、統(tǒng)計(jì)怎么接模型跑通了只是第一步真正的交付是跟業(yè)務(wù)系統(tǒng)打通。檢測結(jié)果要轉(zhuǎn)換成業(yè)務(wù)動作一般流程是算法服務(wù)輸出事件類別、置信度、位置、截圖事件網(wǎng)關(guān)做去重和閾值過濾然后推送告警到工單系統(tǒng)由處置人員接單處理最后形成月度統(tǒng)計(jì)報(bào)表。置信度閾值的設(shè)置需要按場景分開。排水管道病害寧可多報(bào)漏報(bào)一條管道破裂可能導(dǎo)致路面塌陷所以閾值可以放低到0.25并由人工復(fù)核。廢棄物告警則相反誤報(bào)太多會讓處置人員麻木閾值建議拉高到0.5以上并且加一個時序過濾連續(xù)N幀都檢測到同一個目標(biāo)才觸發(fā)生成工單。這個過濾邏輯很關(guān)鍵它能消除單幀誤檢也能避免同一堆垃圾在視頻里反復(fù)告警的情況。6. 部署現(xiàn)場的一個真實(shí)踩坑雨天誤檢率翻倍的教訓(xùn)最后分享一個我在類似項(xiàng)目里親歷過的現(xiàn)場問題。第一次在河道監(jiān)控點(diǎn)跑廢棄物檢測模型晴天效果不錯河流和岸邊的靜態(tài)目標(biāo)區(qū)分得很清楚。結(jié)果第一場雨下來誤檢率直接翻倍雨滴、水花、落葉、波紋全被模型當(dāng)成漂浮垃圾。告警平臺一晚上彈了三百多條差點(diǎn)讓現(xiàn)場運(yùn)維把算法直接停用。根因有兩層第一訓(xùn)練數(shù)據(jù)里幾乎沒有雨天場景模型不知道“水面在雨里長這樣”第二單幀檢測天然缺少時間維度信息雨滴和水花都是短時出現(xiàn)又消失跟真正的漂浮物在時間維度有明顯區(qū)別。解決措施分兩步。第一步是數(shù)據(jù)層面補(bǔ)采雨天、逆光、夜間低照度下的河道監(jiān)控樣本重新微調(diào)模型。第二步也是更有效的一步在業(yè)務(wù)側(cè)加一個時序判定邏輯同一個位置連續(xù)N幀比如10幀以上都檢測到目標(biāo)才上報(bào)雨滴水花這種瞬間出現(xiàn)的檢測結(jié)果會被直接丟棄。加了這兩個措施之后雨天誤報(bào)率降到了晴天水平。這類項(xiàng)目做得越多越有體會真正考驗(yàn)團(tuán)隊(duì)的往往不是YOLO訓(xùn)練的理論知識而是對場景數(shù)據(jù)的理解深度和工程化的耐心。模型結(jié)構(gòu)可以幾個月?lián)Q一版但數(shù)據(jù)清洗、時序過濾、業(yè)務(wù)聯(lián)動這些臟活累活才是決定一個算法項(xiàng)目能不能落地、能不能長久跑下去的關(guān)鍵。本文還有配套的精品資源點(diǎn)擊獲取