简介:本资源面向计算机视觉初学者与目标检测开发者,提供一套罐装饮料识别数据集,可用于YOLOv8模型训练与算法验证。数据覆盖薯片、东鹏特饮、红牛、芬达、养乐多、可乐、雪碧、王老吉、AD钙奶、金典、特仑苏、蒙牛、伊利、旺仔牛奶等常见饮品,适合零售货架识别、智能结算、自动盘点等场景。压缩包共2000个文件,其中1678个txt标注文件、321张jpg图像及1个yaml配置文件,整体约45.95MB,标注与图像一一对应,yaml可直接用于YOLOv8训练配置。目前已有929人学习下载,说明该数据集在同类任务中具备一定参考价值。读者可据此快速搭建训练流程,验证模型对多类别罐装饮料的检测效果,并在此基础上进行数据增强、类别扩展或迁移学习,节省自行采集与标注的时间成本。
1. 罐装饮料识别数据集:一千多张图、YOLOv8 标记,能直接开训吗
货架盘点和智能零售柜最头疼的不是模型结构,而是找不到一批标注干净、类别对齐的罐装饮料图。这份资源给的就是一千多张实拍图,全部按 YOLOv8 格式打好标记,覆盖薯片、东鹏特饮、红牛、芬达、养乐多、可乐、雪碧、王老吉这类常见快消品。拿到手第一件事不是急着train,而是先确认它的目录结构、类别映射和标注质量,否则训练跑起来 loss 不降,你还以为是超参问题,其实是标签错位。这篇按「数据集长什么样 → 怎么接进 YOLOv8 → 怎么训 → 坑在哪」的顺序拆一遍,适合做零售识别、毕业设计、货架检测的从业者直接照着复现。数据集本身是资源,不是教程,所以下面每一步都落到能跑的命令和能改的参数上。
2. 数据集结构与 YOLOv8 格式对齐:先看懂再动手
2.1 目录长什么样,类别怎么映射
YOLOv8 检测任务对数据集的硬性要求就两条:图片和同名 txt 标签放在对应目录,标签每行是class_id x_center y_center width height,坐标全部归一化到 0~1。这份资源给的是已标注好的成品,常见组织方式是images/train、images/val、labels/train、labels/val四件套,也可能全部图堆在一个目录里由你自己切分。拿到压缩包先别解压到中文路径,Ubuntu 下中文路径会让部分 OpenCV 读取直接返回 None,这是血泪经验。
先跑一段脚本把结构摸清楚,顺便统计每个类别的框数量,类别不均衡是罐装饮料数据集最常见的隐性问题——可乐雪碧可能几百个框,养乐多只有几十个。
import os from collections import Counter root = "dataset" # 解压后的根目录,按实际改 img_dir = os.path.join(root, "images") lbl_dir = os.path.join(root, "labels") cls_counter = Counter() img_files = [] for d, _, fs in os.walk(img_dir): for f in fs: if f.lower().endswith((".jpg", ".jpeg", ".png")): img_files.append(os.path.join(d, f)) for img in img_files: # 标签路径:把 images 替换成 labels,后缀换成 txt lbl = img.replace("images", "labels") lbl = os.path.splitext(lbl)[0] + ".txt" if not os.path.exists(lbl): print("缺标签:", img) continue with open(lbl) as fp: for line in fp: line = line.strip() if not line: continue cid = int(line.split()[0]) cls_counter[cid] += 1 print("图片总数:", len(img_files)) print("类别分布:", dict(sorted(cls_counter.items())))这段脚本做三件事:遍历所有图片、按路径规则找同名标签、统计每个 class_id 的框数。img.replace("images", "labels")依赖目录命名规范,如果你的结构不是这样,改成手动拼lbl_dir加文件名。跑完重点看两个数:图片总数是否和简介说的一千多张对得上,类别分布是否严重倾斜。如果某个类别框数为 0,说明标签里根本没出现这个类,训练时它永远学不到,得回头补标。
2.2 data.yaml 怎么写,路径和类别名别写错
YOLOv8 靠一个 yaml 文件告诉训练器去哪找数据、有几个类、类名是什么。这份数据集类别是中文商品名,建议 yaml 里用英文或拼音,避免后续推理时终端乱码。常见做法是建一个drinks.yaml:
# drinks.yaml path: /home/user/dataset # 数据集根目录,绝对路径最稳 train: images/train # 相对 path 的训练图目录 val: images/val # 相对 path 的验证图目录 names: 0: dongpeng 1: redbull 2: fanta 3: yakult 4: cola 5: sprite 6: wanglaoji 7: chipspath用绝对路径能避开「明明文件在却报 dataset not found」的玄学问题,YOLOv8 对相对路径的解析基准有时和你当前工作目录不一致。names的键必须从 0 连续编号,中间断号会导致类别数对不上。如果你不确定原始标签里 class_id 到底对应哪个商品,别猜,用 2.1 的统计脚本配合抽几张图可视化确认,标错类名训练出来的模型会把红牛认成东鹏。
2.3 划分训练验证集:别让同一瓶饮料同时出现在两边
如果资源已经切好 train/val,跳过这步;如果所有图在一个目录,必须自己切。切分有个容易翻车的点:同一瓶饮料连拍的多张图如果被分到训练和验证两边,验证指标会虚高,实际部署就露馅。按拍摄批次或时间切,而不是随机按文件切。
import os, random, shutil src_img = "dataset/images" src_lbl = "dataset/labels" random.seed(42) # 固定种子,保证可复现 files = [f for f in os.listdir(src_img) if f.lower().endswith((".jpg", ".png"))] random.shuffle(files) n_val = max(1, int(len(files) * 0.15)) # 15% 做验证 for split, subset in [("train", files[n_val:]), ("val", files[:n_val])]: os.makedirs(f"dataset/images/{split}", exist_ok=True) os.makedirs(f"dataset/labels/{split}", exist_ok=True) for f in subset: shutil.copy(os.path.join(src_img, f), f"dataset/images/{split}/{f}") lbl = os.path.splitext(f)[0] + ".txt" shutil.copy(os.path.join(src_lbl, lbl), f"dataset/labels/{split}/{lbl}")random.seed(42)是为了每次切分结果一致,方便复现实验。0.15是验证集比例,一千多张图留 150 张左右验证够用,太少指标抖动大,太多训练样本不够。切完记得把drinks.yaml里的train/val路径改成images/train、images/val。
3. 用 YOLOv8 训练罐装饮料检测:环境、命令与参数
3.1 环境搭建:CPU 版也能跑,但要有心理预期
热词里ubuntu20.04搭建yolov8环境cpu版本出现频率很高,说明不少人手头没有独显。CPU 版能训,但一千多张图、七八个类,一轮可能要十几分钟,100 轮就是一天。有gtx1660ti这类卡的话优先用 GPU,显存 6G 跑imgsz=640、batch=8基本稳。
# 建虚拟环境,别污染系统 Python conda create -n drinks python=3.10 -y conda activate drinks # 装 ultralytics,会自动带 torch pip install ultralytics # 验证安装,能打印版本就说明通了 yolo versionpython=3.10是当前 ultralytics 兼容性最好的版本,3.12 偶尔有依赖冲突。pip install ultralytics会拉 torch,CPU 机器上装的是 CPU 版 torch,不用额外指定。装完先yolo version确认命令可用,再往下走。
3.2 训练命令与关键参数含义
YOLOv8 训练就一条命令,但参数决定成败。下面这份是我在罐装饮料这类小数据集上常用的配置:
yolo detect train \ data=drinks.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=8 \ lr0=0.01 \ patience=20 \ project=runs/drinks \ name=exp1逐个说清楚:model=yolov8n.pt用 nano 版预训练权重,一千多张图从零训容易过拟合,用预训练权重微调收敛快得多,yolov8n也方便后续部署到边缘设备。epochs=100配合patience=20,意思是 20 轮验证指标不提升就早停,省得白跑。imgsz=640是输入分辨率,罐装饮料在货架上目标不算小,640 够用,想抓更小的价签再上 1280,但显存和速度代价明显。lr0=0.01是初始学习率,小数据集别开太大,否则 loss 震荡。batch=8是显存和稳定性的折中,显存够可以加到 16。
训练启动后重点盯runs/drinks/exp1/results.csv,看metrics/mAP50是否稳步上升、train/box_loss是否下降。如果 mAP 一直卡在很低的值,八成是标签或类别映射出了问题,回到第 2 章排查。
3.3 训练完怎么验证和推理
训完先别急着部署,用验证集跑一遍确认指标,再拿几张没见过的图做推理看实际效果。
# 验证集评估 yolo detect val model=runs/drinks/exp1/weights/best.pt data=drinks.yaml # 单图推理,保存结果图 yolo detect predict \ model=runs/drinks/exp1/weights/best.pt \ source=test.jpg \ conf=0.25 \ save=Trueconf=0.25是置信度阈值,低于它的框不显示。罐装饮料场景如果漏检多,把conf降到 0.15 试试;如果误检多,往上提到 0.4。best.pt是验证指标最好的权重,last.pt是最后一轮的,部署一般用best.pt。推理结果图默认存在runs/detect/predict下,打开看框的位置和类别对不对,这一步比看数字指标直观得多。
4. 避坑与排查:罐装饮料数据集最容易翻车的五件事
4.1 训练 loss 不降,mAP 一直是 0
现象:命令能跑,但几十轮下来 mAP50 接近 0,box_loss 几乎不动。原因通常是标签格式不对或类别数不匹配——比如标签是class x1 y1 x2 y2的绝对坐标格式,而 YOLOv8 要的是归一化中心点格式。解决:抽一个 txt 打开看,每行应该是 5 个数,后四个都在 0~1 之间;如果出现大于 1 的数,说明是绝对坐标,需要转换。同时确认drinks.yaml的names数量和标签里最大 class_id 对得上。
4.2 报 dataset not found 或找不到图片
现象:yolo detect train直接报找不到数据集。原因多半是path用了相对路径,而你的工作目录和数据集不在同一层。解决:把drinks.yaml里的path改成绝对路径,train/val保持相对path的子路径。另外确认images/train下确实有图,不是空目录。
4.3 验证指标虚高,实际部署一塌糊涂
现象:验证集 mAP 0.9,拿手机拍一张货架图却识别不出来。原因是训练验证集划分时同一瓶饮料的连拍图被分到了两边,模型「见过」验证集。解决:按拍摄批次切分,或者干脆留出一批完全没参与训练的实拍图做最终测试。这个坑在毕业设计里特别常见,答辩时被问一句「验证集怎么划的」就露馅。
4.4 中文类别名导致终端乱码或报错
现象:推理结果里类别名显示成方块,或者 yaml 解析报编码错误。原因是names里直接写了中文,而终端或文件编码不是 UTF-8。解决:names用英文或拼音,显示层再做中文映射。如果一定要中文,确保 yaml 文件保存为 UTF-8 无 BOM。
4.5 显存不足,训练中途 OOM
现象:跑着跑着报 CUDA out of memory。原因是batch或imgsz太大。解决:先把batch降到 4 甚至 2,再考虑降imgsz到 512。YOLOv8 支持batch=-1自动选,但自动值有时偏大,手动设更稳。CPU 训练不存在 OOM,但会慢到怀疑人生,做好时间预算。
5. 从能跑到好用:提升罐装饮料识别精度的一个具体技巧
数据集能跑通只是及格线,真正上线货架盘点,难点在于同类商品外观接近——可乐和雪碧的罐体轮廓几乎一样,芬达和东鹏的橙色也容易混。我一般会在训练前做一件事:把容易混的类别单独抽出来看标注框是否贴边。罐装饮料的标注框如果画得太松,把货架背景也框进去,模型会学到背景特征而不是罐体本身,换一个货架就失效。
具体做法是写个小脚本把每个类别的框可视化出来,重点看框是不是紧贴罐体边缘:
import cv2, os img_dir, lbl_dir, out_dir = "dataset/images/train", "dataset/labels/train", "vis" os.makedirs(out_dir, exist_ok=True) for f in os.listdir(img_dir)[:50]: # 先看 50 张 img = cv2.imread(os.path.join(img_dir, f)) h, w = img.shape[:2] lbl = os.path.splitext(f)[0] + ".txt" p = os.path.join(lbl_dir, lbl) if not os.path.exists(p): continue with open(p) as fp: for line in fp: cid, x, y, bw, bh = line.split() x, y, bw, bh = map(float, (x, y, bw, bh)) # 归一化中心点转像素左上右下 x1, y1 = int((x - bw / 2) * w), int((y - bh / 2) * h) x2, y2 = int((x + bw / 2) * w), int((y + bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imwrite(os.path.join(out_dir, f), img)这段脚本把归一化坐标还原成像素坐标画框,x - bw/2是左上角 x,x + bw/2是右下角 x,y 同理。跑完打开vis目录逐张看,如果发现框明显比罐体大一圈,说明标注偏松,这种样本要么重标要么在训练时靠数据增强部分缓解。另一个技巧是开 YOLOv8 自带的mosaic增强(默认开启),它把四张图拼一起,能逼模型关注局部罐体而不是整张图的构图,对小数据集提升明显。如果发现某两类总是互相误检,可以在drinks.yaml里临时把它们合并成一个大类先训一版,确认是标注问题还是模型容量问题,再决定要不要拆开。
从那以后我每次拿到新数据集,都强制先跑一遍可视化脚本,确认框贴边、类别对、没有漏标,再动训练命令。这一步花十分钟,能省掉后面几小时的无效训练。希望这份拆解帮到你,数据集拿到手先摸结构再开训,别让格式问题背了精度的锅。
本文还有配套的精品资源,点击获取