
简介本资源面向计算机视觉学习者与目标检测开发者提供罐装饮料识别数据集可直接用于YOLOv8模型训练与验证。数据覆盖薯片、东鹏特饮、红牛、芬达、养乐多、可乐、雪碧、王老吉、AD钙奶、金典、特仑苏、蒙牛、伊利、旺仔牛奶等常见饮品适合课堂实验、竞赛项目与算法练手。压缩包共2000个文件含1678个txt标注文件、321张jpg图像及1个yaml配置文件整体约45.95MB标注与图像一一对应yaml可直接指定类别与路径省去手工整理环节。目前已有929人学习下载说明该数据集在同类任务中具备一定参考价值。读者可据此快速搭建训练流程验证模型对多品牌、多包装饮料的检测效果并在此基础上做数据增强、类别扩展或迁移学习减少从零采集与标注的成本。1. 罐装饮料识别数据集一千多张图能撑起一个可用的 YOLOv8 检测器吗手里拿到一份标注好的罐装饮料数据集一千多张图片YOLOv8 格式覆盖薯片、东鹏特饮、红牛、芬达、养乐多、可乐、雪碧、王老吉这类常见快消品。第一反应通常是这点量够不够训出一个能上货架的模型我的经验是够但前提是你得把「够」定义清楚——如果目标是固定机位、固定光照下的货架盘点或自助结算辅助一千多张、七八个类别每类一百多张配合 YOLOv8n 或 YOLOv8smAP50 做到 0.85 以上是现实的如果目标是任意角度、任意遮挡的开放场景那这点数据只能算冷启动后面必须补采。这份数据集真正的价值不在「多」而在「标签已经是 YOLOv8 格式」。做过目标检测的人都知道从 Labelme 的 JSON、VOC 的 XML 转到 YOLO 的 txt中间那层坐标归一化和类别映射是新手最容易翻车的地方。这份数据省掉了这一步意味着你可以把精力全部放在训练策略和部署验证上。它适合三类人想跑通 YOLOv8 全流程的入门者、做零售货架识别的方案验证者、以及需要一个小型多类别检测基线做对比实验的工程师。下面我按「先看懂数据长什么样、再跑通训练、最后避开那些必踩的坑」的顺序把这条路走一遍。2. 拆开这份数据集YOLOv8 标注格式、类别分布与目录结构2.1 YOLOv8 的 txt 标注到底存了什么YOLOv8 沿用 YOLO 系列的标注约定每张图对应一个同名 txt每行一个目标格式是class_id x_center y_center width height后四个值都是相对图像宽高的归一化浮点数范围 0 到 1。这里有两个高频误解。第一x_center y_center是框中心点不是左上角第二归一化是除以图像自身的宽和高不是除以某个固定尺寸。很多人从 VOC 转过来时忘了除以宽高训出来的框会全部挤在左上角损失曲线看着在降实际检测全是废框。先写个脚本把数据集的真实情况摸清楚别急着开训。下面这段代码统计类别分布、检查标注合法性、找出空标签和越界框import os from collections import Counter from pathlib import Path IMG_EXTS {.jpg, .jpeg, .png, .bmp} root Path(dataset) # 改成你的数据集根目录 img_dir root / images lbl_dir root / labels cls_counter Counter() bad_lines [] empty_labels [] missing_labels [] size_pairs [] for img_path in img_dir.rglob(*): if img_path.suffix.lower() not in IMG_EXTS: continue lbl_path lbl_dir / (img_path.stem .txt) if not lbl_path.exists(): missing_labels.append(str(img_path)) continue lines [l.strip() for l in lbl_path.read_text().splitlines() if l.strip()] if not lines: empty_labels.append(str(lbl_path)) continue for ln in lines: parts ln.split() if len(parts) ! 5: bad_lines.append((str(lbl_path), ln)) continue cid, x, y, w, h parts vals list(map(float, [x, y, w, h])) if any(v 0 or v 1 for v in vals) or vals[2] 0 or vals[3] 0: bad_lines.append((str(lbl_path), ln)) continue cls_counter[int(cid)] 1 print(类别分布:, dict(sorted(cls_counter.items()))) print(缺失标签:, len(missing_labels)) print(空标签文件:, len(empty_labels)) print(非法标注行:, len(bad_lines)) for item in bad_lines[:10]: print( 异常:, item)这段脚本的逻辑很直白遍历图片目录按同名规则找标签逐行校验字段数和数值范围。cls_counter告诉你每个类别有多少个框这是判断类别是否失衡的第一手依据。bad_lines抓的是字段数不对或坐标越界的行这类行如果直接喂给训练YOLOv8 的 dataloader 会在某个 batch 上抛异常而且报错信息往往只指向行号不告诉你哪张图排查起来很费时间。empty_labels是空 txtYOLOv8 默认会把它们当负样本如果你不希望背景图参与得在配置里处理。跑完这一步你对数据的底细就有数了。2.2 目录结构与 data.yaml 的正确写法YOLOv8 对目录结构有约定常见的是images/train、images/val、labels/train、labels/val平行放置。如果你的数据现在全堆在一个文件夹里先做一次划分。划分时有个血泪经验同一个视频抽帧出来的连续图片绝不能一部分进 train、一部分进 val否则验证集精度会虚高得离谱因为相邻帧几乎一模一样。正确做法是按「拍摄批次」或「视频来源」整体划分而不是随机按文件划分。import random import shutil from pathlib import Path random.seed(42) root Path(dataset) img_dir root / images lbl_dir root / labels for split in [train, val]: (img_dir / split).mkdir(parentsTrue, exist_okTrue) (lbl_dir / split).mkdir(parentsTrue, exist_okTrue) imgs [p for p in img_dir.glob(*) if p.suffix.lower() in {.jpg, .jpeg, .png, .bmp}] random.shuffle(imgs) val_ratio 0.2 n_val int(len(imgs) * val_ratio) val_set set(imgs[:n_val]) for img in imgs: split val if img in val_set else train lbl lbl_dir / (img.stem .txt) shutil.move(str(img), str(img_dir / split / img.name)) if lbl.exists(): shutil.move(str(lbl), str(lbl_dir / split / lbl.name)) print(train:, len(imgs) - n_val, val:, n_val)random.seed(42)保证划分可复现换台机器跑结果一致。val_ratio0.2是常规起点数据量小的时候可以降到 0.15把更多样本留给训练。注意这里用shutil.move是原地移动跑之前先备份一份原始数据别问我怎么知道的。对应的data.yaml写法如下names的顺序必须和标注里的class_id严格对应错一位整个类别就串了path: /abs/path/to/dataset train: images/train val: images/val nc: 8 names: 0: lays_chips 1: dongpeng 2: redbull 3: fanta 4: yakult 5: cola 6: sprite 7: wanglaojipath建议写绝对路径相对路径在不同工作目录下启动训练时经常找不到文件。nc是类别数必须和names条目数一致不一致时 YOLOv8 会在构建模型头时报维度错误。类别名用英文小写下划线避免中文和空格虽然新版支持中文但在跨平台和导出 ONNX 时英文名省心得多。3. 用 YOLOv8 训练罐装饮料检测模型环境、命令与参数3.1 环境配置与最小训练命令环境这块CPU 版本在 Ubuntu 20.04 上就能跑通只是慢。有 GTX1660Ti 这类 6G 显存的卡用yolov8n或yolov8s完全够。安装就两步pip install ultralytics yolo checksyolo checks会打印环境自检表重点看 torch 版本、CUDA 是否可用、以及 ultralytics 版本。如果 CUDA 显示不可用但你确实有卡多半是 torch 装成了 CPU 版重装对应 CUDA 版本的 torch 即可。最小训练命令yolo detect train \ data/abs/path/to/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ device0 \ projectruns/detect \ namedrink_v1modelyolov8n.pt是从预训练权重起步小数据集强烈建议这么做从头训几乎不可能收敛好。imgsz640是输入分辨率罐装饮料在图中占比通常不大640 是精度和速度的平衡点如果图片里饮料很小可以提到 960但显存和耗时都会涨。batch16在 6G 显存上跑 640 分辨率基本安全爆显存就降到 8。device0指定第一块 GPUCPU 训练写devicecpu。3.2 关键训练参数怎么调YOLOv8 的参数很多但小数据集上真正影响结果的就那么几个。下面这张表是我在罐装饮料这类场景里反复验证过的取值区间参数含义小数据集建议值说明epochs训练轮数100~300数据少可以多跑配合早停patience早停耐心30~50验证指标不升就停省时间lr0初始学习率0.01默认值微调时可降到 0.001lrf最终学习率因子0.01余弦退火终点warmup_epochs预热轮数3防止初期梯度爆炸mosaic马赛克增强1.0小数据集必开提升泛化close_mosaic关闭 mosaic 轮数10最后几轮关掉稳定收敛mixup混类增强0.1类别少时可开别太高degrees旋转角度5~10货架场景轻微旋转hsv_v亮度扰动0.4应对不同光照mosaic是小数据集的生命线它把四张图拼成一张等效于增加了样本组合对罐装饮料这种目标密集的场景尤其有效。但close_mosaic10一定要设最后十轮关掉马赛克让模型在真实分布上收敛否则验证精度会偏低。patience配合epochs用我一般设 epochs200、patience40实际往往跑不到 200 轮就停了。训练启动后重点盯三个东西box_loss是否稳定下降、mAP50是否在涨、以及有没有出现nan。如果 loss 一开始就 nan八成是学习率太高或标注里有非法值回到 2.1 的脚本再查一遍。如果 mAP 长时间不动先看验证集是不是和训练集分布差太远。3.3 训练结果怎么看损失曲线与混淆矩阵训练完在runs/detect/drink_v1下会生成results.csv、confusion_matrix.png、results.png等文件。results.png里那几条曲线是判断训练健康度的核心。train/box_loss和val/box_loss如果同步下降且差距不大说明没怎么过拟合如果 train 一直降、val 早早反弹就是过拟合得加数据或加增强。metrics/mAP50-95比mAP50更严格小数据集上这个值通常比 mAP50 低不少别慌看趋势。混淆矩阵能直接暴露类别混淆问题。罐装饮料里最容易混的是可乐和芬达、雪碧和芬达因为罐体形状接近、颜色在光照下会偏。如果混淆矩阵显示这几类互相误判严重说明模型没学到颜色以外的判别特征这时候要么补采不同角度的图要么在类别定义上做合并。想画更细的损失曲线可以直接读results.csvimport pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/detect/drink_v1/results.csv) df.columns [c.strip() for c in df.columns] plt.plot(df[epoch], df[train/box_loss], labeltrain_box) plt.plot(df[epoch], df[val/box_loss], labelval_box) plt.plot(df[epoch], df[metrics/mAP50], labelmAP50) plt.legend() plt.xlabel(epoch) plt.savefig(curve.png, dpi150)results.csv的列名带空格读进来先 strip 一遍否则按列名取值会 KeyError。这张图比官方生成的更灵活你可以把 mAP50 和 loss 画在一起直观判断收敛点。4. 推理、验证与部署从 predict 到 ONNX 导出4.1 用训练好的权重做推理训练完先别急着部署用predict在几张真实图上看看效果yolo detect predict \ modelruns/detect/drink_v1/weights/best.pt \ source/abs/path/to/test_images \ conf0.25 \ iou0.45 \ saveTrueconf0.25是置信度阈值低于它的框不输出iou0.45是 NMS 的 IoU 阈值控制重叠框的合并。这两个值直接影响召回和误检conf 调低召回高但误检多调高反之。货架盘点场景我一般 conf 设 0.3 到 0.4宁可漏检也别误报。saveTrue会把画框结果存到runs/detect/predict下。如果想在 Python 里批量处理并拿到结构化结果from ultralytics import YOLO model YOLO(runs/detect/drink_v1/weights/best.pt) results model.predict(test.jpg, conf0.3, iou0.45, verboseFalse) for r in results: for box in r.boxes: cls_id int(box.cls) conf float(box.conf) xyxy box.xyxy.tolist()[0] print(model.names[cls_id], round(conf, 3), [round(v, 1) for v in xyxy])box.xyxy是原图坐标系下的左上右下角点直接可用于后续业务逻辑比如判断某个饮料在货架的哪一层。model.names是类别 id 到名字的映射来自 data.yaml。4.2 导出 ONNX 与部署前验证要在非 Python 环境或边缘设备上跑导出 ONNX 是常规做法yolo export modelruns/detect/drink_v1/weights/best.pt formatonnx imgsz640 opset12 simplifyTrueopset12兼容性较好simplifyTrue会做图优化去掉冗余算子。导出后务必做一次一致性验证用同一张图分别跑 PyTorch 权重和 ONNX对比输出框的差异。差异在千分位以内算正常如果差很多多半是预处理归一化、letterbox没对齐。ONNX 推理时的输入是1x3x640x640的 float32通道顺序 RGB归一化到 0 到 1letterbox 的填充值通常是 114。这些细节任何一处不对结果都会偏。提示导出 ONNX 后用 onnxruntime 跑一遍和 PyTorch 对比是部署前最省事的后悔药。别等上了板子才发现框全偏了。5. 罐装饮料识别避坑五条踩出来的经验5.1 现象训练 loss 正常但验证 mAP 一直是 0原因data.yaml里的names顺序和标注class_id对不上或者val路径写错导致验证集为空。YOLOv8 在验证集为空时不会报错只是指标全 0。解决用 2.1 的脚本打印类别分布确认 class_id 从 0 连续再手动ls一下images/val里有没有图。5.2 现象模型把可乐识别成芬达颜色相近的类别互相误判原因数据里这两类的拍摄光照单一模型学到的是「罐体形状 大致色块」没学到包装上的文字和 logo 细节。解决补采不同光照、不同角度的样本或者在训练时提高imgsz到 960让包装细节更清晰实在分不开就考虑业务上是否必须区分。5.3 现象推理时框位置整体偏移原因预处理不一致。PyTorch 推理走的是 ultralytics 内置的 letterbox而你自己写的 ONNX 预处理可能用了直接 resize没保持长宽比。解决ONNX 预处理必须复刻 letterbox记录缩放比例和填充偏移后处理时再映射回原图坐标。5.4 现象训练到一半显存爆了原因batch设太大或者imgsz提高后没同步降 batch。解决6G 显存跑 640 分辨率yolov8n用 batch16yolov8s降到 8开启ampTrue混合精度也能省显存但要注意某些卡上 amp 会导致 nan出现就关掉。5.5 现象验证集精度虚高上线后一塌糊涂原因划分时把同一视频的连续帧分到了 train 和 val验证集和训练集高度相似。解决按拍摄批次整体划分确保 val 里的场景在 train 里没出现过。这是小数据集最隐蔽的坑指标好看但没意义。6. 把一千张图用出三千张的效果几个进阶技巧数据量固定的时候提升空间主要在增强策略和训练技巧上。我常用的一个组合是mosaic1.0打底copy_paste0.3做实例粘贴scale0.5做随机缩放再配合close_mosaic15。copy_paste 会把一个实例抠出来贴到另一张图上对罐装饮料这种独立目标特别合适等效于免费扩充了样本组合。但 copy_paste 开太高会引入不自然的边缘0.2 到 0.3 比较稳。另一个技巧是分阶段训练。先用 640 分辨率跑 100 轮把模型训到基本收敛再用 960 分辨率微调 30 轮。高分辨率微调能让模型适应更清晰的包装细节对区分可乐和芬达这类任务提升明显代价是显存和时间。我一般会在第一阶段结束后把best.pt作为第二阶段的起点yolo detect train \ data/abs/path/to/data.yaml \ modelruns/detect/drink_v1/weights/best.pt \ epochs30 \ imgsz960 \ batch4 \ lr00.001 \ close_mosaic10 \ namedrink_v1_finetune第二阶段学习率降到 0.001因为模型已经接近收敛大学习率会把之前的成果冲掉。batch4是 960 分辨率下的显存妥协。这个两阶段流程在我做过的多个小数据集项目里mAP50 通常能再涨 2 到 4 个点。验证方法上除了看 mAP我习惯抽 20 张验证集图片做人工核对统计漏检和误检的具体类别。指标是平均值业务关心的是「红牛有没有被漏掉」。如果某一类召回明显低优先补这一类的样本而不是无差别加数据。最后说个习惯每次训练前把data.yaml、命令、git commit 记在一个train_log.md里一周后你还能复现出当时的结果。小数据集项目迭代快没有记录两周就忘了哪个参数对应哪次实验。希望帮到你。本文还有配套的精品资源点击获取