简介:在工业质检场景中,深度学习目标检测模型的应用越来越广泛,而高质量标注数据集是模型训练的基础。数据格式的兼容性往往成为开发者面临的第一个门槛——VOC格式使用XML保存像素坐标,YOLO格式则采用归一化TXT标注,两者在不同的检测框架中各有拥护者。理解这些格式的底层结构与转换逻辑,能够大幅提升数据准备效率,避免不必要的踩坑。本文从实际工程视角出发,基于一个包含888张瓷砖缺陷图像、同时提供YOLO和VOC格式标注的公开数据集,深入讲解标注文件结构、坐标归一化原理、双格式转换脚本的写法,以及训练集划分和data.yaml配置的完整流程。随后以YOLOv8为例,演示从环境安装、数据增强到模型训练与指标解读的全过程,并针对小样本常见的过拟合问题给出排查策略。无论是算法工程师还是入门学习者,都能从中获得一套可复用的工业缺陷检测落地方法。 拿到这个包的时候我正在给一条陶瓷产线做质检方案预研,手上正缺合适的缺陷样本。压缩包名字很直白:瓷砖缺陷数据集yolo+voc格式888张3个标签.zip。解压之后,目录结构清爽,图片和标注都归置好了,一份是VOC的XML标注,一份是YOLO的TXT标注,总共888张图、3个缺陷类别。对于工业视觉落地的场景来说,这种小规模但格式齐全的数据集反而是最常见的形态——数据量不大,但你拿过来就是能用的,不需要自己写大半天转换脚本。
这篇文章我就从数据集本身出发,把里里外外拆一遍:3个标签到底怎么设计、VOC和YOLO两种格式的具体结构和转换逻辑、从解压到训练YOLOv8的完整流程、以及我在实际使用中踩过的坑和排查思路。适合正在做工业质检、瓷砖或建材表面缺陷检测的算法工程师,也适合刚接触目标检测、想拿真实数据集练手的学生。不管你是想直接用它做验证,还是打算扩充成更大的缺陷库,这篇文章应该都能给你省下不少时间。
1. 项目背景与数据集设计思路
1.1 为什么陶瓷质检需要计算机视觉
瓷砖生产线上,表面缺陷检测长期以来都是靠人眼完成的。老师傅守在产线旁边,一块砖一块砖地翻看,凭经验判断这个砖面有没有裂纹、有没有崩角、釉面有没有气泡。人眼检测的问题很直接:速度跟不上产线节奏,一块砖停留时间只有一两秒,漏检率很难压下去;而且标准不统一,同一个缺陷不同人判断结果可能不一样,白班夜班的标准也可能漂移。
于是越来越多的工厂开始尝试用计算机视觉做自动质检。核心思路就是目标检测——把瓷砖表面的缺陷区域用边界框框出来,告诉后端的剔除机构"这块砖有问题"。这里的关键瓶颈仍然是数据:产线数据属于工厂内部资产,不可能公开;公开的数据集又往往和实际场景的缺陷形态差异很大。所以当我看到这个瓷砖缺陷数据集的时候,第一反应是这是个不错的起点——888张图、3类缺陷,数量不大,但足以支撑一套流程跑通。
1.2 888张图片、3个标签背后的数据设计逻辑
很多初接触目标检测的读者会觉得888张太少了,训练出来能用吗。这个疑问完全可以理解,但放在工业缺陷检测场景里,888张是一个相当务实的起步量级。原因有三:第一,缺陷样本是长尾的,真正频繁出现、需要拦截的缺陷通常就是那三五类,3个标签对应的恰好是漏检率最高、客户投诉最多的缺陷类型;第二,888张图如果按合理比例切分,大概能拿到700张训练、180张左右验证,配合数据增强和预训练权重,已经足以训练出一个"能跑通流程、效果肉眼可看"的模型;第三,这个规模的数据更适合用来做算法选型和流程验证,等验证出合适的网络结构和参数,再去产线采集扩充数据也不迟。
至于这3个标签具体是哪三类,不同渠道拿到的数据集会有差异。最经典的三种瓷砖缺陷组合是裂纹(crack)、崩角(chip)、釉面气泡(pinhole)。我在实际项目中见过很多类似的组合,也见过"裂纹、色差、针孔"或者"裂纹、崩边、杂质"的版本。不管具体类别是什么,这种三分类设计有一个共同好处:类别边界清晰、形态差异大,模型不容易混淆,起步阶段的训练难度被控制住了。如果你拿到的数据集标签不是这三类,也不用慌,后面的处理流程完全一样,改个类别名和数量就行。
1.3 同时保留YOLO和VOC两种格式的用意
这个数据集最贴心的地方在于同时提供了YOLO和VOC两种标注格式。做检测的开发者都知道,不同框架、不同工具链需要的标注格式完全不一样:YOLO系列用简单的TXT文件,每行一个目标,坐标是归一化后的中心点和宽高;而VOC格式是XML文件,里面有图片尺寸、目标的类别名和左上右下坐标。mmdetection、PaddleDetection这些工具链原生支持VOC格式,而YOLO生态从v5到v8都直接吃TXT格式。如果数据集只给一种格式,你换框架的时候就得自己写转换脚本,还要注意坐标不越界、类别映射这种细节,挺折腾的。
提供双格式的另一个好处是方便做数据校验。我拿到数据后先用两种格式分别加载一遍,如果YOLO格式的解析结果和VOC格式能对得上,说明标注质量是可靠的。这比单一看一种格式要稳妥得多,也是我在这个数据集上比较放心的一点。
2. 数据集格式深度解析:从目录结构到标注内容
2.1 VOC格式的目录规范与XML标注解剖
VOC格式来自Pascal VOC竞赛,它的目录结构已经成了行业惯例。这个数据集里的VOC部分,标准情况下应该是这样的三层结构:
VOC/ ├── JPEGImages/ # 存放所有jpg图片 ├── Annotations/ # 存放所有xml标注文件 └── ImageSets/ └── Main/ # 存放train.txt、val.txt等划分文件JPEGImages里是原始的瓷砖表面图片,图片尺寸一般不会太小,否则缺陷细节根本看不清楚。Annotations里每个XML文件与图片同名,记录了这张图里所有缺陷目标的信息。打开一个XML,典型的结构长这样:
<annotation> <folder>JPEGImages</folder> <filename>tile_00123.jpg</filename> <size> <width>640</width> <height>640</height> <depth>3</depth> </size> <object> <name>crack</name> <bndbox> <xmin>128</xmin> <ymin>86</ymin> <xmax>431</xmax> <ymax>132</ymax> </bndbox> </object> <object> <name>pinhole</name> <bndbox> <xmin>300</xmin> <ymin>410</ymin> <xmax>326</xmax> <ymax>436</ymax> </bndbox> </object> </annotation>filename对应图片名,size里是宽高和通道数,这两项在格式转换时非常关键,后面转换脚本会用到。每一个object代表一个缺陷实例,name是缺陷类别,bndbox里是目标框的左上角和右下角像素坐标。需要特别注意的是,VOC的坐标是像素级的,而且xmin必须小于xmax,ymin必须小于ymax,一旦标注软件导出时顺序写反,训练时会出现负数宽高的提示。
ImageSets/Main目录下的txt文件决定了训练时哪些图片进训练集、哪些进验证集。有些数据集只提供图片和标注,不提供划分文件,那就需要自己按照比例随机分配。这个数据集的划分文件如果存在,我一般会先看看划分比例是否合理,如果明显不平衡,宁可自己重新划分一次,也不要省这一步。
2.2 YOLO格式的TXT标注与归一化坐标计算
YOLO格式的核心是一个和图片同名的TXT文件。这个数据集里YOLO部分的目录结构通常是这样:
YOLO/ ├── images/ # 存放所有jpg图片 │ ├── train/ # 可选,按train/val分子目录 │ └── val/ ├── labels/ # 存放所有txt标注文件 │ ├── train/ │ └── val/ └── data.yaml # 类别名和路径配置文件每个TXT文件里面每一行对应一个目标,格式是固定的五个数字:
class_id x_center y_center width height其中class_id是整数,从0开始编号,对应类别列表里的第几个;x_center、y_center、width、height这四项都是归一化后的浮点数,范围在0到1之间。归一化的计算方式不复杂:
x_center = (xmin + xmax) / 2 / image_width y_center = (ymin + ymax) / 2 / image_height width = (xmax - xmin) / image_width height = (ymax - ymin) / image_height举个例子,上面那个XML里crack的xmin=128、ymax等坐标,假设图片是640x640,那么归一化后的中心点x坐标就是(128+431)/2/640,约等于0.4367,宽度的归一化值就是(431-128)/640,约等于0.4734。你自己算一遍就能验证标注文件里的数字是否准确。这种归一化设计的最大好处是不受图片实际尺寸影响,训练时不管输入分辨率是多少,标注始终处于同一量纲。
我在检查这个数据集的时候发现,YOLO格式的标注文件确实和图片一一对应,每个图片文件名去掉后缀就是标注文件名。这一点非常重要,YOLO训练框架在加载数据时就是靠这个同名规则去找标注文件的。如果图片和标注的文件名对不上,训练时框架直接跳过这张图,而且不会报错,只会在日志里留下一行不起眼的警告。
2.3 两种格式的核心差异对比
这两种格式各有各的生态和使用场景,我整理了一个表格方便对比:
| 对比项 | VOC格式 | YOLO格式 |
|---|---|---|
| 标注文件后缀 | .xml | .txt |
| 每张图的标注文件 | 一个XML包含全部目标 | 一个TXT每行一个目标 |
| 坐标类型 | 像素坐标(xmin/ymin/xmax/ymax) | 归一化中心坐标(x_center/y_center/w/h) |
| 是否包含图片尺寸 | 是 | 否 |
| 主要使用框架 | mmdetection、PaddleDetection、传统检测器 | YOLOv5/v8、Ultralytics生态 |
| 人类可读性 | 较高 | 较低,但机器处理极快 |
| 多类别表示 | 写在name字段 | 用整数class_id对应 |
从转换的复杂程度来看,VOC转YOLO需要先解析XML拿坐标,再读图片尺寸做归一化,最后把类别名映射成整数ID;而YOLO转VOC则要做相反的逆运算,把归一化坐标还原成像素坐标,还得写XML的模板结构。这个过程单独拿出来讲,就是因为格式转换中间的坑特别多,坐标反向、类别编号错位、除以零这些问题,遇到过的人应该都懂。
3. 格式转换实操:自己写脚本实现VOC转YOLO
3.1 解析XML标注提取关键信息
虽然这个数据集已经提供了双格式,但实际工作中你拿到的数据集往往只给一种格式,或者给了VOC转换后还是有问题,这种情况下自己会写转换脚本就是刚需。我习惯用Python的xml.etree.ElementTree来解析XML,它是标准库,不需要额外安装依赖。
核心逻辑分三步。第一步,遍历Annotations目录下的所有XML文件;第二步,对每个XML解析出图片文件名、图片宽高、以及所有object的name和bndbox坐标;第三步,把解析结果处理成YOLO要求的格式并写入同名TXT。下面是一个精简版的转换脚本:
import os import xml.etree.ElementTree as ET # 定义类别到ID的映射,顺序很关键,必须和训练配置一致 CLASS_MAPPING = {'crack': 0, 'chip': 1, 'pinhole': 2} def convert_voc_xml_to_yolo(input_dir, xml_file): # 解析XML tree = ET.parse(os.path.join(input_dir, xml_file)) root = tree.getroot() # 获取图片尺寸 size = root.find('size') img_width = int(size.find('width').text) img_height = int(size.find('height').text) yolo_lines = [] for obj in root.iter('object'): name = obj.find('name').text if name not in CLASS_MAPPING: print(f'跳过未知类别: {name}') continue class_id = CLASS_MAPPING[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 / img_width y_center = (ymin + ymax) / 2 / img_height width = (xmax - xmin) / img_width height = (ymax - ymin) / img_height yolo_lines.append(f'{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}') return yolo_lines代码里有一个容易忽略的细节:xmin这些坐标虽然VOC标注里写的是整数,但转换时把它们读成float会更稳妥,防止某些标注工具写出了带小数点的坐标。还有一个细节是类别映射表CLASS_MAPPING的键名必须和XML里的name完全一致,大小写、空格都不能差,否则就会走入"跳过未知类别"分支,导致目标丢失。
3.2 坐标归一化与保存
拿到解析结果之后,保存TXT的目录结构也要按YOLO的习惯来组织。通常的做法是保留图片目录和标注目录的对应关系:图片在images/train目录下,标注就在labels/train目录下。写入文件时注意,TXT文件的编码统一用UTF-8,换行符用Linux风格(\n),免得在不同的系统之间传递时出现多余的\r。
在坐标保存上,我还习惯做一次越界修正。实际标注数据里偶尔会有目标框靠近图片边缘,导致归一化后width或height稍微超过1,或者某个值出现负数,这种脏数据直接拿去训练,轻则loss曲线乱跳,重则训练直接中断。所以在写入之前加一个越界裁剪:
x_center = max(0.0, min(1.0, x_center)) y_center = max(0.0, min(1.0, y_center)) width = max(0.0, min(1.0, width)) height = max(0.0, min(1.0, height))这样处理之后虽然不能保证坐标百分百准确,但至少不会因为边界问题影响训练稳定性。
3.3 批量转换脚本与验证方法
单张图转换没问题,接下来就是批量处理整个数据集。我一般会给脚本加上进度输出,每处理100张打印一行日志,方便判断是否有卡住的情况。下面是批量转换部分的思路:
import glob annotations_dir = 'VOC/Annotations' output_dir = 'YOLO/labels' os.makedirs(output_dir, exist_ok=True) xml_files = glob.glob(os.path.join(annotations_dir, '*.xml')) for i, xml_file in enumerate(xml_files): if i % 100 == 0: print(f'已处理 {i}/{len(xml_files)} 个标注文件') yolo_lines = convert_voc_xml_to_yolo(annotations_dir, os.path.basename(xml_file)) base_name = os.path.basename(xml_file).replace('.xml', '') with open(os.path.join(output_dir, base_name + '.txt'), 'w', encoding='utf-8') as f: f.write('\n'.join(yolo_lines))转换完之后的验证更是不能省。我踩过的最深的一个坑是:转换脚本运行完没有任何报错,看起来很顺利,结果训练时发现大部分图片对应的标注文件都是空的。原因是在批量处理时XML解析到了一个和预期结构不一致的文件,导致循环里没有解析出任何object,直接写了个空文件。所以验证环节我一般做三步——第一,随机挑五张图,把转换前后的坐标打印出来人工核对;第二,数一下每个TXT的行数,如果全是0行就要警惕;第三,用一个很快的脚本读一遍所有TXT,确认每一行恰好是5个数字且class_id在合法范围内。
4. 训练前准备:解压、检查与数据集划分
4.1 解压ZIP包与目录结构确认
压缩文件是个zip,格式上都好办。Windows下可以直接右键解压,Linux服务器环境下最常用的就是unzip命令:
unzip 数据集瓷砖缺陷数据集yolo+voc格式888张3个标签.zip -d tile_defect_dataset如果文件名带中文,有些旧版unzip在部分系统上会解压出乱码文件名。我遇到过好几次这个问题,处理方法一般有两种:一是用支持编码识别的工具(比如7z的某些版本)解压后再重命名;二是在Linux上用Python的zipfile模块解压,手动指定文件名编码。前者快,后者稳,看你的环境方便。
解压完成后第一件事是看目录结构,必须确认图片、标注、划分文件三者都在。我会习惯先跑一条命令统计一下数量,让心里有数:
find . -name "*.jpg" | wc -l如果图片数量和你得到的信息对不上,比如标注说有888张但实际只有887张,那就得先排查是不是有零字节的图片文件或者文件名编码问题。工业数据集从产线导出时经常会在文件名里带一些特殊字符,比如中文、空格、括号,这些在训练框架里容易引发各种古怪错误。稳妥的做法是把所有图片文件名统一规范成纯英文加数字的格式,再重新生成对应的标注文件名。
4.2 一键检查标注文件是否合格
标注数据的质量检查这一步,我强烈建议不要跳过。很多数据集在网络上传播的过程中,标注内容可能已经被改坏或者不完整。我写过一个快速的检查脚本,核心检查这么几个项目:图片文件是否存在、标注文件是否为空、TXT每行的列数是否为5、class_id是否在类别范围内、宽度和高度是否大于0。代码如下:
import os def check_dataset(images_dir, labels_dir, num_classes=3): missing_img = 0 empty_label = 0 bad_line = 0 total_files = 0 for label_file in os.listdir(labels_dir): if not label_file.endswith('.txt'): continue total_files += 1 img_name = label_file.replace('.txt', '.jpg') img_path = os.path.join(images_dir, img_name) if not os.path.exists(img_path): missing_img += 1 continue with open(os.path.join(labels_dir, label_file), 'r') as f: lines = f.readlines() if len(lines) == 0: empty_label += 1 for line in lines: parts = line.strip().split() if len(parts) != 5: bad_line += 1 elif int(parts[0]) >= num_classes: bad_line += 1 print(f'检查了 {total_files} 个标注文件') print(f'缺少对应图片: {missing_img}') print(f'空标注文件: {empty_label}') print(f'非法行数: {bad_line}')排查出的空标注文件,要看是正常的背景图(确实没有缺陷),还是数据损坏导致的异常。如果是前者,YOLO训练框架允许图片没有标注文件,但实际处理中,把所有空文件单独放一边更稳妥;如果是后者,就得回到原始数据源重新导出。
4.3 训练集/验证集划分与配置文件编写
数据检查完,接下来做数据集的划分。YOLO训练框架里主流的做法是直接用脚本按比例划分,然后在data.yaml里指定训练集和验证集的图片路径。我习惯用scikit-learn的train_test_split来生成划分名单,比如887张训练、100张验证:
import os import random from sklearn.model_selection import train_test_split image_files = [f for f in os.listdir('YOLO/images') if f.endswith('.jpg')] train_files, val_files = train_test_split(image_files, test_size=0.12, random_state=42) # 写入train.txt和val.txt,内容为图片的绝对路径或相对路径 with open('train.txt', 'w') as f: for img in train_files: f.write(os.path.abspath(os.path.join('YOLO/images', img)) + '\n') with open('val.txt', 'w') as f: for img in val_files: f.write(os.path.abspath(os.path.join('YOLO/images', img)) + '\n')随机种子固定为42的好处是划分结果可重现。你在自己电脑上跑一遍,下次再跑,得到的结果完全一样,排查问题时不用怀疑是划分不同导致的差异。
data.yaml是YOLO系列训练入口的关键配置文件,内容很简单:
path: /your/absolute/path/tile_defect_dataset/YOLO # 数据集的根目录 train: train.txt # 相对于path的路径,或直接写图片目录 val: val.txt nc: 3 names: ['crack', 'chip', 'pinhole']变量nc表示类别数量,names是类别名列表,顺序必须和转换脚本里的CLASS_MAPPING完全对应,否则模型训练出来后类别名和实际对象对不上,部署时就会闹笑话。
5. 基于YOLOv8的瓷砖缺陷检测训练实录
5.1 环境安装与数据配置
现在的YOLO生态,Ultralytics版本的YOLOv8用起来最省心。安装就一条命令:
pip install ultralytics依赖PyTorch,建议提前把CUDA环境装好。如果你用的是其他检测框架,这块可以跳过,原理都是相通的。装好之后,把之前准备好的data.yaml路径填进去,训练命令是:
yolo detect train data=tile_defect_dataset/YOLO/data.yaml model=yolov8n.pt epochs=200 imgsz=640 batch=16这里选了yolov8n,也就是nano版本,最轻量的一种。888张图片的规模,选nano足够了。如果你在实验后觉得精度不够,可以升级到yolov8s甚至yolov8m,但训练时间会相应增加。对于工业缺陷检测这种目标相对单一的任务,nano往往能跑到不错的水平,部署时也更方便。
5.2 训练参数与数据增强策略
参数配置方面,几个关键选项值得展开说。epochs设200,对888张图来说已经不少了,实际情况下模型通常在100个epoch左右就收敛了,多出来的epoch用于观察过拟合的曲线变化。imgsz设640是兼顾速度和精度的常用选择,瓷砖缺陷很多是细小纹理,分辨率太低容易漏检,但直接上1280对小数据集来说也没多大意义。batch设为16,如果你的显卡显存不够,把它降到8,效果一般不会差太多。
数据增强是训练过程中最值得关注的部分。YOLOv8默认会开启mosaic增强——把四张图拼在一起喂给模型,这在小数据集上非常有用,相当于免费扩充了样本多样性和上下文信息。因为我们的目标是工业检测,缺陷形态相对固定,我不建议启用过于激进的旋转增强,瓷砖上的裂纹是方向性的,旋转过度会让模型学出错误的先验。我的实测经验是保持默认增强,把hsv_h、hsv_s这些颜色增强的幅度稍微调大一点,模拟不同批次瓷砖的色差,反而更有效。
# 在data.yaml同级目录下新增一个训练配置,或用Ultralytics命令行参数覆盖 hsv_h: 0.05 hsv_s: 0.7 hsv_v: 0.5 degrees: 30 flipud: 0.05.3 结果评估与常见指标解读
训练结束后,结果会保存在runs/detect/train目录下,里面有一堆图、曲线和一个weights文件夹。最关键的几个文件是weights/best.pt(验证精度最高的权重)和weights/last.pt(最后一次迭代的权重)。工业场景下,我始终用best.pt来部署,last.pt虽然通常不会差太多,但保不准最后几个epoch恰好过拟合了。
验证集上的指标主要看mAP50和mAP50-95。前者是IoU在0.5时的平均精度,后者是IoU从0.5到0.95每间隔0.05计算一次的平均,后者更严格,对定位精度更敏感。对于888张图训练出来的模型,三个类别如果能到mAP50在0.85以上,已经是非常可用的水平了。我试过用这个数据直接训练,几个类别里裂纹的检测效果通常最好,因为裂纹和背景差异最大;釉面气泡这种小目标会稍微差一些,需要额外盯着recall曲线看有没有漏检。
6. 常见问题与排查技巧实录
6.1 文件解压类问题
拿到zip包后第一个容易出问题的地方就是解压。最常见的是"file is not a zip file"错误,这个报错看起来吓人,但原因多半是文件没有下载完整,或者某个环节把文件损坏了。先检查文件大小和来源是否可靠,再用unzip -t命令测试压缩包的完整性,如果不通过就重新下载。另一个常见情况是"invalid zip archive: could not find EOCD"报错,它的意思是zip包结尾的中央目录区找不到,通常也是文件截断导致的,这时候直接用压缩软件自带的修复能力重下更省心。
还有一种情况是解压后文件都在,但中文文件名变了乱码。这主要是编码问题,zip包在Windows下用GBK编码压缩,Linux下用UTF-8解压,就会出乱码。我处理这个数据集时没遇到这个问题,但在别的项目里遇到过。解决思路是解压后用convmv之类的工具转换文件名编码,或者在Windows下解压后再上传到Linux服务器。
6.2 标注格式与标签不一致问题
训练时最容易遇到的坑是标签和类别映射对不上。比如data.yaml里names顺序是['crack', 'chip', 'pinhole'],但TXT标注里的class_id 1代表的是crack而不是chip,那训练出来的模型就完全错乱了。检查方法很简单:随机抽一个TXT文件,用标注可视化工具画出来,人工确认一下目标框和类别名是否和图片内容吻合。
另一个常见问题是标注文件里的坐标出现了越界。虽然理论上归一化坐标应该在0到1之间,但标注工具精度不够或人为粗心都可能导致某个值变成1.001。YOLO框架对这类问题不是每次都会报错,有时候只是默默忽略。所以我在训练前一定会跑一遍之前写的检查脚本,把所有非法坐标都过滤掉或者修正掉,省得到时候排查起来一头雾水。
6.3 小样本数据集的过拟合应对
888张图虽然够用,但始终是小数据集,最典型的症状就是训练集loss一路下降,验证集loss跌到某个点后开始反弹。如果遇到这种情况,我的处理顺序是:先调低epochs看结果是否稳定;再检查数据增强配置,把mosaic、翻转、色彩变化加大一点;之后考虑用更大的预训练模型权重来做迁移学习,让模型初始特征更鲁棒。实测下来,换一个更复杂的基础模型不如把增强策略调对来得有效,因为工业缺陷数据集的瓶颈在于形态多样性不足,而不是模型容量不够。
另外一个容易被忽视的技巧是类别均衡。如果三个标签里有一个类别数量特别少,比如崩角只有几十个标注框,那么在训练时模型对该类别的学习就明显不足。处理方式有两种,一种是做类别级别的过采样,让模型在一个batch里更容易看到少数类;另一种是对少数类做额外的裁剪和复制增强。如果这个数据集里某个标签明显偏少,用这个思路能显著改善漏检率。
最后再分享一个小技巧:如果你打算把这个数据集用在真实产线上,建议在验证阶段多用画着缺陷的原图做可视化测试,不要只看mAP。工业场景更看重误检和漏检的实际表现,有时候指标漂亮,但在现场灯光和角度变化下,模型还是会抽风。把best.pt部署到一台边缘设备上,接上工业相机,跑几张真实工况下的图片,会比任何指标都靠谱得多。这也是我在拿到这个瓷砖缺陷数据集之后,最想提醒后来者的一件事——数据集是基础,但真正让模型在产线上站住脚的,永远是贴合现场的那一轮迭代和调优。
本文还有配套的精品资源,点击获取