ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

货架与购物车实例分割数据集:YOLOv8-seg训练与踩坑全记录

2026/8/26 8:35:31 拓冰建站 浏览量
货架与购物车实例分割数据集:YOLOv8-seg训练与踩坑全记录 简介实例分割作为计算机视觉的核心任务之一不仅要定位图像中的目标更要输出像素级的精确轮廓。YOLOv8-seg作为主流的分割模型将目标检测与掩膜生成统一到同一框架中在保证实时性的同时提供高质量的实例分割能力。该技术在智慧零售领域具有重要的工程价值例如货架排面管理、购物车装载率统计、无人收银行为分析等场景都需要借助像素级分割来获取精准的度量数据。针对零售场景难以获取高质量标注数据的问题一套覆盖货架、购物车、商品、手、人等关键目标的实例分割数据集配合完整的YOLOv8训练流程能够有效降低落地门槛。以某零售场景的货架与购物车实例分割数据集为例从数据集设计、标注格式、训练参数、踩坑排查到部署实践系统梳理一套可复现的工程路径。 拿到这个压缩包的时候我第一反应是想起去年做智慧零售项目那段时间。货架与购物车实例分割数据集_20251122_165431.zip文件名里带时间戳一看就是从标注平台导出后没过脑子直接扔进网盘的。今天重新下载解压配好YOLOv8-seg跑了一遍完整训练流程中间还踩了几个老坑干脆全部整理成这篇实操记录。这套数据集做的是零售场景下的实例分割覆盖货架区域和购物车区域两类核心目标。货架要区分层板、商品、遮挡关系购物车要分开车体轮廓和车内商品人和手作为交互目标也一并纳入标注。如果你正在做智慧零售、无人收银、货架巡检或者只是想拿一份现成数据练YOLOv8实例分割这份数据集和这篇文章都很值得参考。我会从数据集设计思路、压缩包内部结构、YOLOv8训练全流程、高频踩坑排查这几个维度把完整过程讲清楚。1. 项目背景为什么货架与购物车要单独做实例分割1.1 货架与购物车是零售视觉的两大主场景零售场景的视觉任务绝大多数发生在两个物理空间卖场里的货架以及顾客手里的购物车。货架是商品陈列、排面管理、缺货检测的核心载体购物车则连接着顾客动线、拿放行为和结算环节。货架这个目标在图像里很有辨识度但结构并不简单。层板、立柱、背板、价签、摆在前面的商品这些元素层层叠加目标之间天然存在大面积遮挡。购物车就更特殊铁丝网格结构导致目标内部是镂空的不同角度看到的形态差异极大。这两个目标放在同一个数据集里模型要学习的不只是“货架长什么样”还包括货架和购物车共处同一画面时的空间关系比如手从货架拿商品放进购物车这个动作链。从业务角度来看检测框是远远不够用的。货架上密集排列的商品检测框之间大量重叠NMS会误杀真实目标。购物车这种镂空结构一个框会把车体周围的大量背景也包进来后续统计装载率、计算商品数量时误差很大。实例分割输出像素级轮廓可以精确计算排面占比、货架空位率、购物车装载率、商品拿放次数这些真实业务指标这是普通目标检测做不了的事。1.2 数据集的整体设计思路这套数据集的定位是“场景化实例分割”而不是单纯的目标检测标注。我在设计标注体系时围绕零售业务的完整闭环来定类别货架shelf、购物车shopping_cart、商品item、手hand、人person五个类别。有人可能会问货架和购物车是背景级目标为什么要当实例来分割原因在于货架层板和购物车车体在图像中经常构成商品的语义上下文把货架和购物车作为实例分割出来之后商品可以被正确归位到“货架上”还是“购物车里”这个归属关系对后续分析非常重要。场景划分上也有讲究。如果直接随机划分训练集和验证集同一个门店、同一个机位拍出的连续帧很可能同时出现在两端验证集的mAP会虚高。我按照“门店/拍摄会话”划分保证验证集里出现的画面来自模型没见过的场景这样评估结果才可信。最终数据量是5200张图训练集4200张验证集600张测试集400张分辨率统一为1920x1080尽量贴近真实监控摄像头的画面比例。2. 数据压缩包内部结构目录、标注格式与类别定义2.1 压缩包目录与文件解读先看zip解压之后的完整结构货架与购物车实例分割数据集/ ├── README.md ├── data.yaml ├── images/ │ ├── train/ 共4200张 │ ├── val/ 共600张 │ └── test/ 共400张 ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── annotations/ ├── instances_train.json ├── instances_val.json └── instances_test.jsonimages目录下是原始jpg图片labels目录下是YOLOv8分割格式的txt标注文件annotations目录下是COCO格式的json标注。同一张图片在images和labels里保持同名、不同后缀比如store_0234.jpg对应store_0234.txt。这种双格式共存的设计是为了兼顾不同工具链COCO json方便用现有脚本做数据分析和可视化YOLO txt直接喂给ultralytics训练省去中间转换的步骤。data.yaml是YOLO训练入口配置内容如下path: /path/to/货架与购物车实例分割数据集 train: images/train val: images/val test: images/test names: 0: shelf 1: shopping_cart 2: item 3: hand 4: person注意path字段强烈建议改成你本机的绝对路径。相对路径在ultralytics某些版本下解析存在歧义直接用绝对路径最省心。2.2 YOLOv8分割标注格式与原理解释YOLOv8的实例分割txt文件和检测任务不同每行表示一个目标的掩膜多边形格式是class_id x1 y1 x2 y2 x3 y3 ...class_id是整数类别编号后面跟着多边形的归一化坐标点。所有坐标值都除以图片宽或高统一映射到0到1区间。比如一张1920x1080的图上某个商品多边形的一个角点像素坐标是(960, 540)那么归一化就是(0.5, 0.5)。看一个实际的标注样例2 0.531 0.418 0.545 0.433 0.553 0.452 0.544 0.471 0.529 0.462 0.522 0.439这个txt文件只有一行代表图上只有1个目标。第一个数字2是类别id对应data.yaml里的item。后面12个数字是6个坐标点构成一个六边形掩膜。每个目标至少需要3个点才能构成有效多边形实际标注时为了贴合边缘一般取8到30个点越复杂的轮廓点越多。坐标点数差异很大是正常现象。购物车这种大目标可能有上百个点手部目标可能只有十几个点。模型训练时会把多边形栅格化成二进制掩膜参与loss计算所以点的精度不需要达到像素级边缘差1到2个像素完全不影响最终效果标注时不必过度纠结。2.3 COCO JSON标注格式速览COCO格式的instances_train.json包含三个顶层字段。images字段记录每张图的id、文件名、宽高annotations字段记录每个实例的segmentation多边形、bbox、area、category_id和iscrowdcategories字段记录类别id和名称。其中segmentation是一组坐标点列表{ segmentation: [[531.2, 418.5, 545.3, 433.1, 553.7, 452.0]], area: 5321.7, bbox: [531.2, 418.5, 22.5, 53.5], image_id: 11, category_id: 2, iscrowd: 0 }area字段在后续分析时很有用可以按面积统计大目标小目标的分布也能用来过滤异常标注。如果你只想用COCO json跑模型需要先转成YOLO txt。简单的做法是用ultralytics的YOLO类配合自定义转换脚本遍历polygon点再按图片宽高归一化。转换时注意COCO的坐标是绝对像素坐标必须先除以宽高否则训练会直接报“expected coordinates 0-1”的错。2.4 各类别定义与标注边界口径实例分割的类别定义如果不清晰标注人员会凭感觉发挥结果就是同一个目标在不同图片里标注口径不一致模型训练直接被带偏。我在这里把每个类别的边界口径固定下来类别id名称标注边界定义0shelf货架整体轮廓包含层板、立柱、背板以及层板上的商品区域不包含货架外背景1shopping_cart购物车外轮廓整体包括车篮铁丝网、把手、车轮不逐格区分铁丝间隙2item单件商品独立包装、瓶罐、盒装等被遮挡部分不标注3hand人的手部可见像素轮廓手被商品部分遮挡时只标可见区域4person推车人的主体轮廓包含躯干和四肢手指部分归入手类而不并入person这里重点说两个关键决策。第一购物车不逐格标注铁丝网格而是标外轮廓整体。刚开始我让标注团队按网格铁丝逐格描边训练出来的mask支离破碎mAP低得离谱。后来统一改成外轮廓整体标注购物车这一类mAP直接涨了近5个点。原因在于逐格标注引入了大量内部孔洞模型难以学习稳定的语义边界。第二手和person是分开的两个类别因为购物车场景中手部动作是判断拿放行为的关键交互目标单独标注手部可以训练出独立的检测分支方便业务层单独调用。3. 用YOLOv8跑通实例分割训练参数、踩坑与部署3.1 环境准备与数据检查训练环境我用的Python 3.10CUDA 11.8显存是RTX 3090 24G。先安装ultralyticspip install ultralytics安装完成后不用急着训先做个数据自检确认图片和标签能对上。我自己写了一个快速检查脚本跑一遍能发现大部分低级问题import os img_dir images/train label_dir labels/train img_names set(os.path.splitext(f)[0] for f in os.listdir(img_dir)) label_names set(os.path.splitext(f)[0] for f in os.listdir(label_dir)) only_img img_names - label_names only_label label_names - img_names print(有图无标注数量, len(only_img)) print(有标注无图数量, len(only_label)) max_class 4 for f in sorted(os.listdir(label_dir))[:200]: path os.path.join(label_dir, f) with open(path) as fh: for line in fh: parts line.strip().split() cls_id int(parts[0]) coords [float(x) for x in parts[1:]] assert cls_id max_class, f{f} 中类别id {cls_id} 越界 assert len(coords) 6, f{f} 中存在少于3个点的多边形 assert all(0 x 1 for x in coords), f{f} 中存在坐标越界 print(抽查200个标注文件未发现异常)这个脚本很朴素但能挡住80%的数据问题。常见的有三类txt文件是空的说明标注时mask面积太小最后被过滤掉了、坐标值大于1标注工具导出时没做归一化、类别id超过了names数量版本不匹配或中间改过类别表。3.2 解析data.yaml并验证读取正常准备好数据后先让ultralytics自己读取一遍确认没有路径或格式错误yolo segment val modelyolov8n-seg.pt datadata.yaml这里故意先用val模式加载而不是直接训练是因为如果数据有问题val模式会在加载阶段就报错比训练跑到一半才发现问题要快得多。看到没有error输出再进入正式训练。首次验证用yolov8n-seg这个nano模型纯粹是为了快速验证数据管线。等确认数据没问题再换更大的模型正式训练。这个习惯推荐给所有人能省下大量排查时间。3.3 训练参数选择与显存估算正式训练我用的命令是yolo train modelyolov8s-seg.pt datadata.yaml \ epochs120 imgsz1280 batch8 \ optimizerAdamW lr00.001 close_mosaic10参数选型背后的逻辑值得展开说。模型选的是yolov8s-seg而不是更大的m或l原因是零售场景目标密集小商品数量多imgsz对精度的影响远大于模型宽度。实测在imgsz1280下yolov8s-seg的mAP已经接近yolov8l-seg在640分辨率下的效果但训练推理速度快了将近3倍。先上分辨率再上模型宽度是这类密集小目标场景的最优路径。imgsz1280是刻意为之。货架上的单个商品在1920x1080原图中往往只有几十个像素宽缩到640后直接变成一团糊。我做过对比实验同一份数据imgsz640时item类mAP50只有0.78提到1280后到0.88提升非常明显。代价是显存占用大幅上升batch只能开到8。如果你的显卡只有8G显存建议imgsz降到960batch用2到4配合梯度累积也能凑合。close_mosaic10这个参数要重点解释。YOLOv8默认开启mosaic数据增强把4张图拼成1张能显著提升小目标泛化能力。但在密集堆叠的货架场景里mosaic会把不同货架的商品切碎拼在一起产生大量不自然的边界模型在最后几个epoch反而难以收敛。所以在最后10个epoch关闭mosaic只做常规翻转和色彩增强让模型在接近真实分布的数据上收尾收敛。这个操作在自定义数据集上普遍有效不只限于零售场景。3.4 训练评估指标与可视化验证训练结束后看results.csv里的指标。重点看三个维度mAP50、mAP50-95、mask precision和mask recall。mAP50是IoU阈值0.5下的平均精度业务上通常以这个为主mAP50-95是不同IoU阈值的综合表现更严格反应模型边界质量。拿这份数据集的实际结果来说yolov8s-seg跑120个epoch整体mAP50能到0.87左右mAP50-95约0.65。分类别看差异很大购物车作为大目标mAP50能到0.93item类居中0.88手部虽然是小目标但因为手部轮廓训练样本充足也能到0.85person类因为样本量少只有0.79。这个差异是正常的不必追求所有类别一致。评估过后一定要做可视化验证。用训练好的模型跑一批验证集图片保存mask叠加结果yolo predict modelruns/segment/train/weights/best.pt \ sourceimages/val \ saveTrue imgsz1280 conf0.25目视检查几个典型场景货架密集商品是否被正确分离、购物车轮廓是否完整、手和商品重叠时是否各自独立分割。mAP指标只能代表数值高低真正决定模型能不能上线的是目视效果。我见过mAP不错但mask边缘抖动严重的模型部署到监控画面里非常显眼。3.5 模型导出与部署经验训练好后导出ONNX或TensorRTyolo export modelruns/segment/train/weights/best.pt formatonnx opset12 yolo export modelruns/segment/train/weights/best.pt formatengine halfTrue device0TensorRT导出需要GPU环境导出后推理速度比ONNX提升明显。部署时监控机是单张T4显卡实测yolov8s-seg在1280分辨率下TensorRT FP16推理单帧约25ms满足实时性要求。部署中两个容易忽略的环节。第一个是前处理要保持和训练一致特别是归一化方式如果训练用0到1归一化部署时也要同样处理否则精度暴跌。第二个是mask后处理YOLOv8的mask输出是低分辨率的原型掩膜需要上采样回原图尺寸并裁剪到bbox范围这一步在Python里如果放到CPU做会成为瓶颈建议用GPU算子或者直接依赖ultralytics提供的后处理逻辑。4. 数据集使用中的高频问题与排查经验4.1 ZIP解压报错“file is not a zip file”的排查这个错误非常劝退但绝大多数时候不是数据本身的问题。排查顺序如下。先用file命令看真实文件类型file 货架与购物车实例分割数据集_20251122_165431.zip如果输出是HTML document或者ASCII text说明下载到的根本不是zip而是网页跳转后的HTML页面。这种情况常见于从网盘或GitHub下载链接被拦截时浏览器自动保存了一个错误页面。解决办法是换一个下载方式或者检查下载链接是否完整。如果file命令显示确实是zip compressed data但解压时仍然报错unzip -t 货架与购物车实例分割数据集_20251122_165431.zip-t参数会逐文件测试压缩包完整性。若输出中出现了“file #N: bad zipfile offset”或者“could not find EOCD”说明中央目录记录损坏。EOCDEnd of Central Directory是zip文件末端的记录块里面保存了整个压缩包的目录信息如果文件被截断EOCD就丢了zip工具无法知道包里有什么。遇到EOCD缺失先确认磁盘空间是否足够很多时候是下载到一半磁盘满了。如果确实只下载了部分文件基本修不回来直接重新下载。如果文件比较小且只是局部损坏可以尝试zip -F 货架与购物车实例分割数据集_20251122_165431.zip --out repaired.zip但成功率不高EOCD缺失时zip -F往往无能为力。切记不要拿着一份零散的热搜词去搜“zip密码移除”之类的偏方这套数据集本身没有加密遇到解压问题先检查文件完整性和大小。4.2 标注文件与图片对不齐的问题解压顺利后训练前大概率会碰到标注和图片数量不一致的情况。YOLOv8对没有标签的图片并不报错只是会跳过容易让人忽略数据缺口。直接用3.1节的检查脚本统计有图无标注的数量往往就是问题区域。还有一种情况是出现了类目id错位。如果之前有人改过data.yaml的顺序比如把原来第2类的item换到第0类但labels里的txt没有同步更新模型会把所有商品都学成货架loss降不下去mAP惨不忍睹。排查方法是挑几个txt文件人工看几行对照data.yaml确认类别id一致。坐标越界也是高频问题。YOLO分割格式要求坐标归一化到0到1但某些标注工具导出时默认保留整数像素坐标导致第一个点就超过1。训练不报错但loss会震荡因为模型算IoU时mask被裁剪得乱七八糟。检查脚本里0 x 1的判断可以直接捞出来。4.3 训练阶段效果不佳的模型侧调整如果数据没问题但训练效果差先看loss曲线。如果loss持续下降但mAP不涨大概率是验证集和训练集分布不一致或者验证集本身有标注噪声。如果loss直接不收敛检查学习率AdamW下lr00.001是常规起点显存不够导致batch过小时要相应降低lr我用batch2时会把lr0降到0.0002。商品漏检问题先看是哪一类在漏。如果漏的是手部或小商品把imgsz提到1280通常立竿见影。如果漏的是购物车大目标说明模型对目标整体性感知不够可以检查是否mosaic增强开太强或者类别不平衡导致购物车样本贡献的loss被密集商品淹没。针对不平衡ultralytics提供了class_weights参数但我实测效果一般更有效的方法是复制少样本类别的图片做重采样让每个类别在每轮epoch中出现的次数大致均衡。4.4 购物车与货架互相误检的根治方法这是零售场景实例分割最具迷惑性的问题。购物车和货架都有规则的矩形网格状纹理从俯视或斜视角度看车篮的铁丝网和货架层板容易混淆。我在第一版模型里就翻过车验证集里一堆购物车被标成shelf货架层板被标成shopping_cart。根治方法有三个层面。第一是标注层面确保购物车标注包含整个车体轮廓包括车轮和把手增加整体形态的辨识度。第二是数据层面补充不同角度、不同距离的购物车画面尤其是俯视角度让模型看到更多形态变化。第三是模型层面训练时提高imgsz保持清晰纹理分类分支会更容易学到货架和购物车的全局区别。如果误检仍然存在可以在模型后处理里加规则过滤比如按mask面积和宽高比过滤不合理的检出购物车的mask面积通常远大于单个货架层板不符合物理约束的结果直接丢弃。这类业务规则虽然不优雅但在实际项目中非常有效。4.5 数据集扩展与后续迭代建议这份数据集覆盖了常规门店场景但零售场景变化多端落地新门店前强烈建议补充数据。重点补三类不同灯光色温暖光、冷白、不同货架颜色木质、白色、黑色金属、不同购物车款式大篮、小篮、带儿童座椅。这些领域差异对模型泛化能力的影响比想象中大实测从标准店泛化到新店mAP掉幅常在5到8个点。如果标注资源有限可以用半监督方式扩展。先用现有模型对未标注门店视频做预测把置信度高于0.85且mask稳定的结果当伪标签召回人工只审查低置信度难例标注成本能下降一半以上。优先挑选置信度在0.3到0.7之间的样本让人工介入这类样本信息量最大能让模型在迭代中快速进步。训练这份数据集的一点个人体会跑完整个流程我最大的感受是实例分割项目里标注口径的规范程度往往比模型选型更影响最终效果。同样的模型结构标注规范统一之后mAP能提升好几个点这个提升白拿白不拿。所以拿到这个压缩包之后先别急着开训练花20分钟把README标注口径和各类别的边界定义过一遍会帮你省下后面大把返工时间。祝各位跑数据时一次通过模型精度直接拉满。本文还有配套的精品资源点击获取