輛檢測(cè)數(shù)據(jù)集:5類(lèi)YOLOV5格式,開(kāi)箱即訓(xùn))
簡(jiǎn)介這份資源面向從事目標(biāo)檢測(cè)算法學(xué)習(xí)與工程落地的開(kāi)發(fā)者提供霧天場(chǎng)景下的行人、車(chē)輛檢測(cè)數(shù)據(jù)集可直接用于YOLOv5訓(xùn)練省去自行采集與標(biāo)注的成本。數(shù)據(jù)按YOLOv5目錄規(guī)范組織圖像為400至1000分辨率的RGB圖片覆蓋霧天馬路上的常見(jiàn)車(chē)輛與人群共劃分人、轎車(chē)、公交車(chē)、自行車(chē)、摩托車(chē)5個(gè)類(lèi)別。包內(nèi)共2000個(gè)文件以1999個(gè)txt標(biāo)注文件與1個(gè)Python可視化腳本為主壓縮包約123.5MB其中訓(xùn)練集含4320張圖片及對(duì)應(yīng)標(biāo)簽驗(yàn)證集含100張圖片及對(duì)應(yīng)標(biāo)簽并附類(lèi)別說(shuō)明文本。資源還提供show.py腳本隨機(jī)傳入一張圖片即可繪制邊界框并保存到當(dāng)前目錄無(wú)需修改即可運(yùn)行便于快速核驗(yàn)標(biāo)注質(zhì)量。目前已有405人學(xué)習(xí)下載適合需要霧天檢測(cè)數(shù)據(jù)、想驗(yàn)證模型魯棒性或開(kāi)展相關(guān)課程實(shí)驗(yàn)的讀者參考使用。1. 霧天行人車(chē)輛檢測(cè)數(shù)據(jù)集5 類(lèi)標(biāo)注、YOLOV5 目錄格式拿到就能開(kāi)訓(xùn)霧天場(chǎng)景的目標(biāo)檢測(cè)是自動(dòng)駕駛和路側(cè)感知里最容易被低估的一類(lèi)臟活。晴天數(shù)據(jù)上 mAP 跑到 0.9 的模型一進(jìn)霧天就集體翻車(chē)行人只剩個(gè)模糊輪廓車(chē)輛尾燈糊成一團(tuán)光斑模型要么漏檢要么把霧團(tuán)當(dāng)目標(biāo)。這個(gè)數(shù)據(jù)集要解決的就是這件事它是一份按 YOLOV5 目錄格式組織、面向霧天場(chǎng)景的行人與車(chē)輛目標(biāo)檢測(cè)數(shù)據(jù)集共 5 個(gè)類(lèi)別標(biāo)注文件是 YOLO 的 txt 格式配好 data.yaml 就能直接喂給 YOLOV5 開(kāi)訓(xùn)。適合三類(lèi)人想驗(yàn)證霧天魯棒性的算法工程師、做自動(dòng)駕駛或智慧交通感知的從業(yè)者、以及想拿一份真實(shí)臟數(shù)據(jù)練手 YOLOV5 訓(xùn)練自己數(shù)據(jù)集流程的新手。它不解決霧的物理建模只解決「有標(biāo)注、能開(kāi)訓(xùn)、能復(fù)現(xiàn)」這一步。2. 先搞清楚這份數(shù)據(jù)集的結(jié)構(gòu)與 5 類(lèi)標(biāo)簽怎么定拿到一份數(shù)據(jù)集第一件事不是急著 train.py而是把目錄結(jié)構(gòu)和標(biāo)簽體系摸清楚。YOLOV5 對(duì)目錄格式有硬性約定標(biāo)簽類(lèi)別順序又直接決定訓(xùn)練出來(lái)的模型認(rèn)不認(rèn)人這兩件事搞錯(cuò)后面全是無(wú)用功。2.1 YOLOV5 目錄格式到底長(zhǎng)什么樣YOLOV5 官方推薦的目錄結(jié)構(gòu)是 images 和 labels 平行放置train/val 各自成對(duì)。常見(jiàn)做法是這樣dataset/ ├── images/ │ ├── train/ # 訓(xùn)練集圖片jpg/png │ │ ├── fog_0001.jpg │ │ └── ... │ └── val/ # 驗(yàn)證集圖片 │ ├── fog_0201.jpg │ └── ... ├── labels/ │ ├── train/ # 與 images/train 同名的 txt │ │ ├── fog_0001.txt │ │ └── ... │ └── val/ │ ├── fog_0201.txt │ └── ... └── data.yaml # 數(shù)據(jù)集描述文件關(guān)鍵約束有三條第一images/train/fog_0001.jpg必須對(duì)應(yīng)labels/train/fog_0001.txt文件名不含擴(kuò)展名嚴(yán)格一致差一個(gè)字符 YOLOV5 就找不到標(biāo)簽訓(xùn)練時(shí)會(huì)把這張圖當(dāng)負(fù)樣本白白污染梯度。第二labels 目錄下不能混入classes.txt、train.cache之外的多余文件YOLOV5 掃描時(shí)會(huì)嘗試解析所有 txt。第三圖片和標(biāo)簽分開(kāi)放不要圖省事把 txt 和 jpg 塞同一個(gè)文件夾YOLOV5 的 dataloader 默認(rèn)按平行目錄找。提示如果數(shù)據(jù)集原始是 VOC 的 xml 或 COCO 的 json先轉(zhuǎn)成 YOLO txt 再按上面結(jié)構(gòu)擺放轉(zhuǎn)換腳本見(jiàn) 2.3。2.2 5 個(gè)類(lèi)別怎么排、data.yaml 怎么寫(xiě)這份數(shù)據(jù)集是 5 類(lèi)別通常覆蓋霧天道路場(chǎng)景里的核心目標(biāo)比如 person、car、bus、truck、motorcycle 這類(lèi)組合具體類(lèi)別名以數(shù)據(jù)集自帶的 classes 說(shuō)明為準(zhǔn)不要憑感覺(jué)改。類(lèi)別順序就是標(biāo)簽文件里數(shù)字的含義txt 每行是class_id x_center y_center width height其中 class_id 從 0 開(kāi)始對(duì)應(yīng) data.yaml 里 names 列表的下標(biāo)。data.yaml 是訓(xùn)練入口寫(xiě)錯(cuò)一個(gè)字段訓(xùn)練直接報(bào)錯(cuò)# data.yaml path: ./dataset # 數(shù)據(jù)集根目錄 train: images/train # 相對(duì) path 的訓(xùn)練圖片路徑 val: images/val # 相對(duì) path 的驗(yàn)證圖片路徑 nc: 5 # 類(lèi)別數(shù)必須和 names 長(zhǎng)度一致 names: # 順序即 class_id0 開(kāi)始 0: person 1: car 2: bus 3: truck 4: motorcyclenc和names長(zhǎng)度不一致是最常見(jiàn)的低級(jí)錯(cuò)誤YOLOV5 會(huì)在構(gòu)建模型頭時(shí)報(bào)維度不匹配。path用相對(duì)路徑時(shí)是相對(duì)于你執(zhí)行 train.py 的工作目錄不是相對(duì)于 data.yaml 所在目錄這點(diǎn)很多人栽過(guò)。穩(wěn)妥做法是寫(xiě)絕對(duì)路徑或者訓(xùn)練前cd到項(xiàng)目根目錄。2.3 從 VOC/COCO 轉(zhuǎn)成 YOLO txt 的轉(zhuǎn)換腳本如果拿到的原始標(biāo)注不是 YOLO 格式得先轉(zhuǎn)。VOC 的 xml 轉(zhuǎn) YOLO txt 是最常見(jiàn)的一步核心是把絕對(duì)坐標(biāo)的 xmin/ymin/xmax/ymax 歸一化成中心點(diǎn)加寬高import os import xml.etree.ElementTree as ET # 類(lèi)別名到 id 的映射順序必須和 data.yaml 的 names 一致 CLASS_MAP {person: 0, car: 1, bus: 2, truck: 3, motorcycle: 4} def voc_to_yolo(xml_path, out_txt, img_w, img_h): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.iter(object): name obj.find(name).text if name not in CLASS_MAP: continue # 跳過(guò)不在 5 類(lèi)里的目標(biāo)避免類(lèi)別越界 cls_id CLASS_MAP[name] bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 歸一化到 0-1YOLO 要求中心點(diǎn) 寬高 x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h # 裁剪到 [0,1]防止標(biāo)注越界導(dǎo)致訓(xùn)練報(bào)錯(cuò) x_center min(max(x_center, 0.0), 1.0) y_center min(max(y_center, 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} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(out_txt, w) as f: f.write(\n.join(lines))邏輯說(shuō)明遍歷 xml 里每個(gè) object按 CLASS_MAP 映射類(lèi)別把絕對(duì)像素坐標(biāo)轉(zhuǎn)成歸一化中心點(diǎn)格式。參數(shù)上img_w、img_h必須傳原圖真實(shí)尺寸不能傳網(wǎng)絡(luò)輸入尺寸比如 640否則坐標(biāo)全錯(cuò)。:.6f保留 6 位小數(shù)是 YOLO 慣例精度足夠。裁剪到 [0,1] 是后悔藥?kù)F天標(biāo)注里偶爾有框超出圖像邊界的臟數(shù)據(jù)不裁 YOLOV5 會(huì)直接拋異常中斷訓(xùn)練。轉(zhuǎn)換完記得抽查幾張用可視化腳本把框畫(huà)回圖上確認(rèn)沒(méi)偏。3. 用 YOLOV5 在霧天數(shù)據(jù)上跑通訓(xùn)練命令、超參與顯存結(jié)構(gòu)摸清后進(jìn)入訓(xùn)練。這一章給的是能直接抄的命令和參數(shù)重點(diǎn)講清楚每個(gè)參數(shù)為什么這么設(shè)以及霧天數(shù)據(jù)相比晴天數(shù)據(jù)要額外注意什么。3.1 環(huán)境配置與最小訓(xùn)練命令環(huán)境用 conda 隔離最省心YOLOV5 對(duì) torch 版本敏感別用系統(tǒng) Python 硬裝conda create -n yolov5_fog python3.9 -y conda activate yolov5_fog git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt裝完先跑一次自檢確認(rèn) torch 能識(shí)別 GPUpython -c import torch; print(torch.__version__, torch.cuda.is_available())輸出里True才說(shuō)明 CUDA 可用。然后是最小訓(xùn)練命令python train.py \ --data ./dataset/data.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --name fog_exp1--weights yolov5s.pt用預(yù)訓(xùn)練權(quán)重霧天數(shù)據(jù)量通常不大從頭訓(xùn)容易過(guò)擬合遷移學(xué)習(xí)是標(biāo)配。--img 640是 YOLOV5 默認(rèn)輸入尺寸霧天小目標(biāo)多的話可以提到 960但顯存翻倍。--batch 16是 8G 顯存的安全值顯存不夠就降到 8 或 4YOLOV5 會(huì)自動(dòng)做梯度累積補(bǔ)償。--name決定結(jié)果存到runs/train/fog_exp1。3.2 霧天場(chǎng)景必調(diào)的 4 個(gè)超參數(shù)YOLOV5 的超參數(shù)在data/hyp.scratch.yaml里霧天數(shù)據(jù)有幾個(gè)參數(shù)值得單獨(dú)調(diào)參數(shù)默認(rèn)值霧天建議原因hsv_v0.40.6霧天亮度變化大增強(qiáng)亮度擾動(dòng)提升魯棒性hsv_s0.70.5霧天色彩飽和度低過(guò)強(qiáng)飽和度增強(qiáng)反而失真mosaic1.01.0保留mosaic 拼接能模擬不同霧濃度疊加fl_gamma0.00.5開(kāi)啟 Focal Loss緩解霧天難樣本的類(lèi)別不平衡改法是在訓(xùn)練命令里加--hyp data/hyp.fog.yaml把默認(rèn)文件復(fù)制一份改。hsv_v提到 0.6 是血淚經(jīng)驗(yàn)霧天圖像整體偏灰模型容易學(xué)到「灰背景」的捷徑加大亮度擾動(dòng)逼它關(guān)注形狀而非亮度。fl_gamma設(shè) 0.5 是因?yàn)殪F天里被遮擋的行人是難樣本Focal Loss 能壓低易樣本權(quán)重讓梯度集中在這些目標(biāo)上。3.3 訓(xùn)練日志怎么看、顯存不夠怎么辦訓(xùn)練啟動(dòng)后重點(diǎn)盯三行train/box_loss、val/box_loss、metrics/mAP_0.5。正常情況 box_loss 持續(xù)下降mAP 上升。如果 train loss 降但 val loss 漲是過(guò)擬合加數(shù)據(jù)增強(qiáng)或減 epoch。如果兩個(gè) loss 都不動(dòng)檢查 data.yaml 路徑和標(biāo)簽是否為空。顯存不夠的排查順序先降--batch再降--img最后換yolov5n小模型。別一上來(lái)就--device cpuCPU 訓(xùn) YOLOV5 慢到懷疑人生。用nvidia-smi看顯存占用如果 batch 16 時(shí)占用 7.8G 還頻繁 OOM說(shuō)明是碎片問(wèn)題加--workers 4減少 dataloader 進(jìn)程數(shù)有時(shí)反而更穩(wěn)。注意霧天數(shù)據(jù)集如果圖片分辨率很高比如 1920x1080--img 640會(huì)把小目標(biāo)縮沒(méi)行人可能只剩幾個(gè)像素。這種情況要么提高 img 尺寸要么先切圖再訓(xùn)。4. 霧天檢測(cè)的避坑清單5 個(gè)真實(shí)翻車(chē)現(xiàn)場(chǎng)這一章全是踩過(guò)的坑每條按現(xiàn)象、原因、解決寫(xiě)。霧天數(shù)據(jù)集的坑和普通數(shù)據(jù)集不太一樣很多是標(biāo)注質(zhì)量和場(chǎng)景特性帶來(lái)的。4.1 現(xiàn)象mAP 虛高但實(shí)際漏檢嚴(yán)重原因驗(yàn)證集和訓(xùn)練集來(lái)自同一段連續(xù)視頻相鄰幀高度相似模型記住了背景而非目標(biāo)。霧天場(chǎng)景尤其明顯因?yàn)殪F的分布在同一段視頻里幾乎不變模型學(xué)到「這片霧這個(gè)位置有車(chē)」。解決按視頻源或時(shí)間段劃分 train/val不要隨機(jī)按幀劃分。如果數(shù)據(jù)集已經(jīng)分好檢查 val 里有沒(méi)有和 train 幾乎一樣的圖用感知哈希去重。4.2 現(xiàn)象訓(xùn)練中途報(bào) Label class X exceeds nc原因標(biāo)簽文件里的 class_id 大于等于 nc。常見(jiàn)于轉(zhuǎn)換腳本類(lèi)別映射寫(xiě)錯(cuò)或者數(shù)據(jù)集混入了其他來(lái)源的標(biāo)注。解決寫(xiě)個(gè)腳本掃一遍所有 txt統(tǒng)計(jì)出現(xiàn)的 class_id 最大值cat labels/train/*.txt | awk {print $1} | sort -n | uniq -c輸出里最大 id 必須小于 nc。超了就回去查轉(zhuǎn)換腳本的 CLASS_MAP。4.3 現(xiàn)象霧天行人框大量重疊NMS 后只剩一個(gè)原因霧天能見(jiàn)度低行人密集時(shí)標(biāo)注框互相重疊默認(rèn) NMS 的 iou_thres 0.45 會(huì)把相鄰行人誤刪。解決推理時(shí)把--iou-thres提到 0.6或者訓(xùn)練時(shí)用--agnostic-nms關(guān)閉類(lèi)別間 NMS。代價(jià)是可能引入少量重復(fù)框需要按場(chǎng)景權(quán)衡。4.4 現(xiàn)象模型把霧團(tuán)、路燈當(dāng)車(chē)輛原因霧天里遠(yuǎn)處車(chē)燈形成的光暈和霧團(tuán)形狀類(lèi)似車(chē)輛標(biāo)注時(shí)如果沒(méi)區(qū)分模型會(huì)學(xué)到錯(cuò)誤特征。解決檢查標(biāo)注把純光暈、無(wú)車(chē)身輪廓的區(qū)域標(biāo)成背景不標(biāo)。訓(xùn)練時(shí)加--rect矩形推理減少 padding 干擾同時(shí)提高h(yuǎn)sv_v讓模型不依賴(lài)亮度。4.5 現(xiàn)象驗(yàn)證集 mAP 波動(dòng)大每次跑結(jié)果差很多原因霧天數(shù)據(jù)集通常偏小驗(yàn)證集樣本少單次評(píng)估方差大。加上 YOLOV5 默認(rèn)開(kāi)啟 mosaic每個(gè) epoch 看到的樣本組合不同。解決跑 3 次取平均或者把--seed固定。評(píng)估時(shí)用--augment開(kāi)啟 TTA能穩(wěn)定 mAP 約 1-2 個(gè)點(diǎn)。數(shù)據(jù)集小于 2000 張時(shí)別太信單次 mAP看 loss 曲線更靠譜。5. 進(jìn)階霧天數(shù)據(jù)增強(qiáng)與模型驗(yàn)證的實(shí)操技巧訓(xùn)練跑通只是起點(diǎn)霧天檢測(cè)真正的難點(diǎn)在于讓模型對(duì)霧濃度變化魯棒。這一章給兩個(gè)具體技巧合成霧增強(qiáng)和分濃度驗(yàn)證。合成霧增強(qiáng)是最劃算的手段。用大氣散射模型給晴天圖加霧能低成本擴(kuò)充數(shù)據(jù)。核心是透射率和大氣光兩個(gè)參數(shù)import cv2 import numpy as np def add_fog(img, beta0.8, A0.9): # beta 霧濃度越大越濃A 大氣光值0-1 h, w img.shape[:2] # 生成深度圖這里用簡(jiǎn)單徑向梯度模擬遠(yuǎn)處?kù)F更濃 depth np.linspace(0.3, 1.0, h).reshape(-1, 1) depth np.repeat(depth, w, axis1) t np.exp(-beta * depth) # 透射率 t np.clip(t, 0.1, 1.0) # 防止除零 foggy img * t[..., None] A * 255 * (1 - t[..., None]) return np.clip(foggy, 0, 255).astype(np.uint8)beta控制霧濃度0.5 是薄霧1.2 是濃霧建議按 0.5/0.8/1.2 三檔生成讓模型見(jiàn)到不同濃度。A是大氣光通常 0.8-0.95太高會(huì)過(guò)曝。這個(gè)函數(shù)只做演示真實(shí)場(chǎng)景深度圖應(yīng)該用單目深度估計(jì)網(wǎng)絡(luò)生成效果更自然。生成后把新圖和對(duì)應(yīng)標(biāo)簽一起放進(jìn)訓(xùn)練集標(biāo)簽不用改因?yàn)殪F不影響目標(biāo)位置。分濃度驗(yàn)證是檢驗(yàn)魯棒性的關(guān)鍵。把驗(yàn)證集按霧濃度分成薄、中、濃三組分別跑val.pypython val.py --data ./dataset/data.yaml --weights runs/train/fog_exp1/weights/best.pt --img 640 --task val如果薄霧 mAP 0.85、濃霧只有 0.5說(shuō)明模型對(duì)濃霧泛化差回去補(bǔ)濃霧訓(xùn)練樣本。我一般會(huì)畫(huà)一張 mAP-霧濃度曲線比單個(gè) mAP 數(shù)字有說(shuō)服力得多。最后一個(gè)習(xí)慣每次改完超參或增強(qiáng)策略先跑 10 個(gè) epoch 看趨勢(shì)別一上來(lái)就 300 epoch。霧天數(shù)據(jù)小10 epoch 足夠看出方向?qū)Σ粚?duì)省下的時(shí)間夠你多試三組參數(shù)。這套流程我踩了太多坑才理順希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取