news 2026/9/28 14:53:50

YOLO小数据集实战:1531张罐头与鲜奶瓶检测全流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
YOLO小数据集实战:1531张罐头与鲜奶瓶检测全流程

简介:本资源为面向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 全流程,也能暴露标注和参数上的问题。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 14:53:06

AI工程从零实践:手写数据管道、推理服务与监控评估全记录

说实话,市面上教AI工程的文章、课程已经多到看不完了,但大部分是教你"怎么调用一个现成的服务",或者"五分钟用框架搭好一个Demo"。等你真上了生产环境,模型一挂、内存一涨、请求一慢,你会发现自己…

作者头像 李华
网站建设 2026/9/28 14:51:35

电热综合能源系统日前经济调度模型:Matlab+MILP实现

1. 为什么做电热综合能源调度:从供热季的“东风”困局说起这几年做综合能源系统优化的同行应该都深有体会——真正的痛点不在夏季,而在北方供热季。风电在冬季夜间往往大发,尤其“三北”地区,风资源最好的时段恰好是热负荷需求最大…

作者头像 李华
网站建设 2026/9/28 14:50:51

Deepseek dsh红队模式实战:安装、插件加载与工具调用链安全验证

1. 从零理解 dsh 红队模式:它到底解决什么问题第一次看到“Deepseek dsh 红队模式”这个组合词,很多人会懵——Deepseek 我熟,红队模式我也大概知道是安全测试用的,但中间这个 dsh 是什么?其实 dsh 是 deepseek harnes…

作者头像 李华
网站建设 2026/9/28 14:48:17

Java版俄罗斯方块源码:从课程设计到面试项目的完整实现指南

简介:这是一份用Java编写的俄罗斯方块小游戏完整源码,面向具备一定Java基础、希望研究桌面小游戏实现或做课程设计的学习者。程序需JRE环境,通过java -jar方式运行,并支持将声音、显示、关卡等配置以cfg文件形式保存在jar同级目录…

作者头像 李华
网站建设 2026/9/28 14:48:16

IAR工程文件详解:eww/ewp/ewd结构与移植避坑指南

干了这么多年嵌入式,几乎天天跟IAR打交道,说说我自己的体会:多数人把IAR当成一个“能编译下载的软件”在用,但工程文件到底是怎么组织的,却很少有人真去拆开看。直到某天从同事那里拷来一个工程,双击eww提示…

作者头像 李华
网站建设 2026/9/28 14:48:12

MATLAB实现QPSK过AWGN信道:误码率仿真与理论曲线对比

我们直接把话说在前头:这期内容讲的是用MATLAB写一个QPSK调制信号过AWGN信道的完整仿真程序,重点落在误符号率(SER)和误比特率(BER)怎么算、怎么画曲线、怎么跟理论值对上。不是只丢一句“理论SER是2Q(sqrt…

作者头像 李华