ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

基于1934张烟盒数据集的YOLOv8训练与部署实战

基于1934张烟盒数据集的YOLOv8训练与部署实战 简介本资源为面向YOLO系列目标检测算法的烟盒识别数据集适合从事目标检测学习、模型训练与验证的开发者及研究人员使用可解决烟盒目标识别任务中数据准备繁琐、标注格式不统一的问题。压缩包共2000个文件约192.79MB包含1545个xml标注文件与455个txt标注文件分别对应VOC格式与YOLO格式方便不同训练流程直接调用。数据集已按训练与验证需求划分完毕并附带data.yaml配置文件可无缝适配yolov5、yolov7、yolov8、yolov9、yolov10及yolo11等主流算法。YOLO格式标注采用类别索引与归一化中心点、宽高比例便于直接读取训练。目前已有176人学习下载读者可快速获得一套开箱即用的烟盒检测数据省去采集与标注成本将精力集中于模型结构调优与识别效果验证。1. 烟盒数据集与 YOLO 训练1934 张图像带标签到底能跑出什么手上拿到一个标注好的烟盒数据集1934 张图像、带标签第一反应通常不是兴奋而是先算一笔账这个量级够不够 YOLO 收敛标签格式是 VOC 还是 YOLO txt类别是只框烟盒还是连品牌一起分。烟盒检测在零售合规、自动盘点、流水线剔除这些场景里都有真实需求但 1934 张属于典型的小数据集直接套默认配置大概率翻车。这篇笔记就围绕这个数据集把从标签检查、格式转换、YOLOv8 训练到推理部署的完整链路讲清楚同时把 YOLO 损失函数、预训练权重选择、混淆矩阵异常这些容易踩的点一并拆开。适合已经跑过 demo、但第一次拿真实小数据集落地的人也适合想搞清楚小数据集怎么调参的熟手。2. 先搞清楚 1934 张烟盒图像的数据底子2.1 标签格式判定VOC XML 还是 YOLO txt拿到压缩包解压后第一件事不是急着写训练脚本而是看标签长什么样。烟盒数据集常见的两种格式一种是 PASCAL VOC 的 XML每个图对应一个 xml里面是bndbox的 xmin/ymin/xmax/ymax另一种是 YOLO 的 txt每行class x_center y_center width height全部归一化到 0~1。这两种格式决定了你后面要不要转换。先跑一段脚本统计别靠肉眼翻import os, glob from collections import Counter img_dir images label_dir labels imgs glob.glob(os.path.join(img_dir, *)) labels glob.glob(os.path.join(label_dir, *)) print(图像数:, len(imgs)) print(标签数:, len(labels)) # 看标签后缀分布 suffix Counter([os.path.splitext(f)[1] for f in labels]) print(标签后缀:, suffix) # 如果是 txt统计每行字段数和类别分布 cls_counter Counter() bad_lines 0 for f in labels: if not f.endswith(.txt): continue with open(f) as fp: for line in fp: parts line.strip().split() if len(parts) ! 5: bad_lines 1 continue cls_counter[parts[0]] 1 print(类别分布:, cls_counter) print(异常行数:, bad_lines)这段脚本做三件事确认图像和标签数量是否一一对应、判断标签后缀、统计类别分布和异常行。参数上img_dir和label_dir按你实际解压路径改。重点看两个信号图像数和标签数差太多说明有漏标或多余文件bad_lines不为 0说明有行字段数不对训练时会被跳过甚至报错。如果后缀是.xml那就需要转成 YOLO txt。转换逻辑是读 XML 的宽高和 bbox做归一化import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_path, out_path, classes): tree ET.parse(xml_path) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) lines [] for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in classes: continue cls_id classes.index(cls_name) bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 归一化并转中心点格式 x_c (xmin xmax) / 2.0 / w y_c (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{cls_id} {x_c:.6f} {y_c:.6f} {bw:.6f} {bh:.6f}) with open(out_path, w) as f: f.write(\n.join(lines))classes是你自己定义的类别顺序列表必须和后面 data.yaml 里的 names 完全一致否则类别会错位。归一化用 6 位小数足够YOLO 读取时不会因为精度丢框。转换完一定要抽查几张用画框脚本可视化别信脚本不报错就等于对。2.2 1934 张的划分策略与类别不平衡处理1934 张不算多划分比例不能照搬大数据的 8:1:1。小数据集我一般用 7:2:1 或者 8:1:1但验证集至少留 150 张以上否则 mAP 波动大到没法判断模型好坏。如果类别里有稀有类比如某个品牌烟盒只有几十个框划分时要做分层抽样保证训练集和验证集里稀有类都出现。import random from collections import defaultdict # 按主类别分层 file_cls {} for f in labels: with open(f) as fp: first fp.readline().strip().split() if first: file_cls[f] first[0] groups defaultdict(list) for f, c in file_cls.items(): groups[c].append(f) train, val, test [], [], [] for c, files in groups.items(): random.shuffle(files) n len(files) n_train int(n * 0.8) n_val int(n * 0.1) train files[:n_train] val files[n_train:n_train n_val] test files[n_train n_val:] print(len(train), len(val), len(test))分层抽样的意义在于稀有类不会因为随机划分全跑到训练集或全跑到验证集。参数上 0.8/0.1/0.1 可以按你的类别数调类别越不平衡验证集比例越要往上提。划分完把文件实际复制到images/train、labels/train这种目录结构YOLO 默认按目录找标签。注意划分前先固定随机种子否则每次跑结果不一样排查问题时没法复现。3. YOLOv8 训练烟盒检测模型的完整命令与参数3.1 环境搭建与预训练权重选择YOLOv8 用 ultralytics 包最省事环境干净的话一条命令pip install ultralytics装完yolo checks看一下环境和 GPU 是否识别。烟盒检测属于单类或少数类目标检测模型规模不用一上来就上 x。我的经验是1934 张这个量级YOLOv8n 或 YOLOv8s 足够n 收敛快、显存占用低s 精度略高但训练时间翻倍。如果你有 V100 或者更好的卡可以试 m但小数据集上 m 容易过拟合收益不明显。预训练权重直接用官方 coco 权重yolov8n.pt会自动下载。别用随机初始化小数据集从零训基本没戏。这里有个常见误区有人觉得烟盒和 coco 类别不重叠预训练没用。实际上预训练学的是边缘、纹理、形状这些底层特征对烟盒一样有效微调比从零快得多也稳得多。3.2 data.yaml 配置与训练命令逐参数说明先写 data.yamlpath: /data/cigarette train: images/train val: images/val test: images/test names: 0: cigarette_box如果烟盒要分品牌names 就按你的类别顺序往下写。path是数据集根目录train/val 是相对路径。写完用yolo train跑yolo detect train \ datadata.yaml \ modelyolov8n.pt \ epochs150 \ imgsz640 \ batch16 \ lr00.01 \ lrf0.01 \ patience30 \ workers8 \ projectruns/cigarette \ namev8n_640逐个说关键参数。epochs150对小数据集够用配合patience30早停验证集 30 轮不涨就停省时间也防过拟合。imgsz640是默认值烟盒在图像里如果占比很小可以提到 960 或 1280但显存和速度要权衡。batch16按显存调V100 上可以到 32 甚至 64。lr00.01是初始学习率小数据集可以降到 0.005 更稳。lrf0.01是最终学习率系数余弦退火到 lr0*lrf。训练过程中重点看三个输出box_loss、cls_loss、dfl_loss。YOLOv8 的损失函数是这三部分加权box 管定位cls 管分类dfl 管边界框分布。如果 box_loss 一直不降多半是标签有问题cls_loss 震荡大可能是类别不平衡或者学习率太高。3.3 训练日志里必须盯住的四个指标训练跑起来不是等着就行日志里四个指标要会读。第一metrics/mAP50烟盒这种形状规整的目标正常收敛后 mAP50 应该到 0.9 以上低于 0.8 说明数据或配置有问题。第二metrics/mAP50-95这个更严格小数据集上通常比 mAP50 低 0.1~0.2。第三train/box_loss和val/box_loss的差距验证损失明显高于训练损失且持续扩大就是过拟合信号。第四混淆矩阵后面单独讲。如果 mAP 卡在某个值不动先别急着调模型回头查标签。烟盒数据集最常见的标签问题是框不贴边、漏标小目标、类别写错。用yolo predict跑几张训练集图片看模型学到的框和标注框差多少比看 loss 曲线直观。4. 烟盒检测训练避坑五条血泪经验4.1 现象mAP 一直上不去loss 正常下降原因标签归一化坐标越界或者宽高为负。VOC 转 YOLO 时如果 xmax 小于 xmin宽高算出来是负数YOLO 读取时不会报错但会当成无效框。解决转换后加一步校验过滤掉 x_c、y_c、w、h 不在 0~1 范围的行并打印出来人工确认。4.2 现象训练到一半显存爆了原因imgsz调大后 batch 没同步降或者 workers 太多导致内存泄漏。解决显存不够时优先降 batch再降 imgsz。V100 16G 上 640 分辨率 batch 32 基本是上限960 分辨率 batch 要降到 8~12。workers 设成 CPU 核数的 0.7 倍左右别拉满。4.3 现象混淆矩阵总合不唯一数字对不上原因YOLO 的混淆矩阵在验证时对每个预测框按置信度阈值筛选同一张图可能有多个框匹配到同一个 GT或者一个框匹配多个类。加上背景类后总数和验证集 GT 数不一致是正常的。解决看混淆矩阵只看对角线占比和误分类方向别纠结总数。如果某个类大量被分到背景说明该类样本太少或标注质量差。4.4 现象推理时框重叠严重同一个烟盒出好几个框原因NMS 的 IoU 阈值默认 0.7对密集排列的烟盒偏松。解决推理时把iou降到 0.5 左右或者用agnostic_nms合并跨类框。如果烟盒是并排摆放还要考虑把max_det调大默认 300 一般够但密集场景要确认没被截断。4.5 现象换一台机器推理结果不一样原因预处理没对齐。训练时用了默认的 letterbox 填充推理时如果自己写预处理没做同样的填充和归一化结果会偏。解决推理统一走 ultralytics 的model.predict别自己手写 cv2 resize。如果必须自己写严格复现 letterbox 的缩放比例和 padding 值 114。5. 从训练到部署烟盒检测的推理与验证技巧训练完拿到best.pt先别急着上生产做两件事验证集全量推理看指标和实际场景抽样看效果。验证集推理yolo detect val \ modelruns/cigarette/v8n_640/weights/best.pt \ datadata.yaml \ imgsz640 \ batch16输出里重点看每类的 P、R、mAP50。烟盒单类的话P 和 R 都在 0.9 以上才算能用。如果 R 低说明漏检多查是不是小目标没学好P 低说明误检多查背景类样本够不够。实际场景抽样用 predictyolo detect predict \ modelruns/cigarette/v8n_640/weights/best.pt \ sourcesamples/ \ conf0.25 \ iou0.5 \ saveTrueconf0.25是置信度阈值烟盒检测可以适当调高到 0.4 减少误检但会牺牲召回。iou0.5控制 NMS 合并程度。这两个参数没有绝对最优按你的业务容忍度调宁可漏检不可误检就提 conf宁可误检不可漏检就降 conf。部署到边缘设备时如果用的是 TensorRT 或 ONNX注意导出时的动态轴和 batch 设置yolo export modelbest.pt formatonnx dynamicTrue simplifyTruedynamicTrue支持变长输入simplifyTrue会做图优化。导出后一定要用同一张图对比 ONNX 和 pt 的输出差异大说明导出有问题。我一般会固定一个随机种子跑 20 张图对比框坐标误差在 1e-3 以内才放心。最后一个习惯每次训练完把 data.yaml、训练命令、best.pt 和验证指标存一个版本目录别覆盖。烟盒数据集小调参频繁没有版本管理两周后你根本记不清哪个权重对应哪组参数。这个后悔药吃过一次就记住了。希望帮到你。本文还有配套的精品资源点击获取
返回列表