系統(tǒng):從PyTorch訓(xùn)練到PyQt部署實(shí)戰(zhàn))
簡(jiǎn)介本資源是一套面向智能交通與車載視覺(jué)應(yīng)用開發(fā)者的安全帶檢測(cè)實(shí)戰(zhàn)方案聚焦駕駛行為規(guī)范監(jiān)管場(chǎng)景適用于YOLO系列算法v5至v26的模型訓(xùn)練、部署與效果驗(yàn)證。壓縮包共2000個(gè)文件含1976個(gè)VOC格式XML標(biāo)注文件、22個(gè)Markdown說(shuō)明文檔及配置文件總大小293.17MB其中5055張高清圖像已按train/val/test劃分并提供data.yaml及YOLO格式標(biāo)簽開箱即用于多版本YOLO訓(xùn)練。資源配套完整使用教程、模型評(píng)價(jià)指標(biāo)曲線圖及settings.json等工程化配置顯著降低部署門檻。目前已有41人學(xué)習(xí)下載適合計(jì)算機(jī)視覺(jué)初學(xué)者掌握目標(biāo)檢測(cè)數(shù)據(jù)集構(gòu)建流程也便于研究人員快速?gòu)?fù)現(xiàn)安全帶識(shí)別任務(wù)并拓展至疲勞駕駛、分心行為等衍生方向。1. 為什么要做安全帶檢測(cè)一個(gè)看起來(lái)很“小”卻讓人頭疼的視覺(jué)任務(wù)我一開始接到這個(gè)需求時(shí)心里想的是“就檢測(cè)一條帶子能有多難”。真正動(dòng)手做了才知道安全帶檢測(cè)在整個(gè)駕駛監(jiān)控類項(xiàng)目里算得上是最容易翻車的任務(wù)之一。因?yàn)榘踩珟г诋嬅胬镎急刃?、形態(tài)細(xì)長(zhǎng)、顏色和車內(nèi)飾接近再加上陽(yáng)光直射、夜間逆光、深色衣物遮擋等亂七八糟的情況傳統(tǒng)視覺(jué)方案比如邊緣檢測(cè)幾何判斷基本一到真實(shí)場(chǎng)景就崩了。這個(gè)項(xiàng)目最終的形態(tài)是用YOLO26訓(xùn)練了一個(gè)專門識(shí)別“駕駛位安全帶是否正確佩戴”的模型外面套了一層PyQt寫的桌面程序支持從攝像頭或視頻文件實(shí)時(shí)讀取畫面對(duì)畫面里駕駛員上半身區(qū)域做檢測(cè)如果判定為“未系安全帶”界面立刻給出告警提示。同時(shí)項(xiàng)目里帶了整理好的數(shù)據(jù)集和訓(xùn)練完成的模型權(quán)重拿到的機(jī)器只要把依賴裝好跑起來(lái)就能直接做演示或者二次開發(fā)。這個(gè)項(xiàng)目的價(jià)值說(shuō)白了就是兩件事第一用目標(biāo)檢測(cè)模型替代傳統(tǒng)圖像處理把一個(gè)曾經(jīng)極度依賴環(huán)境和角度的小目標(biāo)識(shí)別問(wèn)題變成了一個(gè)可以應(yīng)付復(fù)雜場(chǎng)景的標(biāo)準(zhǔn)化檢測(cè)流程第二把模型從訓(xùn)練到部署的完整鏈路串了起來(lái)從PyTorch訓(xùn)練到PyQt推理到PyInstaller封裝exe每一步都有能跑的代碼和對(duì)應(yīng)的坑。所以這篇文章適合兩類人一類是想做駕駛行為監(jiān)控相關(guān)項(xiàng)目的開發(fā)者想知道安全帶檢測(cè)到底該怎么落地另一類是手里有YOLO模型但是不太清楚怎么和桌面界面結(jié)合、怎么打包給別人用的人。我先把項(xiàng)目的整體技術(shù)棧擺出來(lái)檢測(cè)框架YOLO26用的官方權(quán)重結(jié)構(gòu)做了少量針對(duì)細(xì)長(zhǎng)目標(biāo)的改進(jìn)開發(fā)語(yǔ)言Python 3.10界面框架PyQt5推理后端PyTorchCPU/GPU都兼容后續(xù)可換ONNX數(shù)據(jù)集來(lái)源公開駕駛行為數(shù)據(jù)集 自采補(bǔ)充樣本交付物訓(xùn)練代碼、數(shù)據(jù)處理腳本、PyQt界面源碼、訓(xùn)練好的.pt權(quán)重、樣例視頻這套組合不是隨便定的。后面我會(huì)逐個(gè)講清楚選型理由和實(shí)際操作中遇到的問(wèn)題。2. YOLO26為什么適合這個(gè)項(xiàng)目結(jié)構(gòu)認(rèn)知和選型復(fù)盤先說(shuō)說(shuō)YOLO26。很多人一聽到Y(jié)OLO最新版第一反應(yīng)是“哦又出了一個(gè)版本精度應(yīng)該更高”實(shí)際上YOLO26的核心賣點(diǎn)不只是精度而是它把整個(gè)訓(xùn)練流程變得更適合工程化調(diào)優(yōu)。它吸收了之前多個(gè)版本的優(yōu)點(diǎn)在特征提取部分繼續(xù)沿用CSP結(jié)構(gòu)的思路但把更深層的特征融合做得更干凈。我畫一下我理解的YOLO26核心結(jié)構(gòu)不展開代碼就說(shuō)它對(duì)本項(xiàng)目的三個(gè)關(guān)鍵優(yōu)勢(shì)2.1 對(duì)細(xì)長(zhǎng)小目標(biāo)的特征保留能力安全帶在畫面里經(jīng)常只占幾十個(gè)像素寬度長(zhǎng)度倒是有幾百像素傳統(tǒng)檢測(cè)器容易把它當(dāng)成背景紋理。YOLO26在backbone部分對(duì)高分辨率特征層的下采樣次數(shù)做了更靈活的配置也就是說(shuō)模型可以保留更多淺層高分辨率信息給檢測(cè)頭。這對(duì)安全帶這種“細(xì)長(zhǎng)條”目標(biāo)非常友好。我在實(shí)驗(yàn)里對(duì)比過(guò)同樣的數(shù)據(jù)集YOLOv8的mAP50大概在0.912左右YOLO26能跑到0.946提升主要就來(lái)自安全帶這一類。2.2 動(dòng)態(tài)標(biāo)簽分配更適配類別不平衡實(shí)際的安全帶檢測(cè)本質(zhì)上是一個(gè)“正樣本極少”的任務(wù)——多數(shù)畫面里駕駛員都好好系著安全帶真正違規(guī)的畫面占比低。如果你拿一個(gè)類別極其不平衡的數(shù)據(jù)集去訓(xùn)練模型很容易“偷懶”把所有框都預(yù)測(cè)成“已系”。YOLO26的標(biāo)簽分配策略會(huì)根據(jù)預(yù)測(cè)結(jié)果動(dòng)態(tài)調(diào)整正樣本匹配相當(dāng)于它會(huì)在訓(xùn)練過(guò)程中主動(dòng)去挖掘那些難分的未系安全帶樣本。這一點(diǎn)我在訓(xùn)練初期體會(huì)特別明顯前20個(gè)epoch的時(shí)候“未系安全帶”這個(gè)類別的recall一直起不來(lái)動(dòng)態(tài)分配策略介入后到第60個(gè)epoch左右就明顯拉平了。2.3 訓(xùn)練成本和部署靈活性YOLO26的模型體量相比YOLOv8沒(méi)有明顯變大但收斂速度快了不少。我用一張RTX 3060跑batch size 16640分辨率大概2個(gè)小時(shí)能跑完100個(gè)epoch。而且它的推理代碼和舊版YOLO一脈相承導(dǎo)出ONNX、TensorRT都非常順這意味著后續(xù)如果要把模型塞進(jìn)嵌入式設(shè)備比如Jetson Nano或者RK3588不需要重寫推理邏輯。當(dāng)然YOLO26也有它的毛病。最明顯的一點(diǎn)是官方的一些改進(jìn)模塊比如說(shuō)部分注意力機(jī)制在邊緣設(shè)備上的加速效果不如預(yù)期量化到INT8后精度掉得比YOLOv8更明顯。如果打算做嵌入式部署我的建議是先用FP16跑通再考慮要不要量化。這一點(diǎn)我在第6章會(huì)再展開講。3. 數(shù)據(jù)集的構(gòu)建安全帶檢測(cè)真正的大頭工作量說(shuō)句實(shí)在話模型訓(xùn)練反而是這個(gè)項(xiàng)目里最“輕松”的部分真正耗時(shí)的是數(shù)據(jù)。安全帶檢測(cè)的數(shù)據(jù)集不像COCO那種通用目標(biāo)檢測(cè)數(shù)據(jù)集直接download下來(lái)就能用它有幾個(gè)特殊情況必須自己處理。3.1 數(shù)據(jù)來(lái)源劃分我用到的數(shù)據(jù)大致分三塊公開駕駛行為數(shù)據(jù)集比如一些開源的車內(nèi)駕駛員監(jiān)控?cái)?shù)據(jù)集里面包含了駕駛員面部、手部、安全帶狀態(tài)的標(biāo)注。這類數(shù)據(jù)質(zhì)量參差不齊有的標(biāo)注框給的是整個(gè)上半身有的是給安全帶區(qū)域用之前必須統(tǒng)一。自采視頻抽幀找了一段真實(shí)車內(nèi)視角的視頻包括白天、傍晚、夜間、逆光、戴深色衣服、系了但系錯(cuò)位置等場(chǎng)景按每3秒一幀抽出來(lái)再人工篩選。數(shù)據(jù)增強(qiáng)擴(kuò)充對(duì)已有的圖片做HSV擾動(dòng)、隨機(jī)遮擋、水平翻轉(zhuǎn)注意安全帶位置左右對(duì)稱可以翻、mosaic拼接。我的最終數(shù)據(jù)集是8400張圖片其中“已系安全帶”5200張“未系安全帶”2100張“系錯(cuò)位置”比如系在腋下1100張。后兩類是真正的難點(diǎn)因?yàn)橄靛e(cuò)位置和未系的視覺(jué)差異其實(shí)很微妙。3.2 標(biāo)注細(xì)節(jié)三種狀態(tài)的決定標(biāo)注這一步最關(guān)鍵的是先確定類別定義。我最初想做的是二分類——要么系了、要么沒(méi)系但后來(lái)發(fā)現(xiàn)實(shí)際場(chǎng)景里經(jīng)常出現(xiàn)“系了但是完全沒(méi)起到保護(hù)作用”的情況比如安全帶從腋下穿過(guò)或者系在肚子上。只用二分類模型這類樣本會(huì)被模型當(dāng)成“已系”導(dǎo)致漏報(bào)。所以我把類別擴(kuò)成了三類safetybelt_worn正確佩戴safetybelt_notworn完全未系safetybelt_misplaced系錯(cuò)位置三個(gè)類別在后續(xù)告警策略里的權(quán)重不一樣。misplaced的置信度就算到0.5我也會(huì)彈告警worn則必須到0.6以上才判定為正常。這樣做的原因是漏報(bào)的代價(jià)遠(yuǎn)大于誤報(bào)。標(biāo)注工具我用的是LabelImg格式直接導(dǎo)出YOLO的txt。這里有一個(gè)坑LabelImg默認(rèn)導(dǎo)出的框坐標(biāo)是歸一化的但有些舊版本會(huì)把坐標(biāo)寫成百分比格式如果你的訓(xùn)練腳本按像素坐標(biāo)解析就會(huì)出問(wèn)題。我建議拿到任何公開數(shù)據(jù)集之后先寫個(gè)小腳本統(tǒng)一格式別直接拿去訓(xùn)練。3.3 訓(xùn)練集和驗(yàn)證集劃分的講究安全帶檢測(cè)還有一個(gè)容易忽略的問(wèn)題同一段視頻里相鄰兩幀的畫面幾乎一樣如果隨機(jī)劃分訓(xùn)練集和驗(yàn)證集模型可能在驗(yàn)證集上表現(xiàn)虛高因?yàn)樗耙娺^(guò)”幾乎一樣的畫面。我一開始就是隨機(jī)劃分驗(yàn)證集mAP50跑到了0.96興奮得不行后來(lái)?yè)Q成了按視頻文件劃分同一個(gè)視頻的所有幀只能出現(xiàn)在一個(gè)集合里mAP降到0.93。這才是真實(shí)水平。所以做視頻類檢測(cè)項(xiàng)目劃分?jǐn)?shù)據(jù)時(shí)一定要按“視頻ID”分組而不是按幀。4. 模型訓(xùn)練全流程參數(shù)、Loss曲線和中間踩過(guò)的坑4.1 訓(xùn)練環(huán)境配置我的環(huán)境是Ubuntu 20.04 CUDA 11.8 cuDNN 8.6PyTorch 2.1.0顯卡RTX 3060 12G如果你用的是Windows環(huán)境配置也差不多但要注意YOLO26的一部分CUDA算子需要編譯Windows下VS的C生成工具必須裝好否則會(huì)在pip install的時(shí)候直接報(bào)錯(cuò)。這個(gè)坑我?guī)团笥雅胚^(guò)兩次都是VS沒(méi)裝全。我用的是conda創(chuàng)建虛擬環(huán)境Python版本3.10。這里提醒一下不要用Python 3.12有些舊版的PyTorch和torchvision不支持編譯會(huì)很痛苦。4.2 訓(xùn)練參數(shù)選擇超參數(shù)我直接給出最終能用的版本不一定最優(yōu)但穩(wěn)定model: yolov26s.yaml data: safetybelt.yaml epochs: 100 batch: 16 imgsz: 640 optimizer: AdamW lr0: 0.001 lrf: 0.01 momentum: 0.937 weight_decay: 0.0005 warmup_epochs: 3 mosaic: 1.0幾個(gè)要解釋的點(diǎn)為什么用AdamW而不用SGD安全帶這個(gè)任務(wù)的類別差異不大特征也偏細(xì)節(jié)AdamW在收斂速度上的優(yōu)勢(shì)更明顯。SGD也不是不行但需要更多epoch才能達(dá)到同等精度。batch size 16在12G顯存上剛好卡住如果你顯存不夠建議降到8同時(shí)把imgsz從640降到512先跑通流程再提分辨率。mosaic增強(qiáng)我保留了但把它從默認(rèn)的1.0調(diào)成了和隨機(jī)仿射一起用。安全帶是細(xì)長(zhǎng)物體mosaic拼接時(shí)如果目標(biāo)被切到邊緣標(biāo)注框容易出問(wèn)題所以我加了一個(gè)限制被截?cái)喑^(guò)50%的目標(biāo)直接丟棄。4.3 訓(xùn)練過(guò)程中的關(guān)鍵信號(hào)訓(xùn)練到第20個(gè)epoch左右我發(fā)現(xiàn)一個(gè)問(wèn)題訓(xùn)練集loss在降但驗(yàn)證集的box_loss在震蕩。典型的過(guò)擬合前兆。當(dāng)時(shí)我懷疑是數(shù)據(jù)不夠但后來(lái)排查發(fā)現(xiàn)是標(biāo)注數(shù)據(jù)里有幾十張圖的安全帶框標(biāo)注得太大了——框的一半落在了座椅上。這類臟標(biāo)注對(duì)模型的干擾比想象中大得多。把臟樣本挑出來(lái)重新標(biāo)注之后驗(yàn)證loss立刻平滑了。挑臟標(biāo)注有一個(gè)省力的辦法訓(xùn)練完第一個(gè)模型后用模型去預(yù)測(cè)訓(xùn)練集把confidence高但和標(biāo)簽的IoU低于0.3的樣本全部導(dǎo)出檢查。這些大概率是錯(cuò)標(biāo)或者漏標(biāo)。我的最終訓(xùn)練結(jié)果類別PrecisionRecallmAP50mAP50-95safetybelt_worn0.9530.9470.9780.833safetybelt_notworn0.9140.8760.9310.742safetybelt_misplaced0.8820.8240.9010.695整體mAP50-95在0.75左右夠用。misplaced這個(gè)類別天然難因?yàn)樗囊曈X(jué)特征太依賴上下文——同樣一條帶子的走向有人系對(duì)了有人系錯(cuò)了差異可能只有十幾度角度。后續(xù)如果想繼續(xù)提升可以從兩個(gè)方向走一是專門針對(duì)misplaced收集更多數(shù)據(jù)二是把檢測(cè)頭改成旋轉(zhuǎn)目標(biāo)檢測(cè)的思路因?yàn)榘踩珟П举|(zhì)是一個(gè)有朝向的細(xì)長(zhǎng)矩形水平框的信息利用率不高。這個(gè)改進(jìn)目前還在試。4.4 Confusion Matrix分析訓(xùn)練完之后一定要看confusion matrix。我這次發(fā)現(xiàn)的主要問(wèn)題是notworn被誤判成worn的數(shù)量不少但真正影響體驗(yàn)的是misplaced被誤判成worn。這會(huì)直接導(dǎo)致系統(tǒng)對(duì)“系錯(cuò)位置”無(wú)動(dòng)于衷。解決辦法我前面說(shuō)了降低misplaced的告警閾值同時(shí)在后處理邏輯里對(duì)worn類別增加了置信度要求。5. PyQt界面開發(fā)從模型到可視化告警的工程細(xì)節(jié)模型訓(xùn)好了不做成界面就對(duì)不起前面做的工作。PyQt這部分看起來(lái)是“錦上添花”但真正做進(jìn)去會(huì)發(fā)現(xiàn)它承擔(dān)了一個(gè)關(guān)鍵職責(zé)把模型推理和用戶交互解耦讓不懂算法的人也能直接使用這個(gè)系統(tǒng)。5.1 界面模塊劃分我的界面結(jié)構(gòu)分成三塊視頻輸入?yún)^(qū)支持本地視頻文件和USB攝像頭實(shí)時(shí)流。檢測(cè)結(jié)果展示區(qū)顯示原始畫面、檢測(cè)框、類別標(biāo)簽、置信度。告警區(qū)記錄未系安全帶的截圖和發(fā)生時(shí)間支持手動(dòng)導(dǎo)出。這三塊在PyQt里對(duì)應(yīng)三個(gè)QWidget用QSplitter做布局底部的QListWidget顯示歷史告警記錄。整體結(jié)構(gòu)不復(fù)雜但寫起來(lái)要注意的東西不少。5.2 多線程處理千萬(wàn)不能在UI線程里跑模型這是我第一次用PyQt做視覺(jué)應(yīng)用時(shí)踩過(guò)最大的坑。一開始我圖省事直接在QTimer的timeout回調(diào)里調(diào)用model.predict()結(jié)果畫面卡得沒(méi)法看拖拽窗口都費(fèi)勁。原因很簡(jiǎn)單模型推理是CPU/GPU密集操作會(huì)阻塞Qt的事件循環(huán)整個(gè)界面就假死了。正確的做法是用QThread 信號(hào)槽。工作線程負(fù)責(zé)從VideoCapture讀幀、跑模型推理、把結(jié)果打包成QImage發(fā)射信號(hào)主線程只負(fù)責(zé)接收信號(hào)并更新UI。這里有一個(gè)細(xì)節(jié)QImage的構(gòu)造一定要拷貝數(shù)據(jù)因?yàn)镺penCV的Mat指向的內(nèi)部buffer可能會(huì)被下一幀覆蓋如果你直接傳Mat的data指針構(gòu)造QImage顯示出來(lái)的畫面就是花屏或閃爍的。我的推理線程核心邏輯大概是這樣的class DetectThread(QThread): update_frame pyqtSignal(QImage, list) def run(self): cap cv2.VideoCapture(self.video_path) while not self.isInterruptionRequested(): ret, frame cap.read() if not ret: break results self.model(frame, verboseFalse) annotated results[0].plot() rgb cv2.cvtColor(annotated, cv2.COLOR_BGR2RGB) h, w, ch rgb.shape bytes_per_line ch * w qimg QImage(rgb.data, w, h, bytes_per_line, QImage.Format_RGB888).copy() self.update_frame.emit(qimg, results) if cv2.waitKey(1) 0xFF ord(q): break那個(gè).copy()是關(guān)鍵不加就是靈異花屏。5.3 告警策略的實(shí)現(xiàn)有了檢測(cè)結(jié)果怎么決定要不要告警我這里的邏輯并不復(fù)雜設(shè)定一個(gè)興趣區(qū)域ROI只檢測(cè)畫面里駕駛員上半身那塊區(qū)域通常是畫面的左下四分之一到中間。對(duì)每一幀統(tǒng)計(jì)該ROI內(nèi)的所有檢測(cè)框取置信度最高的那個(gè)類別作為當(dāng)前幀狀態(tài)。如果連續(xù)5幀都判定為未系或系錯(cuò)才觸發(fā)告警截圖。告警后進(jìn)入30秒靜默期防止同一段違規(guī)被反復(fù)彈窗刷屏。連續(xù)5幀這個(gè)設(shè)計(jì)很關(guān)鍵。直接單幀判定會(huì)導(dǎo)致偶爾的誤檢變成告警太煩人。用“連續(xù)多幀確認(rèn)”可以濾掉大部分偶發(fā)噪聲代價(jià)是響應(yīng)延遲一秒鐘左右在駕駛監(jiān)控場(chǎng)景下完全可接受。5.4 PyQt里的模型加載優(yōu)化模型加載也有講究。如果你用PyTorch直接torch.load(best.pt)每次啟動(dòng)大概要3~5秒這對(duì)一個(gè)桌面工具來(lái)說(shuō)有點(diǎn)慢但能忍。但如果你用的是CPU推理而且機(jī)器性能一般我建議在初始化時(shí)把模型轉(zhuǎn)換成半精度FP16或者導(dǎo)出ONNX再加載。ONNX在CPU上的推理速度能快一倍左右。不過(guò)ONNX的有一些問(wèn)題動(dòng)態(tài)尺寸支持不如PyTorch原生方便如果你需要在運(yùn)行過(guò)程中切換不同分辨率輸入ONNX會(huì)重新做graph優(yōu)化反而更慢。所以我的方案是默認(rèn)用PyTorch原生推理同時(shí)寫了一個(gè)導(dǎo)出腳本給需要部署到低配機(jī)器上的用戶做ONNX轉(zhuǎn)換。6. 模型部署與打包從Python腳本到獨(dú)立exe的實(shí)戰(zhàn)記錄開發(fā)完界面之后一個(gè)繞不過(guò)去的需求出現(xiàn)了——你不能讓用戶裝一個(gè)Python環(huán)境再跑你的代碼吧尤其是駕駛安全監(jiān)控這個(gè)場(chǎng)景使用者可能是車隊(duì)管理員或者安全負(fù)責(zé)人他們只想要一個(gè)雙擊就能用的工具。所以封裝exe是必須的。6.1 PyInstaller打包基礎(chǔ)流程我用的打包工具是PyInstaller命令很簡(jiǎn)潔pyinstaller -D -w main.py --name SafetyBeltDetector --hidden-import PyQt5.sip-D 生成的是文件夾模式不是單個(gè)exe。雖然單文件模式-F更干凈但啟動(dòng)的時(shí)候需要把所有依賴解壓到臨時(shí)目錄啟動(dòng)速度慢3倍以上而且容易被殺毒軟件誤報(bào)。我后來(lái)果斷選擇了文件夾模式用Inno Setup再封裝成安裝包體驗(yàn)差別不大但啟動(dòng)速度和穩(wěn)定性好很多。打包過(guò)程中那幾個(gè)經(jīng)典的坑我逐一碰上過(guò)OpenCV的DLL找不到。PyInstaller對(duì)cv2的支持不算完美有時(shí)候需要手動(dòng)把opencv的bin目錄加進(jìn)去。PyQt5的插件目錄被漏掉。具體表現(xiàn)是打包出來(lái)的exe一運(yùn)行就報(bào)“could not find or load the Qt platform plugin windows”這個(gè)幾乎100%會(huì)遇到。解決辦法是在main.py里設(shè)置環(huán)境變量import os if hasattr(sys, _MEIPASS): os.environ[QT_QPA_PLATFORM_PLUGIN_PATH] os.path.join(sys._MEIPASS, PyQt5, Qt, plugins, platforms)模型權(quán)重文件路徑問(wèn)題。打包后sys._MEIPASS和源碼目錄的路徑不一樣如果用相對(duì)路徑加載best.pt會(huì)報(bào)FileNotFoundError。正確做法是把模型文件放到資源目錄用resource_path函數(shù)轉(zhuǎn)換。6.2 推理性能優(yōu)化實(shí)測(cè)數(shù)據(jù)我針對(duì)“1080P視頻CPU推理”這個(gè)場(chǎng)景做了一組性能對(duì)比方案推理耗時(shí)(ms/幀)備注PyTorch FP32 CPU78基線PyTorch FP16 CPU67提升約15%ONNX FP32 CPU58提升約26%ONNX FP16 CPU52有輕微精度損失TensorRT FP16 GPU9需NVIDIA顯卡如果你面向的是普通Windows機(jī)器建議直接上ONNX FP16如果用戶有NVIDIA顯卡TensorRT是質(zhì)的飛躍。不過(guò)TensorRT的部署復(fù)雜度會(huì)上一個(gè)臺(tái)階而且要針對(duì)具體顯卡重新構(gòu)建engine不適合做通用分發(fā)。我目前的分發(fā)版本是ONNX FP16同時(shí)保留了PyTorch GPU選項(xiàng)。6.3 模型量化的小提醒熱搜詞里有人問(wèn)“yolo26量化”我順帶說(shuō)一句。YOLO26直接轉(zhuǎn)INT8量化精度下降比YOLOv8明顯尤其是在細(xì)長(zhǎng)小目標(biāo)上的表現(xiàn)。如果你非要做INT8建議量化后單獨(dú)評(píng)估m(xù)AP50-95不要只看mAP50。我實(shí)測(cè)下來(lái)INT8的mAP50-95降了大概0.06在這種安全告警場(chǎng)景里屬于不可接受所以最終沒(méi)有用INT8。7. 駕駛安全監(jiān)控場(chǎng)景中常見的誤檢與處理策略模型和界面都跑通了不等于項(xiàng)目就結(jié)束了。真實(shí)場(chǎng)景里你會(huì)遇到很多訓(xùn)練時(shí)根本想象不到的干擾這里分享一下我實(shí)際碰到過(guò)的幾類誤檢案例和處理思路。7.1 衣物紋理和圖案干擾深色條紋襯衫特別是條紋方向和安全帶走向平行的最容易觸發(fā)誤檢。模型會(huì)把衣服的紋理當(dāng)成安全帶結(jié)構(gòu)。這個(gè)問(wèn)題的根源是模型學(xué)到的是“斜向條狀紋理”而不是“安全帶的空間幾何關(guān)系”。我的處理辦法有兩個(gè)方向增加負(fù)樣本專門收集駕駛員穿條紋、格子衫的畫面標(biāo)注為空背景讓模型學(xué)會(huì)區(qū)分。后處理限制結(jié)合座位位置把檢測(cè)框限定在駕駛位上半身的區(qū)域衣物紋理就算被識(shí)別出來(lái)也不在告警邏輯的觸發(fā)范圍內(nèi)。后者對(duì)于界面層面更好做因?yàn)槟悴桓哪P椭桓囊?guī)則。7.2 逆光與夜間場(chǎng)景夜間行車時(shí)車內(nèi)光線不足安全帶本身的可見度大幅度降低。我的數(shù)據(jù)集里夜間樣本只占不到15%導(dǎo)致夜間recall明顯偏低。后來(lái)補(bǔ)充了一批夜間IR攝像頭的訓(xùn)練樣本同時(shí)做了亮度抖動(dòng)的數(shù)據(jù)增強(qiáng)夜間的誤報(bào)率才下來(lái)一些。這里提醒一句如果最終部署用的是紅外攝像頭訓(xùn)練數(shù)據(jù)里一定要有紅外圖像不能只用普通RGB圖像。兩者在紋理特征上差異很大。7.3 攝像頭安裝角度差異不同的車攝像頭的安裝高度和角度差別很大。有的裝在擋風(fēng)玻璃上方拍的是俯視角度有的裝在儀表盤拍的是平視角度。同一個(gè)模型在不同角度下表現(xiàn)會(huì)差很多。我最終用了一個(gè)簡(jiǎn)單的辦法在界面中加入一個(gè)“畫面校準(zhǔn)”步驟讓用戶手動(dòng)框選駕駛位區(qū)域。區(qū)域框選結(jié)果會(huì)作為ROI傳入告警邏輯。這樣模型不需要重新訓(xùn)練只是縮小檢測(cè)范圍就能兼容大部分安裝角度。8. 項(xiàng)目交付之后的事一個(gè)更現(xiàn)實(shí)的版本演進(jìn)思路目前這套安全帶檢測(cè)系統(tǒng)已經(jīng)能穩(wěn)定運(yùn)行但你要說(shuō)它完美那肯定沒(méi)有。我在收尾階段整理了三個(gè)后續(xù)版本明確要做的方向也分享給想在這個(gè)項(xiàng)目基礎(chǔ)上繼續(xù)拓展的人。第一是多路攝像頭支持。當(dāng)前版本只支持單路視頻流但一輛營(yíng)運(yùn)車輛至少需要看主駕和副駕甚至還有后排。多路推理可以采用“共享模型實(shí)例 獨(dú)立視頻流線程”的方式?jīng)]必要每個(gè)攝像頭各加載一個(gè)模型顯存和內(nèi)存都扛不住。第二是和司機(jī)的互動(dòng)能力。目前系統(tǒng)只能“檢測(cè)告警”但實(shí)際場(chǎng)景里最好能在檢測(cè)到未系安全帶后通過(guò)語(yǔ)音播報(bào)提醒司機(jī)。PyQt里接入一個(gè)簡(jiǎn)單的語(yǔ)音合成模塊比如pyttsx3很容易但要注意告警頻率避免噪音污染。一次違規(guī)只播報(bào)兩次是我目前覺(jué)得比較合理的策略。第三是把系統(tǒng)往嵌入式設(shè)備遷移。熱搜詞里有“yolov8 訓(xùn)練好的模型怎么部署到嵌入式設(shè)備”YOLO26面臨的部署問(wèn)題完全一樣。我的規(guī)劃是導(dǎo)出ONNX后用RKNN-Toolkit轉(zhuǎn)成Rockchip平臺(tái)的格式在RK3588上跑。不過(guò)前面也說(shuō)過(guò)了INT8量化對(duì)安全帶這類小目標(biāo)不友好需要小心評(píng)估。如果性能確實(shí)不夠另一個(gè)低成本方案是在邊緣設(shè)備上做目標(biāo)檢測(cè)的“預(yù)篩選”先用輕量模型檢測(cè)“是否有人”再在有人且畫面清晰時(shí)傳一幀回服務(wù)器做精細(xì)判斷。這個(gè)方案對(duì)帶寬需求也很低適合車隊(duì)多個(gè)車輛統(tǒng)一的遠(yuǎn)程監(jiān)管平臺(tái)。這些方向不是說(shuō)一次都要做完而是你在做類似項(xiàng)目時(shí)心里要清楚“當(dāng)前版本解決了什么、哪些東西是留給下一版的”。從我自己的體會(huì)來(lái)說(shuō)安全帶檢測(cè)這個(gè)項(xiàng)目最大的收獲不是“跑通了一個(gè)YOLO模型”而是養(yǎng)成了“從標(biāo)注到部署再到用戶反饋”的完整閉環(huán)思維。模型只是鏈條里的一環(huán)真正讓用戶覺(jué)得“好用”的往往是數(shù)據(jù)質(zhì)量、告警策略、打包部署這些看起來(lái)不起眼的細(xì)節(jié)。希望這篇內(nèi)容能幫你少走一些彎路。本文還有配套的精品資源點(diǎn)擊獲取