據(jù)集實(shí)戰(zhàn):2127張YOLO+VOC雙格式目標(biāo)檢測(cè)訓(xùn)練指南)
簡(jiǎn)介本資源為面向目標(biāo)檢測(cè)學(xué)習(xí)者的電線桿識(shí)別數(shù)據(jù)集適用于電力巡檢、基礎(chǔ)設(shè)施監(jiān)測(cè)等場(chǎng)景下的模型訓(xùn)練與算法驗(yàn)證適合具備一定深度學(xué)習(xí)基礎(chǔ)、正在開展YOLO或VOC格式目標(biāo)檢測(cè)實(shí)踐的開發(fā)者與研究人員使用。壓縮包共約2000個(gè)文件以1999個(gè)xml標(biāo)注文件和1個(gè)說(shuō)明txt為主另含對(duì)應(yīng)圖片與YOLO格式txt標(biāo)簽整體大小約128.26MB目錄按圖片、xml、txt三類文件分文件夾存放便于直接接入常見檢測(cè)框架。數(shù)據(jù)集共2127張清晰圖片標(biāo)注單一類別telegraph pole矩形框總數(shù)達(dá)2700個(gè)標(biāo)注準(zhǔn)確合理未做數(shù)據(jù)增強(qiáng)可滿足基礎(chǔ)訓(xùn)練與對(duì)比實(shí)驗(yàn)需求。目前已有216人學(xué)習(xí)下載適合需要快速獲取電線桿檢測(cè)樣本、驗(yàn)證模型效果或搭建巡檢原型的讀者參考使用。1. 電線桿數(shù)據(jù)集到底能拿來(lái)干什么2127 張 YOLOVOC 雙格式的實(shí)戰(zhàn)定位如果你正在做電力巡檢、無(wú)人機(jī)航線避障或者遙感影像里的桿狀物識(shí)別大概率繞不開一個(gè)尷尬公開數(shù)據(jù)集里電線桿的樣本少得可憐自己從零標(biāo)又費(fèi)時(shí)費(fèi)力。這份 2127 張的電線桿數(shù)據(jù)集價(jià)值就在于它把「目標(biāo)檢測(cè)」里最耗人力的標(biāo)注環(huán)節(jié)直接跳過了——圖片和標(biāo)簽都現(xiàn)成YOLO 和 VOC 兩套格式同時(shí)給到省掉了格式轉(zhuǎn)換那一步。它適合三類人想快速跑通 YOLO 訓(xùn)練流程的新手、需要電線桿作為負(fù)樣本或干擾類補(bǔ)充檢測(cè)模型的從業(yè)者、以及做電力場(chǎng)景微調(diào)但缺數(shù)據(jù)的團(tuán)隊(duì)。2127 張不算大但作為單類別檢測(cè)的起步集夠你把訓(xùn)練、驗(yàn)證、推理整條鏈路走一遍也能直接塞進(jìn) yolov8訓(xùn)練自己的數(shù)據(jù)集 這類常見流程里當(dāng)練手素材。下面我按「先看清結(jié)構(gòu)、再動(dòng)手訓(xùn)練、最后避坑」的順序拆開講。2. 拆開壓縮包先看什么目錄結(jié)構(gòu)、標(biāo)注格式與類別分布拿到一個(gè)數(shù)據(jù)集我習(xí)慣先不急著寫訓(xùn)練腳本而是把目錄結(jié)構(gòu)和標(biāo)簽文件翻一遍。這一步能提前發(fā)現(xiàn) 80% 的后續(xù)翻車比如標(biāo)簽坐標(biāo)系不對(duì)、圖片和 txt 對(duì)不上號(hào)、類別 id 從 1 開始還是從 0 開始。電線桿這種單類別數(shù)據(jù)集看似簡(jiǎn)單但恰恰因?yàn)楹?jiǎn)單很多人跳過檢查結(jié)果訓(xùn)練 loss 不降還找不到原因。2.1 目錄結(jié)構(gòu)與文件命名規(guī)律解壓后典型的結(jié)構(gòu)是這樣不同打包方式可能略有差異以實(shí)際為準(zhǔn)電線桿數(shù)據(jù)集/ ├── images/ # 所有圖片jpg 或 png │ ├── 000001.jpg │ └── ... ├── labels/ # YOLO 格式標(biāo)簽與圖片同名 │ ├── 000001.txt │ └── ... ├── annotations/ # VOC 格式 XML 標(biāo)簽 │ ├── 000001.xml │ └── ... └── ImageSets/ # VOC 的劃分文件部分打包會(huì)帶 └── Main/先跑一條命令確認(rèn)圖片和標(biāo)簽數(shù)量是否一致這是最基本的自檢# 統(tǒng)計(jì)圖片數(shù)量 ls images/ | wc -l # 統(tǒng)計(jì) YOLO 標(biāo)簽數(shù)量 ls labels/ | wc -l # 找出有圖片但沒有對(duì)應(yīng)標(biāo)簽的文件潛在漏標(biāo) for f in images/*.jpg; do base$(basename $f .jpg) [ -f labels/$base.txt ] || echo 缺標(biāo)簽: $base done邏輯說(shuō)明第三段循環(huán)是核心它逐個(gè)比對(duì)圖片名和標(biāo)簽名。如果輸出一堆「缺標(biāo)簽」說(shuō)明這個(gè)包要么標(biāo)簽沒打全要么命名規(guī)則不統(tǒng)一比如圖片是.jpg標(biāo)簽卻按.png命名。參數(shù)上沒什么可調(diào)的basename去掉擴(kuò)展名后拼.txt是 YOLO 的通用約定。這一步花兩分鐘能省掉后面幾小時(shí)的排查。2.2 YOLO 與 VOC 兩種格式的差異與選用同一批數(shù)據(jù)給了兩套格式不是讓你都用而是讓你按框架選。YOLO 系列v5/v8/v11 等吃 txt每行是類別 x_center y_center width height坐標(biāo)全部歸一化到 0~1VOC 吃 XML存的是絕對(duì)像素坐標(biāo)的xmin ymin xmax ymax。兩者可以互轉(zhuǎn)但轉(zhuǎn)換時(shí)的取整和邊界裁剪是經(jīng)典坑點(diǎn)。格式文件類型坐標(biāo)表示適用框架單類別 idYOLO.txt歸一化中心點(diǎn)寬高YOLOv5/v8/v11、Darknet通常從 0 開始VOC.xml絕對(duì)像素左上右下Faster R-CNN、SSD、部分評(píng)估腳本從 1 開始或按 name 匹配看一個(gè) YOLO 標(biāo)簽長(zhǎng)什么樣0 0.512 0.634 0.021 0.487這行意思是類別 0電線桿中心點(diǎn)在圖片寬 51.2%、高 63.4% 的位置框?qū)捳紙D寬 2.1%框高占圖高 48.7%。電線桿是典型的「高瘦」目標(biāo)寬高比經(jīng)常到 1:20 以上這個(gè)特征后面調(diào) anchor 時(shí)會(huì)用到。對(duì)應(yīng)的 VOC XML 關(guān)鍵片段object namepole/name bndbox xmin512/xmin ymin210/ymin xmax530/xmax ymax690/ymax /bndbox /object提示先確認(rèn)你的框架要哪種格式別兩套都往訓(xùn)練目錄里塞YOLO 訓(xùn)練時(shí)如果 labels 目錄混進(jìn) XML 會(huì)直接報(bào)錯(cuò)或靜默跳過。2.3 類別分布與寬高比統(tǒng)計(jì)單類別數(shù)據(jù)集也要看分布重點(diǎn)看兩點(diǎn)每張圖平均幾個(gè)目標(biāo)、目標(biāo)的寬高比集中在什么范圍。寫個(gè)小腳本統(tǒng)計(jì)import os import glob ratios [] counts [] for txt in glob.glob(labels/*.txt): with open(txt) as f: lines [l for l in f.readlines() if l.strip()] counts.append(len(lines)) for l in lines: _, _, _, w, h map(float, l.split()) if w 0: ratios.append(h / w) # 高寬比 print(f圖片數(shù): {len(counts)}) print(f平均每圖目標(biāo)數(shù): {sum(counts)/len(counts):.2f}) print(f最大目標(biāo)數(shù): {max(counts)}) print(f高寬比中位數(shù): {sorted(ratios)[len(ratios)//2]:.1f})邏輯說(shuō)明h/w算的是高寬比電線桿這個(gè)值通常很大。如果中位數(shù)超過 10說(shuō)明絕大多數(shù)目標(biāo)極度細(xì)長(zhǎng)默認(rèn) anchor比如 YOLOv5 的 8/16/32 網(wǎng)格 anchor可能匹配不好需要重新聚類 anchor 或調(diào)anchor_t閾值。參數(shù)上counts用來(lái)判斷有沒有空標(biāo)簽文件目標(biāo)數(shù)為 0 的圖空標(biāo)簽在訓(xùn)練時(shí)會(huì)被當(dāng)負(fù)樣本如果數(shù)量太多會(huì)拖累召回。3. 用這份數(shù)據(jù)跑通 YOLO 訓(xùn)練從 data.yaml 到第一次推理數(shù)據(jù)檢查完接下來(lái)就是把它喂進(jìn)模型。這一章以 YOLOv8 為主線v5/v11 流程幾乎一致把配置文件、訓(xùn)練命令、參數(shù)含義和驗(yàn)證方法講透。你照著抄能跑起來(lái)跑起來(lái)之后知道每個(gè)數(shù)字在調(diào)什么。3.1 劃分訓(xùn)練驗(yàn)證集與生成 data.yamlYOLO 訓(xùn)練不強(qiáng)制要求預(yù)先劃分但規(guī)范做法是分 train/val。寫個(gè)腳本按 8:2 劃分并復(fù)制文件import os import random import shutil random.seed(42) img_dir, lbl_dir images, labels out_root dataset for split in [train, val]: os.makedirs(f{out_root}/images/{split}, exist_okTrue) os.makedirs(f{out_root}/labels/{split}, exist_okTrue) imgs [f for f in os.listdir(img_dir) if f.endswith((.jpg, .png))] random.shuffle(imgs) split_idx int(len(imgs) * 0.8) train_imgs, val_imgs imgs[:split_idx], imgs[split_idx:] for split, files in [(train, train_imgs), (val, val_imgs)]: for f in files: base os.path.splitext(f)[0] shutil.copy(f{img_dir}/{f}, f{out_root}/images/{split}/{f}) lbl f{lbl_dir}/{base}.txt if os.path.exists(lbl): shutil.copy(lbl, f{out_root}/labels/{split}/{base}.txt) print(ftrain: {len(train_imgs)}, val: {len(val_imgs)})邏輯說(shuō)明random.seed(42)固定隨機(jī)種子保證每次劃分一致方便復(fù)現(xiàn)。8:2 是單類別小數(shù)據(jù)集的常用比例2127 張里約 1700 張訓(xùn)練、425 張驗(yàn)證。注意復(fù)制標(biāo)簽時(shí)做了os.path.exists判斷防止前面發(fā)現(xiàn)的漏標(biāo)文件導(dǎo)致腳本崩潰。然后寫data.yamlpath: ./dataset train: images/train val: images/val nc: 1 names: [pole]參數(shù)說(shuō)明nc是類別數(shù)單類別填 1names順序必須和標(biāo)簽里的類別 id 對(duì)應(yīng)這里 id 0 就是 pole。path用相對(duì)路徑時(shí)訓(xùn)練命令要在data.yaml同級(jí)目錄執(zhí)行否則找不到圖。3.2 訓(xùn)練命令與關(guān)鍵超參一條能跑的命令yolo detect train \ datadata.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/pole \ nameexp1邏輯說(shuō)明modelyolov8n.pt用官方預(yù)訓(xùn)練權(quán)重做遷移學(xué)習(xí)小數(shù)據(jù)集從零訓(xùn)幾乎不可能收斂這是血淚經(jīng)驗(yàn)。imgsz640是輸入分辨率電線桿細(xì)長(zhǎng)分辨率太低會(huì)直接丟目標(biāo)如果顯存夠可以上 960 或 1280。batch16按顯存調(diào)V100 上 640 分辨率跑 32 甚至 64 都行。patience20是早停20 輪驗(yàn)證指標(biāo)不升就停省時(shí)間。幾個(gè)和電線桿強(qiáng)相關(guān)的參數(shù)anchor_tYOLOv5 里叫anchor_tv8 內(nèi)部處理控制 anchor 匹配閾值細(xì)長(zhǎng)目標(biāo)建議適當(dāng)放寬。mosaic默認(rèn)開啟但電線桿拼接后可能出現(xiàn)不自然的截?cái)嗳绻?yàn)證集 mAP 上不去可以試mosaic0。scale隨機(jī)縮放對(duì)小目標(biāo)有利但電線桿本身夠大保持默認(rèn) 0.5 即可。3.3 看訓(xùn)練日志判斷是否正常訓(xùn)練啟動(dòng)后重點(diǎn)盯三行box_loss、cls_loss、mAP50。正常情況 box_loss 從 1.x 穩(wěn)步降到 0.0xcls_loss 因?yàn)閱晤悇e很快趨近 0。如果 box_loss 卡在某個(gè)值不動(dòng)八成是標(biāo)簽坐標(biāo)系錯(cuò)了比如把 VOC 的絕對(duì)坐標(biāo)直接當(dāng) YOLO 歸一化坐標(biāo)用。如果 mAP50 一直 0先查data.yaml的names和標(biāo)簽 id 是否對(duì)得上。驗(yàn)證和推理# 驗(yàn)證 yolo detect val modelruns/pole/exp1/weights/best.pt datadata.yaml # 單圖推理 yolo detect predict modelruns/pole/exp1/weights/best.pt sourcetest.jpg conf0.25conf0.25是置信度閾值電線桿這種背景干擾多的場(chǎng)景可以調(diào)到 0.4 減少誤檢但會(huì)漏掉被遮擋的桿子需要按業(yè)務(wù)權(quán)衡。4. 避坑與排查電線桿數(shù)據(jù)集訓(xùn)練最容易翻車的五個(gè)地方這一章是我自己踩過和幫人排查過的真實(shí)問題每條按「現(xiàn)象 → 原因 → 解決」寫。單類別數(shù)據(jù)集看著簡(jiǎn)單坑反而集中?,F(xiàn)象一訓(xùn)練一開始就報(bào)「No labels found」。原因data.yaml里的train路徑寫成了絕對(duì)路徑或?qū)蛹?jí)不對(duì)YOLO 找不到 labels 目錄或者標(biāo)簽文件名和圖片名大小寫不一致Linux 區(qū)分大小寫。 解決用ls dataset/labels/train | head確認(rèn)標(biāo)簽存在路徑統(tǒng)一用相對(duì)data.yaml的相對(duì)路徑命名統(tǒng)一小寫。現(xiàn)象二box_loss 不降mAP 始終接近 0。原因標(biāo)簽坐標(biāo)系用錯(cuò)。常見是把 VOC 的絕對(duì)像素坐標(biāo)直接寫進(jìn)了 txt沒做歸一化導(dǎo)致所有框都跑到圖片外。 解決抽查一個(gè) txt確認(rèn)四個(gè)值都在 0~1 之間。如果大于 1說(shuō)明是絕對(duì)坐標(biāo)需要除以圖片寬高重新歸一化。現(xiàn)象三驗(yàn)證集 mAP 高但實(shí)際推理漏檢嚴(yán)重。原因訓(xùn)練集和驗(yàn)證集劃分時(shí)沒打亂或者同一根桿子的多張連拍圖被分到了兩邊造成數(shù)據(jù)泄漏驗(yàn)證指標(biāo)虛高。 解決劃分前random.shuffle如果圖片來(lái)自視頻抽幀最好按視頻段劃分而不是按幀隨機(jī)分。現(xiàn)象四顯存爆了CUDA out of memory。原因imgsz或batch設(shè)太大電線桿數(shù)據(jù)集圖片分辨率可能本身很高。 解決先降 batch 到 8再考慮降 imgsz或者開啟ampTrue混合精度V100 上能省近一半顯存?,F(xiàn)象五推理時(shí)同一根桿子出多個(gè)框。原因NMS 的iou閾值默認(rèn) 0.7細(xì)長(zhǎng)目標(biāo)重疊區(qū)域小NMS 壓不干凈。 解決推理時(shí)調(diào)低iou0.5或訓(xùn)練時(shí)用overlap_mask相關(guān)參數(shù)單類別場(chǎng)景也可以直接調(diào)max_det限制輸出數(shù)量。注意改任何參數(shù)后先跑 5 個(gè) epoch 看 loss 趨勢(shì)別一上來(lái)就 100 輪浪費(fèi)時(shí)間。5. 把 2127 張用到極致小數(shù)據(jù)集的增強(qiáng)策略與遷移技巧2127 張對(duì)目標(biāo)檢測(cè)來(lái)說(shuō)屬于小數(shù)據(jù)集直接訓(xùn)容易過擬合驗(yàn)證集 mAP 看著不錯(cuò)換個(gè)場(chǎng)景就崩。這一章講幾個(gè)我常用的增強(qiáng)和遷移手段都是在這類單類別細(xì)長(zhǎng)目標(biāo)上驗(yàn)證過有效的。5.1 針對(duì)細(xì)長(zhǎng)目標(biāo)的增強(qiáng)組合YOLO 內(nèi)置增強(qiáng)里對(duì)電線桿最有用的是這幾項(xiàng)在訓(xùn)練命令里直接加yolo detect train \ datadata.yaml \ modelyolov8n.pt \ epochs150 \ imgsz960 \ batch8 \ degrees10.0 \ translate0.1 \ scale0.3 \ fliplr0.5 \ mosaic0.5 \ mixup0.1 \ copy_paste0.1參數(shù)說(shuō)明degrees10小角度旋轉(zhuǎn)模擬無(wú)人機(jī)不同航向fliplr0.5水平翻轉(zhuǎn)電線桿左右翻轉(zhuǎn)后語(yǔ)義不變安全scale0.3縮放幅度讓模型適應(yīng)不同拍攝距離mosaic0.5比默認(rèn) 1.0 低因?yàn)樗膱D拼接會(huì)讓細(xì)長(zhǎng)桿子被截?cái)啾壤叻炊泻opy_paste0.1把目標(biāo)復(fù)制粘貼到其他圖對(duì)小數(shù)據(jù)集擴(kuò)充很有效但比例別高否則背景失真。5.2 用預(yù)訓(xùn)練權(quán)重和凍結(jié)策略穩(wěn)住訓(xùn)練小數(shù)據(jù)集最忌諱從零訓(xùn)。yolov8n.pt這類在 COCO 上預(yù)訓(xùn)練的權(quán)重已經(jīng)學(xué)到了邊緣、紋理等通用特征遷移過來(lái)能大幅加速收斂。如果數(shù)據(jù)量特別少比如你只取其中 500 張做實(shí)驗(yàn)可以凍結(jié) backbone 前幾層yolo detect train modelyolov8n.pt datadata.yaml epochs100 freeze10freeze10表示凍結(jié)前 10 層只訓(xùn)后面的檢測(cè)頭。等 loss 穩(wěn)定后再解凍全量微調(diào)這是常見的兩階段做法。注意凍結(jié)層數(shù)別太多否則模型學(xué)不到電線桿的專屬特征。5.3 驗(yàn)證方法別只看 mAP單類別數(shù)據(jù)集的 mAP 容易虛高我一般會(huì)額外做兩件事。第一把驗(yàn)證集里預(yù)測(cè)框和真實(shí)框畫出來(lái)肉眼過一遍重點(diǎn)看漏檢的桿子是不是被遮擋或太細(xì)。第二用一批完全沒參與訓(xùn)練的圖比如從別的渠道找的電力場(chǎng)景圖做交叉驗(yàn)證看模型泛化。如果交叉驗(yàn)證掉得厲害說(shuō)明過擬合回去加增強(qiáng)或減模型復(fù)雜度。from ultralytics import YOLO model YOLO(runs/pole/exp1/weights/best.pt) results model.predict(unseen_images/, conf0.3, iou0.5, saveTrue) # 統(tǒng)計(jì)每張圖的檢測(cè)數(shù)量和預(yù)期對(duì)比 for r in results: print(r.path, len(r.boxes))邏輯說(shuō)明conf0.3比默認(rèn)低一點(diǎn)寧可多檢也別漏人工再篩。iou0.5壓重疊框。打印每張圖的檢測(cè)數(shù)如果某張圖預(yù)期有 3 根桿子卻只檢出 1 根這張圖就值得單獨(dú)看。從那以后我每次拿到新數(shù)據(jù)集都強(qiáng)制先跑一遍「圖片標(biāo)簽數(shù)量比對(duì) 坐標(biāo)范圍檢查 劃分后交叉驗(yàn)證」這三步再開始正式訓(xùn)練。這套流程幫我省下的返工時(shí)間遠(yuǎn)比多訓(xùn)幾個(gè) epoch 值。希望這份電線桿數(shù)據(jù)集和上面的流程能幫你把電力場(chǎng)景檢測(cè)的第一步走穩(wěn)。本文還有配套的精品資源點(diǎn)擊獲取