简介:本资源为面向YOLO系列算法目标检测的罐头与瓶子数据集,包含鲜奶、瓶子等类别,适合从事目标检测模型训练与验证的开发者、学生及研究人员使用。数据集已划分好训练与测试集,并附带data.yaml配置文件,可直接适配yolov5、yolov8、yolov9、yolov7、yolov10及yolo11等主流算法。压缩包共2000个文件,其中1073个xml文件与927个txt文件,分别对应VOC格式与YOLO格式标签,YOLO格式采用归一化中心点与宽高坐标,便于直接读取训练;包体大小约68.59MB,结构清晰。目前已有54人学习下载,可作为目标检测入门与实战的参考数据。读者可快速获得完整标注数据、双格式标签及配置文件,省去自行标注与划分的繁琐流程,直接投入模型训练与验证,提升实验效率。
1. 罐头与鲜奶瓶检测:1531 张带标签图像能跑出什么结果
手上拿到一个压缩包,名字叫「YOLO算法-罐头和瓶子数据集-1531张图像带标签-鲜奶-瓶子.zip」,第一反应不该是解压看图片,而是先判断它能不能撑起一个可用的检测模型。1531 张图像在 YOLO 训练里属于小数据集,但小不等于不能用,关键看类别是否聚焦、标注是否干净、场景是否单一。这个数据集瞄准的是罐头和鲜奶瓶两类目标,属于典型的工业包装检测场景,产线质检、货架盘点、仓储出入库都可能用得上。适合谁?适合想跑通 YOLO 训练全流程但不想花几天清洗数据的工程师,也适合需要快速验证包装检测可行性的团队。但别指望 1531 张就能直接上产线,它更像一个起点,让你先把训练管线跑通,再决定要不要扩数据。下面从数据检查、格式转换、训练配置到踩坑排查,一步步拆开讲。
2. 先验数据:1531 张罐头瓶子和鲜奶瓶图像到底该怎么查
拿到数据集先别急着写训练脚本,花二十分钟做数据体检,能省后面几小时的调参玄学。这个数据集的核心价值在于「带标签」,但标签质量参差不齐是常态,尤其是罐头和瓶子这类反光物体,标注框容易偏大或偏小。
2.1 解压后先看目录结构和标签格式
常见做法是解压后先列目录树,确认图像和标签是否一一对应。YOLO 格式的标签是每张图对应一个同名 .txt 文件,每行五个值:类别索引、归一化中心 x、归一化中心 y、归一化宽、归一化高。如果标签是 VOC 的 XML 或 COCO 的 JSON,就得先转换。
# 查看解压后的目录结构,确认图像和标签是否分离 find ./dataset -maxdepth 2 -type d | head -20 # 统计图像数量,验证是否与标题的 1531 张一致 find ./dataset -name "*.jpg" -o -name "*.png" | wc -l # 统计标签文件数量,图像和标签数量必须相等 find ./dataset -name "*.txt" | wc -l # 随机抽一个标签文件看格式 head -5 ./dataset/labels/000001.txt逻辑说明:第一步确认目录层级,YOLO 训练通常要求 images 和 labels 两个平行目录。第二步和第三步做数量对齐,如果图像 1531 张而标签只有 1500 个,说明有 31 张图没标,训练时要么剔除要么补标。第四步看标签内容,正常一行五个数,如果出现六个或七个值,可能是分割格式或带置信度,需要单独处理。
参数说明:-maxdepth 2限制目录深度避免输出爆炸;head -5只看前五行,快速判断格式。如果标签文件里出现负数或大于 1 的值,说明归一化没做对,得重新算。
2.2 用脚本统计类别分布和标注框尺寸
1531 张图里罐头和瓶子各占多少,直接决定训练时要不要设类别权重。如果罐头 1400 个框、瓶子只有 200 个框,模型会严重偏向罐头。另外标注框的宽高分布能告诉你 anchor 该怎么设。
import os import glob from collections import Counter label_dir = "./dataset/labels" class_counter = Counter() width_list, height_list = [], [] for txt_path in glob.glob(os.path.join(label_dir, "*.txt")): with open(txt_path, "r") as f: for line in f.readlines(): parts = line.strip().split() if len(parts) != 5: continue cls_id = int(parts[0]) w, h = float(parts[3]), float(parts[4]) class_counter[cls_id] += 1 width_list.append(w) height_list.append(h) print("类别分布:", dict(class_counter)) print("宽均值:", sum(width_list)/len(width_list)) print("高均值:", sum(height_list)/len(height_list)) print("宽最大:", max(width_list), "高最大:", max(height_list))逻辑说明:遍历所有标签文件,统计每个类别的框数量,同时收集归一化宽高。类别分布告诉你是否类别不平衡,宽高均值用来判断目标尺度。如果宽均值 0.05、高均值 0.08,说明目标偏小,训练时输入尺寸不能低于 640,否则小目标特征会丢。
参数说明:cls_id是类别索引,通常 0 代表罐头、1 代表瓶子,具体看 data.yaml。w和h是归一化值,乘以图像宽高才是像素尺寸。如果发现某个类别框数为 0,说明标签里根本没这个类,得检查标注是否漏了。
2.3 可视化抽查:反光罐头和透明瓶子的标注框是否贴合
罐头和鲜奶瓶都有反光或半透明问题,标注时容易把高光边缘也算进去,导致框偏大。抽 20 张图叠加标注框看一眼,比看统计数字更直接。
import cv2 import os import random img_dir = "./dataset/images" label_dir = "./dataset/labels" img_list = random.sample(os.listdir(img_dir), 20) for img_name in img_list: img = cv2.imread(os.path.join(img_dir, img_name)) h, w = img.shape[:2] txt_path = os.path.join(label_dir, img_name.replace(".jpg", ".txt")) if not os.path.exists(txt_path): continue with open(txt_path) as f: for line in f.readlines(): cls_id, cx, cy, bw, bh = map(float, line.strip().split()) x1 = int((cx - bw/2) * w) y1 = int((cy - bh/2) * h) x2 = int((cx + bw/2) * w) y2 = int((cy + bh/2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imwrite(f"./vis_{img_name}", img)逻辑说明:随机抽 20 张,把归一化坐标还原成像素坐标画框。重点看框是否把整个罐头或瓶子包住,有没有把旁边无关物体框进去。如果发现框明显偏大,训练时模型会学到背景噪声,mAP 上不去。
参数说明:cx, cy是中心点归一化坐标,bw, bh是归一化宽高。还原公式是(cx - bw/2) * w得到左上角 x。random.sample保证每次抽的图不同,多跑几次能覆盖更多场景。
提示:如果发现大量标签框偏移,别硬训,先花时间修标注。1531 张里修 100 张坏标签,比训完再调参划算得多。
3. 从原始压缩包到 YOLO 可训练格式:转换脚本与目录规范
数据体检过关后,下一步是把目录整理成 YOLO 训练框架能直接吃的结构。不管后面用 YOLOv5、YOLOv8 还是 YOLO11,目录规范基本一致:images 和 labels 平行,各自分 train、val、test。
3.1 划分训练集验证集测试集:7:2:1 还是 8:1:1
1531 张图不算多,验证集太小会导致评估波动大。常见做法是 8:1:1,即训练 1224 张、验证 153 张、测试 154 张。如果类别极不平衡,还要做分层抽样,保证每个子集里罐头和瓶子比例接近。
import os import shutil import random random.seed(42) img_dir = "./dataset/images" label_dir = "./dataset/labels" out_dir = "./yolo_dataset" for split in ["train", "val", "test"]: os.makedirs(os.path.join(out_dir, "images", split), exist_ok=True) os.makedirs(os.path.join(out_dir, "labels", split), exist_ok=True) img_list = [f for f in os.listdir(img_dir) if f.endswith((".jpg", ".png"))] random.shuffle(img_list) n = len(img_list) train_end = int(n * 0.8) val_end = int(n * 0.9) split_map = { "train": img_list[:train_end], "val": img_list[train_end:val_end], "test": img_list[val_end:] } for split, files in split_map.items(): for img_name in files: shutil.copy(os.path.join(img_dir, img_name), os.path.join(out_dir, "images", split, img_name)) txt_name = os.path.splitext(img_name)[0] + ".txt" src_txt = os.path.join(label_dir, txt_name) if os.path.exists(src_txt): shutil.copy(src_txt, os.path.join(out_dir, "labels", split, txt_name))逻辑说明:先建好六个目录,然后打乱图像列表按比例切分。random.seed(42)保证每次划分结果一致,方便复现。复制标签时先判断存在性,避免因缺标签报错。
参数说明:0.8和0.9是切分点,训练占 80%,验证占 10%,测试占 10%。如果数据量更小,可以改成 7:2:1。shutil.copy是复制不是移动,保留原始数据做后悔药用。
3.2 写 data.yaml:类别名、路径和 nc 参数怎么填
YOLO 训练靠 data.yaml 找数据,路径写错是最常见的翻车点。相对路径和绝对路径都行,但相对路径是相对于训练脚本的运行目录,容易搞混,我一般写绝对路径。
path: /home/user/yolo_dataset train: images/train val: images/val test: images/test nc: 2 names: 0: can 1: bottle逻辑说明:path是数据集根目录,train、val、test是相对 path 的子路径。nc是类别数,这里罐头和瓶子共 2 类。names是类别索引到名称的映射,顺序必须和标签里的 cls_id 一致,否则模型会把罐头叫成瓶子。
参数说明:如果标签里罐头是 0、瓶子是 1,names 就必须 0 对应 can、1 对应 bottle。写反了训练不报错,但推理结果全错。nc必须等于 names 的条目数,多一个少一个都会在训练启动时报错。
3.3 用 YOLO 官方校验命令检查数据集完整性
目录整理完别直接开训,先用框架自带的校验功能扫一遍。YOLOv8 和 YOLO11 都有yolo checks或训练启动时的自动扫描,能提前发现标签越界、图像损坏、类别不匹配。
# 以 YOLOv8 为例,启动训练前会自动校验,也可以单独跑 yolo detect train data=./data.yaml model=yolov8n.pt epochs=1 imgsz=640 batch=8 # 如果只想校验不训练,看输出里的 warning 和 error逻辑说明:跑一个 epoch 的最小训练,重点不是看精度,而是看数据加载阶段有没有报错。如果出现Label class x exceeds nc,说明标签里的类别索引大于 nc-1。如果出现corrupt image,说明有图像文件损坏。
参数说明:imgsz=640是输入尺寸,batch=8是小批量快速验证。epochs=1只为触发数据扫描。校验通过后再把 epochs 调到 100 以上正式训练。
注意:如果校验时报
No labels found,先检查 labels 目录路径是否写对,再检查标签文件扩展名是不是 .txt。YOLO 不认 .TXT 大写扩展名。
4. 训练参数怎么设:小数据集上 YOLO 的 batch、lr 和增强策略
1531 张图属于小数据集,训练参数和大数据集不一样。batch 太大梯度更新少,学习率太高容易震荡,数据增强开太猛会把小目标增强没了。这一章把关键参数拆开讲。
4.1 batch size 和输入尺寸的搭配:8GB 显存怎么选
显存是硬约束。1531 张图、两类目标,输入 640 时 YOLOv8n 的 batch 8 大约占 4GB 显存,YOLOv8m 的 batch 8 可能到 7GB。如果显存只有 8GB,建议用 n 或 s 模型,batch 设 8 到 16。
# 8GB 显存推荐配置:YOLOv8n + imgsz 640 + batch 16 yolo detect train data=./data.yaml model=yolov8n.pt epochs=150 imgsz=640 batch=16 workers=4逻辑说明:model=yolov8n.pt是 nano 模型,参数量小、训练快,适合先跑通。epochs=150对小数据集够用,太多会过拟合。workers=4是数据加载线程数,设太大反而拖慢。
参数说明:imgsz=640是输入分辨率,如果目标在图中占比很小,可以提到 1280,但显存翻倍。batch=16在 8GB 显存上比较稳,如果报 OOM 就降到 8。workers一般设 CPU 核数的一半。
4.2 学习率和优化器:SGD 还是 AdamW
YOLO 默认用 SGD,学习率 0.01,动量 0.937。小数据集上 SGD 收敛稳定但慢,AdamW 收敛快但容易过拟合。我一般先用默认 SGD 跑 50 epoch 看曲线,如果 loss 下降太慢再换 AdamW。
# 换 AdamW 优化器,学习率降到 0.001 yolo detect train data=./data.yaml model=yolov8n.pt epochs=150 imgsz=640 batch=16 optimizer=AdamW lr0=0.001逻辑说明:optimizer=AdamW切换优化器,lr0=0.001是初始学习率。AdamW 对学习率更敏感,0.01 会直接发散,所以必须降到 0.001 量级。
参数说明:lr0是初始学习率,SGD 常用 0.01,AdamW 常用 0.001。如果训练前期 loss 剧烈震荡,先把 lr0 减半。lrf是最终学习率因子,默认 0.01,控制余弦退火终点。
4.3 数据增强:小数据集该开哪些、该关哪些
YOLO 默认开 mosaic、mixup、hsv 增强。mosaic 把四张图拼成一张,对小数据集能增加样本多样性,但罐头和瓶子如果本身场景单一,mosaic 可能引入不相关背景。mixup 在小数据集上容易让目标重叠,建议关掉。
# 关闭 mixup,保留 mosaic 和 HSV,适合罐头瓶子检测 yolo detect train data=./data.yaml model=yolov8n.pt epochs=150 imgsz=640 batch=16 mixup=0.0 mosaic=1.0 hsv_h=0.015 hsv_s=0.7 hsv_v=0.4逻辑说明:mixup=0.0关闭 mixup,避免目标重叠。mosaic=1.0保持 mosaic 开启,增加背景多样性。hsv_h、hsv_s、hsv_v控制色调、饱和度、亮度扰动,罐头和瓶子颜色固定,扰动别太大。
参数说明:hsv_h=0.015是色调扰动幅度,0.015 约等于 ±1.5% 色相偏移。hsv_s=0.7是饱和度扰动,hsv_v=0.4是亮度扰动。如果图像本身光照变化大,可以适当提高 hsv_v。
提示:如果训练 50 epoch 后验证集 mAP 不升反降,先关 mosaic 试一轮。mosaic 对小目标有时是负优化。
5. 训练过程排查:loss 不降、mAP 震荡和 BN 崩溃怎么处理
训练跑起来不代表能跑好。小数据集上最常见的问题是 loss 不降、mAP 来回震荡、BN 层崩溃。这一章按现象、原因、解决三步走,把踩过的坑列清楚。
5.1 现象:loss 从第一轮就不降,一直卡在 0.8 左右
原因:标签类别索引和 data.yaml 的 names 对不上,或者标签坐标没归一化。模型学的是错误映射,loss 自然下不去。
解决:先跑校验命令看有没有Label class exceeds nc警告。如果没有,抽一个标签文件手动算一遍归一化坐标,确认 x、y、w、h 都在 0 到 1 之间。如果出现大于 1 的值,说明标签是像素坐标没归一化,得重新转换。
5.2 现象:mAP 在 0.5 到 0.7 之间来回跳,没有稳定上升趋势
原因:验证集太小或分布和训练集差异大。153 张验证图如果恰好抽到很多反光严重的罐头,mAP 就会偏低。另外学习率太高也会导致震荡。
解决:把验证集比例从 10% 提到 20%,或者做交叉验证。学习率先减半,lr0=0.005跑一轮看曲线。如果还是震荡,检查数据增强里的 mosaic 是否把目标拼到了图像边缘导致截断。
5.3 现象:训练到一半报 BN 层错误,提示 batch 内样本数不足
原因:batch size 太小,或者最后一批数据不足 batch size 时 BN 计算方差为 NaN。YOLO 训练时如果batch=8但某批只剩 1 张图,BN 就会崩。
解决:把batch设成能整除数据集大小的值,或者开启drop_last。YOLO 默认会处理最后一批,但如果自定义数据加载器,要手动加drop_last=True。另外把batch提到 16 能缓解。
5.4 现象:推理时罐头和瓶子框重叠严重,NMS 后只剩一个框
原因:NMS 的 IoU 阈值设太高,或者模型对两类目标的区分度不够。罐头和瓶子如果外形相似,模型可能给同一个目标同时预测两个类。
解决:降低 NMS 的 IoU 阈值,从默认 0.7 降到 0.5。如果还是重叠,检查标签里有没有把罐头标成瓶子。另外可以在推理时加agnostic_nms=True,让 NMS 跨类别抑制。
5.5 现象:训练完模型在测试集上 mAP 只有 0.3,但训练集 mAP 0.95
原因:严重过拟合。1531 张图对 YOLO 来说太少,模型把训练集背下来了。验证集和测试集如果和训练集同分布,mAP 不会差这么多,差这么多说明测试集场景差异大。
解决:加数据增强,开 mosaic 和随机缩放。加 weight decay,从默认 0.0005 提到 0.001。减少模型参数量,从 YOLOv8m 换回 YOLOv8n。如果还不行,只能扩数据。
注意:BN 崩溃有时不报错,而是 loss 突然变成 NaN。训练时盯着 loss 曲线,一旦出现 NaN 立即停,检查学习率和 batch。
6. 小数据集提点技巧:从 1531 张里榨出更高 mAP 的四个习惯
1531 张图想跑到 0.85 以上 mAP,靠默认参数不够,得在细节上抠。下面四个习惯是我在多个小数据集项目里反复验证过的,不保证每个都涨点,但至少不会掉。
6.1 用预训练权重做热启动,别从零训
YOLO 官方提供的 COCO 预训练权重已经学过通用特征,罐头和瓶子的边缘、纹理和 COCO 里的瓶子、杯子有重叠。从预训练权重开始,比随机初始化收敛快一倍,mAP 通常高 5 到 10 个点。
# 从 COCO 预训练权重开始,而不是从 yaml 随机初始化 yolo detect train data=./data.yaml model=yolov8n.pt pretrained=True epochs=150 imgsz=640 batch=16逻辑说明:model=yolov8n.pt本身就带预训练权重,pretrained=True确保加载。如果写model=yolov8n.yaml就是从零开始,小数据集上不推荐。
参数说明:pretrained默认就是 True,但显式写出来避免歧义。如果换自定义 backbone,要确认权重能对上。
6.2 冻结 backbone 先训 head,再解冻全量微调
小数据集上直接全量微调容易把预训练学到的通用特征破坏掉。先冻结 backbone 训 20 epoch,让 head 适应新类别,再解冻全量训 100 epoch,效果更稳。
# 第一阶段:冻结 backbone,只训 head yolo detect train data=./data.yaml model=yolov8n.pt epochs=20 freeze=10 imgsz=640 batch=16 # 第二阶段:解冻全量微调 yolo detect train data=./data.yaml model=runs/detect/train/weights/last.pt epochs=130 imgsz=640 batch=16逻辑说明:freeze=10冻结前 10 层,YOLOv8n 的 backbone 大约 10 层。第一阶段结束后用last.pt做第二阶段起点,学习率可以调低到 0.001。
参数说明:freeze的值根据模型结构定,YOLOv8n 设 10,YOLOv8m 设 15。第二阶段lr0建议设 0.001,避免破坏已学特征。
6.3 用 TTA 和更高输入尺寸做推理,不重训也能涨点
训练完模型后,推理时开 TTA(测试时增强)和多尺度,能涨 1 到 3 个点 mAP,代价是推理变慢。如果产线对速度不敏感,值得开。
# 推理时开 TTA,输入尺寸提到 1280 yolo detect predict model=runs/detect/train/weights/best.pt source=./test_images imgsz=1280 augment=True逻辑说明:augment=True开启 TTA,对每张图做翻转、缩放后分别推理再融合。imgsz=1280提高分辨率,小目标更容易检出。
参数说明:TTA 会让推理时间增加 3 到 5 倍,产线节拍紧就别开。imgsz提高后要确认显存够,1280 比 640 显存翻倍。
6.4 把验证集当调参集用,但别反复调同一个指标
验证集用来选模型和调超参,但反复在同一个验证集上调,会过拟合验证集。我一般把验证集再切一半做调参,另一半只在最后评估用。1531 张图切完每份都不大,但比没有强。
# 从 val 里再切一半做 tune,另一半做 final_eval import os, shutil, random random.seed(0) val_dir = "./yolo_dataset/images/val" tune_dir = "./yolo_dataset/images/tune" os.makedirs(tune_dir, exist_ok=True) val_list = os.listdir(val_dir) random.shuffle(val_list) for f in val_list[:len(val_list)//2]: shutil.move(os.path.join(val_dir, f), os.path.join(tune_dir, f))逻辑说明:把验证集对半切,一半用于训练中调参,一半留到最后评估。这样最终评估的 mAP 更接近真实泛化能力。
参数说明:random.seed(0)保证切分可复现。shutil.move是移动,切完记得同步移动对应的标签文件。
提示:小数据集上别追求 0.95 mAP,0.85 以上就够用。产线检测更看重漏检率和误检率,mAP 只是参考。
我自己的习惯是,拿到任何小数据集先跑一遍最小训练,看 loss 和 mAP 曲线,再决定要不要花时间调参。1531 张罐头瓶子图不算多,但足够跑通 YOLO 全流程,也能暴露标注和参数上的问题。希望帮到你。
本文还有配套的精品资源,点击获取