简介曲奇饼干缺陷检测图像分类数据集面向食品工业质检、视觉检测算法入门与实战场景适合需要真实产线图像完成分类模型训练的开发者和研究人员。数据集中包含1000张产线采集的曲奇饼干图像按 Defect_Color、Defect_No、Defect_Object、Defect_Shape 四类缺陷以文件夹形式整理类别划分明确标注质量较高可直接用于 YOLOCLS 等图像分类算法的训练。配套提供 YOLO11cls 一键训练脚本和博主训练结果日志便于快速复现训练流程、对比分类效果降低环境搭建与调参门槛。资源采用 PDF 形式托管包内共1个文件大小约5.87MB内附数据集基本情况说明、缩略图展示及百度网盘下载方式已有29人浏览学习适合作为食品外观缺陷检测项目的数据补充与算法验证参考。1. 曲奇饼干缺陷检测为什么用YOLO11cls1000张图能解决的问题边界曲奇饼干外观质检在产线上是典型的“量大、类少、判定快”问题饼干高速通过皮带黑点、裂纹、烤焦边缘混在正常批次里人工挑拣不仅慢不同班次的判定标准还不一致。YOLO11cls 是 YOLO11 的分类模式它不画框只回答“这张图属于哪一类”。配合按类别归文件夹整理的图像分类数据集和一套训练脚本1000张图就能训练出第一版可试运行的模型——前提是缺陷类别聚焦、拍摄环境稳定。适合手里有采集条件、想快速验证分类是否能替代人工挑拣又不打算在标注工具上花太多时间的工程师。2. 缺陷分类为什么够用先想清楚任务边界再决定要不要上检测2.1 图像分类和目标检测的边界同一个缺陷两种代价目标检测输出的是“哪里有缺陷”图像分类输出的是“这张图有没有缺陷、属于哪一类”。曲奇缺陷检测里很多缺陷是整体视觉现象烤焦是表面颜色变化裂纹是纹理断裂夹生是整体偏白。如果质检动作只是“拦截这一块”或“放行这一块”分类就够用没必要让模型去学边界框。检测器需要标注框而曲奇形状不规则框标注误差对缺陷纹理的影响比较明显返工成本高。同一个缺陷标注一张分类图只需要拖进对应文件夹标注一张检测图却要调四个坐标点1000张图如果全用在分类上每个类能分到一两百张如果拿去训检测还要腾出大量图做框标注有效样本被稀释。从数据利用效率上看分类是这个规模下性价比更高的方案。2.2 缺陷类别怎么定从质检动作倒推分类清单我一般不建议照搬论文里的类别体系而是从产线的质检动作倒推。比如质检单上写“挑出烤焦、有裂纹、发白、有异物的”那就对应四类缺陷再加一个正常类。如果产线上对“边缘烤焦”和“局部黑点”的处置动作完全一样就合并成一类不要拆成两个类。参考类别设计如下类别名图片特征产线处置normal表面金黄均匀、无明显破损放行burnt边缘或表面深褐色、发黑拦截cracked可见裂纹或断裂纹路拦截pale整体偏白、像没烤熟拦截foreign_matter表面附着异物或黑点拦截五个类以内、语义不重叠模型压力会小很多。类别名建议只用英文小写下划线连接后面写脚本时能少踩很多编码坑。2.3 YOLO11cls 和 Transformer 分类模型的取舍这个规模下该信谁这两年不少团队会优先考虑 Transformer 系的图像分类模型但它们在千张级小数据集上的表现并不总是比卷积模型让人安心。ViT、Swin 这类模型对预训练权重、学习率、增强策略、EMA 都很敏感调参不顺手时很容易“验证集好看现场崩掉”1000张图也不太够喂饱它们。YOLO11cls 走的是另一条路数据目录组织方式沿用 YOLO 系成熟习惯训练、验证、导出一条命令链下来中途不需要折腾自定义 DataLoader。跑过 YOLOv8 训练自己的数据集的人都知道这套生态最大的价值是“工程闭环完整”分类精度天花板未必最高但能让一个产线小团队在半天内看到完整的混淆矩阵和曲线。3. 从零整理曲奇缺陷数据集文件夹划分脚本与命名规范3.1 采集与清洗什么样的图不该进数据集采集阶段最容易被低估。曲奇检测的目标是稳定的外观缺陷拍摄环境不统一后面训练和推理都会跟着遭殃。建议固定相机或手机支架固定光源方向和亮度背景用白色亚克力板每张图只放一片曲奇、居中、充满画面大部分区域。清洗阶段按以下步骤筛一遍模糊的删掉过曝或过暗的删掉有镜头脏点或手指入镜的删掉同一块曲奇的正反面不要同时混进去。这里最容易翻车的是“顺手拍了一堆糊图还当成有效样本”模型训练时会把模糊特征当成判别信号现场一测就露馅。3.2 用 Python 把流水照片按类别归到分类文件夹采集设备导出的照片通常是同一目录下的流水文件名人工判断类别后建议登记成 CSV。用脚本按 CSV 批量归类顺便统一重命名比手动拖文件夹快得多也方便后续复查。import csv import shutil from pathlib import Path csv_path Path(labels.csv) # 列: filename, category src_dir Path(raw_images) dst_dir Path(dataset) with csv_path.open(newline, encodingutf-8) as f: reader csv.DictReader(f) for row in reader: src_file src_dir / row[filename] category row[category].strip().lower() cls_dir dst_dir / category cls_dir.mkdir(parentsTrue, exist_okTrue) idx len(list(cls_dir.glob(*.jpg))) 1 new_name f{category}_{idx:04d}.jpg shutil.copy2(src_file, cls_dir / new_name) print(归类完成请检查每个类别的数量)这段脚本的流程是读 CSV按类别名创建目标文件夹统计该文件夹现有图片数来生成序号再用shutil.copy2复制原图并保留文件元数据。参数上CSV 列名如果不同就改filename和category两处encodingutf-8建议保留Windows 下导出 CSV 常带 BOM遇到乱码可改成utf-8-sig。归完类后跑一句统计确认每个类都有足够的图。类别少于 50 张的需要回头补拍光靠过采样撑不起稳定的分类边界。3.3 目录结构与 YOLO11cls 的读取逻辑train/val 必须分开YOLO11cls 读取分类数据时走的是 ImageNet 式目录结构。很多公开的图像分类数据集下载下来也是这种结构CIFAR-10 这类经典数据集按类目录组织的思路类似只是这里要求把训练集和验证集分开放在train/和val/两个父目录下。dataset/ ├── train/ │ ├── normal/ │ ├── burnt/ │ ├── cracked/ │ ├── pale/ │ └── foreign_matter/ └── val/ ├── normal/ ├── burnt/ ├── cracked/ ├── pale/ └── foreign_matter/Ultralytics 的分类训练命令里data参数指向dataset这个父目录框架会自己去找train和val子目录不需要额外的标签文件或 yaml。这个机制对新手比较友好但也意味着目录名字不能写错少一个val子目录会导致验证阶段直接跳过而训练进程不会报错容易被忽略。提示划分验证集时要按“曲奇个体”划分而不是按“单张图片”随机划分。同一块曲奇的正反面图一张进训练集、一张进验证集会造成数据泄漏导致验证分数虚高。4. 跑通 YOLO11cls 一键训练环境、命令与必调参数4.1 装好 ultralytics 环境最小可用配置先建一个独立的 conda 环境避免把系统 Python 搞乱。装完后用 Python 快速验证一次 import能通过就说明环境基本可用。conda create -n pookie python3.11 -y conda activate pookie pip install ultralytics python -c from ultralytics import YOLO; print(ok)pip 会拉取 PyTorch 和依赖如果机器有 NVIDIA 显卡建议提前装好对应 CUDA 版本的 PyTorch再装 ultralytics。纯 CPU 机器也能跑只是 224 分辨率、80 轮、1000 张图的训练时间会拉长到几小时而显卡通常十几分钟就够。4.2 一键训练脚本 train.sh把划分、训练、验证串成一次执行标题里说“一键训练脚本”我的做法是把数据集划分、训练、验证写成同一个 shell 脚本每次只跑一行命令就能完成全流程。#!/usr/bin/env bash set -e DATA_DIRdataset SEED42 SPLIT_RATIO0.2 python split_dataset.py --data_dir $DATA_DIR --seed $SEED --val_ratio $SPLIT_RATIO yolo classify train \ modelyolo11cls.pt \ data$DATA_DIR \ epochs80 \ imgsz224 \ batch16 \ lr00.001 \ patience15 \ device0 \ projectruns/classify \ namepookie_v1 yolo classify val \ modelruns/classify/pookie_v1/weights/best.pt \ data$DATA_DIR脚本里set -e的作用是某个环节失败就立刻停止避免用坏模型继续往下跑。第一个 Python 脚本负责按种子和比例划分训练集、验证集第二个命令开始训练第三个命令用best.pt在验证集上复评。配套的split_dataset.py核心逻辑如下import argparse import random import shutil from pathlib import Path parser argparse.ArgumentParser() parser.add_argument(--data_dir, requiredTrue) parser.add_argument(--seed, typeint, default42) parser.add_argument(--val_ratio, typefloat, default0.2) args parser.parse_args() rng random.Random(args.seed) for split in (train, val): (Path(args.data_dir) / split).mkdir(exist_okTrue) for cls_dir in sorted((Path(args.data_dir) / train).glob(*)): cls_name cls_dir.name images list(cls_dir.glob(*.jpg)) # 按文件名的个体前缀分组而不是直接随机打乱单张图片 groups {} for img in images: prefix img.name.split(_)[0] groups.setdefault(prefix, []).append(img) group_list list(groups.values()) rng.shuffle(group_list) val_count max(1, int(len(group_list) * args.val_ratio)) val_groups group_list[:val_count] for group in val_groups: for img in group: target Path(args.data_dir) / val / cls_name / img.name target.parent.mkdir(parentsTrue, exist_okTrue) shutil.move(str(img), str(target))划分脚本里最关键的是“按文件名前缀分组”——这里的前缀对应曲奇个体编号同一块曲奇的所有图片会被分到同一组然后整组划入训练集或验证集从源头避免个体泄漏。如果文件名没有前缀可以在前面采集归类时用cookie_id前缀统一命名。4.3 三个必调参数和一组起步参数训练命令里参数很多但真正影响这 1000 张图效果的主要是data、epochs、imgsz三个。data指错后面全白跑epochs太短学不完纹理差异太长容易过拟合imgsz决定模型看到的输入分辨率曲奇裂纹这类细节纹理224 起步条件允许可以试 256。我常用的起步参数如下参数建议值判断依据epochs80千张级数据集 80 轮足够收敛配合早停兜底imgsz224显存压力小要求更高细节再试 256batch168GB 显存稳妥显存小优先降 batchlr00.001预训练权重微调场景的稳妥起点patience15验证集连续 15 轮不涨就停防止浪费时间device0第一张显卡没显卡就留空给 CPU提示显存不够时优先降 batch不要降 imgsz。224 分辨率对裂纹检测已经是下限降到 160 会让纹理细节大量丢失。训练完成后去runs/classify/pookie_v1/目录看结果results.png里有准确率和 loss 曲线confusion_matrix.png里能看到每个类的对错分布。这是判断第一版模型能不能用的直接依据。5. 曲奇缺陷分类踩坑笔记5 条最值得记的翻车记录5.1 模糊图混进数据集验证集虚高现场现原形现象训练时验证准确率到了 97%拿到产线旁边对着实拍图一测误判率高得没法用尤其是裂纹类频繁漏检。原因采集阶段偷懒手机随手拍了一批轻微糊的图模型在训练时把“模糊”当成了和某些类别强相关的特征。训练集和验证集来自同一批采集环境所以验证分数好看现场拍摄条件一变就崩。解决把所有图过一遍清晰度筛选用 Laplacian 方差做粗筛方差太低的直接淘汰。import cv2 from pathlib import Path for img_path in Path(dataset).rglob(*.jpg): img cv2.imread(str(img_path), cv2.IMREAD_GRAYSCALE) score cv2.Laplacian(img, cv2.CV_64F).var() if score 80: print(f模糊图片: {img_path} (score{score:.1f}))阈值 80 是我的经验值不同相机和光照下差异很大建议先随机抽 20 张图看分数分布再定阈值不要直接照抄。5.2 正常类碾压缺陷类准确率 98% 的假象现象训练完一看总准确率 98%很高兴但打开混淆矩阵发现裂纹类几乎全被算成了 normal。原因正常类拍了 500 张裂纹类只有 60 张。模型学到“都判 normal”就能拿到 85% 以上的准确率缺陷类根本没被认真学。解决先看每个类的样本数对上图。对少数类做补充采集优先实在补不了训练时用类别权重或对少数类做带增强的过采样。不要直接复制原图硬凑数量复制后在文件名后缀加_aug同时配合训练时的翻转、轻微旋转和 HSV 扰动让同一个样本在每轮看到的是不同形态。5.3 同一块饼干的正反面同时进训练集和验证集现象验证集准确率 99%现场却频繁把正常曲奇判成裂纹排查了很久找不到原因。原因采集时一块曲奇拍了正面和反面按单张图随机划分时同一块曲奇的正反面分别进了训练集和验证集。模型记住的是“这块曲奇”而不是“这个缺陷特征”。解决划分验证集时按曲奇个体分组文件名里的个体编号前缀保持一致用 4.2 节的split_dataset.py按组划分。这类问题在公开数据集上不明显因为公开数据集通常已经保证了样本独立性自采数据必须自己处理。5.4 训练 loss 一路下降验证集却提前过拟合现象train loss 从 0.8 一路降到 0.05验证准确率却在前 20 轮冲高后开始回落。原因1000 张图训轻量分类模型照样会过拟合。尤其是数据增强没开、输入分辨率过高、训练轮数过长时模型开始背训练集里的噪声。解决打开 Ultralytics 的增强开关确认训练命令里有augmenttrue加weight_decay5e-4或dropout0.1把学习率适当调低。patience一定要设置让验证集连续不涨时自动停省得空等。增强不是玄学把这些参数列成组合一起调比单调一个参数有效得多。5.5 中文路径和带空格目录在 Windows 上翻车现象训练命令在 Windows 上报FileNotFoundError或者奇怪的编码错误数据集目录名是中文图片文件是.JPEG大写扩展名。原因Ultralytics 读取分类目录时对路径编码和文件扩展名比较敏感中文路径、带空格的目录名、大小写混合的扩展名都容易踩雷。解决数据集根目录、脚本路径全部用英文小写不用空格图片统一转成.jpg用脚本批量重命名一遍。这个坑看似低级但在国内团队里出现频率非常高处理一次能省半天排查时间。6. 训练完怎么验收混淆矩阵、bad case 分析与产线试运行6.1 用混淆矩阵和 bad case 清单验收模型训练结束后别只盯着总准确率。先打开confusion_matrix.png看哪两个类最容易互相混。曲奇分类里最常见的混类是burnt和normal因为边缘轻微烤焦和正常边缘的色差本身是连续过渡的不是非黑即白。接着提取 bad case。把验证集里预测错误的图片单独收集到一个目录集中看一遍判断是标注错误还是类别定义重叠。这个习惯帮我在项目里发现了不少标注问题比在训练参数上反复试要划算得多。yolo classify val \ modelruns/classify/pookie_v1/weights/best.pt \ datadataset跑完后的val输出目录里通常有验证集预测结果文件按预测标签和真实标签不一致的条件筛出文件名再写个小脚本把对应图片复制到 badcase 目录。看完后如果某两类混得很厉害先回头检查那两类的训练图是不是真的区分得开而不是急着加训练轮数。6.2 导出 ONNX接进产线质检小工具验证集分数满意后导出 ONNX 放到工控机上做批量推理。ONNX 格式的好处是不需要装 PyTorch 全家桶也能用 CPU 跑推理适合产线旁边那种没显卡的小机器。import onnxruntime as ort from PIL import Image import numpy as np sess ort.InferenceSession(best.onnx) input_name sess.get_inputs()[0].name img Image.open(test.jpg).resize((224, 224)).convert(RGB) input_tensor np.expand_dims(np.asarray(img) / 255.0, axis0).astype(np.float32) logits sess.run(None, {input_name: input_tensor})[0] cls_id int(np.argmax(logits)) print(f类别序号: {cls_id})导出的预处理和训练时必须保持一致224 分辨率、除以 255、RGB 顺序任何一个对不上推理结果都会漂移。最后在产线试运行时我习惯把现场拍回来的图按天归档每天追加到原始数据池里攒够一定数量就重新划分一次数据集并微调模型。这个“收集现场样片再迭代”的闭环才是分类项目真正稳住精度的关键。我自己的习惯是第一版模型只是起点真正的难点在后续数据回流。每次从现场带回一批误判图模型才往前走一步。希望帮到你。本文还有配套的精品资源点击获取