资讯动态

YOLOv11实战:罐装饮料识别从数据集到部署的避坑指南

发布时间:2026/10/1 4:42:00 来源:尧图企业网站定制
简介面向计算机视觉入门与YOLO实战项目这份罐装饮料识别数据集提供了多品牌商品的图像与标注资源覆盖东鹏特饮、红牛、芬达、养乐多、可乐、雪碧、王老吉、AD钙奶、特仑苏、旺仔牛奶及薯片等常见商品支持YOLOv11格式标注可直接用于检测模型训练与效果验证免去手动标注和格式转换的麻烦。压缩包整体约45.95MB共2000个文件包含321张jpg原图、1678个txt标注文件和1个yaml配置文件其中txt为YOLO格式的框标注信息yaml定义类别与数据集路径结构简明。目前已有929人学习下载适合课程设计、毕业设计或货架场景识别等实际项目。多品牌、多角度图像组合有助于提升模型泛化能力标注细节也可供目标检测入门者作为练习素材无论是快速验证算法还是准备小型演示项目都能节省大量数据整理时间。1. 罐装饮料识别为什么一千多张标注图比一万张杂图更值得先试做零售货架巡检、自助结算台或者库存盘点时罐装饮料识别经常被当成“简单任务”提出来。真正上手才会发现可乐、雪碧、芬达这类罐体在灯光下反光严重红牛和东鹏特饮远看都是金罐养乐多又是小瓶身——YOLOv11 跑通用目标检测很容易要在一千多张带 YOLO 标记格式的图片上把手感调稳坑比想象中多。这个 .zip 数据集恰好覆盖常见的薯片、东鹏特饮、红牛、芬达、养乐多、可乐、雪碧七类适合用来验证检测管线、做算法选型也适合刚接触目标检测的工程师拿一份真实标注数据跑通从解压、训练到部署的完整闭环。2. 罐装饮料为什么难识别外观混淆、小目标与 YOLOv11 的应对2.1 七类目标的视觉边界金罐、白罐、黄瓶和深色罐的区分度先不急着写代码。目标检测数据集的质量问题很多是从“类别之间到底靠什么区分”开始的。这七类在货架上各有各的麻烦。可乐和雪碧是典型的深色罐和浅色罐。光照一变深色罐身会直接糊成一片黑浅色罐会过曝成白色芬达罐体是橙黄色但货架暖光灯一打它和可乐、红牛之间的色块边界迅速收缩。真正要命的是红牛和东鹏特饮这一对一个是蓝银色罐身配红牛标志一个是金色罐身配东鹏标志远看都是竖向金属罐当目标宽度只有 100 像素以内时颜色直方图的重叠度相当高只靠颜色特征完全分不开。养乐多则是物理尺寸问题——它只有普通易拉罐三分之一高在一张 640 分辨率的照片里往往只占 20 到 30 像素正好落在小目标的尴尬区间。薯片袋又完全不同长宽比明显塑料包装在旋转、褶皱下有大量形变。这说明任务难点不是“有没有目标”而是“类别判别”和“小目标召回”。如果直接拿通用场景训练的权重测这份数据最集中的两类错误是红牛被标成东鹏特饮以及养乐多整瓶漏检。这两个结论会反复出现在后面的混淆矩阵和验证日志里提前知道能少走很多弯路。2.2 YOLOv11 的骨架和检测头小目标召回和类别判别靠什么针对这种小样本 SKU 识别任务选 YOLOv11主要不是因为它比前代“更强”而是它在给定数据规模下的收敛速度、部署成本和调试路径最合适。YOLOv11 延续了 YOLO 系列的 anchor-free 检测头设计输出端直接预测每个位置的目标中心和四条框边距离省掉了预先匹配 anchor 的过程。一千多张图、七类目标anchor 都收敛得不够稳定anchor-free 天然少了一个需要人工干预的参数。网络结构上YOLOv11 使用多尺度特征融合检测头分别接在深层、中层和浅层特征图上。对罐装饮料识别真正有用的是浅层特征图它保留了更多纹理和边界信息是小尺寸罐体被召回的主要通道。训练时把输入分辨率订到 640画面角落里一个养乐多罐只有 20 像素时实际上主要靠浅层特征图对应位置的单元去响应。这也是为什么后面会反复强调调小目标的第一手段是抬高输入分辨率而不是盲目加深网络。YOLOv11 还有一个适合这个场景的特点模型体积按 n/s/m/l/x 分档。这个数据集只有一千多张、七个类用 n 或 s 档先跑基线完全足够。几百兆的 x 档在这种小数据上容易过拟合而且推理速度只适合 GPU 服务端。真实货架巡检如果最终要落到嵌入式设备或 Jetson Nano 这类平台上前期用 n 档调通管线比一上来就上大模型省时间得多这也是常被忽略的选型问题。2.3 一千张图到底够不够迁移学习、增强策略和类别平衡先把结论写出来一千多张图对七个 SKU 的检测任务在预训练权重加持下是够用的。原因有三点YOLOv11 自带的 COCO 预训练权重让模型已经学会了边缘、颜色块、物体形状这些通用视觉特征迁移到罐装饮料只需要在顶层微调类别判别罐装饮料结构高度规整形变远小于行人、车辆这类通用目标这份数据本质上是近封闭场景背景大概率是货架、冰柜或桌面分布比开放世界集中得多。但“够用”有前提前提就是增强策略要做对。常见做法是在训练时开启数据增强Mosaic 把四张图拼成一张等于免费扩大了小目标样本数量HSV 扰动能缓解罐体反光带来的颜色抖动随机翻转对薯片袋这类非对称目标要谨慎翻转后文字方向反转模型会学到错误的纹理特征。我一般会在第一批训练时把所有增强全开等验证集 mAP 稳定后再关闭翻转重训一版对比效果。类别不平衡也需要单独看。东鹏特饮、可乐这类整箱货架图出现频率高养乐多如果只在收银台附近出现样本量可能差一个数量级。一个最简单的检查方式是用下面命令统计每个标签文件第一个数字的出现次数find drink_dataset/labels -name *.txt -exec awk {print $1} {} \; | sort | uniq -c运行后如果发现哪一类的计数小于 50就优先补那类的图片。这一步不能省因为训练 loss 曲线不会告诉你“哪一类没学好”只有每类 AP 和混淆矩阵会暴露问题。3. 解压 zip、校验标签和写 data.yaml把数据集喂给 YOLOv11 前的三步3.1 解压与目录约定images 和 labels 的命名必须一一对应拿到 zip 后先别急着训练。第一步是解压然后确认目录结构。YOLOv11 的数据加载器默认在根目录下找 images 和 labels 两个兄弟目录labels 下每个 txt 文件名必须和 images 下对应图片的 basename 一致不含扩展名。所以解压后先看 zip 里是不是套了一层内层目录否则后面的 train 路径会写错。unzip drink_dataset.zip -d drink_dataset find drink_dataset -maxdepth 3 -type d常见结构有两种一种是images/和labels/平级另一种是多套一个train/或val/目录。如果只有一套图片也不需要急着手工切分YOLOv11 的 train 命令支持在读取时做比例划分后面会提到。先保证 labels 里的 txt 数量和 images 里的图片数量一致数量对不上时下面的校验脚本就该上场了。3.2 标签完整性校验用一段 Python 找出缺失、越界和错类标签格式是每行五个数字class_id、x_center、y_center、width、height全部是归一化小数class_id 从 0 开始七类就是 0 到 6。这就是“支持 yolov11 格式的标记”的含义——不是某种 YOLOv11 私有格式而是 Ultralytics 直接能读的 txt 标记。题目里的类别顺序按“薯片、东鹏特饮、红牛、芬达、养乐多、可乐、雪碧”对应 ID 0 到 6但拿到手后永远不要假设标注工具的导出顺序和这个一致必须验证。from pathlib import Path def validate(img_dir, lbl_dir, num_classes7): problems [] img_files [p for p in Path(img_dir).glob(*.*) if p.suffix.lower() in (.jpg, .jpeg, .png, .bmp)] for img in img_files: lbl Path(lbl_dir) / (img.stem .txt) if not lbl.exists(): problems.append(fmissing label: {img.name}) continue for line in lbl.read_text().strip().splitlines(): parts line.split() if len(parts) ! 5: problems.append(fbad line: {lbl.name}: {line}) continue cid int(parts[0]) if not (0 cid num_classes): problems.append(fclass id out of range: {lbl.name}: {cid}) x, y, w, h map(float, parts[1:]) if not (0 x 1 and 0 y 1 and 0 w 1 and 0 h 1): problems.append(fbbox abnormal: {lbl.name}: {line}) print(f{len(img_files)} images, {len(problems)} problems) for p in problems[:20]: print(p) validate(drink_dataset/images, drink_dataset/labels)这段脚本做的事很简单找出没有对应标签的图片、行数不等于 5 的标签、class id 越界、以及边界框坐标异常。我实际跑这类数据集时遇到过两种翻车一种是标注工具导出空 txt文件存在但 0 字节另一种是把坐标从像素值直接写进 txt忘了归一化。这两种情况训练都能跑起来但收敛结果会让人误以为模型不行。出现问题时回到标注阶段修复不要带着问题训练。注意脚本对图片扩展名做了大小写兼容对应了后面避坑章里要讲的.JPG问题。3.3 写 data.yaml类别顺序直接决定模型输出YOLOv11 训练时读的是一个 data.yaml而不是目录名。它告诉框架三件事数据根目录在哪、训练验证图片在哪、七个类别名字按什么顺序排列。names 顺序写错是灾难性的——模型训练正常、推理正常但输出标签和真实物体错位比如把红牛框标成了芬达。更麻烦的是训练时标签同时错位损失函数前期正常下降属于典型的“看起来成功实则全错”。path: drink_dataset train: images val: images names: 0: chips 1: dongpeng_te 2: redbull 3: fanta 4: yakult 5: cola 6: sprite写完后先用上一步的校验统计一遍实际出现的 class id再和 names 列表核对。我的习惯是运行awk统计命令看最大 id 用到了几如果 id 范围不是 0 到 6比如出现 7 或 8说明要么有错误标注要么这套数据的类别定义和你手上的清单不一致先回去查不要继续训练。val 暂时指向 images 目录允许但正式验证一定要留出独立验证集否则 mAP 会虚高。4. 训练与推理实操用 YOLOv11 把罐装饮料识别跑通的最小闭环4.1 环境准备Ultralytics 与 PyTorch 的版本先对齐训练 YOLOv11 用的是 Ultralytics 统一封装的目标检测框架命令行工具叫yoloPython 类名是YOLO。环境上最容易出问题的是 PyTorch 安装方式CPU 版 torch 会把训练速度拖到无法接受GPU 版又要匹配本机 CUDA 版本。我一般先在命令行里做一次环境检查再决定怎么装。python -c import torch; print(torch.__version__, torch.cuda.is_available(), torch.cuda.get_device_name(0)) pip install ultralytics如果第一行输出torch.cuda.is_available()为 False说明装的是 CPU 版 PyTorch需要重装对应 CUDA 版本的 wheel。PyTorch 2.x 搭配 CUDA 11.8 或 12.1 的组合被验证得比较多。pip install ultralytics会同时拉齐依赖但不会自动帮你换 torch 版本所以顺序很重要先确认 torch 能用 GPU再装 ultralytics。4.2 训练命令与五个必调参数从预训练权重开始做迁移学习环境就绪后训练命令非常短。关键是搞清楚每个参数在这份数据集上应该怎么设下面是我在这个项目里的初始配置。yolo train \ datadata.yaml \ modelyolo11n.pt \ epochs150 \ imgsz640 \ batch16 \ cacheTrue \ device0 \ projectruns/drink \ namev11n_baseline参数取值在这个数据集上的理由modelyolo11n.pt一千多张图先跑小模型速度快过拟合风险低epochs150迁移学习不需要 300 轮验证 loss 超过 100 轮不降就提前停imgsz640兼顾速度与精度后续为小目标可提到 960batch16显存不够降到 8但不要低于 4否则 BN 统计会不稳定cacheTrue一千多张图能塞进内存训练快很多modelyolo11n.pt会自动下载预训练权重如果本地网络受限就手动下载后指定路径。训练时重点看两个曲线train/loss在下降val/loss没有在中段拐头向上。如果val/loss从某个 epoch 开始持续上升是典型过拟合信号优先降 epochs 或加强数据增强而不是立刻换大模型。七类目标会自动覆盖 YOLOv11 的输出头类别数不需要手工改模型结构。4.3 推理验证保存带框结果、导出 ONNX 的常用参数训练完“yolov11 保存推理结果”和高频操作是 predict 子命令加saveTrue它会把画好框的图片输出到runs/detect/predict目录这是离线测试数据集最直观的做法。如果目标场景要上嵌入式设备下一步导出 ONNX把模型转成 half推理速度会有明显提升。yolo predict modelruns/drink/v11n_baseline/weights/best.pt \ sourcetest_imgs saveTrue conf0.25 yolo export modelruns/drink/v11n_baseline/weights/best.pt \ formatonnx imgsz640 opset12conf0.25是这类饮品检测的安全门槛类别少、区分度尚可0.25 能压住一部分误检。如果测试集上大量误检上调到 0.4如果漏检严重降到 0.1 观察。导出 ONNX 时 imgsz 必须和训练时一致否则小目标框的位置会偏移。opset12 是兼容性比较好的设置打算用 TensorRT 的话可以再单独导出对应格式。5. 踩坑记录罐装饮料识别从标注到推理的 5 个高频问题5.1 罐体反光把半个框标成了背景mAP 卡在 0.5 上不去现象是训练结束后精确率还行召回率始终上不去放大验证集发现金属罐的框都只有真实罐体的一半。原因是标注阶段在原始大图上没问题一旦图片经过缩放或手机拍摄时高光过曝罐身高光区域接近纯白肉眼觉得像背景标注框就沿着亮面边界画了。解决这类问题的常见做法是开启更强的 HSV 增强并针对反光样本做“过曝模拟”随机提升图片亮度让模型学会忽略高光区域。血泪经验是货架上拍的逆光图宁可淘汰也不要硬塞进训练集模型对反光的注意力会冲掉其他样本学到的特征。5.2 红牛和东鹏特饮互相误检类别判别不过关的典型样本现象是验证集上红牛的框被标成东鹏特饮置信度还挺高。原因有两层视觉上两者都是金属竖罐、颜色接近数据上两类样本数量往往比例失衡模型把“金色罐体”当成了东鹏特征。先去看类别统计命令的输出如果红牛只有几十个标注框优先补拍。解决方法是除了补样本把输入分辨率从 640 提升到 960让罐身文字区域产生足够纹理特征再观察混淆矩阵如果两个类别长期互扰可以在后处理加一条规则同一个位置同时被两个类别以接近的置信度命中时按货架先验保留其中一个。这条规则不复杂但往往是这类 SKU 项目从 85% mAP 提到 92% 的关键一步。5.3 zip 解压后图片和标签错位后缀大小写和嵌套目录的连锁坑现象是训练日志里图片数量正常但 loss 很大打开验证图片发现框画在错误位置。原因是标注包压缩时套了多层目录或者在 Windows 下解压后图片后缀变成.JPGYOLOv11 在 Linux 下按*.jpg匹配时漏掉大部分文件另一种情况是图片和标签本来在 zip 的不同目录层级解压后没有对齐。解决方法是先运行find drink_dataset -maxdepth 3 -type d看层级再用脚本统一后缀。文件名里有空格和中文是另一个隐性坑建议统一改成beverage_00001.jpg这类命名。YOLOv11 能处理中文路径但到 ONNX 导出和部署阶段中文路径会带来不必要的麻烦。5.4 训练到一半 loss 跳成 NaN学习率和坏标签的双重嫌疑现象是前几十个 epoch 正常某个 epoch 开始 loss 变成 NaN 并且不再恢复。原因排查优先做两件事。一是学习率设置太高迁移学习在较小数据集上1e-2 级别会把损失推到爆炸二是数据里有 0 面积或负值标签框这些坏框在损失函数里产生无穷值。解决方法是先别慌把学习率降到lr00.0005量级重跑同时用 3.2 的校验脚本对全部标签做一遍体检特别关注那些 0 字节空 txt。空 txt 会被 YOLOv11 跳过造成实际训练图片比预期少几百张loss 曲线也会因此抖动。batch 太小的情况下 BN 统计不稳定训练后期同样容易发疯建议 batch 至少 8。5.5 货架远端和冰柜深处的小罐体漏检小目标优化的三个切入口现象是贴近镜头的罐子全部正常图片深处或货架高层的罐体几乎一个都检不出来。原因是这些目标在 640 分辨率下只有 15 到 25 像素经过检测头几次下采样后信息被压缩殆尽。解决优先级第一把 imgsz 从 640 提高到 960 或 1280这一步对小目标最有效改动也最小第二训练时保留 Mosaic 增强它会把小目标拼贴到大图上等价于增加小目标出现频率第三仍然不行就做切片推理把一张大图切成 2x2 或 3x3 的小块分别推理再把坐标映射回原图最后用 NMS 合并重叠框。注意切片推理的速度是未切片的 3 到 5 倍验证时不要和 batch 推理的速度混为一谈。6. 再进一步用混淆矩阵和切片推理验证你的真实数据分布模型训练完我不会立刻看总 mAP而是先跑一次带输出结果的验证。yolo val modelruns/drink/v11n_baseline/weights/best.pt \ datadata.yaml plotTrue save_jsonTrueplotTrue会在验证输出目录生成混淆矩阵和一批带预测框的验证图片。我会对照混淆矩阵看两点主对角线是否够亮红牛与东鹏特饮的混淆块是否对称。如果不对称说明某个类别样本量明显偏少这是补数据的方向不是调参的方向。下一步做切片推理验证。下面这个脚本把验证图切成小块分别推理再合并坐标用来对比不切片版本的小目标召回率提升情况。from ultralytics import YOLO import torch import torchvision model YOLO(runs/drink/v11n_baseline/weights/best.pt) def slice_infer(img, patch_size640, overlap0.1): boxes, scores [], [] h, w img.shape[:2] step int(patch_size * (1 - overlap)) for y0 in range(0, h, step): for x0 in range(0, w, step): patch img[y0:y0 patch_size, x0:x0 patch_size] res model(patch, conf0.25, verboseFalse)[0] for bbox, score in zip(res.boxes.xyxy.tolist(), res.boxes.conf.tolist()): x1, y1, x2, y2 bbox boxes.append([x0 x1, y0 y1, x0 x2, y0 y2]) scores.append(score) keep torchvision.ops.nms(torch.tensor(boxes), torch.tensor(scores), 0.5) return [boxes[i] for i in keep.tolist()]这是一个临时验证用的简化思路实际工程可以用现成的切片推理库但自己写几十行反而更可控。overlap 默认 0.1如果目标恰好卡在 patch 边界被截断把 overlap 加到 0.3 即可代价是多算一些重复区域。最后提醒一个小习惯数据集图片统一改成纯数字前缀文件名。zip 解压、Docker 挂载、ONNX 部署三个环节都会顺很多这是我从多个饮料识别项目里踩出来的教训。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑