ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

瓶装白酒疵品检测数据集实战:从数据整理到YOLOv8训练避坑指南

瓶装白酒疵品检测数据集实战:从数据整理到YOLOv8训练避坑指南 简介这份压缩包是面向工业质检场景的瓶装白酒疵品检测数据集适合机器学习与计算机视觉学习者、算法工程师用于训练疵品识别模型解决瓶身划痕、标签破损、密封不良等自动检测问题。包内共2000个文件主体为4516张JPG格式瓶装白酒图像涵盖疵品与非疵品样本另含1个JSON标注文件可用于目标检测或分类任务压缩包整体约213MB。数据集文件命名带有chongqing1_round1_train1_20191223等标识推测为某一竞赛或项目的第一轮训练集图像在光照、背景和焦点方面经过规范采集并注意了样本平衡性。目前已有293人学习下载适合用来训练卷积神经网络CNN、验证检测算法精度并进一步掌握从数据准备、模型训练到性能评估准确率、精确率、召回率等的完整流程。1. 瓶装白酒疵品检测数据集先看清这份资源值不值得下做工业质检的同行应该都有体会模型算法本身早就不是瓶颈真正卡住项目进度的是手里有没有一批干净、带标注、贴合产线场景的真实图像。这份“瓶装白酒疵品检测数据集.zip”就是干这个用的解压后是清一色的 JPEG 图像样本文件名规律是 img_ 加八位数字比如 img_0026903.jpg、img_0005017.jpg从原始目录名 chongqing1_round1_train1_20191223 可以推断这是某个白酒检测竞赛第一轮发布的训练集拍摄时间在 2019 年底。适合谁用准备做瓶装酒外观缺陷检测的算法工程师、搞工业视觉毕业设计的学生以及想验证分类或目标检测模型的入门者。它能帮你省掉最耗时的数据采集和初步整理环节直接进入标注、训练和迭代阶段。但先别急着解压这组数据的组织方式、标签形式和图像质量都直接影响后面的训练策略我拆给你看。2. 数据集结构与图像特点解压前先搞清楚的几件事2.1 文件命名规律与原始目录信息压缩包解压后你会看到大量 img_ 前缀的 JPEG 文件。这个命名规律对后续脚本处理非常友好因为文件名本身就是唯一标识不需要额外解析复杂的元数据。文件名结构如下img_ 前缀固定标识表示这是一个图像样本八位数字样本编号如 0026903扩展名 .jpgJPEG 格式工业相机输出最常见格式兼容性最好。这里有个小细节值得留意。原始目录名里的 20191223 看起来是发布日期或拍摄批次而 round1_train1 说明这是第一轮训练集的第一部分。这种命名习惯在很多工业比赛数据里很常见意味着后续可能还有 round1_train2 之类的补充数据或者验证集测试集是单独发布的。如果你拿这份数据做论文实验建议在文档里注明数据来源批次避免审稿人质疑数据可追溯性。我一般拿到这类压缩包后不会直接开始写代码而是先做一次完整的数据探查。建议写一个简单的 Python 脚本统计图像尺寸分布、文件大小分布和总量这个步骤能帮你提前发现图像分辨率不统一、文件损坏、灰度图和彩色图混用等问题。常见做法是按文件名排序后抽样检查而不是全量加载毕竟几千张 JPEG 同时读进内存会把笔记本直接卡死。下面给一个快速探查脚本用 Pillow 读图像头信息不加载完整像素数据import os import glob from PIL import Image from collections import Counter img_dir ./chongqing1_round1_train1_20191223 img_paths sorted(glob.glob(os.path.join(img_dir, *.jpg))) size_counter Counter() mode_counter Counter() error_list [] for p in img_paths: try: with Image.open(p) as im: size_counter[im.size] 1 mode_counter[im.mode] 1 except Exception as e: error_list.append((p, str(e))) print(f总图像数: {len(img_paths)}) print(f尺寸分布: {size_counter.most_common(5)}) print(f颜色模式: {mode_counter}) print(f无法打开的图片: {len(error_list)})这段脚本的核心逻辑是逐张打开图片但只读取头部信息Pillow 的 Image.open 是惰性加载不会真正解码像素数据所以即使有几千张图跑完也就几秒钟。输出的尺寸分布能告诉你这批数据是统一分辨率还是混合分辨率如果是混合的后面做数据加载器时就必须加 resize 逻辑颜色模式如果是 L 或者 LA说明混入了灰度图需要统一转成 RGB 再喂给预训练模型。如果你发现尺寸分布差异很大比如有 1920x1080 的大图也有 640x480 的小图训练时要注意一个细节直接用整图训练会导致小图上的疵品特征被严重放大或缩小影响泛化。我习惯按最短边缩放到统一尺寸再训练而不是按固定宽高硬压这样至少保持了长宽比。2.2 疵品类别与成像条件推断从文件名本身看不到标签信息但结合瓶装白酒质检场景可以推断图像大概率覆盖以下典型缺陷瓶身划痕、标签破损或起皱、瓶口密封不严、液位异常、瓶底沉淀物。这些缺陷在视觉特征上差异较大划痕是高频边缘特征标签破损是颜色突变和纹理断裂液位异常则是语义级特征。如果后续要训练分类模型建议先按缺陷类型做数据集拆分而不是只做“好/坏”二分类因为不同缺陷对网络层关注的敏感度完全不同。关于成像条件白酒产线质检相机通常使用黑白或彩色工业相机搭配环形 LED 光源或条形光照明背景多为黑色传送带或暗色背板。从文件名编号的连续性和数量来看拍摄环境应该相对固定这就带来一个双面影响优势是背景干扰小模型容易学到瓶子本身的特征隐患是数据分布过于单一换一条产线或换一种光源后模型性能可能急剧下降。做迁移学习或域适应实验时这批数据非常适合作为源域数据使用。如果压缩包里只有图像没有标注文件你需要自己决定怎么处理标签。常见的做法是手动分类整理目录结构比如把图片移动到 bottle_defect/scratch、bottle_defect/label_wrinkle、bottle_defect/good 这类子目录里然后写脚本批量生成 CSV 或 TXT 格式的标签文件。我见过不少人卡在这一步觉得手动整理太费时但说实话一千张图用文件管理器按缩略图模式过一遍大概四十分钟到一个小时能完成比写半自动标注脚本再 debug 来得快。3. 从图像到模型整理目录、划分数据集与训练配置3.1 整理成 ImageNet 风格目录并自动划分训练验证集拿到数据的第一件正事是把散落的平面文件整理成标准目录结构。不管后续用 PyTorch 的 ImageFolder 还是自写 Dataset目录结构清晰能少踩很多坑。推荐结构如下bottle_data/ ├── train/ │ ├── good/ │ ├── scratch/ │ ├── label_wrinkle/ │ └── cap_leak/ ├── val/ │ ├── good/ │ ├── scratch/ │ ├── label_wrinkle/ │ └── cap_leak/ └── test/ └── unlabeled/如果标签需要自己整理先用文件管理器把图片按类别分到 raw 目录下然后用脚本按比例随机切分。注意切分时一定要按类别分层采样防止某一类在验证集中缺失或占比过高。下面是划分脚本的核心逻辑import os import random import shutil random.seed(42) src_root ./raw_by_category dst_root ./bottle_data split_ratio 0.85 # 训练集占比 for category in os.listdir(src_root): cat_path os.path.join(src_root, category) if not os.path.isdir(cat_path): continue imgs [f for f in os.listdir(cat_path) if f.endswith(.jpg)] random.shuffle(imgs) n_train int(len(imgs) * split_ratio) train_imgs imgs[:n_train] val_imgs imgs[n_train:] for split, split_imgs in zip([train, val], [train_imgs, val_imgs]): dest_dir os.path.join(dst_root, split, category) os.makedirs(dest_dir, exist_okTrue) for f in split_imgs: shutil.copy(os.path.join(cat_path, f), os.path.join(dest_dir, f)) print(划分完成各目录图片数量) for split in [train, val]: for category in sorted(os.listdir(os.path.join(dst_root, split))): n len(os.listdir(os.path.join(dst_root, split, category))) print(f{split}/{category}: {n})这段代码做了三件关键事情。第一用 random.seed(42) 固定随机种子保证每次跑划分结果一致这在对比实验时非常重要否则你无法判断模型性能差异是来自算法改进还是数据划分波动。第二按类别目录逐类切分避免了整体混洗后某些小类在训练集或验证集中数量失衡。第三用 shutil.copy 而不是 shutil.move 保留原始数据万一划分有问题还能重新来过我用 move 吃过一次亏后来都改成 copy 了。参数方面split_ratio 设成 0.85 是经验值。如果是小样本场景比如每类只有一两百张可以设到 0.9 甚至 0.95用更多数据训练验证集只看分布如果每类上千张0.8 到 0.85 就够。另外注意 seed 的选择42 是习惯但你也可以换成其他整数建议固定下来并在实验记录里注明。3.2 疵品检测的模型选型与 YOLO 训练配置白酒瓶疵品检测的数据特点决定了模型选型方向。疵品区域在整个图像中的占比通常较小比如一条划痕可能只有几十乘几百像素用图像分类模型整图判断会丢失空间位置信息虽然能告诉你“这瓶有问题”但产线工人还需要知道“问题在哪”。所以目标检测是更贴合场景的方案YOLOv8 是目前性价比最高的选择训练速度快部署生态完善官方预训练权重对 COCO 数据集的特征提取能力可以直接迁移到瓶身检测。如果这批数据只有图像没有目标框标注你有两个选择一是用分类模型先做粗筛再通过 Grad-CAM 热力图定位缺陷区域二是手动用 LabelImg 或 X-AnyLabeling 标注边界框每张图标一个框就行几百张图两小时能完成。我建议标注因为后期部署时目标检测的输出信息量远大于分类。标注完成后整理成 YOLO 格式的目录结构bottle_yolo/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── bottle.yaml数据集配置文件 bottle.yaml 内容如下path: ./bottle_yolo train: images/train val: images/val names: 0: good 1: scratch 2: label_wrinkle 3: cap_leak训练命令用 YOLOv8 官方 CLI 即可yolo detect train \ databottle.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ patience20 \ project./runs \ namebottle_defect_exp1这里的参数有几个值得注意。imgsz640 是速度和精度的平衡点如果缺陷区域非常小可以调到 768 甚至 896但显存占用会明显上涨batch16 是 12GB 显存的常用值显存小就降到 8同时配梯度累积patience20 表示 20 个 epoch 内验证集 mAP 没有提升就提前停止训练白酒疵品数据集通常几十个 epoch 就会收敛这个参数能节省大量时间。训练时重点盯两个输出一是训练结束后的 confusion_matrix.png看哪些类别之间互相混淆二是 results.png 里的 val_mAP50 曲线看模型是否真的收敛。我发现很多人训练完只截图 loss 曲线看个热闹这是不对的loss 下降只能说明优化器在工作mAP 才是检测任务的真标准。4. 常见问题与避坑记录训练白酒疵品检测模型的四个深坑4.1 训练 loss 不降反升学习率设置与数据增强冲突现象用默认学习率训练前 10 个 epoch 的 loss 还在正常下降15 个 epoch 后突然反弹验证集 mAP 同步下滑。原因白酒瓶图像背景单一、前景物体占比大这类数据分布与 COCO 差异明显。YOLOv8 默认的 mosaic 增强会把多张图拼接瓶子边缘被截断后产生了大量“半瓶子”样本模型学到的特征是碎的。加上默认学习率 0.01 在数据量不大时容易震荡。解决关闭 mosaic 和 mixup或者在最后 10 个 epoch 关闭增强做微调。YOLO 训练命令里通过 hsv_h、hsv_s、degrees 等参数控制增强强度最简单的方式是训练前 80 个 epoch 正常跑最后 20 个 epoch 用 close_mosaic10 让模型在真实分布上微调。命令加一个参数即可yolo detect train \ databottle.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ close_mosaic10close_mosaic10 表示最后 10 个 epoch 关闭 mosaic 增强这个功能是 YOLOv8 官方专门为解决“增强分布与真实分布不一致”设计的白酒这类单一背景数据集非常吃这一套。4.2 疵品样本太少导致类别过拟合现象训练集里 good 类有 800 张scratch 类只有 60 张跑完 100 个 epoch 后 scratch 类的 recall 不到 0.5但 good 类的 precision 接近 1.0。原因类别不平衡模型倾向于把所有样本都预测为多数类因为这样训练 loss 最低。这是一种偷懒策略优化器找到了损失函数的局部最优解但这个解没有实用价值。解决给少数类加大 loss 权重YOLOv8 训练时在数据集配置里加 class_weights 参数或者在损失函数层面处理更精细。不过最实用的方式是做离线增强对少数类样本做翻转变换、亮度扰动、随机裁剪把每类的数量拉到接近。还有一种思路是直接用复制粘贴增强把疵品区域裁剪下来随机贴到 good 样本上同时对标签做对应平移这类基于实例的增强对检测任务特别有效因为它增加了正样本的数量而不会破坏上下文真实性。我一般会用离线增强把每类样本数拉到 300 张以上再做训练数据量不足时硬靠网络结构调整收益很低。4.3 图像尺寸不统一导致检测框偏移现象训练时用 imgsz640数据集里有些图是 1920x1080有些是 1280x960。训练过程没有报错但推理时检测框总是偏差几个像素到十几个像素。原因YOLOv8 训练时会对输入做 letterbox 填充但推理时如果代码里忘了保持同样的填充方式模型看到的图像几何关系就和训练时不一致。特别是边缘位置的疵品letterbox 的灰边宽度不同框就会整体偏移。解决推理代码里强制统一预处理流程。官方 ultralytics 库的 predict API 会自动做 letterbox但如果自己写推理脚本复现模型很容易漏掉这个步骤。下面是自写推理时必须注意的预处理部分import cv2 import numpy as np def letterbox(img, new_shape(640, 640), color(114, 114, 114)): shape img.shape[:2] r min(new_shape[0] / shape[0], new_shape[1] / shape[1]) new_unpad (int(round(shape[1] * r)), int(round(shape[0] * r))) dw (new_shape[1] - new_unpad[0]) / 2 dh (new_shape[0] - new_unpad[1]) / 2 top, bottom int(round(dh - 0.1)), int(round(dh 0.1)) left, right int(round(dw - 0.1)), int(round(dw 0.1)) img cv2.resize(img, new_unpad, interpolationcv2.INTER_LINEAR) img cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, valuecolor) return imgletterbox 的核心逻辑是等比缩放后填充灰边使其符合模型输入尺寸。这里的 dw 和 dh 计算出来的偏移量在把检测框映射回原图坐标时要用到如果缺了这步框的位置就会偏移。记住一个原则训练和推理的预处理必须完全一致包括插值方式和填充颜色。4.4 验证集和训练集图像来自同一产线导致评估虚高现象训练集 mAP 达到 0.95但拿到现场测试准确率掉到 0.6 以下模型“见光死”。原因数据集本身的拍摄环境、光照条件和瓶子型号高度一致划分出的验证集实际上和训练集同分布不能代表真实场景。这是单一来源数据集的通病不是模型的问题。解决如果条件允许找另一条产线或不同时间段拍摄的图像做外部测试集。如果没有额外数据至少要按拍摄批次划分训练集和验证集而不是随机打乱。比如这个数据集原始目录里有日期信息可以按日期分组用某一天的数据做验证。这样评估出来的指标更接近真实泛化能力虽然数值会变难看但那才是可信的。我在一次项目里吃过这个亏当时模型在验证集上表现很好上线后翻车后来排查发现验证集里有一半图是从原始训练视频的不同帧里截出来的帧间相关性导致数据泄漏。从那以后无论数据集大小我都会检查是否存在相同来源的相似图像。5. 进阶玩法用小模型蒸馏、难例挖掘与部署前的验证技巧训练到 mAP 稳定在 0.75 以上后你大概率面临一个选择追求更高精度还是压缩模型换速度。白酒产线检测要求通常在每瓶 0.2 秒以内所以推理速度不是加分项而是硬指标。我的做法是先用 yolov8m 或 yolov8l 把精度刷上去然后用蒸馏或直接训练一个 yolov8n 来做部署模型。蒸馏的做法不复杂用大模型对训练集做推理把检测结果整理成软标签再用小模型同时拟合真实标签和软标签。YOLOv8 官方没直接提供蒸馏接口但可以用一个简单思路——把小模型的输出在损失函数层面加一项大模型预测分布的 KL 散度。不过这需要改训练代码工程量大一点。如果图省事直接用小模型在相同数据上重新训练配合在验证集上做难例挖掘往往也能逼近大模型 90% 以上的效果。难例挖掘是我觉得最值得花时间做的事。每轮训练结束后找到验证集里所有预测错误的图像统一输出到一个 hard_examples 目录下肉眼过一遍你会很快发现模型的失败模式。常见情况包括划痕和瓶身反光混淆、标签褶皱在特定光照下完全看不见、透明瓶身与背景分界线处出现假阳框。把这些难例合并进训练集重新训练比单纯调参有效得多。参数上YOLO 的预测阈值也能做文章默认置信度阈值 0.25 在白酒易拉罐这类低误报要求的场景可以调到 0.4 以上但 recall 会损失需要结合产线对漏检和误检的容忍度来定。部署前还有一件必须做的事就是量化与格式转换。如果目标设备是边缘盒子或工控机建议把模型导出为 ONNX 并做 INT8 量化。导出命令很简单yolo export model./runs/bottle_defect_exp1/weights/best.pt formatonnx imgsz640导出后再用 onnxruntime 写一个极简推理接口和 PyTorch 推理结果做逐张对比确保输出框坐标和置信度差异在可接受范围内。这里要提醒你ONNX 导出后模型的 NMS 行为可能和原始 PyTorch 不一致常见的坑是重复框数量暴增或置信度数值漂移解决方法是导出时加 nmsTrue 让模型自带 NMS或用 onnxruntime 的 NMS 插件。最后说一个我的习惯算是一条经验教训。每次训练实验我会把数据集配置 yaml、训练命令、预处理脚本和模型权重文件都打成一个带时间戳的 zip 存档文件名格式类似 bottle_defect_20250614_exp1.zip。这样出了问题能快速回到某个状态不会出现“这模型是谁训的、用的什么数据”这种找不到北的情况。白酒疵品检测的数据集改起来非常快但实验记录乱了是真的要命。希望这个数据集和这套流程能帮你在工业质检这条路上少走几步弯路早点跑出能看的结果。本文还有配套的精品资源点击获取
返回列表