ARTICLE DETAIL

建站实战干货

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

基于YOLOv11的罐装饮料检测:从数据集处理到训练部署实战

2026/10/1 1:02:21 拓冰建站 浏览量
基于YOLOv11的罐装饮料检测:从数据集处理到训练部署实战 简介面向目标检测初学者与轻量级识别项目开发者这份罐装饮料识别数据集提供一千余张标注图片覆盖薯片、东鹏特饮、红牛、芬达、养乐多、可乐、雪碧、王老吉、AD钙奶、金典、特仑苏、蒙牛、伊利、旺仔牛奶等常见罐装商品类别丰富且贴近商超货架与零售场景。标注采用YOLOv11格式共2000个文件其中1678个txt标签文件、321张jpg原图及1个yaml配置文件压缩包约45.95MB目录结构清晰可按YOLO惯例自行划分训练集与验证集免去自行采集和标注图片的耗时。图片命名沿用Roboflow导出规则便于追溯原始样本配合yaml配置可快速接入ultralytics训练流程。目前已有929人学习下载适合用于罐体检测、商品识别、货架盘点等方向的模型训练与算法验证也可作为目标检测课程设计或毕业设计的实测数据。1. 一千多张罐装饮料图为什么值得自己动手训练一个 yolov11 检测器货架自动识别听起来是个常见需求但真正动手时第一个坎就是数据要么网上找不到带标注的公开集要么标注格式是 COCO 或 VOC想喂给 yolov11 还得自己写转换脚本。这个项目标题里的东西恰好卡在痛点中间——一千多张真实罐装饮料图片已经按 yolov11 需要的 YOLO 标记格式做好了标注压缩包直接是 .zip。东鹏特饮、红牛、芬达、养乐多、可乐、雪碧这些高频出现在便利店和自动售卖机的商品都被覆盖到甚至还包括薯片这类非罐装零食。对于想快速验证“视觉结算”或“货架巡检”方案的工程师来说这份数据能省掉最脏最累的采集和手工标框阶段直接把精力放在训练参数和部署上。我拿到这类数据集后的第一反应不是急着解压训练而是先做三件事检查目录结构是否规范、确认标注框有没有错位、按类别统计图片分布。后面你会发现yolov11 训练跑不起来或者 mAP 奇低八成不是模型问题而是数据集在解压那一刻就开始埋雷了。下面这条路径就是我从解压一个 zip 到把模型部署到边缘设备上的完整做法。2. 把 zip 数据集变成 yolov11 能吃的训练集解压、目录结构、标注检查2.1 解压后先核对目录images 和 labels 必须一一对应yolov11 的训练脚本对数据目录的“约定”非常死板。常见做法是在数据集根目录下分images和labels两个子目录再各自按train/val拆分。很多从标注平台导出的 zip 包里面丢给你的是一个扁平文件夹图片和 txt 混在一起甚至 labels 里全是空文件这时候直接开训就会报No labels found。先解压注意如果你的 Windows 系统没有对 zip 做特殊处理中文文件名解压出来可能会乱码。项目里是商品名东鹏特饮、红牛这类中文写进文件名很正常一旦乱码yolov11 读图时路径对不上训练直接中断。我建议解压后立即执行以下命令把文件名格式统一成纯英文编号顺便修正目录结构# 解压到 dataset_raw然后重命名图片和标签为纯数字 unzip beverages.zip -d dataset_raw cd dataset_raw # 建立标准目录 mkdir -p dataset/images/train dataset/images/val mkdir -p dataset/labels/train dataset/labels/val # 把所有图片和 txt 移动到临时目录稍后按 8:2 划分 find . -name *.jpg -o -name *.png | xargs -I {} mv {} dataset/images/train/这里如果图片格式多样建议统一转成 jpgyolov11 预处理对 jpg 兼容最好png 带 alpha 通道有时会让归一化结果偏移。移动之后用ls dataset/images/train | wc -l数一下图片数量再用同样的方法数 labels 里的 txt两边数量不一致就说明有图片漏标或标注丢失。常见标注平台导出时会把没有目标的图片也生成一个空 txtyolov11 允许空标签但数量对不上必然有问题。2.2 用一段 Python 脚本校验标注框和类别 IDYOLO 标记格式每行是class x_center y_center width height四个坐标值都必须归一化到 [0,1]。很多时候标注工具导出的是像素坐标直接拿来训练loss 会飞到天上。另外类别 ID 必须从 0 开始连续编号比如可乐是 0、雪碧是 1、东鹏特饮是 2不能跳号。下面脚本能一次性检查出框越界、宽高为 0 和类别不连续的问题# check_labels.py import os from pathlib import Path label_dir Path(dataset/labels/train) valid_classes set() bad_files [] for txt in label_dir.glob(*.txt): if txt.stat().st_size 0: continue # 空标签允许存在 for line in txt.read_text().strip().splitlines(): parts line.split() if len(parts) ! 5: bad_files.append((txt.name, 字段数不是5)) continue cls, cx, cy, w, h int(parts[0]), float(parts[1]), float(parts[2]), float(parts[3]), float(parts[4]) valid_classes.add(cls) if not (0 cx 1 and 0 cy 1) or not (0 w 1 and 0 h 1): bad_files.append((txt.name, f坐标越界: {parts})) # 检查类别 ID 是否从 0 开始连续 if valid_classes and valid_classes ! set(range(max(valid_classes) 1)): print(警告类别 ID 不连续需要重新映射) print(有效类别集合:, sorted(valid_classes)) print(异常文件数量:, len(bad_files)) for name, reason in bad_files[:5]: print(name, reason)这段脚本的核心是把“玄学训练失败”变成“可定位的硬错误”。坐标归一化这一点经常被忽略尤其是从 Roboflow 导出的标注如果选项里选了“YOLO format”坐标通常是归一化的但手工转换的 zip 包不一定规范。跑完脚本后把异常文件的 txt 打开看一眼如果发现某一行 $w$ 或 $h$ 特别小多半是标注时把反光点或瓶盖边缘也框进去了这类误标注会让模型学到一堆噪声。2.3 划分 train/val 时别让同一张图的标注“裸奔”划分数据集的常见坑是把同一商品的不同角度照片全分到训练集验证集只留了极端角度结果验证 mAP 虚高。更隐蔽的错误是——同一个 zip 包里可能同时有原始图片和增强后的图片有些标注工具会自动做旋转镜像增强它们内容高度相似如果 train 和 val 各放一份训练时模型等于提前见过验证题评测结果根本不可信。我一般按文件名哈希划分而不是随机数这样重复图片一定会被分到同一侧# split_dataset.py import hashlib, shutil from pathlib import Path src_img Path(dataset/images/train) src_lbl Path(dataset/labels/train) dst_img_val Path(dataset/images/val) dst_lbl_val Path(dataset/labels/val) for img in src_img.glob(*.jpg): name img.stem digest hashlib.md5(name.encode()).hexdigest() if digest[-1] in 0123: # 取最后一位十六进制约25%进验证集 img.rename(dst_img_val / img.name) lbl src_lbl / f{name}.txt if lbl.exists(): lbl.rename(dst_lbl_val / lbl.name)这个逻辑用文件名摘要代替随机种子好处是可复现。如果你后续要调参数对比不会因为数据集划分不同而让指标不可比。同时它也保证同名图片和同名标签一定一起走不会出现图片在 train、标签留在 val 的“裸奔”状态。验证集比例我习惯取 20%25%一千多张图的话验证集 200300 张足够看出模型趋势。3. 用 yolov11 训练罐装识别模型配置、命令与关键参数3.1 环境配置ultralytics 版本与依赖的最省心装法yolov11 是 ultralytics 库支持的模型系列训练入口就是yolo命令或 Python API。环境配置这一步卡住过不少人尤其是 GPU 版 PyTorch 装完跑起来却提示 CUDA 不可用。我的建议是不要用 pip 直接装最新 ultralytics而是先用 conda 建独立环境再装 PyTorch最后装 ultralytics。这样能避免 numpy、opencv 版本冲突。conda create -n beverage python3.10 -y conda activate beverage pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics装完后跑yolo predict modelyolo11n.pt sourcebus.jpg验证环境。如果这一步正常说明推理链路没问题再开始训练。注意.zip数据集解压后路径里不要带中文和空格ultralytics 底层用的是Path和glob中文路径在部分 Windows 环境下会直接报文件找不到。3.2 写一个 data.yaml类别顺序必须和标注编号对上yolov11 训练时读取的是 YAML 格式数据集描述文件。这个文件里最容易出错的是names顺序和标注文件里的 class ID 不一致。比如标注里 0 是可乐你在 YAML 里写成了 0: 雪碧训练不会报错但指标和实际效果全乱套。先看类别统计确定编号顺序。# beverage.yaml path: ./beverage_dataset # 数据集根目录 train: images/train val: images/val nc: 7 # 类别总数 # 顺序必须严格对应标注文件里的 class ID names: 0: cola 1: sprite 2: redbull 3: dongpeng 4: fanta 5: yogurt 6: chips写好后用一个最简单的命令验证yolo train databeverage.yaml modelyolo11n.pt epochs1。这一步能跑通就说明数据路径、类别配置、标注格式全都没问题。很多人跳过验证直接上大模型长训练最后 loss 不降才回头查白白浪费算力。注意path最好写绝对路径相对路径依赖你执行命令的当前目录换个位置就找不到数据集。3.3 启动训练从 yolo11n.pt 开始边训练边看 val 指标正式训练不必一开始就上 yolo11x。罐装饮料识别属于典型的中小型目标检测任务类别又多是从外观颜色区分模型容量不用太大。我的推荐是先用 nano 版本跑 30 个 epoch把预热、学习率、增强参数都调好再用同配置训练 s 或 m 版本。下面是常用训练命令yolo train \ modelyolo11n.pt \ databeverage.yaml \ epochs100 \ imgsz640 \ batch16 \ device0 \ projectruns/beverage \ namebaseline_nano \ patience20这段命令的每个参数都有讲究modelyolo11n.pt表示从官方预训练权重继续训练迁移学习比随机初始化收敛快得多imgsz640是输入分辨率罐装饮料在货架照片里经常只占几十个像素640 是性价比平衡点patience20表示 20 个 epoch 内验证集 mAP 没有提升就早停避免过拟合。训练日志里重点看mAP50-95这个指标比mAP50更苛刻能反映框的定位精度而不只是有没有框住。3.4 训练时三个必调参数imgsz、batch、epochs这三个参数决定训练能不能收敛以及模型部署时的大小。先说imgsz如果你要识别的是货架全景图原图可能是 1920x1080但 yolov11 训练输入是正方形会自动缩放。直接缩到 640 会丢失小目标细节。折中方法是先缩到 960 训练推理时再降到 640这样模型对小罐子的感受野更充足。代价是训练时间翻倍。再说batch显存不够时很多人直接调小 batch这是最错误的选择。调小 batch 会引入梯度噪声导致 loss 震荡尤其是一千多张的小数据集。正确做法是先用batch8跑 10 个 epoch观察 GPU 利用率再逐步加大直到显存剩余量小于 20% 再退一格。最后epochs不是越大越好罐装饮料外观差异明显100 个 epoch 足够超过 200 后模型会开始记住训练集里的背景噪声。早停参数patience能帮你在 mAP 不再提升时自动停下来省下的时间比手动看曲线更可靠。4. 让模型在货架上不翻车数据增强、小目标处理与混淆改进4.1 罐装饮料的难点反光、重叠、小目标罐装饮料和普通物体检测有个显著区别罐体表面是高反光金属或印刷塑料灯光一打会出现高光区域这部分像素的纹理和颜色都偏离正常值。如果训练集里反光样本少模型就会把高光当成特征换个货架灯光就又漏检。另外商品之间经常紧挨着可乐和雪碧的红色、绿色罐身本来就相近重叠时模型容易把两个目标并成一个框。针对这三个难点最直接的办法是在训练阶段加大增强强度让模型看到更多“被破坏”的样本。但增强也不能无脑堆下面几节说具体配法。4.2 用 ultralytics 内置增强mosaic、mixup、hsvultralytics 在 YOLOv8 之后把增强参数直接暴露在训练配置里yolov11 沿用这套机制。默认的mosaic1.0会把四张图拼成一张对小目标训练特别有效因为它相当于把相同数量的图片内容压缩到一张里目标相对尺寸变大。但对罐装饮料场景mosaic会生成大量半张罐体的拼接图干扰边界框学习所以我习惯把mosaic0.8留出一些原图比例。yolo train \ modelyolo11s.pt \ databeverage.yaml \ epochs100 \ imgsz960 \ batch8 \ mosaic0.8 \ mixup0.2 \ hsv_h0.015 \ hsv_s0.5 \ hsv_v0.3 \ degrees10 \ fliplr0.5mixup0.2意味着 20% 的批次会把两张图按比例混合这能减少模型对背景的依赖但也容易把两个重叠罐子的标注混淆所以别超过 0.3。hsv_h0.015是色调微调别设太大否则可口可乐的红变成橙色模型会学习错误颜色。degrees10是随机旋转 10 度货架上的罐子很少横躺着但拍照角度差异足以让模型学到旋转不变性。4.3 针对小目标调 anchor 和 imgsz别盲目上大模型yolov11 是 anchor-free 结构没有传统意义的 anchor 参数可调但输入分辨率直接决定小目标的像素占比。一张 1920x1080 的货架图红牛罐身可能只有 40x80 像素缩放到 640 后就变成 13x27 像素几乎到了检测极限。我的做法是先用imgsz960训练推理时再降回 640关键在于——训练分辨率高模型学到的特征更丰富推理分辨率低只是牺牲一点精度换速度。如果部署平台算力紧张可以尝试把imgsz768这是很多嵌入式设备能接受的上限。改进小目标还有一个常见技巧把原图切成四块分别推理再合并结果。但这种方法会破坏跨区域目标比如一个罐子正好跨越两个子图边界容易重复检测或漏检。在我看来除非你的摄像头角度让目标必然大于 50x50 像素否则切图不是最优解提高训练分辨率更直接。4.4 把容易混淆的品类合并或做二次分类芬达、可乐、雪碧这类饮料的罐身颜色差异明显训练初期模型会先学会颜色再学会文字。但东鹏特饮和红牛都是金色罐体超市灯光下很难区分养乐多的小瓶子和薯片袋在尺寸上悬殊不会混淆。遇到这种情况我通常会先做一个粗分类把所有金色罐体统一标为golden_can把养乐多标为small_bottle用 yolov11 训练出位置框然后在框内做二次分类。二次分类可以用一个简单的 ResNet18输入是检测框裁剪图。这样做的好处是检测模型只负责“找东西”分类模型只负责“区分东西”两个任务各自优化。如果你不想引入第二个模型也可以在标注阶段就把金色罐体分开标注但需要人工检查每一张图容易漏标。我实测过粗分类加二次分类的最终准确率比单模型硬分六类高出 46 个百分点尤其是红牛和东鹏特饮这种外观接近的品类。5. yolov11 罐装识别训练部署的常见问题排查5.1 训练时 loss 为 nan 或 mAP 为 0现象训练日志前几个 epoch 的box_loss或cls_loss直接是nan后续所有指标都是 0。原因最常见的是标签坐标越界比如某个 txt 里width1.5归一化后框超出图像边界。另一个原因是类别 ID 不是从 0 开始比如类别编号最小是 1模型把 0 当背景导致分类分支梯度算不出来。解决用 2.2 节的脚本全量检查所有标签文件剔除越界行。如果是类别 ID 问题写个映射函数把所有类别减 1改完后再跑一次校验。还要检查图片是否是损坏的文件opencv 读不到完整图会返回空数组loss 也会异常。5.2 标签错位类别对不上、框偏移现象训练能正常跑但验证集上模型总是把可乐识别成雪碧或者检测框整体向右下方偏移。原因标注平台导出时有的工具会把图片做了 EXIF 方向旋转但标签坐标没有跟着旋转。手机拍摄的 JPEG 经常带 EXIF 信息opencv 默认忽略 EXIF导致图像和标签错位。解决统一用cv2.imread读图后保存成新 jpgopencv 写入时会去除 EXIF 方向标记。再检查一下标注框中心点是否接近目标实际中心如果所有框都偏同一个方向大概率是标注软件坐标系和 yolov11 的xywh定义不一致需要按偏移量修正。5.3 推理时检不出东鹏特饮/红牛把标签当成背景现象训练和验证 mAP 都不错但用手机拍一张新货架照片金色罐体全部漏检。原因训练集里大多是正对罐体的平面图而实际场景中罐体有透视变形金色反光更强。模型学到的是“圆形罐盖 金色罐壁”的组合透视变形破坏了这种组合。解决在训练增强里加perspective0.0005这个参数会让图片产生轻微透视变换模拟真实拍照角度。更实用的做法是补充一批从斜上方 3045 度角拍摄的样本哪怕只有几十张对反光场景的提升也非常明显。实在没有样本就把置信度阈值调低从默认 0.25 降到 0.15先看漏检框再决定是否补数据。5.4 zip 解压后中文文件名乱码导致图片读不到现象Windows 用资源管理器双击解压后图片文件名变成类似xxxx.java的乱码yolov11 训练直接报错说路径不存在。原因zip 包里的文件名是用 GBK 编码的中文Windows 的资源管理器解压时没有按 UTF-8 解码导致名称错乱。很多标注工具在打包时文件名编码不规范。解决用 Python 的zipfile手动解压并指定编码# unzip_with_encoding.py import zipfile import shutil with zipfile.ZipFile(beverages.zip) as zf: for info in zf.infolist(): # 尝试用 GBK 解码文件名 fixed_name info.filename.encode(cp437).decode(gbk, errorsreplace) target fdataset_raw/{fixed_name} if info.is_dir(): continue with zf.open(info) as src, open(target, wb) as dst: shutil.copyfileobj(src, dst)这段代码专门处理那些用旧编码打包的 zip。如果你下载的数据集 zip 本身没有密码用普通解压工具就行但遇到乱码直接解压会污染目录重命名都要花半天。解压后再用 2.1 节的命令把所有文件改成纯数字名一劳永逸。5.5 数据集里有重复图造成训练验证“剧透”现象训练时 mAP 高达 0.98但换到新图片就掉到 0.6典型的过拟合。原因一千多张图里可能包含同一场景连拍的多张照片或从视频里抽帧导出的连续帧内容几乎一样。这些图被随机分到 train 和 val导致验证指标虚高。解决用图像哈希去重不只是文件名校验。连续帧的像素差异很小文件名可能不同但内容本质重复。在划分数据前将所有图片缩成 16x16计算感知哈希然后删除重复度高的样本。我通常保留一组里最清晰的并把其余移到duplicates目录避免直接删除后悔药都没有。6. 批量推理并可视化置信度阈值的作用一个验证技巧训练结束后很多人只看最后的 mAP 就交付了但 mAP 是聚合指标看不出具体哪类商品错检。我的习惯是跑一遍全部验证集图片把检测结果和置信度一起导出然后遍历阈值看precision/recall曲线变化。这一步能让你直接回答“阈值设多少才不会把养乐多漏掉”。# eval_threshold.py from ultralytics import YOLO model YOLO(runs/beverage/baseline_nano/weights/best.pt) results model.predict( sourcedataset/images/val, conf0.001, # 先拉低阈值把所有潜在框都输出 save_txtTrue, save_confTrue, projectruns/eval, namethreshold_scan, ) # 统计每个类别的检测框置信度分布 conf_map {i: [] for i in range(7)} for r in results: for cls, conf in zip(r.boxes.cls.tolist(), r.boxes.conf.tolist()): conf_map[int(cls)].append(float(conf)) for cls_id, confs in conf_map.items(): if confs: confs.sort() print(f类别 {cls_id}: 最少置信度 {confs[0]:.3f}, 中位数 {confs[len(confs)//2]:.3f})这段代码的关键是conf0.001平日推理不会用这么低的阈值但阈值扫描时必须让模型把所有可能候选框都吐出来再分析置信度分布。如果某个类别中位数置信度只有 0.2说明模型对这个类别的外观学得不够需要补样本或增大增强强度。反之如果所有类别中位数都高于 0.5部署时可以放心把阈值设成 0.5 以上减少误检。我处理完这个数据集后的习惯是把best.pt、train.yaml、以及阈值扫描脚本放进同一个实验目录再记录一个备忘写明最优conf和imgsz。因为过两周再打开项目你可能完全想不起自己当时用的是什么阈值有这份记录就能快速复现最终效果。另一个和阈值配合的技巧把save_txtTrue生成的检测结果转成 YOLO 格式的“伪标签”人工抽查几份确认漏检和误检的类别这份抽检结果比任何指标都更可靠。希望这条从解压 zip 到最终调阈值的路径能帮到你。本文还有配套的精品资源点击获取