简介:本资源为基于海康设备实拍构建的方便面调料正反目标检测数据集,面向从事工业质检、食品包装检测及目标检测算法实践的开发者与学习者。数据集将正常放置的调料包标注为one,反方向异常放置标注为two,可用于训练模型识别产线上的方向异常问题,适合具备一定YOLO使用经验的中级用户。压缩包共904个文件,包含441张jpg实拍图像、442个txt标注文件及21个xml标注文件,整体约758.95MB,图像与标注一一对应,便于直接投入训练与验证。据描述,该数据集经手动标注后,在YOLOv8上检测mAP可达90%左右,可作为方向分类与缺陷检测任务的可靠基线。目前已有109人学习下载,读者可据此快速搭建正反识别流程,并在此基础上进行数据增强与模型调优。
1. 海康相机拍出来的调料包数据集:one 和 two 到底怎么分
产线上用海康工业相机拍方便面调料包,正着放和反着放要分开,这事听起来简单,真做起来翻车的人不少。我见过太多人拿到一批图,觉得「正反一眼就能看出来」,结果标注规则没定死,模型训出来把正放判成反放,产线直接误剔。这份数据集的核心价值就在这:它把「正常放置」定义为 one,「异常(反方向)放置」定义为 two,用两个类别把二分类检测问题框死,省去了你自己定规则的纠结。
它适合谁?做食品包装质检的视觉工程师、拿海康相机做产线项目的集成商、以及想用真实工业图练 YOLO 系列目标检测的算法同学。数据集本身是目标检测格式,不是简单的图像分类,也就是说每张图里调料包的位置和类别都要框出来。这一点很关键——很多人拿到数据集第一反应是当分类任务训,那就浪费了标注信息。下面我从数据组织、标注格式、训练配置到避坑,一步步拆开讲,让你拿到就能跑。
2. 数据集结构与标注格式:先搞懂 one/two 的目录逻辑
2.1 图像与标签的对应关系
这类工业目标检测数据集,常见做法是 images 和 labels 两个平行目录,文件名一一对应。图片是海康相机出的 JPG 或 PNG,标签是 YOLO 格式的 txt,每行五个值:类别索引、归一化中心 x、归一化中心 y、归一化宽、归一化高。类别索引 0 对应 one,1 对应 two,这个映射必须在训练前确认,别想当然。
我一般拿到数据集先干三件事:数图片数量、数标签数量、抽查十张图的框是否贴合。命令很简单:
# 统计图片和标签数量,数量对不上说明有漏标或多余文件 find images -type f \( -name "*.jpg" -o -name "*.png" \) | wc -l find labels -type f -name "*.txt" | wc -l # 抽查一个标签文件内容,确认类别索引和坐标范围 cat labels/xxx.txt逻辑说明:第一条命令统计图片总数,第二条统计标签总数,两者必须相等。第三条看具体内容,正常一行应该是0 0.512 0.487 0.321 0.654这种,坐标都在 0 到 1 之间。如果出现大于 1 的值,说明标注工具导出时没归一化,得转。参数上,类别索引 0/1 的顺序要和你的 data.yaml 里 names 列表严格一致,顺序错了模型学出来的语义就反了。
2.2 data.yaml 的写法与类别映射
YOLO 系列训练靠一个 yaml 文件告诉它去哪找图、有几个类。这份数据集是两类,写法如下:
# data.yaml path: ./dataset # 数据集根目录 train: images/train # 训练集图片路径 val: images/val # 验证集图片路径 nc: 2 # 类别数,one 和 two names: 0: one # 正常放置 1: two # 反方向放置逻辑说明:path 是根目录,train 和 val 是相对路径。nc 必须等于 names 的条目数,多一个少一个都会在训练启动时报错。names 的顺序就是类别索引,0 是 one,1 是 two,这个顺序一旦定了,后面推理时输出的类别 id 就按这个来。常见坑是有人把 names 写成中文,某些版本的训练脚本读 yaml 会乱码,建议先用英文,展示层再映射成中文。
2.3 训练集与验证集怎么切
工业数据集往往不给你切好,得自己分。我一般按 8:2 切,且要保证两个类别在训练集和验证集里都有足够样本。如果 two 类样本特别少,就不能纯随机切,否则验证集里可能一个 two 都没有,指标全是虚的。
import os, random, shutil # 按 8:2 切分,保证每个类别都有样本进入验证集 img_dir = "images/all" lbl_dir = "labels/all" train_img, val_img = "images/train", "images/val" train_lbl, val_lbl = "labels/train", "labels/val" for d in [train_img, val_img, train_lbl, val_lbl]: os.makedirs(d, exist_ok=True) files = [f for f in os.listdir(img_dir) if f.endswith((".jpg", ".png"))] random.seed(42) # 固定随机种子,保证可复现 random.shuffle(files) split = int(len(files) * 0.8) for i, f in enumerate(files): src_img = os.path.join(img_dir, f) src_lbl = os.path.join(lbl_dir, os.path.splitext(f)[0] + ".txt") if i < split: shutil.copy(src_img, train_img) shutil.copy(src_lbl, train_lbl) else: shutil.copy(src_img, val_img) shutil.copy(src_lbl, val_lbl)逻辑说明:seed(42) 是为了每次切分结果一致,方便复现。split 取 80% 作为训练。循环里图片和标签同步搬运,标签文件名用 splitext 去掉扩展名再拼 .txt。参数上,如果你的 two 类样本少于总量的 10%,建议改成按类别分层抽样,别用这个纯随机版本,否则验证集可能没有 two,训出来的模型对反放包完全不敏感。
3. 用 YOLOv8 跑通训练:从环境到第一个权重
3.1 环境准备与依赖版本
目标检测训练最烦的就是版本打架。我一般用 conda 建独立环境,Python 3.9 或 3.10,PyTorch 跟 CUDA 版本对齐。海康相机出的图分辨率通常不低,显存 8G 起步比较稳。
# 建环境并装依赖,版本按自己显卡驱动选 conda create -n detect python=3.10 -y conda activate detect pip install ultralytics==8.1.0 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118逻辑说明:ultralytics 是 YOLOv8 的官方包,8.1.0 是相对稳定的版本。torch 的 index-url 指向 CUDA 11.8 的轮子,如果你显卡驱动对应的是 12.1,就把 cu118 换成 cu121。装完用python -c "import torch; print(torch.cuda.is_available())"验证,输出 True 才算能用 GPU。这一步翻车最多,很多人装完发现是 CPU 版,训练慢十倍。
3.2 启动训练与关键参数
环境好了直接上训练命令。这份数据集是两类小目标偏多,输入尺寸和 batch 要调。
yolo detect train \ data=data.yaml \ model=yolov8s.pt \ epochs=100 \ imgsz=640 \ batch=16 \ lr0=0.01 \ patience=20 \ project=runs/train \ name=seasoning逻辑说明:model 选 yolov8s 是精度和速度的折中,n 版更快但小目标容易漏,m 版更准但吃显存。imgsz=640 是默认值,如果调料包在图中占比很小,可以提到 960 或 1280,但显存占用会涨。batch=16 按显存调,爆显存就降到 8。lr0 初始学习率 0.01 是常规起点,数据量小可以降到 0.001。patience=20 表示 20 轮没提升就早停,省时间。project 和 name 决定权重存哪,跑完在 runs/train/seasoning/weights/ 下找 best.pt。
3.3 训练过程看什么指标
训练日志里重点盯三个:box_loss、cls_loss、mAP50。box_loss 管框的位置,cls_loss 管类别判对没有。如果 cls_loss 一直不降,大概率是 one 和 two 的样本不均衡,或者标注里类别索引写反了。mAP50 到 0.9 以上基本可用,但工业场景我更看混淆矩阵,确认 one 被误判成 two 的比例。
from ultralytics import YOLO # 训练完加载最优权重,在验证集上跑一遍看混淆矩阵 model = YOLO("runs/train/seasoning/weights/best.pt") metrics = model.val(data="data.yaml", conf=0.25, iou=0.5) print(metrics.confusion_matrix) # 重点看 one/two 之间的误判逻辑说明:conf=0.25 是置信度阈值,低于它的框不算。iou=0.5 是判定预测框和真值框重合的标准。confusion_matrix 会打印一个 2x2 矩阵,对角线是判对的,非对角线就是 one 判成 two 或反过来。工业质检里,把 two 漏判成 one 比反过来更危险,因为异常品流出去了。所以看矩阵时要针对性调阈值。
4. 避坑与排查:标注、类别、显存这三关最容易翻车
4.1 现象:训练 loss 正常但 mAP 一直上不去
原因:八成是标注框和图片没对齐,或者标签文件名和图片名对不上。YOLO 读标签是按文件名匹配的,图片叫 001.jpg,标签必须叫 001.txt,差一个字符就当成无标签图,训练时那张图的所有目标都被忽略。
解决:写个脚本批量校验文件名对应关系,再抽查框的坐标是否贴合目标。命令如下:
# 找出有图片没标签、或有标签没图片的文件 comm -3 <(ls images/train | sed 's/\.[^.]*$//' | sort) <(ls labels/train | sed 's/\.txt$//' | sort)逻辑说明:comm -3 显示两边不一致的行,sed 去掉扩展名后对比。输出为空说明完全对应。有输出就逐个补标或删多余文件。
4.2 现象:模型把 one 和 two 判反
原因:data.yaml 里 names 的顺序和标注时的类别索引不一致。比如标注时 0 是 two、1 是 one,但 yaml 里写反了,模型学到的语义就整个颠倒。
解决:打开几个标签文件确认 0 和 1 分别对应哪种放置,再改 yaml。改完必须重新训练,不能拿旧权重微调,因为语义已经错了。
4.3 现象:训练到一半 CUDA out of memory
原因:imgsz 或 batch 设太大,或者 dataloader 的 workers 太多导致内存泄漏。
解决:先把 batch 减半,还不行就降 imgsz。另外把 workers 设成 4 或 8,别用默认的 8 以上。命令里加workers=4即可。
4.4 现象:验证集指标很好,产线实测漏检严重
原因:训练集和产线的光照、角度、背景差异大,模型过拟合了训练环境。海康相机在不同工位拍出来的图,白平衡和曝光都可能不一样。
解决:从产线现场再采一批图,混进训练集做增量训练。或者用数据增强,训练时加hsv_h=0.015 hsv_s=0.7 hsv_v=0.4模拟光照变化,加degrees=10模拟角度偏移。
4.5 现象:two 类样本太少,模型几乎不预测 two
原因:类别不均衡,模型倾向于把多数类判对就能拿高准确率。
解决:两个办法。一是训练时给 two 类加权,YOLOv8 可以在 yaml 里加cls_pw参数,或者用 copy-paste 增强把 two 类样本复制粘贴到更多背景上。二是调整验证指标,别只看 mAP,重点看 two 类的 recall,recall 低就继续补样本。
5. 推理部署与阈值调优:让 one/two 判定真正可用
训练出 best.pt 只是第一步,真正上线要解决推理速度和判定阈值。海康相机实时出图,单帧推理得控制在几十毫秒内。我一般用 ONNX 或 TensorRT 加速,YOLOv8 自带导出。
from ultralytics import YOLO # 导出 ONNX,FP16 量化提速 model = YOLO("runs/train/seasoning/weights/best.pt") model.export(format="onnx", half=True, imgsz=640, simplify=True) # 推理时按类别设不同阈值 results = model.predict("test.jpg", conf=0.3, iou=0.45) for r in results: for box in r.boxes: cls_id = int(box.cls) label = "one" if cls_id == 0 else "two" print(label, float(box.conf))逻辑说明:export 的 half=True 用 FP16 量化,速度能提一截,精度掉得很少。simplify=True 优化计算图。推理时 conf=0.3 是全局阈值,但实际产线我会给 two 类单独设更低的阈值,比如 0.2,宁可多报也不漏报异常品。box.cls 是类别索引,映射回 one/two 再输出。
阈值调优有个笨办法但很有效:拿一批已知正反的测试图,从 0.1 到 0.9 扫一遍 conf,画一条 two 类 recall 和误报率的曲线,选 recall 高且误报可接受的点。这个表我一般会存下来:
| conf 阈值 | two 类 recall | one 误报成 two 的比例 | 建议 |
|---|---|---|---|
| 0.15 | 0.99 | 0.12 | 漏检最少,误报偏高 |
| 0.25 | 0.97 | 0.06 | 平衡点,常用 |
| 0.40 | 0.91 | 0.02 | 误报低,漏检上升 |
| 0.60 | 0.78 | 0.01 | 太保守,不建议 |
从那以后我每次部署前都强制走一遍阈值扫描,不再拍脑袋定 0.5。这套数据集的价值不在于图有多难,而在于它把 one/two 这个二分类边界定得干净,你只要把标注对应、类别顺序、阈值这三件事做扎实,产线落地并不玄学。希望帮到你。
本文还有配套的精品资源,点击获取