練工地安全目標(biāo)檢測:600張圖從標(biāo)簽體檢到部署實(shí)踐)
簡介建筑工地安全目標(biāo)檢測數(shù)據(jù)集提供了一套面向AI視覺開發(fā)者和工地安防系統(tǒng)研發(fā)的YOLO標(biāo)準(zhǔn)訓(xùn)練資源。數(shù)據(jù)源自真實(shí)工地監(jiān)控畫面共600張已標(biāo)注圖片訓(xùn)練集426張、驗(yàn)證集117張、測試集57張覆蓋靴子、安全帽、機(jī)械、人員、安全背心等8個(gè)類別同時(shí)標(biāo)注無安全帽、無口罩、無安全背心等違規(guī)行為可用于裝備佩戴檢測與違規(guī)預(yù)警。包體共1202個(gè)文件以jpg圖片與txt標(biāo)注文件為主另含yaml配置及docx說明文檔整體壓縮后約37.43MB可接入YOLOv5、YOLOv8等常用框架快速部署。目前已有264人學(xué)習(xí)下載。依托這份數(shù)據(jù)用戶可開展多類別目標(biāo)檢測實(shí)驗(yàn)搭建工地安全智能監(jiān)控原型降低數(shù)據(jù)采集與標(biāo)注成本也能為工業(yè)安全管理及高校計(jì)算機(jī)視覺研究提供貼近真實(shí)場景的支撐素材。1. 建筑工地安全目標(biāo)檢測數(shù)據(jù)集600張真實(shí)監(jiān)控圖能訓(xùn)出什么做工地安全監(jiān)控的人拿到這份建筑工地安全目標(biāo)檢測數(shù)據(jù)集最容易犯的錯(cuò)是直接丟給YOLOv8開訓(xùn)。600張真實(shí)工地監(jiān)控畫面、8個(gè)類別、YOLO格式標(biāo)注看起來一步就能跑通實(shí)際上拆開看才發(fā)現(xiàn)違規(guī)類無安全帽、無口罩、無安全背心和裝備類高度重疊機(jī)械類樣本稀少類名還有拼寫坑。這些信息不提前盤清楚后面盯著訓(xùn)練日志調(diào)參就是瞎調(diào)。這篇文章按我拆數(shù)據(jù)集的習(xí)慣來寫先查目錄和標(biāo)簽結(jié)構(gòu)再配置YOLOv8跑通訓(xùn)練評估時(shí)看混淆矩陣和badcase最后補(bǔ)兩個(gè)部署階段的實(shí)用動(dòng)作。適合做工業(yè)安防、工地智能監(jiān)控以及想拿真實(shí)場景練手目標(biāo)檢測的開發(fā)者。2. 先盤數(shù)據(jù)集目錄結(jié)構(gòu)、YOLO標(biāo)簽格式與8個(gè)類別分布拿到zip包第一件事不是解壓了就跑而是把壓縮包內(nèi)的目錄結(jié)構(gòu)搞清楚。這個(gè)數(shù)據(jù)集來自Roboflow導(dǎo)出從文件名里那一串_jpg.rf.就能看出來——這是平臺(tái)處理過后重命名的產(chǎn)物中間那段十六進(jìn)制哈希是圖片增強(qiáng)鏈路的標(biāo)記。真正在訓(xùn)練時(shí)起作用的是文件名主體和標(biāo)注文件的同名對應(yīng)關(guān)系哈希部分不影響訓(xùn)練但會(huì)影響你后續(xù)人工核對badcase時(shí)認(rèn)圖。2.1 解壓后的目錄600張圖片和600個(gè)txt怎么對應(yīng)Roboflow導(dǎo)出的YOLO格式壓縮包解壓后一般是train / valid / test三個(gè)子集每個(gè)子集里再分images和labels。這份數(shù)據(jù)集對應(yīng)關(guān)系是訓(xùn)練集426張、驗(yàn)證集117張、測試集57張。images里放.jpg圖片labels里放同名.txt標(biāo)注文件一個(gè)jpg對應(yīng)一個(gè)txt沒有txt的圖片在訓(xùn)練時(shí)會(huì)被靜默跳過。# 解壓后先核對三個(gè)子集數(shù)量 find train/images -name *.jpg | wc -l # 應(yīng)為426 find train/labels -name *.txt | wc -l # 應(yīng)為426 # 再檢查同名對應(yīng)缺標(biāo)簽的文件會(huì)被跳過 for img in train/images/*.jpg; do txttrain/labels/$(basename $img .jpg).txt [ -f $txt ] || echo missing label: $img done這段腳本的價(jià)值在于YOLO訓(xùn)練框架不會(huì)因?yàn)槟闵賻讉€(gè)txt報(bào)錯(cuò)而是直接把對應(yīng)圖片剔除出訓(xùn)練隊(duì)列。如果缺失發(fā)生在某個(gè)稀有類別上你連日志都看不出問題只會(huì)發(fā)現(xiàn)某個(gè)類的AP莫名偏低。我一般會(huì)把這個(gè)檢查腳本在train、valid、test三個(gè)子集上都跑一遍確保圖片和標(biāo)注是完整配對的。另外注意test子集在訓(xùn)練階段完全不用碰它是留給你最后驗(yàn)證模型泛化能力的。很多新手把test也塞進(jìn)訓(xùn)練導(dǎo)致評估時(shí)分?jǐn)?shù)虛高那叫自欺欺人。2.2 YOLO標(biāo)簽格式歸一化坐標(biāo)與標(biāo)簽體檢腳本YOLO格式的每個(gè)txt文件里一行代表一個(gè)目標(biāo)共5個(gè)數(shù)值類別ID、歸一化中心點(diǎn)x、歸一化中心點(diǎn)y、歸一化寬度w、歸一化高度h。所有坐標(biāo)都除以了圖片寬高值域在0到1之間??床欢@個(gè)后面排查標(biāo)簽越界問題就無從下手。import random from glob import glob txts glob(train/labels/*.txt) sample random.choice(txts) with open(sample) as f: for line in f.read().strip().splitlines(): class_id, cx, cy, w, h line.split() print(fclass{class_id}, cx{cx}, cy{cy}, w{w}, h{h})我們隨機(jī)抽一個(gè)標(biāo)簽文件打開看class6, cx0.482, cy0.531, w0.118, h0.204。意思是類別ID為6對應(yīng)Person類目標(biāo)中心點(diǎn)在圖片水平48.2%、垂直53.1%的位置寬度占整圖11.8%高度占20.4%。要換算成像素坐標(biāo)就用cx*圖片寬、cy*圖片高。這種歸一化格式的好處是和圖片分辨率解耦訓(xùn)練時(shí)無論縮放到640還是1280坐標(biāo)比例都不變。下一個(gè)動(dòng)作是體檢檢查所有txt的坐標(biāo)值是否都在0到1范圍內(nèi)。越界坐標(biāo)會(huì)導(dǎo)致訓(xùn)練時(shí)邊界框計(jì)算異常輕則loss波動(dòng)重則訓(xùn)練崩掉。import os from glob import glob bad 0 for txt in glob(train/labels/*.txt) glob(valid/labels/*.txt): for line in open(txt).read().strip().splitlines(): cid, cx, cy, w, h map(float, line.split()) if not (0 cx 1 and 0 cy 1 and 0 w 1 and 0 h 1): print(fout-of-range: {txt} - {line}) bad 1 print(ftotal bad lines: {bad})這個(gè)腳本看起來簡單但實(shí)際作用很大。常見情況是某些增強(qiáng)腳本把物體放到了畫布外導(dǎo)致w或h超過1模型在loss計(jì)算時(shí)對這類框給出的梯度是畸形的。我見過有人因?yàn)檫@類越界標(biāo)簽訓(xùn)練了50輪loss都降不下去最后定位到是幾百個(gè)臟標(biāo)注在拖后腿。2.3 8個(gè)類別逐個(gè)拆解裝備類、違規(guī)類和機(jī)械類數(shù)據(jù)集涵蓋8個(gè)類別按語義可以分成三組安全裝備Boots、Hardhat、Safetyvest、違規(guī)行為No-Hardhat、No-mask、No-safetyvest、以及人和設(shè)備Person、Machinary。類別ID按摘要里列出的順序從0到7排列實(shí)際以壓縮包內(nèi)data.yaml的names字段為準(zhǔn)我按常見順序整理如下類別ID名稱類型業(yè)務(wù)含義0Boots裝備工地防護(hù)靴1Hardhat裝備佩戴安全帽2Machinary設(shè)備起重機(jī)等施工機(jī)械3No-Hardhat違規(guī)未佩戴安全帽4No-mask違規(guī)未佩戴口罩5No-safetyvest違規(guī)未穿反光安全背心6Person人員工地工作人員7Safetyvest裝備穿戴反光安全背心這里有兩個(gè)容易被忽略的細(xì)節(jié)。第一Machinary這個(gè)類名在數(shù)據(jù)集里就是拼寫錯(cuò)誤的正確拼寫是Machinery但訓(xùn)練時(shí)千萬別手滑改成正確拼寫因?yàn)闃?biāo)簽txt里的類別ID和data.yaml的names是一一對應(yīng)的改名字不改ID不影響改錯(cuò)位置就會(huì)錯(cuò)位。第二違規(guī)類和裝備類是成對出現(xiàn)的一個(gè)人戴了安全帽圖上會(huì)有Person和Hardhat兩個(gè)框沒戴安全帽就會(huì)有Person和No-Hardhat。這就是第4章要展開講的標(biāo)簽語義重疊問題它直接影響你在混淆矩陣?yán)锟吹降恼`檢分布。從業(yè)務(wù)視角看這個(gè)數(shù)據(jù)集對應(yīng)的就是一個(gè)智能安全巡檢系統(tǒng)識別工人有沒有戴安全帽、穿反光背心、佩戴口罩同時(shí)識別工地上的大型機(jī)械。600張圖對8個(gè)類別來說屬于中小規(guī)模數(shù)據(jù)集如果某個(gè)類別的樣本量特別稀少比如機(jī)械訓(xùn)練時(shí)就需要特殊處理這個(gè)在第4章的Machinary問題里具體展開。3. 用YOLOv8把它訓(xùn)起來目錄整理、data.yaml與訓(xùn)練命令數(shù)據(jù)集結(jié)構(gòu)盤清楚了接下來就是把它喂給YOLOv8。這里我不推薦拿著Roboflow原始目錄結(jié)構(gòu)直接用而是建議統(tǒng)一成Ultralytics官方推薦的布局images和labels兩個(gè)大目錄內(nèi)部再按train/val/test切分。這樣做的好處是后續(xù)換數(shù)據(jù)集、換模型版本時(shí)訓(xùn)練腳本和data.yaml可以完全復(fù)用。3.1 統(tǒng)一目錄結(jié)構(gòu)與data.yaml配置先建目錄、把文件歸位。這一步純粹是體力活但目錄不統(tǒng)一后續(xù)每次訓(xùn)練都要改路徑很煩。mkdir -p datasets/site_safety/images/train mkdir -p datasets/site_safety/images/val mkdir -p datasets/site_safety/images/test mkdir -p datasets/site_safety/labels/train mkdir -p datasets/site_safety/labels/val mkdir -p datasets/site_safety/labels/test cp train/images/*.jpg datasets/site_safety/images/train/ cp train/labels/*.txt datasets/site_safety/labels/train/ cp valid/images/*.jpg datasets/site_safety/images/val/ cp valid/labels/*.txt datasets/site_safety/labels/val/ cp test/images/*.jpg datasets/site_safety/images/test/ cp test/labels/*.txt datasets/site_safety/labels/test/復(fù)制完之后用前面的find | wc -l再核對一遍確保每個(gè)子集的圖片和標(biāo)簽數(shù)量一致。然后創(chuàng)建data.yaml。這里注意path字段使用相對路徑不要寫/home/xxx/這種絕對路徑否則換機(jī)器跑就得改配置。# datasets/site_safety/data.yaml path: ./datasets/site_safety train: images/train val: images/val test: images/test names: 0: Boots 1: Hardhat 2: Machinary 3: No-Hardhat 4: No-mask 5: No-safetyvest 6: Person 7: Safetyvestnames的順序必須和標(biāo)簽txt里的類別ID完全對齊這是YOLO系列訓(xùn)練框架的硬性要求錯(cuò)一位就是災(zāi)難性的類別錯(cuò)位。test字段寫上并不會(huì)影響訓(xùn)練只是在訓(xùn)練完調(diào)用val時(shí)可以指定用test子集來評估這樣得到的指標(biāo)才是模型在沒見過的數(shù)據(jù)上的真實(shí)表現(xiàn)。3.2 訓(xùn)練命令與關(guān)鍵超參img、batch、epochs怎么定600張圖、8個(gè)類別這個(gè)規(guī)模下我不建議直接用YOLOv8m或者更大的模型。常見做法是從最小的yolov8n開始用COCO預(yù)訓(xùn)練權(quán)重做遷移。COCO上訓(xùn)過的權(quán)重已經(jīng)學(xué)會(huì)了通用的邊緣、紋理和物體形狀特征遷移到工地場景能顯著緩解小數(shù)據(jù)量帶來的欠擬合問題。# 在項(xiàng)目根目錄執(zhí)行 yolo detect train \ modelyolov8n.pt \ datadatasets/site_safety/data.yaml \ epochs100 \ img640 \ batch16 \ patience20 \ projectruns/site_safety \ nameyolov8n_600img逐項(xiàng)說明參數(shù)含義。modelyolov8n.pt表示加載COCO預(yù)訓(xùn)練權(quán)重啟動(dòng)訓(xùn)練而不是隨機(jī)初始化如果不加這個(gè)參數(shù)從零訓(xùn)練600張圖的效果會(huì)差很多。epochs100對600張圖是合理范圍配合patience20早停機(jī)制如果驗(yàn)證集mAP連續(xù)20輪不漲就自動(dòng)停止避免浪費(fèi)時(shí)間。img640是訓(xùn)練分辨率也是默認(rèn)推理分辨率如果你發(fā)現(xiàn)監(jiān)控畫面里遠(yuǎn)處的人很小可以嘗試img1280效果可能有明顯提升但顯存占用和推理耗時(shí)都會(huì)上漲。batch16在8GB顯存上剛好如果顯存告急就降到8。Ultralytics默認(rèn)開啟了mosaic、hsv擾動(dòng)等數(shù)據(jù)增強(qiáng)在小數(shù)據(jù)集上默認(rèn)配置通常不用改這也是YOLOv8這類框架對小數(shù)據(jù)集友好的原因之一。我自己在600張圖規(guī)模上一般不加額外增強(qiáng)參數(shù)先跑一個(gè)baseline有問題再針對性地開增強(qiáng)。這里隱含的策略是先拿baseline暴露問題而不是一上來就堆技巧。3.3 訓(xùn)練產(chǎn)物best.pt、results.csv、confusion_matrix去哪找訓(xùn)練結(jié)束后輸出目錄下會(huì)有完整的過程記錄和控制臺(tái)輸出的匯總ls runs/site_safety/yolov8n_600img/ # weights/ best.pt last.pt # results.csv 每輪的loss、mAP、PR曲線數(shù)據(jù) # confusion_matrix.png 驗(yàn)證集混淆矩陣圖 # PR_curve.png 每個(gè)類別的PR曲線 # train_batch*.jpg 訓(xùn)練批次的增強(qiáng)可視化這里最重要的兩個(gè)文件是weights/best.pt和weights/last.pt。best.pt是驗(yàn)證集mAP最高那輪的權(quán)重后續(xù)做推理、導(dǎo)出ONNX都用它last.pt只是最后一輪的狀態(tài)通常直接用best。results.csv是判斷訓(xùn)練是否健康的關(guān)鍵依據(jù)看loss曲線是否平穩(wěn)下降、mAP50是否逐步爬升。如果loss降了但mAP不動(dòng)說明模型在死記訓(xùn)練集而沒有學(xué)到可泛化的特征這種問題在標(biāo)簽語義重疊的數(shù)據(jù)集里特別常見下一章展開說。4. 常見問題排查這份工地?cái)?shù)據(jù)集訓(xùn)練時(shí)的五個(gè)坑這一章是整篇文章里最值錢的部分。前面幾章是流程這里是我實(shí)際拆數(shù)據(jù)時(shí)踩過的坑。每一條都按“現(xiàn)象→原因→解決”來寫你在訓(xùn)練這份數(shù)據(jù)集時(shí)如果碰到類似癥狀直接對號入座。4.1 標(biāo)簽體檢漏掉圖片比預(yù)期少某個(gè)類完全學(xué)不出來現(xiàn)象訓(xùn)練日志里顯示的圖片數(shù)比426少或者某個(gè)類別在混淆矩陣?yán)镆徽卸际呛诘腁P數(shù)值在0.05以下徘徊。原因jpg和txt不同名導(dǎo)致圖片被靜默跳過。Roboflow導(dǎo)出的文件名很長里面帶哈希和rf標(biāo)記有些人用腳本批量移動(dòng)文件時(shí)按.切割文件名切出來的主體對不上造成label丟失。還有一種情況是txt里存在空文件YOLO訓(xùn)練框架讀到空標(biāo)簽會(huì)跳過該圖。解決訓(xùn)練前強(qiáng)制跑一遍2.1和2.2里的腳本把缺失標(biāo)簽的圖片和空txt文件全部列出來。缺失的看能不能從原始數(shù)據(jù)補(bǔ)補(bǔ)不了就直接刪掉對應(yīng)圖片保證訓(xùn)練集“圖標(biāo)配對”是干凈的。從那以后我每次拿到新數(shù)據(jù)集都會(huì)先做這一步幾分鐘的時(shí)間能省下后面好幾輪的排查。4.2 安全帽和人員互相誤檢Hardhat與Person嚴(yán)重混淆現(xiàn)象驗(yàn)證集上Hardhat的檢出框經(jīng)常壓在Person框上明明沒戴安全帽的人也被打上Hardhat標(biāo)簽?;煜仃?yán)颒ardhat和Person兩塊交叉位置亮度很高。原因這是標(biāo)注語義本身的問題。一個(gè)戴安全帽的工人圖片上同時(shí)有Person框和Hardhat框兩個(gè)框的中心高度重疊模型學(xué)到的特征是“凡是像人的地方大概率有安全帽”。如果訓(xùn)練數(shù)據(jù)里戴帽子的正例遠(yuǎn)多于背景反例模型就會(huì)把Person和Hardhat當(dāng)成強(qiáng)綁定關(guān)系。解決先看混淆矩陣確認(rèn)混淆程度然后再?zèng)Q定策略。輕度的可以用后處理規(guī)則修正——同一位置如果同時(shí)出現(xiàn)Hardhat和No-Hardhat按置信度取高者嚴(yán)重的可以考慮干脆把標(biāo)注合并成二分類只檢測Hardhat戴帽和No-Hardhat沒戴帽去掉Person類讓模型專注解決戴沒戴的問題。我在類似場景做過這種刪類合并因?yàn)閷さ匕踩O(jiān)控來說真正要報(bào)警的就是“有人且沒戴帽”Person類本身并沒有獨(dú)立業(yè)務(wù)價(jià)值。4.3 Machinary類持久學(xué)不出來mAP一直趨近于0現(xiàn)象loss正常下降其他類別AP都在漲只有Machinary類的AP曲線貼著0軸走混淆矩陣?yán)镞@一行幾乎全黑檢測結(jié)果偶爾把它預(yù)測成Person或背景。原因機(jī)械類樣本太少。這份數(shù)據(jù)集總共600張圖、8個(gè)類別分配到Machinary上的可能只有幾十個(gè)實(shí)例而且起重機(jī)和挖掘機(jī)在不同角度、不同距離下的外觀差異極大幾十個(gè)樣本根本覆蓋不了類內(nèi)差異。模型在有限的迭代輪次里只能記住訓(xùn)練集里那幾張圖的樣子泛化自然無從談起。解決短期內(nèi)把Machinary類別從訓(xùn)練里去掉把它對應(yīng)的框忽略掉先保住其他7個(gè)類別的精度。長期看如果你真的需要機(jī)械檢測就得單獨(dú)補(bǔ)充機(jī)械類數(shù)據(jù)哪怕補(bǔ)100張也比在這600張圖里硬扛強(qiáng)。另外注意一個(gè)操作細(xì)節(jié)刪類時(shí)標(biāo)簽txt里的其他類別ID要重新排不能留空洞否則ID對不上names。4.4 遠(yuǎn)處安全帽漏檢近處能檢遠(yuǎn)處一塌糊涂現(xiàn)象靠近攝像頭的工人檢測效果不錯(cuò)越遠(yuǎn)的畫面漏檢越嚴(yán)重。mAP50可能還行但mAP50-95低得離譜。原因640分辨率下遠(yuǎn)處一個(gè)安全帽可能只有十幾個(gè)像素寬的小目標(biāo)特征。YOLOv8n本身對小目標(biāo)不敏感加上訓(xùn)練分辨率壓到640小目標(biāo)信息在特征圖下采樣過程中被抹掉了。工地監(jiān)控的特點(diǎn)是視野寬、目標(biāo)密集這個(gè)問題幾乎一定會(huì)出現(xiàn)。解決第一步把img提到1280訓(xùn)練和推理通常小目標(biāo)AP會(huì)有肉眼可見的提升代價(jià)是顯存占用翻倍、推理速度變慢。如果后期要部署到實(shí)時(shí)監(jiān)控就用切圖推理把大圖切成512×512的塊分別檢測再合并結(jié)果。這個(gè)方案現(xiàn)在已經(jīng)很成熟推薦給有實(shí)時(shí)需求的場景。4.5 訓(xùn)練中途loss變成NaN先查臟標(biāo)簽和壞圖現(xiàn)象訓(xùn)練進(jìn)行到十幾輪loss突然變成nan之后每個(gè)epoch的loss都是nan訓(xùn)練實(shí)際上已經(jīng)失效。原因最常見的是數(shù)據(jù)集里混入了損壞圖片jpg文件不完整或者標(biāo)簽里有極端坐標(biāo)值比如w或h為0的框甚至類別ID超出names長度。這種臟數(shù)據(jù)在訓(xùn)練中被隨機(jī)采樣到導(dǎo)致loss計(jì)算出現(xiàn)除零或梯度爆炸。解決寫一個(gè)腳本遍歷所有圖片用OpenCV讀取讀不出來的標(biāo)記為損壞并剔除同時(shí)用2.2的越界檢查腳本把所有txt過濾一遍發(fā)現(xiàn)w或h為0的行直接刪掉。如果是梯度爆炸導(dǎo)致的把lr0從默認(rèn)的0.01降到0.005再試但優(yōu)先還是處理數(shù)據(jù)。5. 驗(yàn)證模型而不是相信訓(xùn)練日志val評估、PR曲線與badcase分析訓(xùn)練完看loss曲線覺得“穩(wěn)了”就收工是很多新手的習(xí)慣。但在這個(gè)數(shù)據(jù)集上訓(xùn)練loss下降只能說明模型記住了訓(xùn)練集驗(yàn)證集上的表現(xiàn)才是真正要關(guān)注的。第3章里訓(xùn)練日志最后輸出的mAP值只是訓(xùn)練過程中對驗(yàn)證集的一個(gè)快照遠(yuǎn)不夠全面。這里用測試集做獨(dú)立評估再結(jié)合badcase分析得到的是可落地判斷。5.1 用測試集評估命令與指標(biāo)取舍# 用57張測試集圖片評估而不是默認(rèn)的驗(yàn)證集 yolo detect val \ modelruns/site_safety/yolov8n_600img/weights/best.pt \ datadatasets/site_safety/data.yaml \ splittest \ conf0.25 \ iou0.5splittest是這里的要點(diǎn)。Ultralytics默認(rèn)用val目錄做評估但我們在第3章配置了test字段加上這個(gè)參數(shù)就會(huì)用那57張從未參與訓(xùn)練和驗(yàn)證的圖片來評估結(jié)果更接近部署時(shí)的真實(shí)表現(xiàn)。conf0.25是默認(rèn)置信度閾值iou0.5是NMS的IoU閾值剛開始評估就用默認(rèn)值跑出baseline再說。輸出會(huì)給出每個(gè)類別單獨(dú)的mAP50和mAP50-95這才是判斷每個(gè)類健康狀況的第一手資料。mAP50和mAP50-95的區(qū)別要明確mAP50只要求預(yù)測框和真實(shí)框交并比超過0.5就算對比較寬容mAP50-95會(huì)對從0.5到0.95的一系列IoU閾值平均要求極其嚴(yán)格。小目標(biāo)居多的數(shù)據(jù)集mAP50-95普遍偏低這不必焦慮——工地安全監(jiān)控這個(gè)場景框的位置大致準(zhǔn)就行mAP50才是主要參考指標(biāo)mAP50-95用來橫向?qū)Ρ饶P桶姹尽?.2 混淆矩陣的讀法重點(diǎn)看哪幾個(gè)位置confusion_matrix.png是一個(gè)8類背景的方陣行代表真實(shí)類別列代表預(yù)測類別對角線越亮越好。拿到圖先不急著看整體準(zhǔn)確率而是盯著三塊位置一是Hardhat行里和Person列交叉的地方亮則代表安全帽被誤檢成人員二是No-Hardhat行里和背景列交叉的地方亮則代表未戴帽違規(guī)行為被漏檢三是背景行里如果有大塊亮區(qū)說明模型在沒有任何目標(biāo)的地方畫了框這類誤檢在巡檢場景會(huì)直接觸發(fā)誤報(bào)。讀混淆矩陣還有一個(gè)技巧不要只看亮不亮要看同行的其他列是否出現(xiàn)“結(jié)構(gòu)性偏斜”。比如Person行里Hardhat列也很亮說明模型本質(zhì)上把“人”和“帽子”耦合了這就是4.2說的語義重疊問題在圖上會(huì)表現(xiàn)為戴帽和沒戴帽的檢測結(jié)果互相打架。解決方向在前面已經(jīng)說了合并類別或者加后處理規(guī)則而不是單純堆訓(xùn)練輪次。5.3 badcase可視化按置信度排序找最難樣本指標(biāo)是匯總數(shù)據(jù)badcase才是具體問題。用訓(xùn)練好的模型跑一遍測試集把預(yù)測結(jié)果可視化輸出然后人工翻圖。注意不要隨機(jī)翻按置信度排序來看。from ultralytics import YOLO model YOLO(runs/site_safety/yolov8n_600img/weights/best.pt) results model.predict( sourcedatasets/site_safety/images/test, conf0.25, saveTrue, # 把標(biāo)注了框的圖片存下來 projectruns/badcase, nametest_pred, save_txtTrue, # 同時(shí)輸出預(yù)測的txt標(biāo)注方便后續(xù)對比 )跑完之后runs/badcase/test_pred里每張圖都畫了預(yù)測框。我一般先從置信度最高的誤檢看起——高置信度還檢錯(cuò)說明模型學(xué)到了一個(gè)錯(cuò)誤模式這是最要命的然后看漏檢特別是No-Hardhat的漏檢因?yàn)檫@是工地安全監(jiān)控的核心報(bào)警項(xiàng)。corresponding的txt文件可以用來和真實(shí)標(biāo)注做IoU對比IoU低的那批圖就是你需要針對性補(bǔ)數(shù)據(jù)的樣本或者需要調(diào)整后處理邏輯的樣本。6. 進(jìn)階部署到工地實(shí)時(shí)監(jiān)控前先做這兩個(gè)動(dòng)作訓(xùn)練好的模型要真正放到工地監(jiān)控里光有best.pt是不夠的。工地現(xiàn)場跑的一般是邊緣計(jì)算盒子或者帶GPU的NVR設(shè)備PyTorch直接推理在性能和部署友好度上都不過關(guān)。第一步先把模型導(dǎo)成ONNX格式。yolo export modelruns/site_safety/yolov8n_600img/weights/best.pt \ formatonnx \ opset12 \ imgsz640導(dǎo)出后得到一個(gè)best.onnx用ONNX Runtime或者OpenVINO都能直接跑。opset12是兼容性比較好的版本老設(shè)備也能識別。導(dǎo)出前可以先跑一遍val對比ONNX和PyTorch的mAP因?yàn)榱炕騩pset轉(zhuǎn)換偶爾會(huì)帶來精度損失如果掉了超過1個(gè)點(diǎn)就要檢查哪層出了問題。第二個(gè)動(dòng)作是設(shè)計(jì)報(bào)警后處理規(guī)則這是工地場景區(qū)別于通用目標(biāo)檢測的地方。監(jiān)控視頻每秒25幀不可能每幀都報(bào)警否則誤報(bào)會(huì)淹沒真實(shí)違規(guī)。常見做法是幀采樣加持續(xù)確認(rèn)每5秒取一幀做檢測檢測結(jié)果不直接觸發(fā)報(bào)警而是送入一個(gè)計(jì)數(shù)器連續(xù)N幀確認(rèn)存在違規(guī)才推送告警。# 偽代碼安全帽違規(guī)報(bào)警邏輯 frame_count 0 warn_count 0 while True: frame capture_next_frame() # 每5秒抽一幀 dets model(frame) # 目標(biāo)檢測 hardhat_off [d for d in dets if d.cls 3] # No-Hardhat persons [d for d in dets if d.cls 6] # Person # 核心規(guī)則違規(guī)框和人員框位置匹配才算數(shù) for h in hardhat_off: if has_overlap(h, persons, iou_thresh0.3): warn_count 1 break if warn_count 3: # 連續(xù)3次抽查都發(fā)現(xiàn)違規(guī) send_alert(工人未佩戴安全帽) warn_count 0 if frame_count 10: # 一段時(shí)間后重置計(jì)數(shù)避免重復(fù)報(bào)警 warn_count 0這段偽代碼里最值得注意是has_overlap這一步。前面花了很長的篇幅說Hardhat和Person標(biāo)簽語義高度重疊那么在推理階段No-Hardhat框如果沒有和Person框重疊大概率是誤檢不應(yīng)該進(jìn)入報(bào)警計(jì)數(shù)。另外No-Hardhat和Hardhat同時(shí)出現(xiàn)在同一位置時(shí)按置信度取高者這個(gè)規(guī)則能過濾掉相當(dāng)一部分模型自身的不穩(wěn)定輸出。工地安全監(jiān)控這個(gè)場景模型的mAP只要夠用就行真正決定產(chǎn)品體驗(yàn)的是后處理規(guī)則能不能把誤報(bào)率壓下去。從那以后我每次拿到一個(gè)新的目標(biāo)檢測數(shù)據(jù)集都會(huì)強(qiáng)制先跑一遍標(biāo)簽體檢腳本把越界坐標(biāo)、缺失標(biāo)簽、類別分布打印出來貼到項(xiàng)目文檔里。這個(gè)習(xí)慣救過我很多次希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取