基于YOLOv11的罐装饮料识别:从数据集标注到推理部署实战
发布时间:2026/8/31 16:22:02 作者:尧图编辑部 阅读量:1,286

简介本资源是一套面向计算机视觉初学者与YOLO系列模型实践者的罐装饮料目标检测数据集聚焦超市货架、自动售货机等场景下的常见饮品识别任务可支撑模型训练、算法验证与课程实验。压缩包共2000个文件含321张高质量JPG图像涵盖东鹏特饮、红牛、可乐、雪碧、芬达、养乐多、王老吉、AD钙奶及伊利、蒙牛等乳饮品牌、1678个YOLOv11格式标注TXT文件每图对应唯一标签类别坐标规范以及1个整合全部类别的data.yaml配置文件总大小45.95MB结构简洁、开箱即用。目前已有923人学习下载适合快速构建饮料品类识别baseline、开展小样本迁移训练或拓展多类别工业质检应用。 做这个罐装饮料识别项目的初衷其实挺生活化的。起因是有朋友在做一个智能零售柜相关的小产品想通过摄像头自动识别货柜里还剩哪些饮料、哪些已经售罄免去人工补货巡检的成本。所以当时就攒了这么一套数据集一千多张从不同角度、不同光照条件下拍摄的常见包装商品图片标注了薯片、东鹏特饮、红牛、芬达、养乐多、可乐、雪碧这七个类别并且整套数据都按YOLOv11的标准格式整理成了txt标注文件打包成一个zip方便分发和复用。这篇文章就把这套数据集从标注到训练再到推理部署的完整链路拆开讲一遍包括过程中踩过的坑、调参的心得以及zip文件处理、环境配置这些看起来很基础但实际很容易卡住的细节。如果你也想用YOLOv11训练一个自己的商品识别或者物体检测模型这篇文章应该能帮你省下不少摸索的时间尤其是数据集这边怎么做才不容易坑到模型、训练时怎么判断模型是真的学好了以及推理结果怎么正确保存这些都是能直接照着操作的内容。1. 项目整体设计与思路拆解1.1 需求定位不是科研项目是能用就行的东西这个项目的核心场景是货柜商品识别所以目标非常明确用摄像头对准货架层板拍摄模型要能在画面中直接把每一件商品框出来并告诉上层系统“这是红牛”“这是可乐”。相比学术性质的竞赛任务这个场景有几个显著特点。第一类别数量少但混淆度高。七个类别里可乐和雪碧是深色与浅色的关系芬达是橙色的东鹏特饮和红牛都是金黄色的罐体形状高度接近。模型如果只学“颜色”和“形状”的粗特征很容易把红牛和东鹏搞混。第二推理设备大概率不是顶级GPU可能是ARM架构的边缘盒子所以模型不能太大推理速度要快。第三识别结果是要驱动业务动作的比如补货提示、结算扣款漏检的代价比误检更高所以训练时要在召回率上稍微多留一点余量。基于这三点我选了YOLOv11n作为主力模型。n是nano版本模型权重只有几兆在CPU上也能跑到几十毫秒一帧放在边缘设备上完全够用。而且YOLOv11的ultralytics框架对数据格式的兼容性做得很好不管是标注文件、数据集结构还是训练脚本几乎都是“约定优于配置”对快速迭代非常友好。1.2 为什么用txt标注而不是直接用标注工具的格式很多刚入门的人会用LabelImg的XML格式或者用Labelme的JSON格式然后再写脚本转成YOLO格式。我的建议是既然决定用YOLOv11训练标注时就直接产出txt格式一步到位不要中间转换。YOLO格式的标注文件是每个图片对应一个同名txt文件每一行代表一个目标格式是class_id center_x center_y width height注意这里的四个坐标值全部是归一化到0到1的小数不是像素坐标。归一化的好处是不管你输入图片是1920×1080还是640×480模型都能一视同仁地学习目标的位置关系。标注工具的坐标转换是自动完成的比如LabelImg如果是YOLO模式保存出来的就是txt不需要自己换算。这个数据集打包的时候目录结构是这样的dataset/ ├── images/ │ ├── train/ # 约850张 │ └── val/ # 约200张 ├── labels/ │ ├── train/ # 与images/train同名对应的txt │ └── val/ # 与images/val同名对应的txt └── data.yaml # 类别定义和路径配置images和labels必须是严格同名的后缀不同这一点在整理数据时特别容易出错。YOLO框架会按同名规则去匹配图片和标签如果图片叫IMG_001.jpg那标签就一定要叫IMG_001.txt多一个空格都不行。2. 数据集的构建与标注实操2.1 收集一千多张图片质量比数量重要同类的数据集收集方式常见的有两种一种是找现成的开源数据集去筛另一种是自己拍。我们这个项目两种都用了前期从开源数据集和网络渠道收集了一部分后期又用手机和测试摄像头补拍了几百张最终筛到一千多张高质量图片。我强调“高质量”是因为很多公开数据集里的图片存在几个问题商品在画面里太小、被遮挡、光照极暗、或者一瓶饮料占据了大半个画面导致目标框太大。这些图片训练进去不仅不会提升泛化能力反而会拉低模型对尺度的鲁棒性。所以我的筛选标准是目标在画面中占比适中最大不超过60%最小不低于15%。每个类别至少要有100张以上图片且尽量覆盖多角度、多距离。画面不过曝、不欠曝无严重运动模糊。同类商品尽量有不同摆放方向、不同数量组合。最后我统计了一下红牛和东鹏特饮这类常见饮料数量最多每类大概180张养乐多因为体型小数量少一些但也在130张左右。这个数据量对于YOLOv11的预训练权重微调来说是完全够用的。重点不是你有一千张还是两千张而是每个类别有没有覆盖到模型在真实场景里会遇到的各种变化。2.2 标注的细节框怎么画决定了模型怎么学标注这件事看起来简单一个框拖过去就完事但实际操作中很有讲究。第一步先在LabelImg里把图片打开选择YOLO模式然后按类别列表从0开始编号0代表薯片、1代表东鹏特饮、2代表红牛、3代表芬达、4代表养乐多、5代表可乐、6代表雪碧。框怎么画我总结了几条经验贴合物体边缘但不要卯着物体的外轮廓画。对于罐装饮料我的做法是四边留出大概2到3个像素的余量完全贴着边缘的话训练时随机裁剪增强容易把边上的特征切掉。透明包装商品要覆盖包含内容物的部分。东鹏特饮有大瓶装和小罐装大瓶是透明塑料材质标签只覆盖瓶身一部分。框应该包含整个瓶身包括没贴标签但能看出液体的部分而不是只框标签。遮挡目标的处理。货柜里商品经常相互遮挡我处理的原则是如果遮挡面积小于30%直接按可见部分画框如果遮挡超过30%但还能明确判断类别也画框如果只露出一个角实在看不出是什么直接跳过不标。同一类商品颜色差异大时不要拆成多个类别。比如薯片有红色包装、绿色包装、蓝色包装但商业需求上只关心“薯片”这个品类那就统一归为一个类。拆太细会让类别间特征边界模糊模型反而不容易收敛。标注完以后一定要检查类别id有没有标错。一个特别容易犯的错是改掉了classes.txt里的顺序但之前标过的txt文件里的id没改导致类别错位。我自己踩过一次红牛和东鹏的标签全反了训练出来的模型把两个金罐子完全搞混。排查方法是写个小脚本扫描所有txt文件统计每个类别id出现的次数和图片内容做抽样比对一旦发现某个id的数量异常多或异常少就重点检查。2.3 数据划分与增强只做必要的增强数据划分上我用了8:2的train/val比例没有单独留test。原因很简单总共一千多张图再拆出test的话训练和验证的数据量都太紧张了。而且验证集本身就是从训练分布里分出来的只要保证训练和验证之间没有完全相同的图片尤其防止一张图同时出现在两个集合里用val指标来做选模和调参就够了。数据增强要克制。YOLOv11默认开启的mosaic增强、随机翻转、HSV扰动、平移缩放等对这个项目基本够用。我自己额外做的一件事是针对养乐多这种小目标在训练时把imgsz设成了800而不是默认的640。这相当于把图片缩放得更细让原本只有几十个像素高的小瓶子在特征图上占有更多像素点小目标的召回率会有肉眼可见的提升。代价是训练和推理速度都会慢一些但如果你的应用场景里小目标确实存在这个取舍是值得的。这里还要提一个很多人忽略的点不要在训练前手动做大量离线数据增强比如先把每张图翻转、裁剪、调亮度各生成一张。YOLO训练时的在线增强是随机的每轮epoch看到的增强结果都不一样手动离线增强只会让数据量看起来变大实际上模型很快就把重复的增强模式背下来了对泛化几乎没帮助还极大增加了训练时间。3. YOLOv11训练全流程环境、配置与训练实现3.1 Anaconda环境配置与ultralytics安装YOLOv11的训练代码是基于ultralytics这个框架的安装方式很简单在Anaconda的虚拟环境里执行conda create -n yolo python3.10 -y conda activate yolo pip install ultralytics这里特别说明一下python版本。ultralytics框架对Python 3.8到3.12都有支持但实测中3.10最稳3.12在某些依赖库上还偶尔有兼容问题。如果你的机器有NVIDIA显卡建议接着装GPU版PyTorchpip install torch torchvision --index-url https://download.pytorch.org/whl/cu121如果不用GPUCPU也能跑只是训练速度会慢很多。用CPU训练一千多张图、50个epoch可能要跑十几个小时而一块中端显卡比如RTX 3060级别大概只需要一两个小时。我个人建议前期调试阶段就算没显卡也不要紧先用几百张图跑几个epoch验证流程通不通再去租带GPU的实例跑完整训练。我一贯的做法是先在CPU上跑通代码再上GPU这样排错的时候不会把环境问题和代码问题混在一起。环境配置好以后可以跑一下版本验证import ultralytics ultralytics.checks()这个命令会帮你检查依赖是否齐全、GPU是否可用、torch和CUDA的匹配情况。如果输出里没有异常说明基础环境已经就绪。3.2 数据集配置与训练参数调优在训练之前需要准备一个data.yaml文件内容如下path: /path/to/dataset train: images/train val: images/val names: 0: chips 1: dongpeng 2: redbull 3: fanta 4: yakult 5: cola 6: spritepath是数据集根目录的绝对路径也可以是相对路径train和val是相对于path的图片文件夹路径。names字典里的key必须是从0开始的连续整数不能跳号否则训练时会直接报错。然后是训练命令我最终采用的组合是yolo train datadata.yaml modelyolo11n.pt epochs80 imgsz800 batch16几个核心参数的选择逻辑modelyolo11n.pt代表从官方预训练权重yolo11n.pt开始微调而不是从头训练。COCO数据集上预训练过的模型已经学会了通用的边缘、纹理、颜色组合等低级特征迁移到饮料识别这个小任务上只需要在高层特征上做调整收敛速度快且不容易过拟合。epochs设80是因为这个数据集不算大训练到50轮左右val-loss就已经基本平了再多训练容易过拟合。我会在训练结束后再看一次训练曲线如果最后的val-loss还在明显下降才会加10到20轮。batch16取决于显卡显存。如果显存不够优先降低batch而不是降低imgsz因为imgsz对小目标的影响更大。batch过小时BN层的统计量不稳定训练容易震荡。另外还需要明确一个通用观点训练时不要一上来就用大模型。YOLOv11n是nano版本参数量最小先跑通全流程验证数据没问题再换s、m版本看指标是否有提升。很多初学者一上来就用yolo11x结果数据量撑不起大模型的参数量训练完的效果反而不如nano版本。3.3 训练过程监控与常见误判训练启动后ultralytics会打印每个epoch的详细信息包括box_loss、cls_loss、dfl_loss、precision、recall、mAP50、mAP50-95这些指标。这里面重点看两个mAP50和mAP50-95。mAP50衡量的是预测框和真实框的IoU超过0.5时算对的概率这个指标对业务场景更友好mAP50-95则更严格IoU从0.5到0.95每隔0.05算一次再取平均学术研究上更看重。如果训练结束后mAP50在0.9以上mAP50-95在0.7左右对于这个七个类别的商品识别任务来说已经是能用的水平了。但如果出现mAP50很高但mAP50-95很低的组合说明模型定位精度不够框的位置和大小不够准。这种情况一般是因为标注框本身画得粗糙或者imgsz太小建议检查标注质量并把imgsz调大一些。另外要注意区分“loss很小”和“模型很好”。有时候loss一直在降但不能只看训练集的loss因为过拟合时训练loss也会降而val-loss反升。我的做法是训练跑完后先生成混淆矩阵from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) model.val(datadata.yaml, plotsTrue)这一步会在runs/detect/train目录下生成混淆矩阵图和各类别的PR曲线。重点看红牛和东鹏这两个容易混淆的类如果混淆矩阵里这两个类互相预测的错误率超过5%就需要考虑加数据或者调整训练策略。4. 推理部署、结果保存与zip文件处理4.1 预测命令与结果保存模型训练完成后推理就简单了。ultralytics的predict命令可以直接对图片、视频、摄像头甚至是文件夹里的所有图片进行推理yolo predict modelruns/detect/train/weights/best.pt source./test_images saveTrue关键参数saveTrue这决定了推理结果图是否保存到本地。默认情况下保存路径会在runs/detect/predict目录下每次运行会生成新的predict2、predict3文件夹不会覆盖上一次的结果。如果是在代码里推理并保存更灵活的方式是from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) results model.predict(source./test_images, imgsz800, conf0.35, saveTrue, nameinference_result, show_labelsTrue)这里conf0.35是置信度阈值。默认值0.25在背景相对干净的测试图上没问题但在真实货柜场景里容易把一些饮料瓶上的图案误检成目标所以我在实际部署时把阈值提到了0.35到0.4之间漏检率上升了一点点但误检率大幅下降。对于零售场景把一个不存在的商品识别出来比漏掉一个商品更让客户恼火所以阈值取高一些更合适。推理结果保存后如果只是想看图片有没有识别出来打开save出来的jpg即可如果你要的是带坐标的结构化结果用results[0].boxes.data可以得到一个N×6的tensor每一行是[x1, y1, x2, y2, conf, class_id]方便后续对接业务逻辑。4.2 Linux下解压zip文件的完整命令整理数据集时我习惯把最终版的标注文件和图片打包成zip方便传给其他人或者在不同机器上同步。但zip文件在不同系统之间传递时经常出现各种问题这里把Linux下的常用解压命令整理一下# 基础解压 unzip dataset_v1.zip # 解压到指定目录 unzip dataset_v1.zip -d /data/ # 查看压缩包里有什么而不解压 unzip -l dataset_v1.zip # 压缩包有中文文件名时保留编码格式 unzip -O GBK dataset_v1.zip # 创建zip压缩文件 zip -r dataset_v1.zip dataset/ # 指定压缩级别0不压缩9最高压缩 zip -r -9 dataset_v1.zip dataset/其中unzip -O GBK这个参数非常实用Windows上用中文名压缩的文件在Linux下解压经常出现乱码指定GBK编码能解决大部分问题。另外如果压缩包特别大可以先列出文件列表确认结构再决定要不要全部解压避免一解压出来把当前目录撑爆。4.3 常见zip问题全解报错、损坏与加密数据集zip在传递过程中最容易遇到的报错按照我实际遇到的经验依次说下。第一个是“file is not a zip file”。这个报错出现的原因可能有这么几个一是下载不完整文件只有几十KB但压缩包本身有几GB基本都是下载中断导致二是文件后缀被篡改比如实际是个rar或者7z文件但扩展名改成了zip三是文件本身在传输过程中损坏。排查方法先用file命令看真实文件类型file dataset_v1.zip如果输出显示是Zip archive data那说明文件类型没问题如果输出是数据或者gzip压缩数据那就要检查下载源。第二个是“invalid zip archive: could not find eocd”。EOCD是zip压缩包末尾的一个结束记录结构如果找不到它说明压缩包不完整或者被截断。这个报错在Windows、Linux下都常见处理思路是重新下载或者用修复工具尝试恢复。Linux下可以用zip -FF进行修复zip -FF dataset_v1.zip --out dataset_v1_fixed.zip这个命令用的是zip规范中的修复逻辑会把损坏压缩包中还能读取的文件提取出来重新打包。实测能救回一部分覆盖了连续文件块的数据但完全无法救回被截断的尾部文件。第三个是zip密码相关问题。我这里想说的是如果你给数据集压缩包加了密码请一定用7-Zip的AES-256加密不要用古老的ZipCrypto算法。后者安全性很低极易被破解而前者在暴力破解面前要稳健得多。另外密码保护是双刃剑如果密码忘了基本没有官方途径恢复。所以我给数据集包加密前都会额外存一份密码到密码管理器里而不是只记在脑子里或者聊天记录里。第四个是分卷压缩的z01文件。有的超大压缩包会拆分成多个文件比如dataset.z01、dataset.z02、dataset.zip。这时候必须把所有分卷放在同一个目录下并且文件名保持完整再用unzip命令或者7-Zip打开.zip主文件它会自动读取分卷。如果提示找不到分卷多半是因为文件名被改名或者放错目录了。5. 训练过程遇到的坑与排查技巧5.1 标注错位与类别混淆的排查训练到中期的时候我发现mAP50始终在0.8附近徘徊怎么也上不去。后来仔细看混淆矩阵发现红牛和东鹏的互相误检率高达12%明显不正常。排查过程分为三步第一步随机抽了20张红牛的图片和20张东鹏的图片人工检查标注框是否贴合、类别是否正确发现标注本身没问题。第二步检查训练时的数据增强发现mosaic增强把不同类别的图片拼接在一起偶尔会产生标注框交叉的情况但这种情况在YOLO标准训练中是常见的不应该导致这么高的混淆。第三步统计了两个类别的图片环境发现红牛的图片大多是白色背景的货架层板而东鹏的图片很多是深色背景模型很可能学的是背景而不是瓶子本身。这就引出一个重要的数据策略每个类别的图片要尽量覆盖多种背景。如果某类图片都只出现在一种环境中模型会把背景特征与类别特征绑定。我后来专门补充了一批红牛在东鹏相同深色场景下、东鹏在红牛浅色场景下的图片重新训练后混淆率降到了4%以下。5.2 训练集和验证集数据泄露一个更加隐蔽的问题数据泄露。因为部分图片是从开源数据集收集的我最初在处理时没有严格删除重复图片。有些图片可能在另一个数据集里被翻转或者稍微裁剪过导致验证集里出现了跟训练集中的图片高度相似的版本。这会让val指标虚高看似mAP50-95有0.8实际换到真实环境中只剩0.65。解决办法是写一个基于感知哈希的去重脚本把所有图片计算pHash值再比较汉明距离距离小于阈值就把重复图片标记出来。处理后我发现大约有30多张图片是重复或近似重复的从验证集中移除后指标回归到了正常范围。这个过程花的时间不长但价值极大让我对模型的真实能力有了准确的判断。5.3 推理阶段置信度阈值的选择模型训练好了推理部署时阈值设置是一个值得细调的环节。YOLO模型的默认conf阈值是0.25但这个值在高精度要求的业务场景下偏保守。我在测试集上跑了一遍不同阈值的准确率和召回率记录如下置信度阈值精确率召回率适用场景0.2592.3%96.1%需要尽量框出所有商品允许少量误检0.3595.7%94.0%零售控损减少误检优先0.5097.8%88.2%只需识别高度确定的商品最终我选了0.35作为默认值。对于那些本身就容易被混淆的类别比如红牛和东鹏我还会在业务层再加一道逻辑如果一个框中同时出现了两个类别的置信度都超过阈值就取置信度更高的那个同时记录一条待人工复核日志。这个后处理逻辑成本极低但能显著降低系统性的误检影响。6. 从YOLOv11模型到实际落地额外建议6.1 模型导出与部署形态选择训练完成之后如果需要部署到边缘设备建议把模型导出为ONNX或者TensorRT格式。ultralytics框架里一条命令就能完成yolo export modelruns/detect/train/weights/best.pt formatonnx imgsz800 yolo export modelruns/detect/train/weights/best.pt formatengine device0ONNX的好处是跨平台几乎所有推理框架OpenVINO、ONNX Runtime、TFLite都能加载TensorRT则是NVIDIA GPU上的性能最优解。对于CPU或者ARM设备通常导出为ONNX后用ONNX Runtime推理即可不用刻意追求TensorRT。导出时有一个细节如果你的训练是用imgsz800完成的导出时imgsz最好跟训练时保持一致。因为模型对输入尺寸是有一定依赖的虽然理论上可以调整但一旦resize到和训练不一致的尺寸精度会有可感知的下降。我在导出ONNX之后会在测试集上跑一遍推理对比一下pytorch模型和ONNX模型的mAP确保导出过程没有损失精度。6.2 扩展类别与新数据的持续学习这个项目目前只支持七个类别但现实场景远不止这些。如果你后续要增加类别要格外小心“增量学习”的坑。直接把新数据加到旧数据里重新训练的话如果旧数据没被完整保留模型会对旧类别产生灾难性遗忘——新的类别学得越好旧类别识别就越差。我的做法是保留所有原始图片和标注每加一批新类别就用完整的旧数据加新数据重新训练一次而不是只拿新数据做增量。虽然训练时间变长了但模型稳定性高得多。另外如果新类别与旧类别外观很像比如加一个百事可乐跟可口可乐的红色包装很接近建议在新类别数据里刻意混合一部分旧类别数据专门让模型学习区分两者。6.3 关于标注成本与数据质量的关系最后说一个常被忽略的问题数据标注的质量直接影响训练效果的上限。模型结构再好、训练技巧再多标注框画得歪七扭八模型学到的边界就不稳定。我在这个项目里标注一千多张图片花了大概两天时间每天只做四五个小时因为标注这件事集中注意力做三小时以上就容易疲劳出错。如果项目和资金允许建议至少让两个人独立标同一批图片然后计算标注一致性比如IoU大于0.8的比例不一致的图片由第三人裁决。这是工业级数据集的标准做法能显著提升标注质量。即使是个人项目也至少要在标注完成后做一轮抽检尤其是对容易混淆的类别。7. 项目复现完整清单为了让这篇分享可以直接当“作业抄”我把整个项目从头到尾的关键命令和配置汇总一下环境准备conda create -n yolo python3.10 -y conda activate yolo pip install ultralytics数据集结构dataset/ ├── images/train/ 和 images/val/ ├── labels/train/ 和 labels/val/ └── data.yamldata.yaml内容path: dataset train: images/train val: images/val names: 0: chips 1: dongpeng 2: redbull 3: fanta 4: yakult 5: cola 6: sprite训练yolo train datadata.yaml modelyolo11n.pt epochs80 imgsz800 batch16验证与绘图yolo val modelruns/detect/train/weights/best.pt datadata.yaml plotsTrue推理并保存结果yolo predict modelruns/detect/train/weights/best.pt source./test_images imgsz800 conf0.35 saveTrue导出ONNXyolo export modelruns/detect/train/weights/best.pt formatonnx imgsz800这套流程里最值得花时间的是数据整理和标注环节最开始的那次标注和清洗我花了最多精力但换来的模型效果也是最明显的。后续调参、换模型结构这些反而都是“锦上添花”如果数据本身有问题再先进的模型结构也发挥不出来。从我个人的操作经验来看用YOLOv11做商品识别这类垂直场景的检测任务整个链路已经非常成熟核心技术难点不在算法本身而在于对数据的理解和对每个环节细节的把控。这套罐装饮料识别的项目做完之后我又用同样的流程快速适配了另外几个零售场景的检测需求效果都稳定在可用水平。如果你手里也有一套标注好的图标数据集照着这篇文章的思路走一遍大概率能少走不少弯路。本文还有配套的精品资源点击获取