ARTICLE DETAIL

资讯详情

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

智能零售柜商品识别数据集:5000张VOC与YOLO双格式实战指南

智能零售柜商品识别数据集:5000张VOC与YOLO双格式实战指南 简介面向智能零售结算场景的商品识别检测数据集适合从事计算机视觉目标检测的开发者、学生及算法工程师用于训练与评估自动结算系统中的商品识别模型。数据集共5422张已标注图片覆盖113类商品并已划分训练集3796张、验证集1084张、测试集542张可直接用于PaddleDetection、PaddleX及YOLO系列、SSD、PPYOLO等主流检测框架。压缩包内共8057个文件以jpg图像、xml标注和txt标签为主分别对应原始图片、VOC格式标注与YOLO格式标签整体约881.5MB兼顾两种常用标注格式省去格式转换环节。已有597人学习下载参考项目中最高mAP可达96.41可作为智能零售柜商品检测的基线数据帮助读者快速复现训练流程、验证算法效果并对比不同检测模型的表现。1. 智能零售柜商品识别数据集5000 张 VOC 与 YOLO 双格式到底怎么用做智能零售柜这行绕不开一个现实柜子里塞满饮料、零食、日用品SKU 动辄几百上千靠人工盘点不现实靠 RFID 成本高还容易串读最后大家都会走到视觉识别这条路。而视觉识别的第一道坎从来不是模型选哪个而是数据从哪来。你手上如果有一个 5000 张规模、同时带 VOC 格式和 YOLO 格式标签的商品识别检测数据集那基本等于把冷启动阶段最痛苦的一步给省了。这个标题讲的正是这样一份资源5000 张零售柜场景的商品图像标注同时提供 Pascal VOC 的 XML 和 YOLO 的 txt 两套覆盖检测任务里最常见的两种训练框架入口。它适合三类人刚接手零售柜算法、需要快速跑通 baseline 的工程师想验证自己检测模型在密集小目标上表现的算法同学以及做商品识别产品、需要评估数据成本的项目负责人。下面我不谈虚的直接讲这份数据怎么落地、参数怎么设、坑在哪。2. 先搞清楚 VOC 和 YOLO 两套标签的差异与转换逻辑2.1 两种格式的本质区别不在文件后缀而在坐标表达很多人第一次拿到双格式数据集会以为只是同一份标注换了扩展名其实不是。VOC 的 XML 存的是绝对像素坐标xmin/ymin/xmax/ymax直接对应原图上的框位置宽高由框自身决定YOLO 的 txt 存的是归一化后的中心点加宽高class cx cy w h四个值都在 0 到 1 之间且 cx、cy 是框中心相对整图宽高的比例。这个差异决定了VOC 标签换一张分辨率不同的图就失效YOLO 标签天然跟分辨率解耦。零售柜场景里同一款商品在不同柜机、不同摄像头下分辨率可能不一样所以 YOLO 格式在跨设备迁移时更省事。但 VOC 格式可读性强用 LabelImg 打开能直接看到框排查标注错误时更直观。两套都留着本质是给你两条路想快速可视化核对用 VOC想直接喂训练用 YOLO。2.2 目录结构要先对齐否则训练脚本第一步就报错拿到压缩包解压后常见做法是整理成下面这种结构VOC 和 YOLO 各占一个根目录图片共用一份避免重复占空间retail_dataset/ ├── images/ │ ├── 000001.jpg │ ├── 000002.jpg │ └── ... ├── voc_annotations/ │ ├── 000001.xml │ ├── 000002.xml │ └── ... ├── yolo_labels/ │ ├── 000001.txt │ ├── 000002.txt │ └── ... └── classes.txtclasses.txt里一行一个类别名顺序必须和 YOLO 标签里的 class id 严格对应第 0 行对应 id 0第 1 行对应 id 1。这个文件看着不起眼但它是后面所有类别映射的唯一依据写错一行整个训练集的标签全乱。我一般会先wc -l classes.txt确认类别数再抽查几张图的 txt看 class id 有没有超出范围。2.3 从 VOC 转 YOLO 的脚本与四个边界坑如果手上只有 VOC或者想自己重新生成一遍 YOLO 标签做校验用下面这段脚本转换。它读 XML 里的尺寸和框算出归一化值写进 txtimport os import xml.etree.ElementTree as ET # 类别名到 id 的映射顺序必须和 classes.txt 一致 classes [drink, snack, daily, other] class_to_id {c: i for i, c in enumerate(classes)} def voc_to_yolo(xml_path, out_txt_path): tree ET.parse(xml_path) root tree.getroot() size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) lines [] for obj in root.iter(object): cls_name obj.find(name).text.strip() if cls_name not in class_to_id: continue # 类别不在表里就跳过避免脏标签污染训练 bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 边界裁剪防止标注越界导致归一化后出现负值或大于1 xmin max(0, min(xmin, img_w)) xmax max(0, min(xmax, img_w)) ymin max(0, min(ymin, img_h)) ymax max(0, min(ymax, img_h)) cx (xmin xmax) / 2.0 / img_w cy (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h # 过滤掉宽高为0的无效框 if w 0 or h 0: continue lines.append(f{class_to_id[cls_name]} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) with open(out_txt_path, w) as f: f.write(\n.join(lines)) if __name__ __main__: xml_dir retail_dataset/voc_annotations out_dir retail_dataset/yolo_labels os.makedirs(out_dir, exist_okTrue) for name in os.listdir(xml_dir): if name.endswith(.xml): voc_to_yolo( os.path.join(xml_dir, name), os.path.join(out_dir, name.replace(.xml, .txt)) )逻辑上这段脚本做了三件关键事一是用size里的真实宽高做归一化不能拿固定值二是对框做边界裁剪零售柜标注里经常出现框超出图像边缘的情况不裁就会算出负数或大于 1 的值训练时直接报错三是过滤宽高为 0 的退化框。参数上classes列表必须和你的classes.txt完全一致:.6f保留六位小数是 YOLO 生态里比较通用的精度够用且不会让文件过大。跑完记得抽查随便挑一张图用cat看 txt再用 LabelImg 打开对应 XML肉眼比对框位置是否一致。3. 用这份数据集跑通 YOLO 训练的最小闭环3.1 数据划分与 data.yaml 的写法5000 张不能全拿去训练常规做法是训练集 70%、验证集 20%、测试集 10%也就是 3500 / 1000 / 500。划分时要注意同一款商品、同一个柜机角度尽量别跨集否则验证集指标会虚高。划分完写一个data.yamlpath: /data/retail_dataset train: images/train val: images/val test: images/test nc: 4 names: [drink, snack, daily, other]nc是类别数必须和names长度一致也和classes.txt行数一致。path用绝对路径最稳相对路径在不同工作目录下跑容易找不到图。YOLO 找标签的默认逻辑是把images替换成labels所以你的目录里最好保持images/train对应labels/train这种镜像结构省得改代码。3.2 训练命令与关键参数怎么设以常见的 YOLOv8 训练入口为例最小命令是这样yolo detect train \ data/data/retail_dataset/data.yaml \ modelyolov8s.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/retail \ nameexp1参数逐个说model选 s 而不是 n是因为零售柜商品密集、小目标多n 的容量容易欠拟合imgsz640是通用起点如果你的柜机图像里商品特别小可以提到 960 甚至 1280但显存和速度要权衡batch16在 8G 显存上跑 640 基本稳爆显存就降到 8lr00.01是 SGD 的常规初始学习率用 Adam 的话要降到 0.001 量级patience20表示 20 轮验证指标不涨就早停避免过拟合。训练过程中重点看mAP50和mAP50-95两条曲线如果训练 loss 一直降但验证 mAP 早早平掉多半是过拟合回去加数据增强或者减模型容量。3.3 零售柜场景必须开的增强项通用增强不够用零售柜有几个特点商品排列密集、遮挡严重、光照受柜门玻璃影响大。所以增强配置里我一般会显式打开这几项mosaic1.0提升小目标召回mixup0.1缓解过拟合hsv_h0.015、hsv_s0.7、hsv_v0.4模拟不同柜内灯光degrees5做小角度旋转因为摄像头安装角度通常有轻微偏差。flipud建议关掉商品上下翻转不符合真实摆放逻辑开了反而引入噪声。这些值不是拍脑袋是多次在零售柜数据上试出来的经验区间你可以在此基础上微调。4. 商品识别数据集落地时的避坑与排查4.1 类别不均衡导致小类几乎检不出现象训练完看混淆矩阵饮料类 mAP 0.8日用品类只有 0.2。原因5000 张里日用品样本可能只占 5%模型被大类主导。解决先统计每个类别的框数量对少于 500 框的类别做过采样或者在损失里给稀有类加权。YOLO 本身没有直接的类权重参数常见做法是复制含稀有类的图像进训练集或者用copy-paste增强把稀有商品贴到其他图上。4.2 标签越界和宽高为 0 让训练直接崩现象训练启动几轮后报nan或者断言失败。原因VOC 转 YOLO 时没做边界裁剪出现负坐标或大于 1 的值或者标注时手滑画了零面积框。解决转换脚本里必须加裁剪和过滤转换完再跑一遍校验脚本遍历所有 txt检查每个值是否在 0 到 1 之间、w 和 h 是否大于 0。这一步花十分钟能省掉后面几小时的排查。4.3 图像和标签文件名对不上现象训练日志里 warning 一堆「image not found」或者「label missing」。原因图片是.jpg标签是.txt但有的图没有对应标签或者扩展名大小写不一致。解决写个脚本比对images和labels两个目录的文件名集合找出差集缺标签的图要么补标要么移出训练集。零售柜数据里经常有纯背景图这种图没有目标YOLO 允许空标签文件但文件名必须存在。4.4 验证集指标虚高上线就翻车现象验证集 mAP 0.9实际柜机测试掉到 0.5。原因划分数据时同一柜机、同一批次的图被分到了训练和验证两边模型其实见过类似场景。解决按柜机 ID 或拍摄批次做分组划分确保验证集的柜机和训练集不重叠。这个坑最隐蔽因为指标好看的时候没人会怀疑划分方式等上线才发现问题后悔药没得吃。4.5 玻璃反光和遮挡造成的漏检现象柜门有反光或者商品被前排挡住时漏检明显。原因训练集里这类困难样本太少模型没学到。解决专门收集一批反光、遮挡的图哪怕只有两三百张加进训练集做微调效果比调参明显。另外推理时可以适当降低置信度阈值从 0.25 降到 0.15召回会回来一些代价是误检略增零售柜场景里漏检比误检更不可接受。5. 把 5000 张用出 5 万张的效果进阶技巧与验证习惯数据量固定的时候提升空间在用法上。第一个技巧是「难例回流」模型上线后把置信度在 0.3 到 0.5 之间的预测框对应的图挑出来人工复核后加进训练集迭代两三轮mAP 通常能涨 5 到 10 个点。第二个技巧是「多尺度训练」在data.yaml同级配置里把imgsz设成范围比如 640 到 960 随机让模型适应不同柜机分辨率比固定尺寸泛化好。第三个是「类别合并再拆分」如果某些 SKU 外观极像先合并成一个大类训一版再把 backbone 冻结、换分类头做细分类比直接训几百类稳得多。验证习惯上我坚持两件事一是每次训练完必须用测试集跑一遍yolo detect val看混淆矩阵和 PR 曲线不能只看训练日志的 mAP二是抽 20 张测试图做可视化把预测框画出来肉眼过一遍很多标注错误和逻辑问题只有看图才能发现。表格里是我常用的验证检查项检查项合格标准不达标时先查类别框数量分布稀有类不少于 300 框是否需过采样标签值范围全部在 0~1 之间转换脚本边界裁剪训练/验证 mAP 差距小于 0.15是否过拟合或划分泄漏单图推理耗时满足柜机实时要求模型尺寸和 imgsz困难样本召回反光遮挡场景可接受是否需补难例最后说个我自己的习惯拿到任何一份商品识别数据集先别急着训模型花半小时把类别分布、框大小分布、图像分辨率分布画出来。这三个分布图能告诉你这份数据适合什么模型、该设什么 imgsz、哪些类需要特殊照顾。我早期跳过这一步直接开训结果跑了三天才发现某类样本只有几十个白白浪费算力。数据这行前期多看一眼后期少熬一夜。希望帮到你。本文还有配套的精品资源点击获取
返回列表