YOLO到Y(jié)OLOv8訓練實戰(zhàn))
簡介這份數(shù)據(jù)集面向光伏運維、目標檢測及深度學習入門者用于太陽能光伏板表面灰塵Dirt檢測模型的訓練與驗證。資源共包含1463張jpg圖片每張均對應Pascal VOC格式的xml標注和YOLO格式的txt標注總計標注目標框6822個類別僅Dirt一項采用labelImg工具以矩形框方式標注。壓縮包內(nèi)文件總數(shù)2000主要由1463個xml、537個txt及圖片文件組成整體大小75.98MB目錄按圖片編號組織可直接對接YOLO等常見訓練流程。目前已有537人瀏覽/學習數(shù)據(jù)熱度適中。數(shù)據(jù)集標注規(guī)范、邊界框定位準確適合快速開展光伏積灰檢測實驗或作為目標檢測教學案例作者同時提示圖片重復度較高且不對特定模型權(quán)重精度作保證因此更適合對樣本多樣性要求不高、追求低成本獲取標注數(shù)據(jù)的場景正式項目使用前建議抽樣核查。1. 光伏板積灰檢測數(shù)據(jù)集1463張單類別能撐起什么場景光伏電站最頭疼的運維問題之一就是積灰。板面落灰之后發(fā)電量直線掉人工巡檢又慢又貴所以很多團隊轉(zhuǎn)向“無人機巡檢 目標檢測”的路線。這個數(shù)據(jù)集包就是為這條路準備的1463張光伏板圖像只標注一個類別——積灰同時提供VOC和YOLO兩套標注格式。如果你正在做光伏積灰檢測相關(guān)的yolo入門項目或者手里有電站圖像但不知道怎么組織成能訓練的數(shù)據(jù)集這套數(shù)據(jù)可以直接作為起點。它適合兩類人一是想驗證“積灰檢測到底能不能用視覺做”的工程師二是已經(jīng)在跑yolov8訓練自己的數(shù)據(jù)集但被數(shù)據(jù)格式卡住的新手。不適合誰想做灰塵厚度分級、想?yún)^(qū)分鳥糞和灰、想判斷清洗優(yōu)先級的人單類別標注撐不起這種需求。2. VOC轉(zhuǎn)YOLO格式歸一化坐標是所有轉(zhuǎn)換腳本的核心拿到一個同時帶VOC和YOLO格式的數(shù)據(jù)集第一件事不是急著訓練而是搞清楚兩種格式的坐標邏輯。Pascal VOC用XML保存絕對像素坐標YOLO用txt保存相對坐標。兩套格式在數(shù)據(jù)集的目錄結(jié)構(gòu)、標注內(nèi)容、類別編號方式上完全不同轉(zhuǎn)換腳本寫錯一個分母檢測框就全偏。2.1 Pascal VOC的XML里到底存了什么VOC格式的目錄通常長這樣VOCdevkit/ └── VOC2007/ ├── Annotations/ # 每個jpg對應一個xml ├── JPEGImages/ # 原圖 └── ImageSets/Main # 訓練/驗證劃分文件一個標注文件內(nèi)關(guān)鍵節(jié)點有三個size原圖寬高、object的name類別名、bndboxxmin、ymin、xmax、ymax四個絕對坐標。比如annotation size width1920/width height1080/height /size object namedust/name bndbox xmin300/xmin ymin450/ymin xmax720/xmax ymax610/ymax /bndbox /object /annotation這里的坐標是像素值直接基于原圖分辨率不需要任何額外計算。老工具鏈、標注軟件很多都吃這套格式這也是為什么很多數(shù)據(jù)分發(fā)喜歡附帶VOC版本——通用性最好。2.2 YOLO的txt標注為什么必須歸一化YOLO格式不關(guān)心原圖是多大每個目標單獨一行五個數(shù)class_id x_center y_center width height后四個全部歸一化到[0,1]。歸一化意味著坐標除以原圖寬高模型在訓練時不用處理不同分辨率帶來的尺度問題這是YOLO系算法能批量縮放輸入圖的基礎。注意一個細節(jié)YOLO的中心坐標和寬高都是相對值所以轉(zhuǎn)換公式是x_center (xmin xmax) / 2 / image_width y_center (ymin ymax) / 2 / image_height width (xmax - xmin) / image_width height (ymax - ymin) / image_height很多轉(zhuǎn)換翻車就翻在忘記除以寬高或者只歸一化了中心點而忘記把框?qū)捀咭矚w一化。另外類別ID必須從0開始單類別數(shù)據(jù)集就是0不是1。2.3 用Python把VOC轉(zhuǎn)成YOLO的常用寫法如果你拿到手的數(shù)據(jù)只有VOC格式或者想驗證數(shù)據(jù)集里自帶YOLO標注是否正確可以自己寫一個轉(zhuǎn)換腳本。下面這個是我常用的版本import xml.etree.ElementTree as ET from pathlib import Path def voc_to_yolo(xml_path: Path, out_txt_path: Path, class_names: list): tree ET.parse(xml_path) root tree.getroot() # 讀原圖尺寸這是歸一化的分母讀錯全盤皆輸 size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) lines [] for obj in root.iter(object): name obj.find(name).text.strip() if name not in class_names: continue cls_id class_names.index(name) box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) # 全部轉(zhuǎn)成歸一化坐標 x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h box_w (xmax - xmin) / img_w box_h (ymax - ymin) / img_h # 限制在[0,1]區(qū)間防止標注越界影響訓練 x_center min(max(x_center, 0.0), 1.0) y_center min(max(y_center, 0.0), 1.0) box_w min(max(box_w, 0.0), 1.0) box_h min(max(box_h, 0.0), 1.0) lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}) out_txt_path.write_text(\n.join(lines)) class_names [dust] # 單類別ID為0 xml_dir Path(Annotations) txt_dir Path(labels) for xml_file in xml_dir.glob(*.xml): voc_to_yolo(xml_file, txt_dir / f{xml_file.stem}.txt, class_names)邏輯說明腳本先解析XML讀原圖寬高再遍歷每個object取類別和邊框最后把絕對坐標轉(zhuǎn)成相對坐標寫入txt。class_names.index(name)決定了類別ID如果你把類別名列表寫成[dust, dust2]但數(shù)據(jù)里只有dust一個類訓練不會報錯只是模型會以為存在兩個類導致類別數(shù)不匹配問題。參數(shù)說明Class_names的順序就是ID順序必須和后續(xù)訓練配置文件保持一致min(max(...), 1.0)是為了防止標注數(shù)據(jù)越界導致訓練時loss異常。如果你發(fā)現(xiàn)轉(zhuǎn)換后的框整體偏移先查size節(jié)點里寬高和實際圖片分辨率是否一致。3. 用YOLOv8訓練自己的積灰數(shù)據(jù)集從解壓到出結(jié)果的完整命令格式確認沒問題之后下一步就是把數(shù)據(jù)集喂給模型?,F(xiàn)階段用ultralytics的YOLOv8訓練自己的數(shù)據(jù)集是主流做法社區(qū)資料多、命令收斂、報錯也好搜。整個流程分三步整理目錄、寫data.yaml、跑訓練命令。3.1 數(shù)據(jù)集目錄和data.yaml怎么組織先把壓縮包解壓成一個固定結(jié)構(gòu)的目錄YOLO系列訓練器對目錄有默認約定。我一般這樣組織solar_dust/ ├── images/ │ ├── train/ │ └── val/ └── labels/ ├── train/ └── val/每個jpg在images/train下同名txt必須在labels/train下。圖片和標注文件名一一對應缺一個txt就少一個訓練樣本。如果解壓出來的數(shù)據(jù)集是VOC的ImageSets劃分你需要先按劃分文件把圖片和XML拷到對應目錄。然后寫data.yamlpath: /data/solar_dust # 數(shù)據(jù)集絕對路徑 train: images/train # 相對于path val: images/val # 相對于path names: 0: dust # 類別ID從0開始參數(shù)說明path盡量寫絕對路徑避免相對路徑在不同工作目錄下解析錯誤names的鍵是類別ID0對應第2章轉(zhuǎn)換腳本里的class_name順序單類別場景names只有一項模型輸出維度會相應收斂推理時只需要一個置信度閾值。3.2 訓練、驗證一條命令跑通目錄和yaml就緒后直接跑yolo detect train datadata.yaml modelyolov8s.pt epochs120 imgsz640 batch16 patience20 projectruns namesolar_dust參數(shù)說明modelyolov8s.pt是加載COCO預訓練權(quán)重對小數(shù)據(jù)集有幫助不建議從頭訓練imgsz640是訓練輸入尺寸光伏板圖像通常分辨率很高1920以上但訓練時YOLO會做縮放640是速度和精度折中batch16要看顯存8G顯存可以降到8patience20表示20個epoch沒有提升就自動停防止過擬合。如果你用的是ultralytics庫而不是CLI等價寫法是from ultralytics import YOLO model YOLO(yolov8s.pt) model.train(datadata.yaml, epochs120, imgsz640, batch16, patience20)跑起來之后終端會打印每個epoch的box_loss、cls_loss、dfl_loss和mAP指標。第一次跑完你會在runs/solar_dust下看到權(quán)重文件best.pt和last.pt以及一堆可視化輸出。3.3 訓練輸出的幾個關(guān)鍵文件怎么看訓練完成后重點看四個東西results.png整個訓練過程的loss曲線和mAP曲線。如果epoch到中期loss就掉不下去可能是學習率或數(shù)據(jù)問題如果驗證曲線在訓練曲線還在降時就開始反彈就是過擬合。confusion_matrix.png單類別下主要看背景誤檢情況。如果很多干凈板面被預測成積灰說明負樣本不夠。val_batch0_pred.jpg第一張驗證集圖像的預測可視化。這一步能最直觀地看到框有沒有偏移、積灰區(qū)域是不是被漏檢。best.pt和last.ptbest是驗證集指標最好的權(quán)重部署時用best。提示單類別數(shù)據(jù)集不建議只盯mAP50-95光伏積灰檢測的現(xiàn)實需求是“框得準、別誤報”mAP50更有參考價值。4. 單類別檢測調(diào)參mAP和損失函數(shù)不看錯方向就是白調(diào)1463張小數(shù)據(jù)集訓練本身不難難的是驗證集怎么分、loss怎么看、增強怎么開。這幾個坑不處理訓練日志再漂亮現(xiàn)場一跑就露餡。4.1 訓練/驗證劃分按電站分別按文件隨機分這是小數(shù)據(jù)集最容易犯的錯誤。隨機劃分會把同一個電站、同一個組件在不同角度、光照下的照片同時分進訓練集和驗證集驗證mAP會虛高到接近1.0看起來完美部署到新電站直接崩。常見做法是按拍攝來源劃分。如果文件名有電站前綴比如site01_0001.jpg、site02_0012.jpg先按前綴分組再劃分from pathlib import Path import random img_files sorted(Path(images).glob(*.jpg)) grouped {} for img in img_files: site img.stem.split(_)[0] # 按文件名前綴分組 grouped.setdefault(site, []).append(img) random.seed(42) groups list(grouped.values()) random.shuffle(groups) train_ratio 0.85 train_groups groups[:int(len(groups) * train_ratio)] val_groups groups[int(len(groups) * train_ratio):] # 落盤到目錄并在labels目錄中同步對應txt如果不能按來源分至少保證同一張圖片的變體裁剪、翻轉(zhuǎn)、濾鏡版本不跨集合。判斷標準很簡單驗證是衡量“沒見過的電站”能不能檢測而不是“見過的電站換個角度”能不能檢測。4.2 讀yolo訓練日志box_loss、cls_loss、dfl_loss分別盯什么單類別訓練時三個loss的變化意義完全不同cls_loss分類損失。單類別下它很快會降到一個極低值因為模型只需要區(qū)分“前景/背景”這是正常的不用覺得詭異。box_loss定位損失決定框準不準。這是單類別數(shù)據(jù)集最需要盯的指標。如果box_loss收斂慢或震蕩優(yōu)先懷疑標注框質(zhì)量問題。dfl_lossDistributed Focal Loss影響邊界框回歸的分布。它和box_loss趨勢一致如果兩者背離檢查學習率是否過大。另外單類別模型的驗證集mAP很可能遠高于多類別因為只有一個類混淆矩陣里只有正類和背景兩個維度。不要因為這個數(shù)字高就認為模型可以上線真正決定能不能用的指標是誤報率。4.3 小數(shù)據(jù)集數(shù)據(jù)增強怎么開到不翻車YOLOv8默認開mosaic等增強但對1463張的單類別積灰數(shù)據(jù)增強不是越大越好。光伏板方向固定、積灰區(qū)域紋理也無明顯旋轉(zhuǎn)不變性過強的旋轉(zhuǎn)和色彩增強反而讓模型學到錯誤特征。我常用的調(diào)整方向yolo detect train datadata.yaml modelyolov8s.pt \ epochs120 imgsz640 batch16 \ mosaic0.5 hsv_h0.01 hsv_s0.3 hsv_v0.3 degrees5 fliplr0.5參數(shù)說明mosaic0.5把默認的1.0降下來小數(shù)據(jù)集mosaic太猛會過度混合背景degrees5只允許小角度旋轉(zhuǎn)光伏板要么水平要么小傾角不需要90度旋轉(zhuǎn)增強fliplr0.5水平翻轉(zhuǎn)保留對積灰檢測基本無副作用。如果你發(fā)現(xiàn)驗證集mAP波動大可以進一步把mosaic降到0.2甚至關(guān)掉用mosaic0.0鎖定對比。4.4 置信度閾值和NMS的Iou閾值怎么定訓練完成后推理時的默認閾值是conf0.25, iou0.45但這套默認值在單類別積灰檢測里通常偏松。積灰檢測一旦誤檢運維人員就得跑一趟現(xiàn)場誤報代價高。我一般會先用驗證集掃一遍yolo predict modelbest.pt sourceval_images conf0.4 iou0.5然后看預測結(jié)果里的誤檢數(shù)量。confidence從0.3到0.5逐檔試選擇誤檢數(shù)量和召回率平衡點。太陽能板面反光、邊框陰影、雜草遮擋都會產(chǎn)生高分誤檢閾值設到0.4左右通常能壓掉大部分但也會犧牲部分小面積積灰區(qū)域需要結(jié)合現(xiàn)場接受度來定。5. 積灰檢測常見問題與避坑標注、轉(zhuǎn)換、訓練三類翻車現(xiàn)場這個方向我自己跑的時候踩過不少坑挑五個最典型的寫出來。每條都是真實的現(xiàn)場問題按“現(xiàn)象→原因→解決”寫方便你遇到時對號入座。5.1 VOC轉(zhuǎn)YOLO后框全偏多半是沒按原圖寬高做歸一化現(xiàn)象訓練時loss正常下降但可視化預測框整體向左上或右下偏移框的尺寸比例明顯不對。 原因轉(zhuǎn)換腳本沒有讀size節(jié)點或者size里的寬高和實際圖片分辨率不一致。還有一種可能是XML里存的是縮放后的標注坐標但圖片本身沒縮放。 解決先用PIL讀圖片寬高與XML的size節(jié)點逐一比對轉(zhuǎn)換時統(tǒng)一用圖片實際寬高做分母。我習慣直接在轉(zhuǎn)換腳本里同時讀原圖from PIL import Image img_w, img_h Image.open(jpg_path).size用圖片真實寬高代替XML里的size能避免源標注文件本身沒更新分辨率的問題。5.2 訓練loss收斂但驗證mAP很低先查數(shù)據(jù)泄漏和樣本不平衡現(xiàn)象訓練集mAP能到0.95以上驗證集mAP只有0.6甚至更低且波動大。 原因兩個可能。第一個是驗證集場景和訓練集差異過大比如訓練集全是地面電站平視角度驗證集全是無人機俯拍第二個是積灰面積大的極端樣本都集中在訓練集驗證集只剩小面積積灰。 解決按4.1的分組方式重新劃分確保每個劃分里都有不同面積積灰的樣本。另外檢查驗證集是否存在難樣本比如灰塵顏色和板面底色接近的低對比度圖這類樣本會嚴重拉低mAP但恰恰是現(xiàn)場最需要處理的。5.3 預測時把干凈板面誤檢測成積灰負樣本和閾值要一起調(diào)現(xiàn)象模型在正常光伏板上框出一大片“積灰”尤其反光強烈的時候。 原因這是單類別檢測的老毛病——模型只在正樣本上學習沒見過“干凈的板面”也可以作為背景。如果積灰區(qū)域和板面清洗后的反光區(qū)域紋理相似模型就會混淆。 解決收集負樣本。不需要額外標注直接拉一批干凈光伏板圖片放進訓練集不配txt標簽模型就會把它們當作背景學習。同時配合提高置信度閾值到0.4以上雙管齊下。負樣本來源可以是網(wǎng)上的清洗后電站照片也可以是自己拍的未積灰板面。5.4 類別ID不一致導致訓練報錯單類別也要統(tǒng)一從0開始現(xiàn)象訓練啟動時報錯提示number of classes mismatch或者模型訓練正常但推理時把所有檢測框都歸為0類而0類又是錯誤的類別。 原因VOC里的類別名是字符串dustYOLO是整數(shù)ID。如果你在data.yaml里寫成names: {1: dust}或者轉(zhuǎn)換腳本里用class_names.index(name)1把ID變成1就會出現(xiàn)類別數(shù)對不上。 解決單類別的類別ID固定是0。檢查轉(zhuǎn)換腳本里是否加了1檢查data.yaml里names是否從0開始兩者確認一致再啟動訓練。5.5 文件名對不上導致圖片被跳過訓練前先跑一遍校驗腳本現(xiàn)象訓練日志里顯示圖片數(shù)量比數(shù)據(jù)集少幾十張或者模型對某幾張圖完全檢測不到。 原因圖片是jpg標簽txt名字里多了空格、后綴大小寫不一致——比如IMG_001.JPG對應img_001.txtWindows和Linux文件名大小寫敏感差異會直接漏讀。 解決訓練前先做一次強制校驗from pathlib import Path for split in [train, val]: img_dir Path(fimages/{split}) lbl_dir Path(flabels/{split}) imgs {p.stem.lower(): p for p in img_dir.glob(*.jpg)} for lbl in lbl_dir.glob(*.txt): if lbl.stem.lower() not in imgs: print(f標簽無對應圖片: {lbl.name})這段腳本把所有文件名統(tǒng)一轉(zhuǎn)小寫后比對能快速揪出大小寫不一致、多余空格、后綴差異三類問題。跑一遍再訓練避免靜默丟數(shù)據(jù)。6. 把檢測框變成運維指標積灰面積占比的現(xiàn)場后處理模型輸出的是一堆框運維要的是一個可以排期的指標。常見做法是用檢測框面積除以整塊光伏板面積得到“積灰面積占比”再按占比分清洗優(yōu)先級低于10%不處理10%到30%列入計劃超過30%優(yōu)先清洗。6.1 用檢測框算每塊組件的積灰面積占比思路是先檢測出組件區(qū)域再在組件內(nèi)聚合所有積灰框計算覆蓋比例。如果你的數(shù)據(jù)是單塊板面特寫組件區(qū)域就是整張圖如果是多塊板面的巡檢圖要先拿到組件框。以下代碼按“整圖是一塊板”的假設聚合def dust_ratio(dust_boxes, img_w, img_h): panel_area img_w * img_h dust_area 0.0 for x1, y1, x2, y2 in dust_boxes: # 將歸一化坐標轉(zhuǎn)回像素假設輸入已歸一化 px1, py1 int(x1 * img_w), int(y1 * img_h) px2, py2 int(x2 * img_w), int(y2 * img_h) dust_area (px2 - px1) * (py2 - py1) return min(dust_area / panel_area, 1.0)這段的用途是給出一個可用指標但要注意重復檢測問題。同一塊積灰區(qū)域被模型輸出5個重疊框時面積會被算5次。合理做法是先做NMS或者按中心點聚類再把聚類的框面積合并。6.2 導出ONNX并在連續(xù)幀上做置信度過濾驗證完效果就要考慮部署。把best.pt導出成ONNX格式y(tǒng)olo export modelbest.pt formatonnx imgsz640導出后的ONNX可以在Jetson、工控機、樹莓派上跑CPU或GPU推理。現(xiàn)場巡檢往往是連續(xù)拍攝單幀誤檢不可避免我的習慣是連續(xù)10幀里至少7幀檢測到積灰才觸發(fā)告警用時間維度換掉一半誤報。再疊加一個“相鄰幀檢測框IoU大于0.5才認為是同一目標”的過濾基本能壓住偶發(fā)的光照突變誤檢。另一個低成本交叉驗證是灰度直方圖積灰區(qū)域會讓光伏板表面灰度分布偏離干凈板面的峰值。取檢測框內(nèi)灰度均值和同組件干凈區(qū)域的灰度均值做對比兩者差異低于閾值就認為是一次誤檢。這個方法不增加模型復雜度只作后處理但在低對比度場景下能救回不少誤報。我的實際經(jīng)驗是任何檢測模型到了現(xiàn)場都要按電站重新校準閾值別指望一次訓練吃遍所有電站。如果你調(diào)的模型在A電站很穩(wěn)換到B電站又翻車先檢查訓練集里有沒有B電站的樣本再懷疑模型本身。希望幫到你。本文還有配套的精品資源點擊獲取