简介:这份易拉罐缺陷识别数据集面向工业质检方向的算法工程师、高校学生与视觉项目开发者,聚焦罐体表面划痕、罐底异常等缺陷的自动检测任务,可用于训练与验证目标检测模型。资源包共1709个文件,包含854张jpg实拍图像、854个同名txt标注文件及1个yaml配置文件,压缩包约38.27MB,标注同时兼容YOLO、COCO JSON与Pascal VOC XML三种主流格式,其中yaml文件可直接用于YOLO系列训练配置,txt文件对应每张图像的边界框与类别信息。据描述,该数据集在YOLO v8上的平均正确识别率可达98.9%,已有457人学习下载。借助成对的图像与标注,读者可快速完成数据加载、模型训练与精度复现,省去自行采集与标注的成本,适合作为缺陷检测入门练手或产线质检方案的原型验证素材。
1. 易拉罐缺陷识别数据集:从产线质检到 YOLOv8 训练的一条龙落地
产线质检上有个很尴尬的现实:人眼盯罐底划痕,盯两小时就开始漏检,而客户投诉往往就出在那些漏掉的微小凹坑上。这份易拉罐缺陷识别数据集就是冲着这个场景来的——它把罐底、罐身的划痕、凹坑、变形等缺陷用 YOLO 格式标好,官方给出的平均正确识别率能到 98.9%。数据集同时提供 COCO JSON 和 Pascal VOC XML 两种标注格式,意味着你不管是用 YOLOv8 直接开训,还是想拿 Ultralytics 之外的其他检测框架做对比实验,都能少走一道格式转换的弯路。适合谁?做工业质检落地的算法工程师、想拿真实缺陷数据跑通检测流程的学生,以及需要快速验证产线视觉方案可行性的集成商。下面我按「拿到数据怎么用 → 训练怎么配 → 坑在哪」的顺序拆一遍。
2. 数据集结构与 YOLOv8 标注格式拆解:先看懂再动手
2.1 目录长什么样,标注文件怎么对应
从项目正文给出的文件名看,原始图片是WIN_20240410_20_40_37_Pro_jpg.rf.b46e051eab21da1eebf7cbc6ee892f93.jpg这种带 Roboflow 风格哈希后缀的命名。这种命名不是随便起的,.rf.后面那串哈希是数据增强或版本切分时生成的唯一标识,好处是同一张原图经过翻转、亮度调整后生成的新图不会重名,坏处是你没法直接从文件名看出它属于训练集还是验证集。所以拿到压缩包后第一件事不是急着解压训练,而是先确认目录结构。
常见做法是解压后看到这样的层级:
dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yamlimages/train/下放 jpg 原图,labels/train/下放同名 txt 标注文件。注意这里有个容易翻车的点:图片名是xxx.jpg,标注名必须是xxx.txt,前缀完全一致,只换扩展名。如果你从 COCO JSON 自己转 YOLO 格式,转换脚本里忘了去掉.jpg再拼.txt,训练时就会报「找不到标签」或者更隐蔽的「标签全为空」,模型训出来全是背景。
2.2 YOLO 标注格式的五个字段到底怎么读
YOLO 格式的每一行是一个目标,格式为:
<class_id> <x_center> <y_center> <width> <height>这五个值里,后四个都是归一化到 0~1 的浮点数,不是像素坐标。很多新手第一次看标注文件会懵:明明图片是 1920×1080,怎么坐标是 0.53 这种小数?因为 YOLO 训练时会把图片 resize 到固定输入尺寸(比如 640×640),用归一化坐标可以避免 resize 后坐标错位。x_center和y_center是目标框中心点相对整图宽高的比例,width和height是框宽高相对整图宽高的比例。
假设一张罐底图里有一个划痕,标注文件WIN_20240410_20_40_37_Pro_jpg.rf.b46e051eab21da1eebf7cbc6ee892f93.txt内容可能是:
0 0.512 0.487 0.231 0.156 1 0.734 0.622 0.089 0.112第一行class_id=0代表划痕,第二行class_id=1代表凹坑。类别 id 从 0 开始连续编号,具体哪个 id 对应哪个缺陷,得看data.yaml里的names列表。这里有个血泪经验:如果你自己合并了多个来源的数据集,两个来源的class_id含义不一样(比如 A 数据集 0 是划痕,B 数据集 0 是凹坑),直接混在一起训,模型会学出一个「薛定谔的类别」,验证集精度看着还行,一上产线就乱报。合并前必须统一类别映射表。
2.3 data.yaml 的四个关键字段
data.yaml是 YOLOv8 训练的入口配置文件,典型内容如下:
path: /home/user/dataset train: images/train val: images/val test: images/test nc: 3 names: 0: scratch 1: dent 2: deformationpath是数据集根目录,train/val/test是相对path的子路径。nc是类别数,names是类别名列表。这里最容易踩的坑是path用了相对路径,而你在不同目录下执行训练命令,导致找不到数据。我一般会强制写成绝对路径,或者用os.path.abspath在脚本里动态生成。另外names的缩进必须是两个空格,用 Tab 会报 YAML 解析错误,这个错误信息往往只提示「mapping values are not allowed here」,不告诉你是 Tab 的问题,排查起来很费时间。
提示:拿到数据集后先跑一遍
ls labels/train | wc -l和ls images/train | wc -l,两个数字必须相等。不相等说明有图片没标或者标注文件多余,直接开训会在 dataloader 阶段报错。
3. 用 YOLOv8 训练易拉罐缺陷检测模型:从环境到推理的完整链路
3.1 环境准备与 ultralytics 安装
训练环境我一般用 Python 3.10 + PyTorch 2.1 + CUDA 11.8 这套组合,兼容性最稳。安装 ultralytics 不要直接pip install ultralytics就完事,因为默认会拉最新版,而最新版可能和你本地的 PyTorch 版本打架。常见做法是先把 PyTorch 装好,再装 ultralytics:
# 先装 PyTorch,以 CUDA 11.8 为例 pip install torch==2.1.0 torchvision==0.16.0 --index-url https://download.pytorch.org/whl/cu118 # 再装 ultralytics,指定版本避免自动升级 pip install ultralytics==8.1.0 # 验证 GPU 是否可用 python -c "import torch; print(torch.cuda.is_available())"最后一行输出True才算环境通了。如果输出False,先别急着改代码,大概率是 CUDA 版本和 PyTorch 版本不匹配。用nvidia-smi看驱动支持的 CUDA 版本,再去 PyTorch 官网查对应关系。这一步没通就开训,YOLOv8 会静默回退到 CPU,训练速度从每轮几分钟变成几小时,很多人以为是自己参数设错了,其实是 GPU 根本没吃上。
3.2 训练命令与关键参数含义
YOLOv8 的训练入口是yolo detect train,最简命令如下:
yolo detect train \ data=/home/user/dataset/data.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ device=0 \ project=runs/can_defect \ name=exp1逐项说参数。data指向data.yaml,必须绝对路径。model选yolov8n.pt是最小的 nano 模型,适合先跑通流程;如果精度不够再换yolov8s.pt或yolov8m.pt。epochs=100是训练轮数,缺陷检测这种任务一般 100~300 轮能看到收敛,但要看验证集 mAP 曲线,不是越多越好。imgsz=640是输入尺寸,罐底划痕如果很细,可以提到 1280,但显存占用会翻倍。batch=16是批大小,显存不够就降到 8 或 4。device=0指定第一块 GPU,多卡用device=0,1。
训练过程中重点看三个指标:box_loss应该持续下降,mAP50应该持续上升,mAP50-95上升速度会比mAP50慢。如果box_loss降到某个值就不动了,而mAP50还在涨,说明模型在细化框的位置,是正常现象。如果box_loss震荡不降,先检查学习率,YOLOv8 默认用余弦退火,初始 lr 是 0.01,小数据集可以降到 0.001。
3.3 推理验证与置信度阈值调整
训练完在runs/can_defect/exp1/weights/best.pt拿到最优权重,推理命令:
yolo detect predict \ model=runs/can_defect/exp1/weights/best.pt \ source=/home/user/test_images \ conf=0.25 \ iou=0.45 \ save=Trueconf=0.25是置信度阈值,低于这个值的检测框直接丢弃。iou=0.45是 NMS 的 IoU 阈值,控制重叠框的合并程度。这两个参数对最终效果影响极大。产线质检场景下,如果漏检代价高,把conf降到 0.15,宁可多报几个假阳性也不能漏;如果误报会导致频繁停机,把conf提到 0.4 以上。iou一般保持 0.45~0.5,除非你的缺陷目标特别密集,才需要调低到 0.3 避免框被误合并。
推理结果会保存到runs/detect/predict/下,每张图带检测框和类别标签。我一般会再写个小脚本统计每类的检出数量,和人工抽检结果对比,算一下实际产线上的召回率和准确率。官方说的 98.9% 是在特定测试集上的平均正确识别率,你自己的产线光照、相机角度、罐体型号一变,这个数字就得重新验证。
4. 多格式标注互转与数据增强:COCO、VOC 和 YOLO 之间怎么不丢信息
4.1 三种格式的核心差异
这份数据集同时提供 YOLO、COCO JSON、Pascal VOC XML 三种标注,不是凑数,是因为不同框架吃不同格式。YOLO 用归一化 txt,COCO 用单个 JSON 存所有图片的标注,VOC 用每张图一个 XML。核心差异在坐标表示和类别存储方式:
| 格式 | 坐标类型 | 类别存储 | 典型用途 |
|---|---|---|---|
| YOLO | 归一化中心点+宽高 | 独立 txt,class_id 数字 | Ultralytics 系列 |
| COCO | 绝对像素左上角+宽高 | 单个 JSON,category_id | Detectron2、MMDetection |
| VOC | 绝对像素左上角+右下角 | 独立 XML,类别名文本 | 老版 TensorFlow、部分工业软件 |
转换时最容易丢信息的是类别名。YOLO 只存数字 id,COCO 存 id 和 name 的映射,VOC 直接存 name。从 YOLO 转 VOC 时,你得自己维护一份 id 到 name 的映射表,否则转出来的 XML 里类别全是0、1、2,下游工具不认。
4.2 用 Python 做 YOLO 转 COCO 的实操
下面这段脚本把 YOLO 格式转成 COCO JSON,关键步骤都加了注释:
import json import os from PIL import Image # 类别映射,必须和 data.yaml 里的 names 一致 class_names = {0: "scratch", 1: "dent", 2: "deformation"} def yolo_to_coco(image_dir, label_dir, output_json): coco = { "images": [], "annotations": [], "categories": [] } # 构建 categories for cid, cname in class_names.items(): coco["categories"].append({ "id": cid, "name": cname, "supercategory": "defect" }) ann_id = 1 img_id = 1 for fname in os.listdir(image_dir): if not fname.lower().endswith((".jpg", ".png")): continue img_path = os.path.join(image_dir, fname) w, h = Image.open(img_path).size coco["images"].append({ "id": img_id, "file_name": fname, "width": w, "height": h }) label_path = os.path.join(label_dir, fname.rsplit(".", 1)[0] + ".txt") if os.path.exists(label_path): with open(label_path) as f: for line in f: parts = line.strip().split() if len(parts) != 5: continue cid, xc, yc, bw, bh = map(float, parts) # YOLO 归一化坐标转 COCO 绝对像素 x = (xc - bw / 2) * w y = (yc - bh / 2) * h abs_w = bw * w abs_h = bh * h coco["annotations"].append({ "id": ann_id, "image_id": img_id, "category_id": int(cid), "bbox": [x, y, abs_w, abs_h], "area": abs_w * abs_h, "iscrowd": 0 }) ann_id += 1 img_id += 1 with open(output_json, "w") as f: json.dump(coco, f, indent=2) yolo_to_coco("dataset/images/train", "dataset/labels/train", "train_coco.json")逻辑说明:先遍历图片目录拿到每张图的宽高,这是反归一化的前提。然后读同名 txt,把归一化中心点坐标转成左上角绝对坐标。area字段是 COCO 评估时必须的,等于框面积。iscrowd=0表示不是密集人群那种难例,缺陷检测一般都用 0。参数上唯一需要你改的是class_names,必须和data.yaml完全一致,否则 COCO 评估时类别对不上,mAP 算出来是错的。
4.3 数据增强的边界:什么时候该增强,什么时候不该
YOLOv8 默认开启 mosaic、HSV 抖动、随机翻转等增强。对易拉罐缺陷检测来说,mosaic 增强要谨慎。mosaic 会把四张图拼成一张,罐底划痕这种细长目标被拼到边缘时可能被裁掉一半,模型学到的就是残缺特征。我一般会在data.yaml同级加一个augment.yaml,把mosaic概率从默认的 1.0 降到 0.5,degrees旋转角度从 0 提到 10,因为产线上罐体摆放角度确实有偏差。但flipud上下翻转要关掉,罐底缺陷上下翻转后不符合物理规律,模型学了反而干扰。
注意:数据增强不是越多越好。缺陷检测的核心是让模型学到缺陷的纹理和形状特征,过度增强会让模型把增强噪声当成缺陷特征。验证集 mAP 涨了但产线实测降了,往往就是增强过头。
5. 避坑与排查:易拉罐缺陷数据集训练中最容易翻车的五个点
5.1 现象:训练 loss 正常下降,但验证集 mAP 始终为 0
原因:标注文件里的class_id超出了data.yaml里nc定义的范围。比如nc=3,但某个标注文件里出现了3或更大的 id,YOLOv8 在计算损失时会把这类目标忽略,验证时也匹配不上任何类别,mAP 自然为 0。
解决:写个脚本扫一遍所有 label 文件,统计出现的 class_id 集合,和data.yaml的names键做差集。有超出范围的,要么改标注,要么扩nc。
import os ids = set() for f in os.listdir("dataset/labels/train"): with open(os.path.join("dataset/labels/train", f)) as fp: for line in fp: ids.add(int(line.split()[0])) print("出现的类别 id:", sorted(ids))5.2 现象:训练报错「No labels found in ...」
原因:图片和标注的目录结构不匹配,或者文件名前缀不一致。YOLOv8 默认在images/train同级找labels/train,如果你把 labels 放到了别的地方,或者图片是a.jpg而标注是a.JPG.txt,都会报这个错。
解决:确认data.yaml里train和val指向的是 images 目录,YOLOv8 会自动把路径里的images替换成labels去找标注。如果目录结构特殊,用path字段显式指定根目录。文件名大小写敏感的问题在 Linux 上尤其常见,Windows 上跑通不代表 Linux 上没问题。
5.3 现象:推理时框的位置整体偏移
原因:训练时用了rect=True(矩形推理),但推理时没开,或者反过来。YOLOv8 默认训练用矩形推理减少 padding,推理时如果输入尺寸和训练不一致,框的归一化坐标反算回原图时就会偏。
解决:训练和推理的imgsz保持一致,推理时加rect=True参数。如果还是偏,检查原图是否被 EXIF 旋转信息影响,PIL 读图和 OpenCV 读图对 EXIF 的处理不一样,会导致宽高互换。
5.4 现象:小目标划痕漏检严重
原因:输入尺寸 640 时,一条只占原图 2% 宽度的划痕,resize 后只剩十几个像素,特征在 backbone 下采样几次后就消失了。
解决:把imgsz提到 1280,或者在模型里加 P2 小目标检测层。YOLOv8 官方没有直接暴露 P2 配置,常见做法是改用yolov8-p2.yaml这种社区配置,但要注意预训练权重不匹配,得从头训或者只加载 backbone。另一个思路是把大图切patch训练,推理时再拼回去,适合罐底这种固定视野的场景。
5.5 现象:模型在测试集上 98%,产线上只有 80%
原因:测试集和产线的光照、相机、罐体批次不一致。数据集里的图片是特定条件下采集的,产线换一批罐子、换个光源,分布就变了。
解决:这不是模型问题,是数据问题。在产线上采集一批新图,人工标 50~100 张,用训练好的模型做预标注,人工修正后加入训练集做增量训练。YOLOv8 支持resume继续训练,但增量训练建议用低学习率(0.0001)微调,避免灾难性遗忘。
6. 进阶技巧:用验证集反推标注质量与置信度校准
训练完不是终点,验证集除了算 mAP,还能反推标注质量。我一般会跑一遍val模式,把预测结果和真实标注叠在一起看:
yolo detect val \ model=runs/can_defect/exp1/weights/best.pt \ data=/home/user/dataset/data.yaml \ conf=0.001 \ iou=0.6 \ plots=True注意这里conf故意设成 0.001,是为了让模型输出所有可能的框,包括低置信度的。plots=True会在输出目录生成val_batch0_pred.jpg和val_batch0_labels.jpg,前者是预测结果,后者是真实标注。把两张图并排看,如果某个缺陷在 labels 图里有框但 pred 图里没有,说明模型漏检;如果 pred 图里框的位置和 labels 图差很多,说明标注本身可能就不准。
置信度校准是另一个实用技巧。YOLOv8 输出的置信度不是概率,不能直接当「有缺陷的概率」用。我一般会统计验证集上不同conf阈值下的精确率和召回率,画一条 P-R 曲线,然后根据产线能接受的误报率反推阈值。比如产线要求误报率低于 5%,那就找精确率 95% 对应的conf值,而不是拍脑袋定 0.25。
还有一个容易被忽略的点:类别不平衡。如果划痕样本远多于凹坑,模型会偏向划痕,凹坑的召回率上不去。常见做法是在data.yaml里给每个类别加权重,但 YOLOv8 不直接支持类别权重,得改损失函数。更简单的办法是对凹坑样本做过采样,或者用copy_paste增强把凹坑贴到更多背景上。
从那以后我每次拿到新数据集,都强制先跑一遍标注 id 扫描和图片-标注数量对齐检查,再开训。这两个检查花不了五分钟,但能省掉后面几小时的无效训练。希望帮到你。
本文还有配套的精品资源,点击获取