據(jù)集實戰(zhàn):從標(biāo)注格式到訓(xùn)練推理全流程拆解)
簡介這份YOLO抽煙目標(biāo)檢測數(shù)據(jù)集面向計算機(jī)視覺初學(xué)者與目標(biāo)檢測實踐者用于訓(xùn)練和驗證吸煙行為識別模型可應(yīng)用于公共場所禁煙監(jiān)控、工地安全巡檢等場景。資源包共594個文件由297張jpg圖片與297個xml標(biāo)注文件一一對應(yīng)組成壓縮包約59.11MBxml采用Pascal VOC格式記錄目標(biāo)類別與邊界框坐標(biāo)可直接轉(zhuǎn)換為YOLO訓(xùn)練所需的txt標(biāo)簽省去自行標(biāo)注的時間成本。目前已有376人學(xué)習(xí)下載具備一定的參考熱度。數(shù)據(jù)集覆蓋多種人物姿態(tài)與拍攝角度圖片命名規(guī)范、標(biāo)注與圖像嚴(yán)格配對便于按比例劃分訓(xùn)練集、驗證集與測試集快速搭建數(shù)據(jù)加載與增強(qiáng)流程。讀者可基于此完成模型訓(xùn)練、精度評估與推理部署的完整鏈路也可用于對比不同檢測算法的性能差異是入門目標(biāo)檢測與行為識別任務(wù)的實用素材。1. 從一次翻車現(xiàn)場說起這套 YOLO 抽煙檢測數(shù)據(jù)集到底能干什么去年幫一個做智慧工地安全巡檢的朋友調(diào)模型他手里有一批現(xiàn)場攝像頭截圖想自動識別工人有沒有在禁煙區(qū)抽煙。想法很直接但卡在了第一步——沒有標(biāo)注數(shù)據(jù)。網(wǎng)上找的開源數(shù)據(jù)集要么類別對不上要么標(biāo)注格式是 VOC XML跟他用的 YOLO 訓(xùn)練腳本對不上號。折騰了三天最后發(fā)現(xiàn)真正缺的不是模型結(jié)構(gòu)而是一份拿來就能用的抽煙目標(biāo)檢測數(shù)據(jù)集。這次要拆的這份資源就是沖著這個場景來的一批已經(jīng)標(biāo)好的抽煙行為圖片標(biāo)注文件直接適配 YOLO 系列訓(xùn)練流程。它解決的不是“模型怎么設(shè)計”的問題而是“數(shù)據(jù)從哪來、格式怎么對齊、訓(xùn)練腳本怎么接”的問題。適合兩類人一是剛接觸目標(biāo)檢測、想拿一個真實場景數(shù)據(jù)集跑通訓(xùn)練和推理全流程的新手二是手頭有類似安防、巡檢需求需要快速驗證方案可行性的開發(fā)者。數(shù)據(jù)集本身不復(fù)雜但“能直接跑起來”這件事比想象中省事得多。2. 數(shù)據(jù)集結(jié)構(gòu)與標(biāo)注格式先搞清楚手里拿的是什么2.1 目錄組織與文件命名習(xí)慣拿到一份目標(biāo)檢測數(shù)據(jù)集第一件事不是急著寫訓(xùn)練腳本而是把目錄結(jié)構(gòu)摸清楚。這份抽煙檢測數(shù)據(jù)集的組織方式比較典型常見做法是分成 images 和 labels 兩個平行目錄各自下面再按 train、val 甚至 test 劃分。圖片格式一般是 jpg 或 png標(biāo)注文件是同名的 txt放在 labels 對應(yīng)子目錄里。一個典型的目錄長這樣smoking_dataset/ ├── images/ │ ├── train/ │ │ ├── 0001.jpg │ │ ├── 0002.jpg │ │ └── ... │ └── val/ │ ├── 0101.jpg │ └── ... ├── labels/ │ ├── train/ │ │ ├── 0001.txt │ │ ├── 0002.txt │ │ └── ... │ └── val/ │ ├── 0101.txt │ └── ... └── data.yaml這里有個容易翻車的點圖片和標(biāo)注文件的文件名必須嚴(yán)格對應(yīng)包括大小寫。有些數(shù)據(jù)集從不同來源拼湊會出現(xiàn)圖片叫IMG_001.JPG、標(biāo)注叫img_001.txt的情況訓(xùn)練時找不到標(biāo)簽loss 直接不降。我一般會先跑一段腳本做文件名一致性校驗確認(rèn)沒問題再往下走。2.2 YOLO 標(biāo)注格式逐字段拆解YOLO 用的標(biāo)注格式是每張圖一個 txt每行代表一個目標(biāo)框格式為class_id x_center y_center width height這五個字段都是歸一化到 0 到 1 之間的浮點數(shù)。class_id從 0 開始編號這份數(shù)據(jù)集如果只檢測“抽煙”一個類別那所有行的 class_id 都是 0。x_center和y_center是框中心點相對于圖片寬高的比例width和height是框的寬高相對于圖片寬高的比例。舉個例子一張 640x480 的圖某個人手部夾煙的區(qū)域框在像素坐標(biāo) (320, 240) 為中心寬 80 像素、高 60 像素那標(biāo)注行就是0 0.5 0.5 0.125 0.125計算方式x_center 320/640 0.5y_center 240/480 0.5width 80/640 0.125height 60/480 0.125。注意如果標(biāo)注文件里出現(xiàn)大于 1 的數(shù)值說明標(biāo)注時沒有做歸一化直接用了像素坐標(biāo)。這種情況需要自己寫腳本轉(zhuǎn)換否則訓(xùn)練時框會跑到圖片外面去。2.3 data.yaml 配置文件的寫法YOLO 訓(xùn)練時需要一個 yaml 文件告訴它數(shù)據(jù)在哪、有幾個類別、類別名是什么。這份數(shù)據(jù)集的 data.yaml 常見寫法如下path: ./smoking_dataset train: images/train val: images/val nc: 1 names: 0: smokingpath是數(shù)據(jù)集根目錄train和val是相對于根目錄的圖片路徑。nc是類別數(shù)量這里只有抽煙一個類所以是 1。names是類別索引到名稱的映射推理時輸出的類別名就來自這里。如果后續(xù)想擴(kuò)展成“抽煙”和“打電話”兩個類只需要把 nc 改成 2names 里加一行1: calling然后確保標(biāo)注文件里對應(yīng)類別的 class_id 正確即可。這個配置文件看著簡單但路徑寫錯、縮進(jìn)用 tab 而不是空格都會導(dǎo)致訓(xùn)練啟動時報錯。我習(xí)慣用python -c import yaml; yaml.safe_load(open(data.yaml))先驗證一下 yaml 能不能正常解析。3. 從零跑通訓(xùn)練環(huán)境、命令與參數(shù)調(diào)優(yōu)3.1 環(huán)境準(zhǔn)備與依賴安裝這份數(shù)據(jù)集適配的是 Ultralytics 版本的 YOLO也就是常說的 YOLOv5 或 YOLOv8 那一套。環(huán)境準(zhǔn)備不復(fù)雜但版本對齊很重要。我一般用 conda 建一個干凈環(huán)境避免和系統(tǒng)里的包打架conda create -n yolo_smoke python3.9 -y conda activate yolo_smoke # 安裝 PyTorch根據(jù)自己顯卡的 CUDA 版本選對應(yīng)命令 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 安裝 ultralytics pip install ultralytics裝完之后用yolo checks看一眼環(huán)境確認(rèn) PyTorch 能識別到 GPU。如果顯示 CPU only訓(xùn)練會慢到懷疑人生。顯卡驅(qū)動和 CUDA 版本對不上是新手最常見的翻車點表現(xiàn)是torch.cuda.is_available()返回 False這時候別急著換代碼先查驅(qū)動版本和 CUDA 版本是否匹配。3.2 訓(xùn)練命令與關(guān)鍵參數(shù)說明環(huán)境沒問題之后訓(xùn)練命令其實就一行yolo detect train \ data./smoking_dataset/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ project./runs/smoke \ nameexp1逐項說一下這幾個參數(shù)。data指向剛才的 yaml 文件。model是預(yù)訓(xùn)練權(quán)重yolov8n 是最小的 nano 版本速度快、精度夠用適合先跑通流程如果顯存充足可以換 yolov8s 或 yolov8m。epochs是訓(xùn)練輪數(shù)100 輪對這個小數(shù)據(jù)集通常夠收斂但要看 loss 曲線決定要不要加。imgsz是輸入圖片尺寸640 是默認(rèn)值如果原始圖片分辨率很高可以調(diào)到 1280但顯存占用會明顯上升。batch是批大小16 在 8G 顯存上比較穩(wěn)爆顯存就降到 8 或 4。lr0是初始學(xué)習(xí)率0.01 是 YOLO 系列的常用值數(shù)據(jù)集小的時候可以降到 0.001 防止過擬合。訓(xùn)練過程中會在runs/smoke/exp1下生成權(quán)重文件、loss 曲線和驗證結(jié)果。重點看results.png里的 box_loss 和 cls_loss 是否穩(wěn)定下降如果震蕩劇烈多半是學(xué)習(xí)率太大或者 batch 太小。3.3 推理驗證與結(jié)果解讀訓(xùn)練完之后拿驗證集或自己的圖片跑推理yolo detect predict \ model./runs/smoke/exp1/weights/best.pt \ source./smoking_dataset/images/val \ conf0.25 \ saveTrueconf是置信度閾值低于這個值的框會被過濾掉。0.25 是常用起點如果發(fā)現(xiàn)漏檢多就降到 0.1誤檢多就升到 0.5。推理結(jié)果默認(rèn)保存在runs/detect/predict下每張圖會畫出檢測框和類別置信度。看結(jié)果的時候別只看畫框的圖要對照原始標(biāo)注看有沒有漏標(biāo)或錯標(biāo)。數(shù)據(jù)集質(zhì)量比模型結(jié)構(gòu)更影響最終效果如果標(biāo)注本身把煙頭、手指、打火機(jī)混在一起標(biāo)成 smoking模型學(xué)出來的框會很不穩(wěn)定。我一般會隨機(jī)抽 20 張訓(xùn)練圖把標(biāo)注框畫出來和原圖疊在一起看確認(rèn)標(biāo)注區(qū)域確實是抽煙行為本身而不是周圍無關(guān)物體。4. 避坑與排查訓(xùn)練不收斂、顯存爆炸、標(biāo)注錯位怎么處理4.1 現(xiàn)象loss 不下降或震蕩劇烈原因最常見的是學(xué)習(xí)率過大、batch 太小導(dǎo)致梯度噪聲大或者標(biāo)注文件里有大量越界框坐標(biāo)大于 1 或小于 0。另外如果 data.yaml 里 nc 寫錯比如實際有 2 類但 nc 寫了 1模型會把第二類當(dāng)成背景l(fā)oss 也會異常。解決先把 lr0 降到 0.001 試 10 個 epoch看 loss 是否開始下降。同時寫腳本掃描所有標(biāo)注文件檢查每行是否有超出 [0,1] 范圍的數(shù)值。如果 nc 寫錯修正后重新訓(xùn)練。我習(xí)慣在訓(xùn)練前跑一遍數(shù)據(jù)校驗?zāi)_本把越界框、空標(biāo)注文件、圖片損壞這些問題提前暴露出來。4.2 現(xiàn)象CUDA out of memory原因batch 太大、imgsz 太高或者顯卡被其他進(jìn)程占用。YOLO 訓(xùn)練時顯存占用和 batch * imgsz 基本成正比。解決先把 batch 減半如果還爆就把 imgsz 從 640 降到 416。另外用nvidia-smi看一下是不是有殘留進(jìn)程占著顯存有的話 kill 掉再跑。如果顯卡本身顯存小于 6G建議直接用 yolov8n 加 imgsz416別硬上大模型。4.3 現(xiàn)象推理時框的位置明顯偏移原因標(biāo)注時用的歸一化基準(zhǔn)和推理時不一致。比如標(biāo)注時按圖片原始尺寸歸一化但推理時 YOLO 會把圖片 resize 到 imgsz如果 resize 時沒有保持寬高比框就會偏。另一種可能是標(biāo)注文件里的坐標(biāo)是像素值而不是歸一化值訓(xùn)練時被當(dāng)成歸一化值用了。解決檢查標(biāo)注文件里是否有大于 1 的數(shù)值有的話說明沒歸一化。另外確認(rèn)推理時的 imgsz 和訓(xùn)練時一致YOLO 默認(rèn)會做 letterbox 保持寬高比一般不會偏但如果自己改了預(yù)處理邏輯就要注意。4.4 現(xiàn)象驗證集指標(biāo)很好但實際場景漏檢嚴(yán)重原因訓(xùn)練集和驗證集分布太接近或者數(shù)據(jù)量太少導(dǎo)致過擬合。這份數(shù)據(jù)集如果場景單一比如都是同一個攝像頭角度模型學(xué)到的是背景特征而不是抽煙行為本身。解決盡量在驗證集里放不同角度、不同光照的圖片。如果數(shù)據(jù)量確實少可以用 YOLO 自帶的增強(qiáng)參數(shù)比如degrees10、hsv_h0.015、flipud0.5在訓(xùn)練時隨機(jī)旋轉(zhuǎn)、調(diào)色、翻轉(zhuǎn)增加樣本多樣性。但增強(qiáng)不是萬能的如果原始數(shù)據(jù)里抽煙行為本身就不清晰增強(qiáng)也救不回來。4.5 現(xiàn)象訓(xùn)練完模型文件很大推理速度慢原因用了較大的模型如 yolov8l 或 yolov8x或者沒有做模型導(dǎo)出優(yōu)化。解決如果只是驗證方案yolov8n 足夠。如果要部署到邊緣設(shè)備可以把訓(xùn)練好的 pt 文件導(dǎo)出成 ONNX 或 TensorRTyolo export model./runs/smoke/exp1/weights/best.pt formatonnx導(dǎo)出后推理速度通常能提升 20% 到 50%具體取決于硬件。導(dǎo)出時注意 opset 版本和推理引擎的兼容性O(shè)NNX Runtime 一般用 opset 12 或 13 比較穩(wěn)。5. 二次開發(fā)與改造從單類檢測到多場景適配的實用技巧5.1 擴(kuò)展類別加一個“打電話”檢測如果業(yè)務(wù)場景里還需要檢測打電話行為最直接的做法是在現(xiàn)有數(shù)據(jù)集基礎(chǔ)上補(bǔ)充打電話的標(biāo)注圖片然后把 data.yaml 改成nc: 2 names: 0: smoking 1: calling標(biāo)注文件里打電話的框 class_id 寫 1。重新訓(xùn)練時建議用之前訓(xùn)練好的權(quán)重做初始化而不是從 COCO 預(yù)訓(xùn)練權(quán)重開始這樣收斂更快。命令里把model換成./runs/smoke/exp1/weights/best.pt即可。5.2 替換主干網(wǎng)絡(luò)換更輕量的 backbone如果部署設(shè)備算力有限可以把 YOLOv8 的 backbone 換成 MobileNet 或 ShuffleNet。Ultralytics 支持通過 yaml 配置文件自定義模型結(jié)構(gòu)常見做法是復(fù)制一份 yolov8n.yaml把 backbone 部分的 Conv 模塊替換成輕量卷積。改完之后用yolo detect train model./custom_yolov8n.yaml從頭訓(xùn)練。這個操作對新手不太友好建議先把默認(rèn)模型跑通再折騰。5.3 數(shù)據(jù)增強(qiáng)策略調(diào)整針對抽煙場景的定制抽煙檢測有個特殊點煙頭很小如果增強(qiáng)時縮放太狠煙頭可能直接消失。我一般會把scale參數(shù)控制在 0.5 以內(nèi)避免過度縮小。另外mosaic增強(qiáng)默認(rèn)開啟它會把四張圖拼成一張對小目標(biāo)檢測有幫助但如果圖片里抽煙區(qū)域本來就小mosaic 后可能更小這時候可以適當(dāng)降低 mosaic 概率。5.4 模型導(dǎo)出與部署驗證訓(xùn)練完的模型最終要落到實際業(yè)務(wù)里。如果部署在服務(wù)器上可以用 ONNX Runtime 或 TensorRT如果部署在邊緣設(shè)備可以用 NCNN 或 OpenVINO。導(dǎo)出命令前面提過這里補(bǔ)充一個驗證導(dǎo)出模型是否正確的技巧用同樣的驗證集分別跑 pt 和 onnx 模型對比檢測框數(shù)量和置信度如果差異超過 5%說明導(dǎo)出過程有問題重點檢查輸入尺寸和歸一化參數(shù)是否一致。5.5 一個我踩過的坑別在訓(xùn)練集上調(diào)參剛開始做這個項目的時候我習(xí)慣在訓(xùn)練集上看 loss 和指標(biāo)覺得降得不錯就收工。結(jié)果上線后發(fā)現(xiàn)實際場景漏檢嚴(yán)重。后來才意識到訓(xùn)練集上的指標(biāo)只能說明模型“記住”了這些圖不能說明它“學(xué)會”了抽煙行為。從那以后我每次訓(xùn)練都強(qiáng)制留出一部分完全沒參與訓(xùn)練的圖片做最終驗證哪怕數(shù)據(jù)量少也要留 10% 出來。這個習(xí)慣幫我省了很多次返工。希望這份拆解能幫你把這份抽煙檢測數(shù)據(jù)集順利跑起來少走點我當(dāng)年走過的彎路。本文還有配套的精品資源點擊獲取