數(shù)據(jù)集VOC+YOLO格式實(shí)戰(zhàn)與YOLOv8訓(xùn)練指南)
連續(xù)做了幾條產(chǎn)線的視覺檢測(cè)項(xiàng)目之后我越來越覺得數(shù)據(jù)集才是真正的門檻。算法結(jié)構(gòu)大家都會(huì)調(diào)YOLO也好、其他框架也好真正拉開差距的是你手里有沒有貼合實(shí)際工況的高質(zhì)量缺陷樣本。所以當(dāng)我看到這套“工業(yè)金屬表面缺陷檢測(cè)數(shù)據(jù)集VOCYOLO格式1259張3類別”時(shí)第一反應(yīng)不是嫌棄它小而是覺得只要格式規(guī)整、類別定義符合產(chǎn)線邏輯1259張完全能作為基線數(shù)據(jù)跑通一條完整的工業(yè)檢測(cè)流程。這篇就把這套數(shù)據(jù)集的構(gòu)成邏輯、兩種標(biāo)注格式的實(shí)際差異、用YOLO訓(xùn)練時(shí)的完整操作細(xì)節(jié)以及我在落地過程中踩過的坑一次說清楚。1. 數(shù)據(jù)集的構(gòu)成邏輯為什么偏袒這三類缺陷1.1 三種缺陷在金屬表面的視覺特征先把結(jié)論放前面工業(yè)缺陷檢測(cè)的數(shù)據(jù)集類別越少越好關(guān)鍵是每一類內(nèi)部的特征一致性要高。這套數(shù)據(jù)集的3個(gè)類別我按工業(yè)現(xiàn)場(chǎng)的常駐缺陷推測(cè)大概率是劃痕scratch、壓傷/凹坑dent、銹蝕或氧化斑rust/stain。這類組合之所以常見是因?yàn)樗鼈儗?duì)應(yīng)了金屬加工過程中三條完全不同的失效路徑機(jī)械接觸產(chǎn)生的劃痕、沖壓或磕碰產(chǎn)生的形變、環(huán)境或化學(xué)因素產(chǎn)生的表面變質(zhì)。從視覺特征上看這三類缺陷的區(qū)別其實(shí)很清晰。劃痕在灰度圖上表現(xiàn)為細(xì)長(zhǎng)的低灰度連續(xù)區(qū)域方向性很強(qiáng)邊緣銳利有時(shí)伴隨亮邊壓傷或凹坑則是局部區(qū)域的灰度突變形狀呈塊狀或橢圓狀內(nèi)部紋理和周圍基體有明顯差異某些光照條件下還會(huì)出現(xiàn)中心暗、邊緣亮的光暈效果銹蝕或氧化斑的灰度分布比較雜亂邊緣過渡相對(duì)緩和但顏色信息非常關(guān)鍵在RGB空間里往往偏向棕褐色或暗紅色。在標(biāo)注層面這三類缺陷的box形狀差異很大。劃痕哪怕是長(zhǎng)條狀標(biāo)注框也經(jīng)常是那種長(zhǎng)寬比懸殊的窄矩形壓傷/凹坑則趨近于正方形或?qū)捑匦巍_@個(gè)特征直接決定了訓(xùn)練時(shí)錨框anchor分布是否合理。YOLOv8已經(jīng)弱化了手動(dòng)錨框的設(shè)計(jì)但訓(xùn)練前檢查數(shù)據(jù)集中所有標(biāo)注框的寬高比分布仍然是個(gè)好習(xí)慣——如果發(fā)現(xiàn)大量長(zhǎng)條框說明這個(gè)數(shù)據(jù)集確實(shí)反映了真實(shí)缺陷形態(tài)而不是簡(jiǎn)單畫個(gè)方框湊數(shù)。1.2 1259張樣本在工業(yè)檢測(cè)里算多算少很多剛接觸視覺檢測(cè)的工程師會(huì)有一個(gè)誤區(qū)看到“1259張”就覺得數(shù)據(jù)少得可憐恨不得拿公開的COCO數(shù)據(jù)集來湊。但工業(yè)缺陷檢測(cè)和通用目標(biāo)檢測(cè)有一個(gè)本質(zhì)差異——場(chǎng)景極度狹隘背景相對(duì)可控。COCO的80類物體需要幾千甚至上萬張是因?yàn)槊款愇矬w的外觀變化太大一個(gè)“椅子”可以是辦公椅、餐椅、電競(jìng)椅。而金屬表面缺陷不是這樣同一條產(chǎn)線上的劃痕基本就是那幾種形態(tài)光照固定、材料固定、加工工藝固定缺陷的外觀波動(dòng)范圍其實(shí)遠(yuǎn)小于通用物體。1259張圖假設(shè)里面有3000到4000個(gè)標(biāo)注實(shí)例平均每類1000多個(gè)正樣本對(duì)于二階段或單階段的工業(yè)檢測(cè)模型來說是足以訓(xùn)練出一個(gè)可用基線的數(shù)據(jù)量。配合數(shù)據(jù)增強(qiáng)和合理的先驗(yàn)知識(shí)比如限制檢測(cè)頭的輸出類別、固定輸入尺寸完全能跑出像樣的mAP值。真正傷腦筋的不是數(shù)據(jù)量小而是背景多樣性缺失——如果這1259張圖全是在同一臺(tái)設(shè)備上拍的模型學(xué)到的是“這臺(tái)設(shè)備的背景特征”而不是“缺陷本身的特征”換產(chǎn)線立刻失效。我的經(jīng)驗(yàn)是拿到數(shù)據(jù)先做可視化批量檢查看背景是否單一、光照是否有變化、缺陷是否有重疊遮擋。如果背景多樣性不足后面訓(xùn)練時(shí)數(shù)據(jù)增強(qiáng)里mosaic和random_perspective必須開滿這是在數(shù)據(jù)層面做“虛擬多樣化”的唯一手段。2. VOC與YOLO標(biāo)簽的世界觀差異2.1 兩種標(biāo)注格式的坐標(biāo)系與文件組織這套數(shù)據(jù)集同時(shí)提供了VOC和YOLO兩種格式這是非常良心的一點(diǎn)。兩種格式看似都是在畫框?qū)嶋H底層邏輯完全不同。VOC格式用的是XML文件每個(gè)圖像對(duì)應(yīng)一個(gè)同名XML。bbox的坐標(biāo)是絕對(duì)的像素坐標(biāo)記錄的是xmin, ymin, xmax, ymax四個(gè)值表示框左上角和右下角在原始圖像中的具體位置。這種格式的優(yōu)點(diǎn)是人類可讀性極強(qiáng)任何標(biāo)注工具打開XML都能準(zhǔn)確還原框的位置也方便修改和審查。缺點(diǎn)是同一圖像在縮放、裁剪后XML里的坐標(biāo)就失效了必須重新映射。YOLO格式則是歸一化的相對(duì)坐標(biāo)每個(gè)標(biāo)注目標(biāo)在txt文件里占一行格式為class_id, x_center, y_center, width, height。這里的前四個(gè)值全部除以圖像寬度和高度所以w和h的取值范圍都在0到1之間。這種設(shè)計(jì)的巧妙之處在于模型在訓(xùn)練時(shí)無論輸入尺寸怎么resize標(biāo)注框都自動(dòng)適配不需要做任何坐標(biāo)換算。舉個(gè)具體例子一張1280×1024的圖上有個(gè)劃痕框的絕對(duì)坐標(biāo)是(xmin240, ymin380, xmax680, ymax410)。換算成中心點(diǎn)坐標(biāo)就是((240680)/2, (380410)/2, 680-240, 410-380) (460, 395, 440, 30)再除以圖像的寬高得到Y(jié)OLO格式的行就是class_id 0.359375 0.385742 0.343750 0.029297。這個(gè)數(shù)據(jù)丟給YOLO模型才能直接訓(xùn)練。2.2 標(biāo)簽轉(zhuǎn)格式最容易錯(cuò)的地方拿到雙格式數(shù)據(jù)集時(shí)大部分人的第一反應(yīng)是“既然要用YOLO訓(xùn)練那VOC格式就不管了”。但實(shí)際項(xiàng)目中VOC格式反而更適合做數(shù)據(jù)審查和二次校驗(yàn)YOLO格式適合直接喂模型。兩種格式之間的轉(zhuǎn)換看著簡(jiǎn)單實(shí)際上有幾個(gè)特別容易踩的坑。第一是坐標(biāo)除以寬高時(shí)用錯(cuò)了分母。YOLO的中心點(diǎn)x必須除以圖像寬度y必須除以圖像高度。新手經(jīng)常兩個(gè)都用圖像的長(zhǎng)邊或者直接用圖像的短邊結(jié)果標(biāo)注框全部偏移訓(xùn)練出來AP曲線看著正常實(shí)際推理時(shí)框全部偏到一邊。我在腳本里會(huì)強(qiáng)制加斷言檢查所有歸一化坐標(biāo)是否都在0到1之間一旦有超范圍直接報(bào)錯(cuò)中斷。第二是類別編號(hào)的映射必須和yaml文件嚴(yán)格一致。同一套數(shù)據(jù)VOC的XML里寫的是字符串類別名“scratch”YOLO的txt里寫的是數(shù)字“0”。如果你的yaml文件里類別順序是[stain, scratch, dent]但轉(zhuǎn)換腳本里按照字母序把scratch排到了0模型訓(xùn)練時(shí)就會(huì)把劃痕當(dāng)成銹斑來學(xué)mAP看著還行現(xiàn)場(chǎng)跑起來全是誤判。第三是寬高和中心點(diǎn)順序搞混。YOLO格式的第三、四個(gè)值是width和height不是右下角坐標(biāo)。有相當(dāng)一部分標(biāo)注工具導(dǎo)出時(shí)會(huì)用右下角坐標(biāo)填入這兩個(gè)字段報(bào)文給的txt如果是這種情況訓(xùn)練時(shí)loss會(huì)居高不下。我的排查辦法是隨機(jī)抽幾張圖把txt里的數(shù)值反畫到圖像上目視檢查框的位置和大小是否和缺陷本體吻合。# 我常用的VOC轉(zhuǎn)YOLO腳本片段跑之前先驗(yàn)證再批量轉(zhuǎn) python -c import os, glob, xml.etree.ElementTree as ET from PIL import Image def voc2yolo(xml_path, out_dir, class_dict): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_dict: continue cls_id class_dict[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) 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 assert 0 x_center 1 and 0 y_center 1, fcoord out of range in {xml_path} lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) txt_path os.path.join(out_dir, os.path.splitext(os.path.basename(xml_path))[0] .txt) with open(txt_path, w) as f: f.write(\n.join(lines)) class_dict {scratch: 0, dent: 1, stain: 2} for x in glob.glob(labels_voc/*.xml): voc2yolo(x, labels_yolo, class_dict) 提示任何第三方的格式轉(zhuǎn)換腳本拿到手先拿20張圖做可視化驗(yàn)證再全量處理不要盲目信任腳本本身。標(biāo)注數(shù)據(jù)是整個(gè)項(xiàng)目最貴的資產(chǎn)跑壞了修復(fù)成本極高。3. 用這套數(shù)據(jù)訓(xùn)練YOLOv8的操作細(xì)節(jié)3.1 數(shù)據(jù)集目錄結(jié)構(gòu)與yaml配置YOLOv8是目前工業(yè)檢測(cè)里用起來最順手的版本之一訓(xùn)練這套1259張的數(shù)據(jù)集不需要寫任何自定義網(wǎng)絡(luò)代碼關(guān)鍵是把數(shù)據(jù)集目錄和yaml配置文件寫好。具體目錄結(jié)構(gòu)我習(xí)慣這樣組織metal_defect/ ├── images/ │ ├── train/ # 約940張 │ └── val/ # 約319張 ├── labels/ │ ├── train/ │ └── val/ └── metal_defect.yaml注意一個(gè)細(xì)節(jié)images和labels必須在同一級(jí)目錄下train和val的子目錄名要一一對(duì)應(yīng)圖片名和標(biāo)簽文件名完全一致。YOLOv8會(huì)通過替換后綴的方式查找標(biāo)簽文件如果圖片叫img_001.jpg它會(huì)在labels目錄下找img_001.txt不會(huì)容忍任何命名偏差。yaml文件內(nèi)容非常簡(jiǎn)潔核心就是三行路徑加一行類別列表path: /path/to/metal_defect # 數(shù)據(jù)集根目錄絕對(duì)路徑最穩(wěn) train: images/train # train圖像相對(duì)路徑 val: images/val # val圖像相對(duì)路徑 nc: 3 # 類別數(shù)量 names: [scratch, dent, stain] # 類別名稱順序必須和標(biāo)簽數(shù)字對(duì)應(yīng)這里有個(gè)容易踩坑的點(diǎn)如果你用相對(duì)路徑y(tǒng)aml里的path字段是相對(duì)于當(dāng)前腳本的運(yùn)行目錄解析的。我把訓(xùn)練腳本封裝在自己的工程目錄下結(jié)果那段時(shí)間反復(fù)報(bào)“image not found”最后發(fā)現(xiàn)是我直接改了yaml里的相對(duì)路徑而沒有改path根目錄。最省心的做法是寫死絕對(duì)路徑如果項(xiàng)目要遷移機(jī)器再寫個(gè)小腳本批量替換路徑頭。3.2 訓(xùn)練集/驗(yàn)證集劃分與增強(qiáng)策略1259張的規(guī)模訓(xùn)練驗(yàn)證集劃分不能粗暴地隨機(jī)打亂要按“設(shè)備狀態(tài)”或“時(shí)間批次”來分。如果整套數(shù)據(jù)是在不同時(shí)段、不同批次采集的建議一個(gè)批次的圖全部進(jìn)入訓(xùn)練集或驗(yàn)證集避免同一批次的相似圖像同時(shí)出現(xiàn)在兩邊把驗(yàn)證集的評(píng)估指標(biāo)虛高。工業(yè)現(xiàn)場(chǎng)最常見的劃分比例是8:2或9:1我這里推薦8:2因?yàn)槿毕輼颖咎贂r(shí)驗(yàn)證集會(huì)失去統(tǒng)計(jì)意義。訓(xùn)練參數(shù)方面我給的初始建議是yolo detect train \ data/path/to/metal_defect.yaml \ modelyolov8n.pt \ epochs150 \ imgsz640 \ batch16 \ lr00.01 \ augmentTrue \ mosaic1.0 \ mixup0.2 \ fliplr0.5 \ scale0.5 \ patience30如果你是第一次訓(xùn)這套數(shù)據(jù)個(gè)人建議用yolov8n或yolov8s起步。小模型在1259張數(shù)據(jù)上不容易過擬合訓(xùn)練速度快迭代效率高。等到模型結(jié)構(gòu)和超參數(shù)驗(yàn)證得差不多了再換更大的模型做最終版本。數(shù)據(jù)增強(qiáng)的開法需要格外小心。mosaic在YOLOv8里默認(rèn)是開啟的它把4張圖拼在一起訓(xùn)練對(duì)小目標(biāo)檢測(cè)非常友好但工業(yè)缺陷場(chǎng)景下部分缺陷會(huì)被拼貼截?cái)鄬?dǎo)致標(biāo)注框被強(qiáng)制改小。如果你的缺陷長(zhǎng)寬比特別極端比如很長(zhǎng)的劃痕mosaic1.0可能會(huì)讓模型學(xué)不到完整的長(zhǎng)劃痕形態(tài)。我建議先保持mosaic0.8等看驗(yàn)證集Recall不對(duì)勁再調(diào)。HSV增強(qiáng)、平移縮放這些在金屬表面檢測(cè)里可以適度開啟但別太猛。金屬表面的缺陷特征通常是低對(duì)比度的HSV增強(qiáng)尤其是飽和度變化太大會(huì)讓“銹斑”的顏色特征漂移模型學(xué)到的顏色先驗(yàn)不再可靠。一般把hsv_h設(shè)為0.01、hsv_s設(shè)為0.5、hsv_v設(shè)為0.5就夠用了。4. 小樣本條件下的訓(xùn)練監(jiān)測(cè)與故障定位4.1 loss曲線怎么算正常1259張數(shù)據(jù)訓(xùn)練YOLO最怕的不是acc低而是“看著收斂了實(shí)測(cè)一塌糊涂”。所以我建議訓(xùn)練過程中把box_loss、cls_loss、dfl_loss和驗(yàn)證集的mAP50、mAP50-95全部記錄下來用可視化工具盯曲線走向。正常的訓(xùn)練過程是train loss在前20個(gè)epoch快速下降之后進(jìn)入緩慢下降平臺(tái)val loss先降后穩(wěn)mAP50在30到50個(gè)epoch間快速抬升然后小幅震蕩緩慢增長(zhǎng)。如果出現(xiàn)val loss持續(xù)上升而train loss繼續(xù)下降的情況基本可以判斷過擬合已經(jīng)開始了。此時(shí)回滾到val loss最低的那個(gè)epoch權(quán)重然后減少epoch數(shù)或者增強(qiáng)正則項(xiàng)。有一個(gè)反常識(shí)的點(diǎn)需要提醒工業(yè)缺陷檢測(cè)里mAP50-95的作用沒那么大更重要的是mAP50和低置信度下的召回率。因?yàn)楫a(chǎn)線上缺陷判定是二元決策——有缺陷就NG沒有就OK定位精度只要能確保后續(xù)裁剪或機(jī)械臂抓取夠用就行。mAP50-95對(duì)框的精確位置要求更高在缺陷形態(tài)復(fù)雜的小數(shù)據(jù)集上反而很難漲別把它當(dāng)成唯一追求。4.2 常見翻車現(xiàn)場(chǎng)與排查方法我見過最多的翻車情況有兩類。第一類是標(biāo)簽噪聲較大標(biāo)注框邊緣超出缺陷本體太多。YOLO模型會(huì)把背景信息也學(xué)進(jìn)特征里導(dǎo)致推理時(shí)判斷框右邊界對(duì)得很準(zhǔn)、左邊界偏出半個(gè)身位。這種問題訓(xùn)練時(shí)看不出來甚至mAP還挺高一到產(chǎn)線上需要精確切割區(qū)域時(shí)就暴露了。排查辦法是畫PR曲線觀察在不同IoU閾值下AP的衰減速度如果IoU從0.5提高到0.75時(shí)AP斷崖式下跌大概率是標(biāo)簽框不夠緊致。第二類是訓(xùn)練和推理的預(yù)處理不一致。有些工程師在訓(xùn)練時(shí)開了letterbox等比縮放填充推理部署時(shí)直接resize成正方形導(dǎo)致目標(biāo)形狀被拉伸或壓扁。金屬表面的劃痕本來就是細(xì)長(zhǎng)結(jié)構(gòu)一旦寬高比被破壞模型輸出會(huì)大量漏檢。為了規(guī)避這種問題我統(tǒng)一在推理代碼里復(fù)用YOLO的letterbox邏輯。還有一個(gè)容易被忽略的排查點(diǎn)檢查驗(yàn)證集里“容易漏檢的樣本”到底長(zhǎng)什么樣。把驗(yàn)證集里所有漏檢圖像單獨(dú)提取出來和正確檢出的圖像對(duì)比你會(huì)很快發(fā)現(xiàn)規(guī)律。比如漏檢的全部是暗光條件下的圖或者全部是背景紋理較重的圖。這些規(guī)律的發(fā)現(xiàn)對(duì)后續(xù)擴(kuò)充數(shù)據(jù)有精準(zhǔn)指導(dǎo)意義比盲目加數(shù)據(jù)高效得多。5. 這只是開始工業(yè)落地的擴(kuò)展操作5.1 從數(shù)據(jù)到產(chǎn)線差多遠(yuǎn)必須潑一盆冷水跑通YOLO檢測(cè)只是工業(yè)視覺項(xiàng)目的20%剩下80%在于你怎么把模型輸出變成產(chǎn)線可用的決策邏輯。這套1259張的數(shù)據(jù)集可以直接用于模型原型驗(yàn)證但直接上產(chǎn)線的話至少在以下幾方面需要補(bǔ)充第一是負(fù)面樣本無缺陷樣本的收集。缺陷檢測(cè)項(xiàng)目的難點(diǎn)從來不是把缺陷找出來而是不把良品誤判成缺陷。如果數(shù)據(jù)集里只有缺陷圖模型會(huì)對(duì)“正常狀態(tài)”一無所知隨便一個(gè)反光、一個(gè)指紋、一個(gè)機(jī)臺(tái)震動(dòng)產(chǎn)生的重影都會(huì)被判定為NG。我見過剛開始做檢測(cè)項(xiàng)目的團(tuán)隊(duì)第一版模型誤檢率高達(dá)30%原因就是訓(xùn)練集里缺正常的負(fù)樣本。第二是現(xiàn)場(chǎng)的圖像采集系統(tǒng)性規(guī)劃。產(chǎn)線上需要在不同燈光角度、不同曝光時(shí)間、不同工件材質(zhì)表面各拍一輪把這些真實(shí)工況下的圖像注入數(shù)據(jù)集做增量訓(xùn)練。1259張的基座數(shù)據(jù)用來冷啟動(dòng)產(chǎn)線上線后每?jī)芍芑貍饕慌e(cuò)檢和漏檢樣本迭代三個(gè)月后模型可靠性會(huì)有質(zhì)的變化。第三是缺陷分級(jí)與業(yè)務(wù)規(guī)則結(jié)合。比如劃痕長(zhǎng)度小于2毫米且位于非功能區(qū)時(shí)在業(yè)務(wù)邏輯里可能判定為“可接受外觀”但模型輸出的缺陷框中并沒有體現(xiàn)這個(gè)信息。正確做法是讓檢測(cè)模型輸出所有潛在的缺陷位置和置信度再用后處理邏輯結(jié)合長(zhǎng)度、面積、位置、缺陷間距等參數(shù)做最終判定。5.2 如何用這套數(shù)據(jù)快速啟動(dòng)自己的產(chǎn)線缺陷庫如果你手里有一套類似的金屬表面缺陷數(shù)據(jù)我建議按下面這套流程走能省掉大量試錯(cuò)時(shí)間解壓數(shù)據(jù)后先做標(biāo)簽分布統(tǒng)計(jì)明確每個(gè)類別有多少實(shí)例、框的寬高比分布如何這直接決定你對(duì)數(shù)據(jù)增強(qiáng)的敏感度。做一次全量可視化檢查把標(biāo)注框畫在原圖上輸出成一張拼接大圖花半小時(shí)掃一遍排除標(biāo)注錯(cuò)位、label name拼寫錯(cuò)誤、圖像損壞三類問題。按照2:8劃分驗(yàn)證集和訓(xùn)練集按時(shí)間或批次分組不要純隨機(jī)。用自己的業(yè)務(wù)場(chǎng)景選擇輸入分辨率。513×513到640×640之間對(duì)小型缺陷相對(duì)友好太大容易把背景細(xì)節(jié)都卷進(jìn)來導(dǎo)致過擬合。第一次訓(xùn)練直接用默認(rèn)參數(shù)不要從網(wǎng)上亂抄別人的復(fù)雜配置。先把baseline跑出來看mAP50和過擬合趨勢(shì)再?zèng)Q定動(dòng)哪一項(xiàng)超參。導(dǎo)出ONNX或TensorRT模型時(shí)必須檢查預(yù)處理細(xì)節(jié)尤其是歸一化系數(shù)YOLOv8用的是0-1縮放不是ImageNet的mean/std歸一化搞錯(cuò)了會(huì)在部署端直接引發(fā)推理異常。從這套1259張的數(shù)據(jù)出發(fā)你得到的不僅是一個(gè)能跑的模型更是一整套工業(yè)視覺項(xiàng)目從數(shù)據(jù)組織、模型訓(xùn)練到部署驗(yàn)證的方法論。我個(gè)人的體會(huì)是數(shù)據(jù)集的價(jià)值不在于有多大而在于它的組織和標(biāo)注有多規(guī)范以及你能否從它身上挖掘出產(chǎn)線場(chǎng)景的規(guī)律。先把這套數(shù)據(jù)用透后續(xù)不管換成哪種金屬材料、哪類缺陷你都不會(huì)再覺得“數(shù)據(jù)不夠”是攔住項(xiàng)目的致命問題了。