资讯详情

吸烟检测数据集PASCAL VOC解析与YOLO训练实战指南

📅 2026/10/5 5:55:09 | 华诺云谱 👁 阅读
吸烟检测数据集PASCAL VOC解析与YOLO训练实战指南
简介这套吸烟检测数据集面向目标检测开发者和算法训练人员包含991张原始JPG图片和991个PASCAL VOC格式的XML标注文件共1982个文件压缩包大小约44.92MB。图片均为真实场景原始采集XML标注文件包含完整的类别与边界框信息可直接用于YOLO、Faster R-CNN、SSD等主流目标检测框架的训练、验证与测试。数据量适中既适合入门级模型快速迭代也可作为补充数据扩充既有训练集经过前期验证该数据集平均识别率可达88.3%为算法效果提供了可靠的基线参考。目前已有262人学习浏览是评估和选用吸烟检测数据集的有益参照。获取后无需自行采集和标注可直接开展数据格式转换、模型训练与业务验证显著降低开发成本适用于公共场所禁烟监控、安全生产等场景的吸烟行为识别应用。1. 991张图、88.3%识别率这套吸烟数据集到底能不能直接拿去做检测拿到991张原始图片、平均识别率88.3%、PASCAL VOC XML格式标注的吸烟数据集第一反应别是高兴而是先问三个问题这88.3%是什么口径991张图够不够训练标注质量能不能直接吃做工地安全帽、加油站明火、厨房监控这类场景的工程师大概率都遇到过同一个尴尬吸烟检测有需求但标注数据要么贵要么找不到。这套数据集的价值在于它按PASCAL VOC标准用XML做了目标级标注能直接喂给YOLO、MMDetection这类主流检测框架适合用来验证流程、做算法选型、搭第一版预警原型。想直接上生产建议把它当起点数据而不是终点。标题里的PASICAL是PASCAL的常见笔误不影响使用重点看格式和指标口径。2. PASCAL VOC XML格式拆解991张图的标注里到底存了什么2.1 标准VOC目录结构与991张图的组织方式数据集解压后第一件事不是写代码而是先摸清目录结构。PASCAL VOC从2007年那版开始目录布局基本固定这套991张图的数据集大概率也是按这个风格组织的VOCdevkit/ ├── JPEGImages/ # 原始图片991张jpg ├── Annotations/ # 每张图对应一个xml标注 └── ImageSets/ └── Main/ # 划分文件train.txt / val.txt / test.txtJPEGImages和Annotations是一一对应的文件名相同、扩展名不同。比如一张图叫IMG_0231.jpg它的标注就是Annotations/IMG_0231.xml。ImageSets/Main下通常有train.txt、val.txt、test.txt三个文本文件每行写一个不带扩展名的文件名模型训练时就是按这个列表去JPEGImages和Annotations里取数的。这套数据我也见过另一种组织方式991张图和xml平铺在一个目录里另外附一个划分脚本或data.yaml。这种结构多见于标注平台直接导出的数据不是严格按VOC树来放。顺序反过来没关系但要先搞清楚一件事xml里filename字段写的路径和你实际解压后的路径是否一致。不一致的话后面转格式时会有大量匹配失败而且失败原因不好定位。这里有个新手容易忽略的坑JPEGImages里的图片可能是不同分辨率混放的有的来自网络爬虫有的来自监控截图有的来自手机拍摄。这意味着XML标注里的size字段必须和真实图片尺寸一致不然坐标归一化时宽高比会错位。建议先写一个核对脚本把每张图的真实尺寸和XML里的size做个比对不一致的先修正再往下走。这一步听着繁琐但在991张这种小数据集上花几十分钟核对能省后面几天的排查时间。2.2 一个XML标注文件里到底有哪些字段VOC格式的XML标注文件结构非常直白。用VS Code、Notepad或者直接在Linux下用vim打开一个标注文件就能看到全貌。这里给一个典型结构也是xml解析时最常见的字段集合?xml version1.0 encodingutf-8? annotation folderJPEGImages/folder filenameIMG_0231.jpg/filename path/home/user/smoking_dataset/JPEGImages/IMG_0231.jpg/path source databaseSmoking Dataset/database /source size width1920/width height1080/height depth3/depth /size segmented0/segmented object namesmoking/name poseUnspecified/pose truncated0/truncated difficult0/difficult bndbox xmin642/xmin ymin380/ymin xmax758/xmax ymax530/ymax /bndbox /object /annotation用xml.etree.ElementTree解析这个结构很方便但有几个字段直接影响后面训练。第一个是size下的width和height所有坐标归一化都要拿它们做分母第二个是object下的name如果要区分吸烟和打火机这种多类别场景name映射表必须提前定好第三个是bndboxxmin/ymin/xmax/ymax四个值都是像素坐标原点在图片左上角右下方向为正。字段含义整理成表会更清楚字段类型含义训练时的用途filenamestr图片文件名匹配JPEGImages里的实际图片size/width、size/heightint图片宽高坐标归一化的分母object/namestr目标类别名映射到class_idobject/truncatedint 0/1目标是否被图像边缘截断可选过滤object/difficultint 0/1是否属于难例建议过滤object/bndbox4个int左上角右下角坐标转成YOLO中心点宽高格式注意一个细节一张图里可能有多个object节点。比如一个人手里拿着烟另一个人手里拿着打火机那这张图的xml里就有两个object每个object对应一个检测框。991张图不等于991个标注框实际目标数可能多不少这会影响后面对识别率88.3%的理解。2.3 为什么这套数据选XML而不是COCO的JSON这也是一个值得说道的点。PASCAL VOC的XML标注格式是LabelImg这类工具的默认导出格式标注人员下拉一个框、选一个类别、点保存直接生成XML学习成本几乎为零。COCO的JSON格式虽然信息密度更高但手工书写几乎不可能必须靠脚本转换。从工程角度看XML的好处是单个文件独立、损坏一个不影响其他、用git管理时diff相对友好从生态看YOLO系列、MMDetection、Detectron2都有专门的VOC转换工具绕一圈都能转成模型需要的格式。三种格式放一起对比更直观格式存储方式手工可读性训练框架支持典型工具VOC XML每张图一个XML可读结构清晰需转换LabelImgCOCO JSON全部标注集中在一个JSON可读性差部分框架原生labelme等YOLO txt每张图一个txt可读YOLO系列原生LabelImg导出解析XML时最常见的坑是编码。一份标注文件如果以GBK或者ANSI编码保存在Linux下直接用open()读取、不指定encodingxml.etree.ElementTree的parse阶段很可能直接抛ParsingError。遇到这个问题我一般的做法是先把文件头读出来做编码探测或者用errorsignore兜底但更稳的方法是批量解析前先统一转成UTF-8。另外给零基础读者一句实在话就算不会写代码也可以用VS Code直接打开xml文件阅读和编辑看清结构再写脚本比盲改配置稳得多。xml文件怎么打开和编辑这个问题本质上就是找一个支持语法高亮的编辑器然后按上面表格里的字段逐个对照。3. 训练吸烟检测模型VOC转YOLO格式、数据划分与训练命令3.1 把VOC XML转成YOLO需要的txt标注训练检测模型从VOC格式起步是最常见的路径。标题里给的是VOC XML标注但YOLO系列训练需要的是txt格式标注每行是class cx cy w h且坐标全部归一化到0到1之间。第一步先写转换脚本常见做法是用Python内置的xml.etree.ElementTree解析完全不依赖第三方库import xml.etree.ElementTree as ET import os # class顺序一旦确定不要随便改训练和推理共用同一份 CLASS_DICT {smoking: 0, cigarette: 1} # 按自己数据集的类别改 def voc2yolo(xml_path, label_dir): tree ET.parse(xml_path) root tree.getroot() # 读取图片宽高坐标归一化全靠它 size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) txt_name os.path.basename(xml_path).replace(.xml, .txt) lines [] for obj in root.iter(object): name obj.find(name).text if difficult in [f.tag for f in obj] and int(obj.find(difficult).text) 1: continue # 难例跳过避免干扰训练 if name not in CLASS_DICT: continue # 不在类别表里的直接忽略 bndbox obj.find(bndbox) xmin float(bndbox.find(xmin).text) ymin float(bndbox.find(ymin).text) xmax float(bndbox.find(xmax).text) ymax float(bndbox.find(ymax).text) # VOC格式是左上角右下角YOLO要中心点宽高全部除以图片宽高归一化 x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h box_w (xmax - xmin) / img_w box_h (ymax - ymin) / img_h lines.append(f{CLASS_DICT[name]} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}) # 一张图可能没有目标或全部被跳过此时写空文件 with open(os.path.join(label_dir, txt_name), w) as f: if lines: f.write(\n.join(lines)) else: f.write() # 空文件训练时会忽略该图 # 批量处理991张图的xml xml_dir Annotations label_dir labels os.makedirs(label_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if xml_file.endswith(.xml): voc2yolo(os.path.join(xml_dir, xml_file), label_dir)逻辑说明CLASS_DICT的键值对顺序就是训练时类别的索引后面data.yaml里的names列表必须和它保持一致。对每个object节点取出bndbox的四个坐标把VOC的左上有右下格式换算成YOLO的中心点加宽高并除以图片宽高完成归一化。difficult1的框直接跳过这是VOC规范里标注的难例强行训练会干扰模型。最后写的空txt文件对应没有有效目标的图片YOLO训练时自动忽略但不会报错如果直接删掉txt会导致图片和标注数量对不上。参数说明这里最需要注意的是img_w和img_h来自XML里的size字段而不是来自图片本身。如果XML里写的是1920x1080而图片解码出来是720x480那归一化坐标全部错位训练出来的框全偏。脚本跑完以后抽查几个txt文件用文本编辑器打开确认坐标值都在0到1之间再进入下一步。3.2 数据划分与data.yaml准备标注转换完还要划分训练集和验证集。991张图的小数据集我一般直接用train_test_split固定随机种子保证每次复现的结果一致import os, random from sklearn.model_selection import train_test_split images [f for f in os.listdir(JPEGImages) if f.endswith(.jpg)] train_files, val_files train_test_split(images, test_size0.15, random_state42) with open(train.txt, w) as f: for name in train_files: f.write(f./JPEGImages/{name}\n) # 相对路径训练机迁移不用改 with open(val.txt, w) as f: for name in val_files: f.write(f./JPEGImages/{name}\n)这里用15%做验证集991张图就是训练集841张、验证集150张。这个比例对单类别检测来说验证集略小但对小数据集是合理的折中验证集太小会导致评估结果抖动大。图片路径写相对路径而不是绝对路径不然换机器训练全废。写完txt后要自查一遍train.txt和val.txt里的每一行对应的图片和txt标注必须同时存在缺一个就在训练时报错。然后准备data.yamltrain: ./train.txt val: ./val.txt nc: 2 names: [smoking, cigarette]nc的值必须和CLASS_DICT里的类别数量一致names的顺序必须和CLASS_DICT的key顺序一致。这两个顺序对不上训练不会报错但训练完的权重在推理时类别全乱这是后面第5章要细说的坑。3.3 用YOLOv8把模型训起来数据齐了用YOLOv8训练是当前最省心的选择。v5和v8命令大同小异以ultralytics的YOLOv8为例yolo detect train \ datasmoking.yaml \ modelyolov8s.pt \ imgsz640 \ batch16 \ epochs150 \ cacheTrue \ patience20 \ workers4参数说明imgsz640是大多数场景下的安全值烟头属于小目标后面可以尝试768甚至960但显存和推理速度要同步考虑batch16在991张图这个规模下比较稳太大容易后期过拟合太小收敛慢epochs150对这个小数据集偏多配合patience20会在验证集指标连续20轮不涨时提前停实际跑到60到80轮左右就会自动停。modelyolov8s.pt是官方预训练权重迁移学习在小数据上的效果明显优于从零训练强烈建议保留。训练完看runs/detect/train目录下的weights/best.pt和last.ptbest是验证集上表现最好的权重推理时一律用best。整个流程在单张消费级显卡上大约20到40分钟。训练参数落在同一个表里方便调参参数取值说明imgsz640输入分辨率烟头小可提升到768/960batch16显存不够降到8epochs150配patience提前停patience20验证集不涨则停cacheTrue991张图可以全缓存加速这里解释一下为什么用s模型而不是n或mn的参数少在小数据集上容易欠拟合m和l参数量大991张图不够喂会明显过拟合s是性价比平衡点。等以后数据量超过3000张再考虑切m。4. 识别率88.3%的水分在哪里指标口径、复现评估与两个虚高信号4.1 平均识别率不等于mAP先搞清口径平均识别率在88.3%这句话在目标检测任务里没有标准定义。检测任务通用的汇报口径是mAP0.5或者mAP0.5:0.95但识别率更接近分类任务里的accuracy也就是所有测试样本里模型正确识别的比例。这两个口径相差很远拿到数据集必须先确认这一点。指标全称定义适合场景accuracy识别准确率正确预测数/总样本数每张图只有一个类别precision精确率TP/(TPFP)关心误报的场景如明火预警recall召回率TP/(TPFN)关心漏报的场景如安全巡检mAP0.5均值平均精度IOU阈值0.5下全类别AP均值目标检测通用指标对吸烟检测来说precision和recall通常比accuracy重要。在加油站场景漏报一次可能出事故recall优先在办公区禁烟场景误报太多会让人疲化precision优先。88.3%如果是accuracy说明有11.7%的图片整张被分错如果是mAP0.5说明框定位和分类综合正确率是88.3%。两种解释差了很远拿到数据集后先按下面方法复现一遍再判断这个数字可不可信。4.2 用验证命令复现一个可信的数字自己训练完评估这一步建议用官方命令不要自己写评估脚本yolo detect val \ modelruns/detect/train/weights/best.pt \ datasmoking.yaml \ conf0.25 \ iou0.5conf0.25是置信度阈值iou0.5是NMS用的IOU阈值这两个值直接影响输出指标。如果把conf设成0.01precision会下降、recall会上升最后算出的mAP会完全不同所以评估时保持默认值。官方会在终端输出mAP50、mAP50-95、precision、recall四项。拿自己的模型跑一遍看mAP50离88.3%差多远。如果差得不多说明88.3%大概率是mAP50口径如果差很多说明发布者的测试集划分或者数据增强策略和你不同这个数字没法直接复现不需要强行对齐。多补一句991张图上跑出的mAP50如果是88.3%本身是个不错的基线但这个数字有小数据集乐观偏差。样本少训练集和验证集分布差异就小评估结果偏乐观。这也是很多数据集页面上标的指标好看、部署出去就翻车的原因。真要上线数据量至少是十倍起。4.3 991张数据量下指标虚高的两个信号第一个信号验证集loss曲线在最后20个epoch像心电图一样上下抖动说明模型在记忆训练集特征验证样本稍微一变就错。这不是收敛问题是数据量撑不起模型容量。第二个信号把模型输出的框可视化把置信度阈值拉低到0.1再看一遍会发现很多框其实是框到了电线、充电宝、烟盒这类长条形物体上。这是88.3%掩盖下的真实水平也是吸烟检测最常见的误报来源。可视化这一步不要省直接看图和框比看任何指标都直观。5. 吸烟检测训练中的5个高频坑现象、原因与排查方法5.1 图片文件名和XML里的filename对不上训练集加载了0张图现象训练一开始日志显示数据集为空或者训练loss一直是NaN不下降。原因XML里filename字段写的是IMG_0231.jpg但实际解压的图片叫img_0231.JPG大小写不一致。Linux下这个情况会导致文件打开失败Windows下偶尔能打开但标注对应错乱。还有一种是xml里的filename带了路径前缀和train.txt里的相对路径拼接后变成双重路径。解决写一个校验脚本读取每个XML的filename再在JPEGImages里探测实际文件名统一重命名或改XML里的filename。这个操作必须在转换标注之前完成否则转换后的txt全是脏数据。5.2 class_id顺移一位模型把打火机学成了香烟现象训练loss正常下降推理时把打火机识别成香烟或者把无烟的框标成了smoking。原因CLASS_DICT的顺序、data.yaml里names的顺序、模型推理输出类别索引三者不一致。检测模型输出的是索引号转成类别名靠names列表顺序一错全错。解决把CLASS_DICT和data.yaml放在同一个地方维护任何一次增删类别都同时改这两处。改完以后重新转一遍标注再训练不要手改txt里的编号手动改很容易顾此失彼。5.3 数据增强把烟头和其他目标拼在一起误检率突然上升现象开了Mosaic增强训练几十个epoch后验证集precision还可以实际部署时误报特别多。原因Mosaic把四张图拼成一张等于把不同图片里的目标放进了同一场景。如果烟头被裁剪成小块再拼到另一张图的背景上模型会学到背景里有桌子加长条形物体就是烟而不是手和嘴附近的长条形才是烟。烟头本身是小目标拼图操作对小目标的伤害尤其大。解决对小目标密集的吸烟检测建议把Mosaic关掉或者把增强比例从1.0调到0.1左右。也可以在训练的最后一阶段关闭增强让模型在干净数据上收尾。具体做法是训练时在ultralytics的配置里把mosaic参数单独降低只针对这个数据集调整不影响其他项目。5.4 随机划分数据集导致验证集泄漏指标虚高现象mAP50高到不敢信线上视频里同一个画面反复误报。原因991张图里很可能包含同一段监控视频的连续帧连续帧内容几乎一样。随机划分时这些相似帧一部分进了训练集一部分进了验证集评估结果天然偏高。模型实际没有见过真正的新场景验证集测试了个寂寞。解决划分前按文件名前缀或拍摄时间聚类确保同一批次视频帧只在train或val其中一边。991张图的场景如果来源分散这个问题就轻很多如果来源是几段监控视频必须手动按视频ID划分不能直接random split。5.5 忘了过滤difficult1的样本训练集里混入噪声现象训练loss曲线总体正常但偶尔出现尖刺评估时mAP忽高忽低不稳定。原因数据集里difficult1的框表示目标非常小、遮挡严重或本身就模糊。拿这些框当正样本模型学到的特征不可靠反向传播时会产生抖动梯度。解决转换脚本里显式跳过difficult1验证集里如果出现difficult样本也建议剔除否则mAP计算时同样会被拉低。前面的voc2yolo脚本已经内置了跳过逻辑前提是XML里存在difficult字段且值正确。有些标注工具导出的XML没有difficult字段这种情况直接忽略即可不要手动补。6. 把88.3%往上顶难例挖掘与切图训练两个实操技巧6.1 难例挖掘让模型自己的错误变成训练数据训练完best.pt以后在验证集上跑一遍推理把置信度在0.1到0.5之间徘徊的框全部导出来重新标注这些难例加入训练集再训练一轮。两轮迭代往往就能把88.3%的基线推到90%以上。注意难例挖掘不能只挖正样本也要挖负样本比如手握成拳头、嘴里叼笔杆这类容易误判为吸烟的图像同样应该作为负样本加入。991张图的正样本分布可能不均衡难例挖掘是性价比最高的提升手段。我在实际项目里用过一次把工地场景的吸烟识别从81%提到91%没有改任何模型结构只是加了两轮难例和负例。数据清洗的优先级永远在调参之前模型结构不是黑匣子数据才是真正决定上限的地方。6.2 烟头小目标的切图训练与大分辨率权衡如果部署场景里烟头只有20到40像素在640分辨率下训练几乎学不到纹理特征。常见做法是把原图按512或640滑动切块overlap设置50%把切出来的子图重新生成标注再训练。推理时同样切块再合并NMS结果。代价是推理时间涨三倍左右需要自己权衡。还有一条便宜路线把输入分辨率从640提到960同时关掉Mosaic能让模型对烟头更敏感。具体效果还是得用验证集mAP说话参数不是玄学是你在训练脚本里反复试出来的。我第一次接吸烟检测单子时一上来就折腾模型结构换来换去识别率始终卡在90%后来排查发现是验证集划分泄漏和difficult样本没过滤。把数据洗干净以后同一套模型直接跳到93%以上。数据质量决定模型上限这个教训到现在都适用。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑