简介面向食品工业智能质检与曲奇饼干缺陷检测场景这份资源提供了一套可直接用于图像分类算法训练的数据集配套说明。数据集包含1000张真实产线采集的曲奇饼干图片按Defect_Color、Defect_No、Defect_Object、Defect_Shape四类缺陷整理为对应分类文件夹标注质量高可直接接入YOLOCLS/YOLO11cls等图像分类流程。随附的PDF中介绍了数据集基本情况、类别分布及百度网盘获取方式并通过缩略图直观展示四类缺陷的典型样本与目录组织方式同时额外提供YOLO11cls一键训练脚本和博主训练结果日志便于快速跑通训练、对照调参。资源包共1个文件为5.87MB的PDF文档轻量易下载已有29人学习适合食品质检算法初学者或需要补充通用食品缺陷样本的开发者作为曲奇饼干缺陷分类项目的前期数据准备与模型起步参考。1. 目标分类曲奇饼干缺陷检测数据集为什么只用 YOLO11cls 就够了做曲奇饼干缺陷检测很多人第一反应是上目标检测画框、出坐标。但手头只有 1000 张图的时候我一般会直接转到“目标分类”这条路用 YOLO11cls 做整图级别的图像分类把缺陷检测拆成“这张图是正常还是某一类缺陷”。这不是绕路而是数据量决定的取舍——1000 张图分给 5 个类别每类平均只有 200 张目标检测要同时学“框的位置”和“框的内容”参数空间比分类大得多很容易在这么小的数据量上翻车。这篇笔记适合两类人一类是产线质检场景里想快速验证“AI 能不能分拣缺陷饼干”的工程师另一类是刚接触图像分类、手里有一批杂乱图片但不知道如何组织成数据集的初学者。标题里“对应分类文件夹整理”和“YOLO11cls 一键训练脚本”是整套方案的两条腿前者解决数据和标签怎么摆后者解决怎么用最少命令跑出一个可用模型。后面我会把这些拆成能直接抄作业的步骤覆盖目录结构、类别定义、训练参数和几个我踩过的坑。2. 把 1000 张饼干图整理成 YOLO11cls 能吃的目录结构自检脚本与分类文件夹约定2.1 先搞清楚 YOLO11cls 的“cls”到底要什么格式YOLO11cls 是 Ultralytics YOLO11 系列里的图像分类分支后缀 cls 是 classification。它不像 YOLO11 detect 那样要 txt 标注框也不像 segment 要多边形坐标。它吃的就是最朴素的 ImageFolder 结构按类别建文件夹文件夹里放对应类别的图片训练时它自动用文件夹名当标签。很多人第一次用的时候拿“目标检测格式”的思维去套结果把标签文件放进去训练直接报错。我一般会先把目录结构摆成下面这样再往后走cookie_ds/ ├── train/ │ ├── normal/ # 正常饼干 │ │ ├── 0001.jpg │ │ └── 0002.jpg │ ├── crack/ # 裂纹饼干 │ │ └── ... │ ├── chipped/ # 缺角饼干 │ └── burnt/ # 焦斑/过烤 ├── val/ │ ├── normal/ │ ├── crack/ │ ├── chipped/ │ └── burnt/ └── test/ # 可选纯推理用 ├── normal/ └── crack/train 和 val 下面各自再挂类别文件夹这是 YOLO11cls 的默认约定。它的 Train 参数只接收 data 指向“有 train 和 val 子目录”的根目录。如果你只有一个平铺的文件夹里面所有图片混在一起那必须先做一次划分不能直接把平铺目录塞进去。2.2 用脚本检查图片能不能用损坏文件、非图片文件、类别数量统计整理 1000 张图时最容易翻车的不是目录少了而是图片本身有问题。有些是下载来的缩略图损坏有些是拍照时生成的空文件甚至还有隐藏的 .DS_Store 混在文件夹里。YOLO 训练时一旦读到无法解码的图片轻则跳过重则中断训练进程。我习惯先跑下面这个自检脚本#!/usr/bin/env python3 # -*- coding: utf-8 -*- 曲奇饼干缺陷数据集自检与统计脚本 用法: python check_dataset.py /path/to/dataset import os import sys from collections import Counter from PIL import Image def verify_dataset(root): allowed_ext {.jpg, .jpeg, .png, .bmp, .webp} counter Counter() broken [] total 0 for cls_name in os.listdir(root): cls_dir os.path.join(root, cls_name) if not os.path.isdir(cls_dir): continue for fname in os.listdir(cls_dir): ext os.path.splitext(fname)[1].lower() if ext not in allowed_ext: print(f[skip] 非图片文件: {cls_name}/{fname}) continue path os.path.join(cls_dir, fname) total 1 counter[cls_name] 1 try: with Image.open(path) as im: im.verify() # 只校验文件头不加载完整像素 except Exception: broken.append(path) print(类别统计:, dict(counter)) print(f总图片数: {total}, 损坏数: {len(broken)}) for p in broken: print(损坏文件:, p) if __name__ __main__: verify_dataset(sys.argv[1] if len(sys.argv) 1 else .)这段脚本的逻辑很直白遍历根目录下的每一层把文件夹名当类别名。im.verify()是 PIL 里开销很小的校验方式它只检查图片文件头是否符合 JPEG/PNG 格式不会把整张图解码成像素数组所以 1000 张图跑完也就几秒钟。损坏的文件不要留着直接删掉或移出数据集目录否则后面训练时会在数据加载阶段莫名其妙卡住。参数说明allowed_ext白名单防止把配置文件、临时文件混进数据集counter用collections.Counter统计每个类别张数方便你一眼看出类别是否失衡。如果某个类别只有几十张而其他类有三百张后文的数据增强和类别权重就要提前做准备而不是等训练完再后悔。2.3 训练集和验证集怎么切按“炉次”切不要按“图片”随机切划分 train/val 是这类整理里最玄学的一步。很多人图省事把所有图片随机打乱按 8:2 比例分。我踩过的坑是曲奇饼干通常是一炉一炉烤的同一炉的照片光线、烤箱温度、冷却时间完全一致随机切分会把同一炉的图同时分进训练集和验证集。模型看着“验证集准确率 98%”实际只是记住了炉子编号换一条产线直接垮掉。常见做法是按拍照批次或炉次分组。整理时文件夹里每批命名加前缀比如batch01_0001.jpg、batch01_0002.jpg脚本里先取前缀分组再整组划入 train 或 val。这样验证集是真没见过的批次结果才可信。划分比例上1000 张图我一般用 8:2验证集至少 200 张如果类别多会额外抽 100 张做 test 集只在最终验证时用一次。3. 缺陷类别怎么定才不白标从“正常/裂纹/缺角/焦斑”到类别映射脚本3.1 缺陷分类粒度宁可粗分五类不要细碎分十五类曲奇饼干缺陷和轴承缺陷检测、试管缺陷检测这类工业场景有个共同点缺陷花样多但可用的标注数据少。标题里明确说的是“图像分类数据集”不是目标检测所以类别定义直接决定了模型能不能训出来。常见的分类方案是五类normal正常、crack裂纹、chipped缺角、burnt焦斑/过烤、foreign异物/杂质。为什么不把焦斑细分成“表面焦斑”“边缘焦斑”因为 1000 张图分到十几个类每类不到 100 张分类头根本学不到稳定的视觉特征。分类任务的类别设计第一条原则是类间差异要大类内差异可以大但必须有共同视觉指纹。焦斑不管在边缘还是表面视觉指纹都是“深褐色区域”归成一类没问题。裂纹的形态差异大但核心指纹是“细长的深色线状结构”也可以归为一类。下面的脚本解决的是另一个实际问题从现场收集的图片文件夹命名往往乱七八糟有中文、有英文缩写、有大小写混用。先把它们全部映射到统一类别再生成 YOLO 需要的目录结构#!/usr/bin/env python3 # -*- coding: utf-8 -*- 统一类别映射与数据集目录生成脚本 用法: python build_dataset.py /path/to/raw_images /path/to/output import os import sys import shutil CLASS_MAP { good: normal, normal: normal, ok: normal, 合格: normal, crack: crack, cracked: crack, 裂纹: crack, 裂: crack, chipped: chipped, 缺角: chipped, break: chipped, burnt: burnt, burn: burnt, 焦: burnt, 过烤: burnt, foreign: foreign, 异物: foreign, 杂质: foreign, } def map_and_copy(raw_root, out_root, split_ratio0.8): os.makedirs(out_root, exist_okTrue) for cls_name in os.listdir(raw_root): cls_dir os.path.join(raw_root, cls_name) if not os.path.isdir(cls_dir): continue unified CLASS_MAP.get(cls_name.lower()) if unified is None: print(f[warn] 未映射的类别: {cls_name}跳过) continue for split in [train, val]: os.makedirs(os.path.join(out_root, split, unified), exist_okTrue) files [f for f in os.listdir(cls_dir) if os.path.splitext(f)[1].lower() in {.jpg, .jpeg, .png}] for i, fname in enumerate(files): dst_split train if i len(files) * split_ratio else val shutil.copy2(os.path.join(cls_dir, fname), os.path.join(out_root, dst_split, unified, fname)) if __name__ __main__: map_and_copy(sys.argv[1], sys.argv[2])这段脚本的价值在于把“脏名字”统一成干净类别。CLASS_MAP里我预先做了大小写归一cls_name.lower()保证 “Crack” 和 “crack” 不会被拆成两个类。没有映射到的名字会打 warn 并跳过而不是直接静默忽略这样你能发现哪些文件夹命名超出了预设。脚本里的划分是按单个类内文件顺序前 80% 进 train。这只适合已经完全打乱顺序的原始目录如果要按炉次划分改成“取文件名前缀分组”即可。shutil.copy2保留文件元数据如果磁盘吃紧可以改成shutil.move但移动操作不可逆我一般先复制后人工检查产物。3.2 样本不平衡1000 张图里的“二八定律”怎么处理真实产线收集的缺陷数据永远是不平衡的正常饼干占 60%裂纹占 20%缺角占 10%焦斑和异物各占 5%。如果不做处理模型会走向“偷懒策略”——把所有图都判成 normal因为这样准确率已经有 60%。这不是模型坏了是损失函数在数据不平衡下自然收敛到这个状态。常见做法有三个层级。第一层训练时把weightedTrue打开Ultralytics 的分类训练接口支持类别权重少数类样本在损失函数里会被放大第二层对 minority 类做离线增强比如对焦斑类做旋转、亮度抖动、随机裁剪把 50 张扩到 150 张第三层如果懒得写增强代码就用augmentTrue让 YOLO 内置的 HSV、翻转、缩放策略在训练时生效。我一般三层同时上但第一层是底线哪怕只开weighted也能明显改善焦斑和异物这两类的召回率。4. 用 YOLO11cls 一键训练脚本跑通分类模型命令、参数与训练日志解读4.1 一条命令启动训练但“一键脚本”不是只写一行 yolo网上到处是“一键训练脚本”但很多脚本只是把yolo classify train一行命令包了层皮没有任何容错。我的一键脚本一般做三件事检查数据集目录存在、创建日志目录、设置好相对路径后执行训练。这样做的好处是下次换机器、换路径时不用一条条手改命令也避免因为当前目录不对导致 data 路径解析失败。#!/usr/bin/env bash # 一键训练脚本 train.sh: YOLO11cls 曲奇饼干缺陷图像分类 set -e # 任何一行失败立即退出不要带病继续训 cd $(dirname $0) DATAdata/cookie_ds # 前面整理好的数据集根目录 PROJECTruns/classify # 训练输出目录 NAMEcookie_run_$(date %Y%m%d_%H%M%S) # 检查数据集目录 if [ ! -d $DATA/train ] || [ ! -d $DATA/val ]; then echo 数据集目录不完整, 需要包含 train/ 和 val/ 子目录 exit 1 fi mkdir -p $PROJECT yolo classify train \ data$DATA \ modelyolo11cls.pt \ epochs50 \ imgsz224 \ batch32 \ lr00.001 \ patience15 \ cacheFalse \ project$PROJECT \ name$NAME \ pretrainedTrue \ augmentTrue echo 训练完成, 输出目录: $PROJECT/$NAME脚本里set -e很多人会忽略但命令行工具一旦报错还会继续往下跑会把错误的中间产物当成成功结果。数据目录检查是防止你在data...传错路径时花 20 分钟等一个必然失败的训练。$(date %Y%m%d_%H%M%S)给每次训练一个独立名称这样多次实验不会互相覆盖回看结果时也能分清是哪一次跑的。4.2 关键参数怎么调imgsz、batch、epochs、cache 的取舍参数我的默认值什么时候改imgsz224缺陷面积小如细裂纹可试 320再大收益有限且显存暴涨batch32显存不足报 OOM 时降到 16 或 8epochs50验证集精度还有上升趋势时加到 80但超过 100 要小心里patience15验证集连续 15 轮不提升就早停省时间也防过拟合cacheFalse数据集存在内存盘/SSD 时可开lr00.001用预训练模型时保持从零训练时可放大到 0.01数据层面再说一次1000 张图对图像分类来说是小样本所以pretrainedTrue是我必开的选项。yolo11cls.pt 是 YOLO11 在 ImageNet 上预训练好的分类权重backbone 已经懂得纹理、边缘、颜色这些基础特征我们要做的只是把最后一层分类头换成 5 类再微调。这是小样本图像分类里性价比最高的一条路比从随机初始化硬训省下大量时间和数据。lr00.001是微调的保守值如果发现模型学得很慢可以先看准确率曲线再决定是否调大不要一上来就 0.01。4.3 训练日志里真正要盯的三个信号训练过程中fit 信息每轮都会刷一行。我会重点盯三个信号train loss 是否在稳定下降、val accuracy 是否随之上升、两者之间的差距是否越来越大。第一个信号说明模型在正常拟合。第二个信号说明学习率没设废。第三个信号是过拟合的早期预警——如果 train accuracy 到了 98% 但 val 只有 82%说明模型开始背训练集了。YOLO 分类训练默认会在 output 目录里存下 results.png里面有 loss 曲线和 accuracy 曲线不用自己记数字。早停只说 true 时实际跑多少轮取决于 patience 是否触发这比固定 epoch 更稳妥。5. YOLO11cls 训练曲奇缺陷分类的四个必踩坑标签错位、缓存报错、过拟合与假收敛5.1 坑一验证集准确率异常高换新图直接现原形现象训练时 val accuracy 冲到 96%看起来可以直接上产线结果拿手机现场拍 20 张曲奇正常和裂纹分得稀里糊涂。原因数据集划分时偷懒用了全随机打散。同一炉、同一光线条件下的图片随机分到了 train 和 val模型实际是在“认炉子”而不是“认缺陷”。这是图像分类数据集整理中最常见的系统性错误不是模型问题。解决回到第 2.3 节的做法按炉次/批次分组划分数据集。划分前先看图片文件名如果命名里有批次号就必须整组切。没有批次号的看图片 EXIF 时间戳按拍照时间段分组。5.2 坑二训练中突然报内存错误进程退出一半现象训练跑到第 20 轮终端报错RuntimeError: CUDA out of memory或者卡死不动进度条停在某个百分比。原因多数是cacheTrue把所有图片预加载进内存。1000 张 224x224 的图本身不大但 YOLO 内部做完整的数据增强流水线缓存占的是 RAM 和显存双重空间。如果同时开 batch64 和 cacheTrue小显存机器很容易在增强阶段爆掉。解决把cacheFalse让每轮实时读图。如果读图成为瓶颈先把 imgsz 降到 160 试跑确认稳定后再升到 224。数据集放在机械硬盘上时可以把图片转成 LMDB 格式或直接放 SSD比纠结 cache 参数更有效。5.3 坑三模型把所有图都判成 normal准确率却显示 60%现象训练完成查看混淆矩阵发现 crack、burnt 等缺陷类几乎全是 0 预测但总准确率 60% 看起来“还行”。原因类别不平衡加上损失函数默认加权方式不对。之前说过 normal 占大头模型学到的决策边界是“只要不确定就猜 normal”因为这样损失最小。准确率这个指标在这种场景下严重失真不能作为唯一验收标准。解决第一训练时加weightedTrue对少数类做损失加权第二看验证结果时用yolo classify val输出的每个类别 precision/recall而不是只看总 accuracy第三给少数类做离线增强把焦斑和异物各扩到 100 张以上。这三步做完缺陷类的召回率通常能从接近 0 拉到 70% 以上。5.4 坑四loss 降得很稳准确率却像心电图一样忽高忽低现象train loss 每轮都在降说明模型在学但 val accuracy 一会儿 90% 一会儿 70%波动非常大。原因常见是验证集太小。1000 张图分出 20% 验证集是 200 张平均每类 40 张随机采样的方差本来就大。另一个可能原因是验证集里某个类只有个位数样本那几张图质量差一点准确率就剧烈抖动。解决扩大验证集到 30%确保每个类至少有 30 张验证图。如果原始数据不够先做离线增强补足少数类再划分而不是先划分再增强。波动还在的话开patience并在训练结束后取 best.pt——Ultralytics 默认保存最优权重不要拿最后一轮的结果当最终模型。6. 训练完不等于能用用 CAM 热图、1-shot 对比和分类头微调验证模型模型训完先别急着拷到产线。我会做三件额外的验证每一件都只花十几分钟但能筛掉大部分“看着指标挺好、实际不能用的模型”。第一件事是看 CAM 热图。YOLO11cls 是卷积网络可以用 Grad-CAM 检查模型的注意力区域。正常饼干的热图应该集中在饼干主体裂纹类热图应该聚焦在裂纹线条附近如果热图永远在背景或角落说明模型学到的是环境特征而不是饼干缺陷本质。写个几十行的 PyTorch 脚本注册最后一个卷积层的 forward hook 就能出热图不用改模型结构。第二件事是做 1-shot/5-shot 小样本评估。从没参与训练的图片里每类抽出 1 张和 5 张分别测试模型的 top-1 准确率变化。1-shot 准说明类别边界清晰模型主干特征提取得好如果 1-shot 全乱、5-shot 正常说明类别边界依赖训练数据里的特殊纹理泛化仍不足。这个测试不需要重新训练只是把固定分类头换成临时线性层做评估。第三件事是回答那个常见问题用 ViT 做评估时分类头需要调整吗需要。不管是 ViT 还是 YOLO11cls预训练模型的分类头都对应 ImageNet 的 1000 类输出维度和你 5 类不匹配。常见做法是冻结 backbone、只换一个 Lineare 分类头并进行 linear probing 评估如果样本充足再解冻部分层微调。换头但不微调直接拿预训练头输出做评估是我见过最多的误用。我自己的习惯是每次换数据集都先跑一次 CAM 热图再谈准确率。没有热图佐证的准确率我心里始终打问号。这几个检查做完模型能不能上产线才算有底气。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?