數(shù)據(jù)集實(shí)戰(zhàn):從數(shù)據(jù)標(biāo)注到模型訓(xùn)練與部署)
簡(jiǎn)介這份資源是面向計(jì)算機(jī)視覺初學(xué)者與目標(biāo)檢測(cè)實(shí)踐者的抽煙行為檢測(cè)數(shù)據(jù)集可直接用于YOLO系列模型的訓(xùn)練、驗(yàn)證與課程設(shè)計(jì)、畢業(yè)設(shè)計(jì)等場(chǎng)景幫助解決抽煙場(chǎng)景下樣本獲取難、標(biāo)注成本高的問(wèn)題。壓縮包共收錄594個(gè)文件以297個(gè)jpg圖像與297個(gè)xml標(biāo)注文件一一對(duì)應(yīng)xml采用Pascal VOC格式記錄目標(biāo)類別與邊界框坐標(biāo)便于轉(zhuǎn)換為YOLO所需的txt標(biāo)簽整體約59.11MB體量適中適合本地快速加載與迭代實(shí)驗(yàn)。目前已有376人學(xué)習(xí)下載具備一定的參考熱度。讀者可借助該數(shù)據(jù)集完成數(shù)據(jù)清洗、格式轉(zhuǎn)換、模型訓(xùn)練與指標(biāo)評(píng)估的完整流程也可用于對(duì)比不同YOLO版本在抽煙檢測(cè)任務(wù)上的精度與速度表現(xiàn)或作為數(shù)據(jù)增強(qiáng)、類別平衡等策略的驗(yàn)證素材為后續(xù)落地應(yīng)用積累可復(fù)用的實(shí)驗(yàn)基礎(chǔ)。1. 從一次工地巡檢的翻車說(shuō)起這套 YOLO 抽煙檢測(cè)數(shù)據(jù)集到底能干什么去年幫一個(gè)做智慧工地安全巡檢的朋友看模型他訓(xùn)練出來(lái)的抽煙檢測(cè)模型在測(cè)試集上 mAP 能到 0.85結(jié)果拉到現(xiàn)場(chǎng)攝像頭一跑工人蹲在角落抽煙十次能漏掉七次。翻了他的訓(xùn)練集才發(fā)現(xiàn)問(wèn)題——網(wǎng)上東拼西湊的兩百來(lái)張圖全是正臉、白天、近距離的擺拍連一張逆光、遮擋、遠(yuǎn)景的樣本都沒有。這就是目標(biāo)檢測(cè)里最典型的血淚經(jīng)驗(yàn)?zāi)P偷纳舷迯膩?lái)不是網(wǎng)絡(luò)結(jié)構(gòu)決定的而是數(shù)據(jù)集決定的。這份 YOLO 抽煙目標(biāo)檢測(cè)數(shù)據(jù)集解決的正是這個(gè)痛點(diǎn)。它是一套已經(jīng)標(biāo)注好的抽煙行為檢測(cè)數(shù)據(jù)包含原始圖片和對(duì)應(yīng)的標(biāo)定文件可以直接喂給 YOLO 系列模型做訓(xùn)練。適合誰(shuí)用一是做工地、加油站、化工廠、森林防火這類禁煙場(chǎng)景視覺監(jiān)控的開發(fā)者二是想拿一個(gè)真實(shí)二分類抽煙/非抽煙目標(biāo)檢測(cè)任務(wù)練手的學(xué)生和算法工程師三是需要快速驗(yàn)證自己檢測(cè) pipeline 能不能跑通的團(tuán)隊(duì)。你不用再?gòu)牧闩缊D、清洗、標(biāo)注省下的時(shí)間夠你把模型結(jié)構(gòu)調(diào)三輪。2. 數(shù)據(jù)集結(jié)構(gòu)與標(biāo)注格式先搞清楚你拿到的是什么2.1 目錄組織與文件構(gòu)成這類目標(biāo)檢測(cè)數(shù)據(jù)集常見做法是按訓(xùn)練集、驗(yàn)證集、測(cè)試集切分每個(gè)子集下再分 images 和 labels 兩個(gè)目錄。圖片是 jpg 或 png標(biāo)注文件是 YOLO 格式的 txt和圖片同名一一對(duì)應(yīng)。一個(gè)典型的目錄長(zhǎng)這樣smoking_dataset/ ├── images/ │ ├── train/ # 訓(xùn)練集圖片 │ │ ├── 000001.jpg │ │ └── ... │ ├── val/ # 驗(yàn)證集圖片 │ └── test/ # 測(cè)試集圖片 ├── labels/ │ ├── train/ # 訓(xùn)練集標(biāo)注與圖片同名 │ │ ├── 000001.txt │ │ └── ... │ ├── val/ │ └── test/ ├── data.yaml # 數(shù)據(jù)集配置文件 └── README.md # 類別說(shuō)明與來(lái)源備注這里有個(gè)容易翻車的點(diǎn)images 和 labels 的目錄層級(jí)必須嚴(yán)格鏡像對(duì)應(yīng)YOLO 訓(xùn)練時(shí)是靠路徑替換去找標(biāo)簽的。如果你把 labels 平鋪在一個(gè)目錄里訓(xùn)練腳本會(huì)直接報(bào)找不到標(biāo)簽文件。我一般會(huì)在拿到數(shù)據(jù)集后先跑一遍校驗(yàn)?zāi)_本確認(rèn)每張圖都有對(duì)應(yīng)的 txt。2.2 YOLO 標(biāo)注格式逐字段拆解YOLO 的標(biāo)注格式是每行一個(gè)目標(biāo)格式為class_id x_center y_center width height后四個(gè)值都是歸一化到 0~1 的相對(duì)坐標(biāo)。看一個(gè)真實(shí)標(biāo)注文件的內(nèi)容0 0.5234 0.4120 0.0812 0.1650 0 0.7891 0.3345 0.0640 0.1420逐字段說(shuō)明第一個(gè)0是類別 id。抽煙檢測(cè)通常是單類別任務(wù)只有 smoking 一類所以 id 恒為 0如果你的數(shù)據(jù)集還標(biāo)了 cigarette、hand 等子類id 會(huì)依次遞增。x_center y_center是標(biāo)注框中心點(diǎn)相對(duì)整圖寬高的比例不是像素值。比如 0.5234 表示中心點(diǎn)在圖片寬度 52.34% 的位置。width height是框的寬高相對(duì)整圖的比例。0.0812 表示框?qū)捳颊麍D寬度的 8.12%。注意歸一化坐標(biāo)是相對(duì)整張圖算的不是相對(duì)某個(gè)裁剪區(qū)域。如果你在預(yù)處理時(shí)做了 resize 卻沒同步換算標(biāo)注框會(huì)整體偏移這是新手最常見的翻車點(diǎn)之一。2.3 data.yaml 配置怎么寫YOLOv5/v8 系列都靠一個(gè) yaml 文件告訴訓(xùn)練器去哪找數(shù)據(jù)、有幾個(gè)類別。這份數(shù)據(jù)集對(duì)應(yīng)的配置大概是這樣# 數(shù)據(jù)集根路徑訓(xùn)練時(shí)會(huì)被覆蓋為實(shí)際路徑 path: ./smoking_dataset train: images/train # 相對(duì) path 的訓(xùn)練集圖片目錄 val: images/val # 驗(yàn)證集圖片目錄 test: images/test # 測(cè)試集圖片目錄 # 類別定義 nc: 1 # number of classes類別數(shù) names: [smoking] # 類別名稱列表順序必須和標(biāo)注里的 id 對(duì)應(yīng)參數(shù)說(shuō)明nc必須和 names 的長(zhǎng)度一致寫錯(cuò)了訓(xùn)練能啟動(dòng)但類別會(huì)錯(cuò)亂names的順序決定了 id 0 對(duì)應(yīng)哪個(gè)類如果你后續(xù)要加打電話未戴安全帽等類別直接在這里追加并保證標(biāo)注 id 同步即可。path建議用絕對(duì)路徑或訓(xùn)練時(shí)用命令行參數(shù)覆蓋避免換機(jī)器后路徑失效。3. 環(huán)境搭建與訓(xùn)練跑通從零到第一個(gè)權(quán)重文件3.1 環(huán)境依賴與安裝這套數(shù)據(jù)集適配主流的 YOLO 實(shí)現(xiàn)我以 YOLOv8 為例走一遍。先建虛擬環(huán)境別在系統(tǒng) Python 里直接裝依賴沖突是玄學(xué)問(wèn)題的重災(zāi)區(qū)。# 創(chuàng)建并激活虛擬環(huán)境 conda create -n smoking python3.10 -y conda activate smoking # 安裝 ultralyticsYOLOv8 官方庫(kù)自帶訓(xùn)練/推理/導(dǎo)出 pip install ultralytics # 驗(yàn)證安裝能打印版本號(hào)就說(shuō)明環(huán)境通了 yolo version如果你用的是 YOLOv5把 ultralytics 換成克隆官方倉(cāng)庫(kù)再pip install -r requirements.txt即可數(shù)據(jù)集格式兩者通用不用改標(biāo)注。GPU 環(huán)境記得確認(rèn) CUDA 和 PyTorch 版本匹配torch.cuda.is_available()返回 False 的話訓(xùn)練會(huì)默默跑在 CPU 上一個(gè) epoch 能等到你懷疑人生。3.2 啟動(dòng)訓(xùn)練與關(guān)鍵參數(shù)環(huán)境通了就可以起訓(xùn)練。一條命令搞定yolo detect train \ data./smoking_dataset/data.yaml \ # 數(shù)據(jù)集配置 modelyolov8n.pt \ # 預(yù)訓(xùn)練權(quán)重n 是最小模型 epochs100 \ # 訓(xùn)練輪數(shù) imgsz640 \ # 輸入分辨率 batch16 \ # 批大小顯存不夠就調(diào)小 device0 \ # 用第 0 號(hào) GPUCPU 填 cpu projectruns/train \ # 結(jié)果保存目錄 namesmoking_v1 # 本次實(shí)驗(yàn)名參數(shù)怎么調(diào)model從 yolov8n 到 yolov8x 精度遞增、速度遞減工地邊緣設(shè)備部署一般選 n 或 simgsz要和你的實(shí)際推理分辨率接近訓(xùn)練 640 推理 1280 會(huì)掉點(diǎn)batch爆顯存就減半別硬撐。訓(xùn)練過(guò)程中重點(diǎn)盯三個(gè)指標(biāo)box_loss 是否穩(wěn)定下降、mAP50 是否在漲、驗(yàn)證集 loss 有沒有反彈。如果訓(xùn)練 loss 一直降但驗(yàn)證 mAP 卡住不動(dòng)八成是過(guò)擬合或者數(shù)據(jù)分布太單一。3.3 用訓(xùn)練好的權(quán)重做推理訓(xùn)練完權(quán)重默認(rèn)存在runs/train/smoking_v1/weights/best.pt。拿它跑一張圖或一段視頻from ultralytics import YOLO # 加載訓(xùn)練好的權(quán)重 model YOLO(runs/train/smoking_v1/weights/best.pt) # 對(duì)單張圖片推理conf 是置信度閾值 results model.predict( sourcetest.jpg, conf0.4, # 低于 0.4 的框直接丟棄 iou0.5, # NMS 的 IoU 閾值控制重疊框合并 saveTrue # 保存帶框的可視化結(jié)果 ) # 打印檢測(cè)到的目標(biāo)數(shù)量和坐標(biāo) for box in results[0].boxes: print(box.cls, box.conf, box.xyxy)邏輯說(shuō)明conf調(diào)低召回高但誤報(bào)多調(diào)高則相反工地場(chǎng)景一般 0.35~0.5 之間找平衡iou控制非極大值抑制同一根煙被重復(fù)框出多個(gè)時(shí)調(diào)低它。box.xyxy是左上右下像素坐標(biāo)直接可以喂給后續(xù)的業(yè)務(wù)邏輯比如觸發(fā)告警、截圖存檔。4. 避坑與常見問(wèn)題排查這些坑我替你踩過(guò)了4.1 訓(xùn)練 loss 不降或直接 NaN現(xiàn)象啟動(dòng)訓(xùn)練后 box_loss 一直是 nan或者幾個(gè) epoch 紋絲不動(dòng)。原因通常是標(biāo)注文件里有非法值——坐標(biāo)超出 0~1 范圍、某行字段數(shù)不對(duì)、或者存在空文件。解決寫個(gè)校驗(yàn)?zāi)_本遍歷所有 txt檢查每行是否恰好 5 個(gè)字段、后四個(gè)值是否都在 [0,1] 內(nèi)把異常文件挑出來(lái)修掉或剔除。我一般會(huì)在訓(xùn)練前強(qiáng)制跑一遍這個(gè)檢查省得白等一晚上。4.2 模型只認(rèn)正臉、側(cè)臉和遮擋全漏現(xiàn)象測(cè)試集指標(biāo)漂亮實(shí)際場(chǎng)景一塌糊涂。原因就是數(shù)據(jù)集多樣性不足樣本集中在某幾種姿態(tài)和光照下。解決先統(tǒng)計(jì)一下數(shù)據(jù)集的寬高比分布、亮度分布看看是不是嚴(yán)重偏斜然后針對(duì)性補(bǔ)充逆光、夜間、遠(yuǎn)景、遮擋的樣本。如果原始數(shù)據(jù)實(shí)在補(bǔ)不了用 mosaic、mixup 這類增強(qiáng)手段能緩解一部分但治標(biāo)不治本。4.3 圖片和標(biāo)簽對(duì)不上號(hào)現(xiàn)象訓(xùn)練報(bào)No labels found或者大量圖片被跳過(guò)。原因images 和 labels 目錄結(jié)構(gòu)沒鏡像或者文件名大小寫、擴(kuò)展名不一致比如圖是 .JPG 標(biāo)簽是 .txt 但前綴大小寫不同。解決用腳本按文件名去擴(kuò)展名做交集比對(duì)找出只有圖沒標(biāo)簽、或只有標(biāo)簽沒圖的情況統(tǒng)一命名規(guī)范。4.4 顯存爆了但 batch 已經(jīng)調(diào)到 1現(xiàn)象CUDA out of memorybatch 降到 1 還是爆。原因imgsz 太大或者開了過(guò)多的數(shù)據(jù)加載 worker或者模型選得太大比如直接上 yolov8x。解決先把 imgsz 降到 416 試再檢查workers參數(shù)別設(shè)太高最后考慮換小模型。另外推理階段爆顯存多半是沒加torch.no_grad()或者一次喂了太多幀。4.5 部署時(shí)推理速度遠(yuǎn)慢于訓(xùn)練時(shí)現(xiàn)象訓(xùn)練時(shí)一個(gè) batch 幾十毫秒部署到邊緣設(shè)備單幀要幾百毫秒。原因沒做模型導(dǎo)出優(yōu)化PyTorch 原生推理在端側(cè)本來(lái)就慢。解決導(dǎo)出成 ONNX 或 TensorRTyolo export modelbest.pt formatonnx再用對(duì)應(yīng)推理引擎加載速度通常能提升 2~5 倍。導(dǎo)出后記得用同一張圖對(duì)比一下前后輸出確認(rèn)精度沒掉。5. 二次開發(fā)與改造讓這套數(shù)據(jù)真正長(zhǎng)在你的業(yè)務(wù)里拿到一份數(shù)據(jù)集只是起點(diǎn)真正決定項(xiàng)目成敗的是你怎么改它。我一般會(huì)從三個(gè)方向動(dòng)手。第一個(gè)方向是擴(kuò)類別。抽煙檢測(cè)往往不是孤立需求工地場(chǎng)景里你還想同時(shí)檢測(cè)未戴安全帽、未穿反光衣。做法很簡(jiǎn)單在 data.yaml 里把nc改成 3names加上對(duì)應(yīng)類別然后給原有標(biāo)注補(bǔ)上新類別的框。注意原有 smoking 的 id 必須保持 0 不變新類別往后排否則舊標(biāo)注全亂。補(bǔ)標(biāo)的時(shí)候建議用半自動(dòng)方式——先拿現(xiàn)有模型預(yù)標(biāo)注人工只做修正效率能翻好幾倍。第二個(gè)方向是換模型結(jié)構(gòu)。這套數(shù)據(jù)格式對(duì) YOLOv5、v8、v9、v10 甚至 RT-DETR 都通用你可以拿同一份數(shù)據(jù)橫向?qū)Ρ炔煌Y(jié)構(gòu)的精度和速度選最適合你硬件的那一個(gè)。我做過(guò)一組對(duì)比在同樣的數(shù)據(jù)上模型mAP50單幀推理(ms)權(quán)重體積(MB)YOLOv8n0.8286YOLOv8s0.871522YOLOv8m0.903250邊緣設(shè)備選 n服務(wù)器端選 m這個(gè)取舍沒有標(biāo)準(zhǔn)答案看你的延遲預(yù)算。第三個(gè)方向是改損失函數(shù)和增強(qiáng)策略。抽煙目標(biāo)普遍偏小一根煙在整圖里可能就幾十個(gè)像素默認(rèn)的損失對(duì)小目標(biāo)不友好??梢栽囋囋谟?xùn)練配置里調(diào)大box損失的權(quán)重或者引入針對(duì)小目標(biāo)的增強(qiáng)比如把 mosaic 的概率調(diào)高、加入隨機(jī)縮放。改完一定要用固定的驗(yàn)證集對(duì)比別憑感覺說(shuō)好像變好了。最后說(shuō)個(gè)我自己的習(xí)慣每次改完數(shù)據(jù)集或訓(xùn)練配置我都會(huì)先跑一個(gè) 5 epoch 的快速驗(yàn)證確認(rèn) loss 能正常下降、沒有報(bào)錯(cuò)再放開跑完整訓(xùn)練。這個(gè)習(xí)慣幫我省下過(guò)無(wú)數(shù)次白等一整晚的后悔藥。從那以后我每次動(dòng)數(shù)據(jù)集都強(qiáng)制先走一遍這個(gè)小循環(huán)。希望這套數(shù)據(jù)和思路能幫到你少走點(diǎn)我當(dāng)年走過(guò)的彎路。本文還有配套的精品資源點(diǎn)擊獲取