资讯动态

YOLO目标检测实战:香烟数据集处理与训练全指南

发布时间:2026/9/8 8:56:17 来源:尧图企业网站定制
简介面向YOLO目标检测训练的香烟标注数据集适合目标检测初学者及烟草识别相关项目开发者使用。资源共9742个文件包括4879张jpg原始图像、4861份xml标注文件和2张png示例图压缩包整体约483.55MB。xml标注文件采用标准格式记录每个香烟实例的边界框坐标和类别标签与jpg图像一一对应可直接用于YOLO系列模型的训练与验证图像覆盖多种角度、光照和背景场景有助于提升检测模型在真实环境中的泛化能力。资源目录结构清晰图像与标注分开存放便于用户按需划分训练集、验证集和测试集。已有967人学习下载对于需要快速获取高质量标注数据、减少人工标注成本的开发者而言可节省大量时间将精力集中在模型调优及公共场所禁烟监控、烟草制品识别等实际应用落地。 最近在做一个室内吸烟行为识别的项目最缺的就是带标注的香烟图像。公开数据集要么是国外场景要么标注格式老旧真正能直接扔进 YOLO 里训练的很有限。所以当拿到一份标注好的香烟数据集时我第一时间把目录结构、标签格式和训练效果完整过了一遍。这篇文章会把整个验证过程和训练落地的细节拆开讲包括数据集格式检查、清洗、增强以及 YOLO 训练时最容易踩的坑。如果你是准备做目标检测、手头又是香烟这类小目标的场景这篇可以直接参考。1. 数据集核心解析香烟目标检测到底在检测什么1.1 先搞清楚应用场景这份数据集能用来做什么香烟目标检测的应用场景比我一开始预想的要宽得多。最常见的自然是公共场所吸烟行为识别办公园区、商场出入口、校园周边都有这类需求模型需要从画面里把烟支或者烟头找出来。其次是烟草行业内部的库存盘点摄像头对着货架拍一圈通过识别烟盒数量辅助核对省掉人工清点。另外还能用在安防场景比如停车场、仓库里的烟头检测用来做火灾隐患预警安检场景里对违禁携带物品的识别同样属于这一类。这些场景决定了数据集的构成。我拿到的这份标注好的香烟数据集图片来源比较杂涵盖室内外手持烟支、桌面烟盒、地面烟头特写还有一部分监控视角画面。类别定义方面有的版本只标一个类全部归入 cigarette有的版本会拆成 cigarette烟支、cigarette_box烟盒、cigarette_end烟头三个类。这个定义差别很关键训练之前一定要确认自己手里是哪一种否则后面做完一半才发现类别语义不对返工成本很高。数据量方面也需要心里有数。单类别香烟检测我个人建议图片数量至少 1000 张以上2000 到 3000 张是一个比较舒服的范围。如果手里只有两三百张训练出来的模型泛化能力会很弱换个光线条件就漏检。划分训练集和验证集时常规做法是 8:2 或者 9:1注意要按目录随机打乱不要按图片来源打乱否则同一个场景的相似图片可能同时出现在训练集和验证集里指标虚高。1.2 标注格式VOC 和 YOLO 的转换逻辑YOLO 训练用的标注格式是 txt每行五个值类别 id、归一化中心点 x、归一化中心点 y、归一化宽度、归一化高度。而很多公开数据集给的是 VOC 格式的 XML或者 COCO 格式的 json直接喂给 YOLO 会报错所以第一步通常是把标注统一转成 YOLO txt。我写过一个简单的 VOC 转 YOLO 脚本核心逻辑是解析 XML 里每个 object 的 bndbox 坐标把左上角和右下角坐标换算成中心点和宽高再除以图片宽度高度做归一化。脚本长这样import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_path, out_dir, class_names): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) for obj in root.iter(object): cls obj.find(name).text if cls not in class_names: continue cls_id class_names.index(cls) box obj.find(bndbox) x_min float(box.find(xmin).text) y_min float(box.find(ymin).text) x_max float(box.find(xmax).text) y_max float(box.find(ymax).text) x_center (x_min x_max) / 2 / img_w y_center (y_min y_max) / 2 / img_h w (x_max - x_min) / img_w h (y_max - y_min) / img_h # 越界保护 x_center min(max(x_center, 0), 1) y_center min(max(y_center, 0), 1) w min(w, 1) h min(h, 1) txt_name os.path.splitext(os.path.basename(xml_path))[0] .txt with open(os.path.join(out_dir, txt_name), a) as f: f.write(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}\n)这里有一个非常实际的细节很多标注工具生成的框会超出图像边界训练时 YOLO 遇到这类异常标签不会马上报错但会拖慢收敛甚至导致结果诡异。所以我在代码里加了 clip 处理把所有坐标限制在 0 到 1 之间。另外要特别注意类别 id 必须从 0 开始连续编号不能跳号也不能从 1 开始这是 YOLO 数据集格式里最容易踩的坑之一。2. 数据预处理从原始图像到可直接训练的数据2.1 必须先做的图像筛选与标签自检拿到一份现成的标注好的数据集我一般不会直接开训而是先花半小时做两件事图像质量筛选和标签自检。图像质量筛选主要处理三类问题模糊图、重复图、损坏图。香烟目标本身往往很小如果图像本身模糊模型很容易学到错误纹理推理时反而对焦外背景敏感。标签自检则是用脚本扫一遍检查每个 txt 文件是否存在、是否为空、每一行的数值是否都在 0 到 1 之间、类别 id 是否超范围。这个检查很便宜但能省掉训练中大量的排错时间。下面是一个简单的检查脚本import os def check_labels(labels_dir, num_classes): for root, _, files in os.walk(labels_dir): for file in files: if not file.endswith(.txt): continue path os.path.join(root, file) with open(path) as f: lines f.read().strip().splitlines() if not lines: print(f空标签: {file}) continue for line in lines: parts line.split() if len(parts) ! 5: print(f格式错误: {file}: {line}) elif int(parts[0]) num_classes: print(f类别越界: {file}: {line})自检脚本跑完我还会随手写个可视化脚本把标签框画到原图上肉眼过一遍。这一步看着原始但效果比任何自动化检查都可靠。代码很简单读一张图按 txt 里的坐标换算成像素的左上角和右下角用 cv2.rectangle 画框再保存出来。抽二十张图看一遍基本就能发现类别标错、坐标偏移、目标过小这类问题。2.2 数据增强香烟这种小目标该怎么调香烟在监控画面里往往只占几十个像素属于典型的小目标检测问题。增强策略如果直接用通用配置很容易出现过拟合或者泛化不足。我这一版配置里保留了 mosaic、水平翻转、亮度对比度扰动再加了一个轻量的运动模糊用来模拟监控画面中物体运动产生的拖影。增强我用的是 albumentations它对 bbox 的同步处理很成熟不用担心变换后标注框错位。示例配置如下import albumentations as A train_transform A.Compose([ A.HorizontalFlip(p0.5), A.RandomBrightnessContrast(brightness_limit0.2, contrast_limit0.2, p0.4), A.HueSaturationValue(hue_shift_limit10, sat_shift_limit20, val_shift_limit20, p0.3), A.MotionBlur(blur_limit5, p0.2), ], bbox_paramsA.BboxParams(formatyolo, label_fields[class_labels]))需要提醒的是增强不是越多越好。香烟数据集的背景差异本来就不小过度做随机裁剪或者旋转反而会让模型学到无关的背景模式。另外如果发现训练集 loss 降得特别快、验证集效果却不理想优先检查是不是增强强度过大把样本的真实分布破坏了。我见过有人把 mosaic 概率开到 1.0结果训练集全是拼贴图模型在真实监控画面上的表现反而下降这就是典型的增强过度。3. YOLO 训练配置与实操要点3.1 训练环境与 data.yaml 配置文件Ultralytics YOLO 系列的配置入口是 data.yaml。这个文件写不对后面所有工作都白费。我常用的写法是# cigarette.yaml path: E:/datasets/cigarette train: images/train val: images/val names: 0: cigarette有几个细节必须注意。path 建议写绝对路径别依赖相对路径否则换机器跑直接找不到数据。train 和 val 填的是相对于 path 的目录目录结构一般是 images/train 配 labels/trainYOLO 会自动去 labels 目录找同名 txt。names 里的类别顺序必须和 txt 里的 id 完全一致一旦顺序错了模型分出来的类就是张冠李戴而且训练时还不会报错。如果想拆成多个类就改成names: 0: cigarette 1: cigarette_box 2: cigarette_end但前提是 txt 里的标签确实按这个编号生成。如果训练时报错 “no labels found”多半是 images 和 labels 目录名不对应或者路径写错了检查顺序优先于一切其他操作。3.2 模型选型与训练命令如果你是第一次训练这类数据集我建议直接用 YOLOv8 系列别折腾老版本。模型选型上yolov8n 参数少、跑得快适合先验证数据质量yolov8s 综合性价比高是香烟检测这类中小目标的常见起点如果显存和训练时间都充裕再考虑 yolov8m。从实际效果看单类目标检测用大模型收益有限n 到 m 的精度差距没有 COCO 那种大类别场景那么明显。训练命令我习惯写成这样yolo detect train \ datacigarette.yaml \ modelyolov8s.pt \ epochs100 \ imgsz640 \ batch16 \ patience20 \ device0epochs 设 100 对单类数据集通常够了配合 patience20 开启早停如果连续 20 轮验证集指标不涨训练会自动停止没必要死磕完整轮数。batch 大小受显存限制如果 16 太大导致 CUDA out of memory就降到 8再不行降 imgsz别指望用虚拟内存硬抗。训练时如果发现 loss 震荡剧烈可以把学习率从默认的 0.01 调到 0.005或者开启 cos_lr 让学习率余弦衰减曲线会更平稳。4. 训练评价标准与指标解读4.1 三个核心指标Precision、Recall、mAP训练过程中最容易被问到的就是到底看哪个指标判断模型好坏。对目标检测来说首要关注的是 Precision、Recall 和 mAP。指标含义重点关注Precision模型预测出的框中真正包含目标的占比误检多不多Recall真实目标中被模型找出来的比例漏检多不多mAP0.5IoU0.5 时各类别 AP 的均值常规工程指标mAP0.5:0.95IoU 从 0.5 到 0.95 逐档平均精度更严苛举一个实际例子测试集里手工标了 100 个香烟目标模型一共预测出 90 个框其中 72 个确实框中了目标剩下 18 个是误检。此时 Precision 是 72/9080%Recall 是 72/10072%。如果误检少但漏检多说明模型偏保守反过来就是偏激进。香烟检测这种场景我宁可提高 Recall 多框一些可疑目标也不希望漏掉真实的烟支所以在调参阶段可以适当降低置信度阈值。mAP 的数值和 IoU 阈值绑定。mAP0.5 对框的位置要求没那么严通常能达到 0.9 以上才算合格mAP0.5:0.95 会把 IoU 从 0.5 到 0.95 按 0.05 步长都算一遍再取平均数值一般会掉 15 到 25 个百分点这是正常的。AP 本身的含义是 Precision-Recall 曲线下的面积不同置信度阈值下算出一组组精确率和召回率连成曲线再求积分所以 AP 高意味着模型在多个阈值下都能保持又准又全。4.2 从损失曲线判断训练状态很多人训练完只看 mAP不在意损失曲线这是不对的。YOLOv8 训练时会输出三类 lossbox_loss 管预测框的位置准不准cls_loss 管目标分类对不对dfl_loss 管边界框分布的质量。三类 loss 在训练集上都应该前期快速下降、后期缓慢收敛。判断标准很简单训练 loss 持续下降验证集 mAP 也在涨这是健康状态。如果训练 loss 还在降、验证 loss 开始反弹说明过拟合了这时候可以停止训练、回退到验证 loss 最低那一轮的权重。我习惯在训练结束后打开 results.png 扫一眼曲线重点看有没有大起大落。出现大起大落通常是学习率设置有问题或者数据集里有标签和图片不匹配的脏数据需要回到预处理阶段排查而不是在这里调参硬扛。5. 常见问题与排查技巧实录5.1 训练直接报错类别数不匹配与空标签YOLO 训练最常见的报错就两类。一类是 Class 3 is not in class list意思是某个 txt 里写了 id3但 data.yaml 的 names 只定义了 0 到 2多出来的 id 找不到对应类别。我遇到这种情况基本都是多源数据集合并时不同来源的类别编号没有统一用脚本把编号映射一遍就能解决。另一类是 No labels found in ...原因是 labels 目录路径不对或者 txt 内容为空。空标签文件训练时会被忽略但大量空标签会浪费训练时间最好在预处理阶段直接过滤掉。还有一个隐蔽问题图片是 jpg标注是 txt 但文件名对不上。YOLO 要求图片名和标签名完全一致比如 001.jpg 对应 001.txt。如果你用脚本从 XML 生成 txt 时文件名带了额外后缀就会导致大量图片在训练时被忽略。我的排查方式很简单直接统计 images/train 和 labels/train 的文件数数量对不上就去查差集。5.2 小目标检测效果差提升召回率的三个手段我实测过香烟数据集直接 640 分辨率训练对小目标召回率也就是六成多肉眼可见的漏检集中在远处烟盒和烟头。针对这个问题有三个手段建议按顺序试。第一把 imgsz 从 640 提到 960目标像素占比变大特征更明显但显存占用会涨batch 要相应缩小。第二推理阶段用 SAHI 这类切片推理工具把大图按 512x512 切块检测再合并结果对小目标有奇效缺点是推理时间变长想在边缘设备实时跑会比较吃力。第三在模型结构上补充 P2 小目标检测头YOLOv8 的小目标检测头分支对应更大尺寸的特征图能保留更多细节信息但需要自己改模型配置训练成本也会增加。我实际项目里是先用 960 分辨率加 SAHI 解决了大部分漏检小目标检测头那步因为改结构风险大留到了后续版本再迭代。5.3 AMD 显卡能不能跑 YOLO环境选择实测不少人在用 AMD 显卡想知道自己的机器能不能跑 YOLO 训练。先说结论Ultralytics 官方支持的 GPU 训练依赖 NVIDIA CUDA 生态AMD 显卡没有 CUDA 核心直接用标准 pip 包无法调用显卡加速只能拿 CPU 硬跑。我拿 AMD RX 580 实测过CPU 模式训练 yolov8n640 分辨率的单张图片前向推理大约需要 1 到 2 秒几百张图片训 100 轮可能要十几个小时能跑但效率很低。如果你现在只有 AMD 显卡先小 batch 用 CPU 验证数据流程是没问题的真要大规模训练还是建议换 NVIDIA 显卡或者直接用云端训练环境。另外显卡驱动和 CUDA 版本不匹配时训练会在初始化阶段直接报错先跑一下 nvidia-smi 确认 torch 能正常调用 GPU再开训练。我个人的操作习惯是拿到任何香烟数据集都先跑一版 yolov8n、训 30 轮以内确认整个流程没有报错、loss 在正常下降再切换成目标模型正式训练。千万别拿大模型一步到位开训出了问题排查周期会非常长。最后再分享一个小技巧训练结束后的 best.pt 并不是终点。把验证集里预测错的那几十张图单独拎出来看比看任何指标都直观。如果误检集中在烟盒和烟头混淆说明类别语义本身有交叉考虑合并类如果漏检集中在远景说明小目标问题还没彻底解决。数据集的价值不是一次训练就榨干的根据错误样本反推数据补充方向比继续调参有效得多。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价