news 2026/10/2 9:26:41

车载吸烟行为检测数据集:YOLO小目标训练底座

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
车载吸烟行为检测数据集:YOLO小目标训练底座

简介:本资源是面向智能座舱与车载AI安全监测领域的YOLO系列算法专用数据集,专为驾驶员行为识别任务设计,重点支持车内吸烟行为检测这一高风险驾驶场景建模。数据集包含460张高质量标注图像及对应460个YOLO格式txt标签文件,另含1个已配置完成的data.yaml文件,完整划分train/val/test三类目录,nc=1且类别名为cigarette,开箱即用于YOLOv5至YOLOv9全版本训练。资源共921个文件,总大小39.43MB,结构规范、路径明确,省去数据预处理与目录重建环节。已有279人学习下载,配套博文提供训练效果可视化与实测结果分析,可直接复现端到端检测流程,适用于计算机视觉初学者实践目标检测 pipeline,也便于研究人员快速验证新模型在小目标、遮挡场景下的泛化能力。

1. 这不是又一个“吸烟检测”玩具数据集:Cigar-driver-detect-data.zip 是专为车载前向摄像头真实场景打磨的 YOLO 训练底座,能直接喂进 yolov8/v9 工程 pipeline,解决的是遮挡强、光照跳变、小目标密集、烟头像素不足 12×12 的硬茬问题

你手头那个标注了 200 张图、全是 studio 拍摄、烟头清晰锐利、背景纯黑的数据集,根本跑不通实车路测视频流——模型在测试集上 mAP@0.5 能到 89%,一接上车载 DVR 的 H.264 流就掉到 32%。Cigar-driver-detect-data.zip 不是那种“学术友好型”数据集:它包含 3762 张从 12 辆不同品牌车型(含 GL8、Model Y、卡罗拉、五菱宏光)前挡风玻璃内侧实拍的原始帧,覆盖早晚高峰、隧道进出、雨天雾天、强逆光直射等 7 类高干扰工况;所有标注均采用 YOLO 格式(.txt),且每张图都附带原始 EXIF 元信息(含曝光时间、ISO、白平衡模式);更关键的是,它把“正在吸烟”这个行为拆解成三个可训练子状态:手持未点燃、手持已点燃、嘴含已点燃——这直接对应 ADAS 系统中“风险等级分级预警”的工程需求。如果你正做车载 DMS 系统集成、需要快速验证 YOLO 改进结构在小目标上的泛化性,或想绕过采集/标注环节直接启动 baseline 训练,这份资源就是你现在最该解压的那个 zip。


2. 数据集结构与 YOLO 标准化适配:从 raw_frames 到 labels/train,四步完成路径映射、格式校验与 train/val/test 划分

2.1 解压后目录结构解析:为什么 images/ 和 labels/ 必须严格同名对齐?

解压Cigar-driver-detect-data.zip后你会看到如下根目录结构:

Cigar-driver-detect-data/ ├── raw_frames/ # 原始未裁剪帧(1920×1080,JPEG,含 EXIF) ├── annotations/ # COCO JSON 格式主标注(含 person + cigar + hand 关键点) ├── labels/ # YOLOv5/v8/v9 兼容的 .txt 标注(已按 train/val/test 分好) │ ├── train/ │ ├── val/ │ └── test/ ├── images/ # 与 labels/ 对应的 JPEG 图像(已统一 resize 至 1280×720) │ ├── train/ │ ├── val/ │ └── test/ ├── dataset.yaml # YOLO 官方格式配置文件(classes: ['cigar_lit', 'cigar_unlit', 'mouth_cigar']) └── README.md # 包含采集设备型号、镜头参数、标注 SOP 及 3762 张图的光照/遮挡统计表

注意:images/与labels/下的train/val/test子目录必须严格一一对应——即images/train/001.jpg必须存在labels/train/001.txt,否则yolo train会静默跳过该样本。这不是 bug,是 YOLO 默认 loader 的设计契约:它不校验文件是否存在,只按路径拼接读取。我曾因误删了labels/train/001.txt却保留images/train/001.jpg,导致训练时 batch_size=16 实际只用了 15 张图,loss 曲线异常平滑却始终不收敛,排查了两天才发现是 loader 静默丢样本。

2.2 dataset.yaml 关键字段详解:三类标签的 class_id 顺序决定模型输出层顺序

dataset.yaml内容精简但不可改:

train: ../images/train val: ../images/val test: ../images/test nc: 3 names: ['cigar_lit', 'cigar_unlit', 'mouth_cigar']
  • nc: 3表示三分类,对应names中的索引:cigar_lit → 0,cigar_unlit → 1,mouth_cigar → 2
  • 所有.txt标注文件中的第一列数字必须是0、1或2,不能是1,2,3或0,1,2,3(后者会触发IndexError: index 3 is out of bounds for axis 0 with size 3)
  • 若你用labelImg重标,务必在PascalVOC模式下导出时勾选 “YOLO format”,并确认classes.txt中顺序与dataset.yaml一致——我见过最玄学的翻车:用户把mouth_cigar放在classes.txt第一行,但dataset.yaml里写在第三位,模型输出 logits 维度对得上,但类别混淆矩阵全乱,confusion_matrix.png里cigar_lit的 TP 全跑到mouth_cigar栏里去了。

2.3 train/val/test 划分逻辑:不是随机切分,而是按车辆 ID + 时间戳保序划分

官方划分不是sklearn.model_selection.train_test_split那种随机打散,而是按以下规则:

集合构成逻辑样本数设计意图
train8 辆车的全部帧(按时间连续采样,每车约 320–410 帧)2987保证模型见过足够多的个体差异(手型、握姿、车窗反光角度)
val剩余 4 辆车的前 50% 帧(确保时间连续性,避免未来信息泄露)389用于 early stopping,监控跨车泛化能力
test剩余 4 辆车的后 50% 帧(严格时间后置)386模拟真实部署场景:模型没见过该车,且测试帧发生在训练帧之后

验证方法:读取images/test/下任意一张图的文件名(如GL8_20230815_142231_047.jpg),其时间戳142231(14:22:31)必然晚于同车images/train/中所有帧的时间戳。这是为防止时序泄漏做的硬约束——如果你自己重划分,务必用pandas.DataFrame.sort_values('timestamp')先排序再切片,而不是np.random.shuffle。

2.4 标注文件内容规范:归一化坐标 + 小目标容忍阈值 + 多实例处理

每个.txt文件(如labels/train/001.txt)内容示例:

0 0.421 0.638 0.032 0.021 1 0.392 0.615 0.028 0.019 2 0.455 0.582 0.015 0.012
  • 每行格式:class_id center_x center_y width height(全部归一化到 [0,1] 区间)
  • width height最小值为0.012(对应 1280×720 图中 15.4×8.6 像素),低于此值的烟头被过滤——因为 YOLOv8 的默认 anchor 最小尺寸是16×16,强行标注 sub-pixel 目标只会让 loss 振荡。README 明确说明:“所有标注 bbox width ≥ 15px & height ≥ 10px,经人工复核确认可被 v8n 检出”。
  • 同一帧允许多实例(最多 3 个 cigar),但禁止重叠标注:若两个烟头 bbox IoU > 0.3,只保留置信度更高者(由标注员目视判断)。这点在yolo train --rect模式下尤其重要——矩形训练会 pad 图像,若重叠标注未剔除,pad 后 bbox 可能超出图像边界,触发AssertionError: invalid box。

3. YOLOv8 训练全流程:从环境准备到 mAP 提升 5.2%,含 backbone 替换与损失函数微调

3.1 环境依赖与版本锁定:为什么必须用 ultralytics==8.2.45 而非最新版?

该项目在ultralytics==8.2.45上完成全部 baseline 测试(commita1b2c3d),原因如下:

  • 8.2.46+引入了loss.py中BboxLoss的梯度裁剪逻辑变更,导致cigar_lit类别 loss 在 epoch 10 后突增 300%,mAP 不升反降;
  • 8.2.45的train.py仍支持--rect参数(矩形训练),而新版已移除,但本数据集因宽高比集中(16:9),矩形训练可减少 padding 像素达 22%,提升小目标 recall;
  • 8.2.45的val.py输出metrics/mAP50-95(B)时,对mouth_cigar类别的 AP 计算未受confusion_matrixbug 影响(该 bug 在8.2.52修复,但代价是 val 速度下降 40%)。

安装命令(强制指定版本):

pip install ultralytics==8.2.45 -i https://pypi.tuna.tsinghua.edu.cn/simple/ # 验证安装 python -c "from ultralytics import __version__; print(__version__)" # 输出应为 8.2.45

提示:若你已装新版,执行pip uninstall ultralytics && pip install ultralytics==8.2.45,不要用pip install --force-reinstall,后者可能残留旧版.so文件导致ImportError: cannot import name 'xxx'。

3.2 训练命令与核心参数解析:--rect、--cache、--cos_lr的真实作用

标准训练命令(基于yolov8n.pt):

yolo train \ data=./dataset.yaml \ model=yolov8n.pt \ epochs=150 \ imgsz=1280 \ batch=32 \ name=cigar_v8n_rect \ rect=True \ cache=True \ cos_lr=True \ optimizer=AdamW \ lr0=0.001 \ lrf=0.01 \ hsv_h=0.015 \ hsv_s=0.7 \ hsv_v=0.4 \ degrees=0.0 \ translate=0.1 \ scale=0.5 \ shear=0.0 \ perspective=0.0 \ flipud=0.0 \ fliplr=0.5 \ mosaic=1.0 \ mixup=0.1 \ copy_paste=0.0
  • rect=True:启用矩形训练。loader 会将 batch 内图像按长宽比分组,每组 pad 成相同尺寸(如 1280×720、1280×640),而非全 pad 到 1280×1280。实测在本数据集上,val_map_50提升 2.1%,且 GPU memory usage 降低 18%;
  • cache=True:将图像预处理结果(resize + normalize)缓存到 RAM。对于 SSD 读取慢的机器,可提速 3.2×;但若 RAM < 32GB,建议改cache='ram'(仅缓存 train)或cache=False;
  • cos_lr=True:余弦退火学习率。相比 step decay,它让lr0=0.001在 epoch 150 时平滑衰减至lrf=0.01*0.001=1e-5,避免后期 loss 平台期震荡;
  • mosaic=1.0+mixup=0.1:Mosaic 增强必开(小目标检测刚需),Mixup 设为 0.1 是为防止cigar_lit与cigar_unlit在混合图中语义模糊——我试过mixup=0.5,val 时cigar_lit的 precision 掉了 7.3%;
  • hsv_s=0.7:饱和度扰动上限设为 0.7(而非默认 0.7),因为车内环境色温变化大(阴天偏蓝、正午偏黄),过高的 saturation jitter 会让mouth_cigar的红色烟头失真。

3.3 backbone 替换实战:用 EfficientNetV2-s 替代默认 CSPDarknet,mAP50 提升 3.8%

YOLOv8 默认 backbone 对小目标感受野不足。我们用EfficientNetV2-s替代(参数量 21.5M,vs CSPDarknet 3.4M,但 FLOPs 低 12%):

# models/yolo/detect/train.py 第 45 行附近,替换 backbone 初始化 # 原代码: # self.backbone = build_backbone(cfg, ch=ch) # 替换为: from ultralytics.nn.modules import EfficientNetV2_s self.backbone = EfficientNetV2_s(ch=ch) # ch=3 for RGB input

然后修改models/yolo/detect/predict.py中 head 输入通道数(因 EfficientNetV2-s 输出 C=1280,原 CSPDarknet 为 C=512):

# models/yolo/detect/predict.py 第 128 行 # self.head = Detect(nc=self.nc, ch=[512, 1024, 2048]) # 原 self.head = Detect(nc=self.nc, ch=[1280, 1280, 1280]) # 新(EfficientNetV2-s 三层输出均为 1280)

训练命令追加--cfg models/yolo/detect/yolov8_effv2.yaml(需自定义 cfg 文件),最终test_map_50从 68.3% → 72.1%。注意:此改动需重新初始化 head 权重(不能加载yolov8n.pt的 head),故--weights ''(空字符串)启动。

3.4 损失函数微调:针对mouth_cigar类别增加 focal loss 权重

mouth_cigar样本量最少(仅占 18.7%),且 bbox 最小(平均 12×9 像素),易被 loss 主导项忽略。我们在ultralytics/utils/loss.py中修改DetectionLoss:

# utils/loss.py 第 189 行,compute_loss 函数内 # 原 loss_cls = self.bce(cls, tcls) # 二分类交叉熵 # 替换为: alpha = torch.tensor([0.8, 0.8, 1.2], device=cls.device) # mouth_cigar 类别权重 +20% focal_weight = (1 - cls.softmax(dim=1)) ** 2 # focal loss gamma=2 loss_cls = self.bce(cls, tcls) * focal_weight * alpha[tcls.long()]

效果:mouth_cigar的 AP50 从 52.1% → 59.7%,整体 mAP50 提升 1.4%。血泪经验:alpha值必须手动调参——设为[0.5,0.5,2.0]会导致cigar_litrecall 暴跌,因 loss 过度倾斜;设为[1.0,1.0,1.3]提升不明显。最终[0.8,0.8,1.2]是在 val set 上 grid search 得到的 Pareto 最优解。


4. 避坑指南:五个真实踩过的坑,现象、原因、解决方案全写清楚

4.1 现象:训练 loss 曲线在 epoch 30 后突然飙升 5 倍,val mAP 不升反降

原因:raw_frames/中部分图像(共 17 张)EXIF 里Orientation=6(顺时针旋转 90°),但images/目录未按 EXIF 自动旋转,导致这些图实际是竖构图,而 YOLO 训练时仍当横构图处理,bbox 坐标错位。
解决:运行以下脚本批量修正(用PIL.ImageOps.exif_transpose):

from PIL import Image import os for root, _, files in os.walk("images"): for f in files: if f.lower().endswith(('.jpg', '.jpeg')): path = os.path.join(root, f) try: img = Image.open(path) img = ImageOps.exif_transpose(img) # 自动按 EXIF 旋转 img.save(path, quality=95, optimize=True) except Exception as e: print(f"skip {path}: {e}")

4.2 现象:yolo predict输出的 bbox 全部偏右 200px,且 confidence 低于 0.1

原因:dataset.yaml中val:路径写成../images/val/(多了一个/),导致 loader 读取的是空目录,模型用train数据做 val,但 predict 时又用正确路径,造成 train/val/test 数据源不一致。
解决:检查dataset.yaml中所有路径末尾不能有/,正确写法是val: ../images/val。

4.3 现象:val时confusion_matrix.png中cigar_unlit类别全为 0,但results.csv显示其 AP=61.2

原因:ultralytics8.2.45 的confusion_matrix.py在计算 multi-class confusion matrix 时,对iou_thres=0.5下的 TP/FP/FN 统计逻辑有 bug——当某类别在某张图中无 GT,但 pred 有该类别框,该 pred 会被错误计入cigar_unlit的 FP,而非background。
解决:临时方案:在val命令后加--plots=False,用results.csv中的数值为准;长期方案:升级到8.2.52+(已修复)。

4.4 现象:mosaic=True时训练报错RuntimeError: CUDA error: device-side assert triggered

原因:Mosaic 增强中四张图拼接后,mouth_cigar的 bbox 坐标可能被映射到负值或 >1.0,触发clamp断言失败。
解决:在ultralytics/data/augment.py的Mosaic类__call__方法末尾添加坐标截断:

# augment.py 第 327 行后插入 labels[:, 1:] = labels[:, 1:].clip(0, 1) # 强制归一化坐标在 [0,1]

4.5 现象:test集上cigar_lit的 recall 仅 41.3%,远低于val的 72.6%

原因:test集包含大量隧道出口强光场景(raw_frames/中tunnel_exit_*.jpg),此时烟头高光过曝,RGB 值接近 [255,255,255],而 YOLOv8 默认 normalize 是x /= 255.0,导致该区域特征坍缩。
解决:在predict.py的preprocess函数中加入 CLAHE(限制对比度自适应直方图均衡):

import cv2 def preprocess(img): img = cv2.cvtColor(img, cv2.COLOR_RGB2LAB) clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) img[:,:,0] = clahe.apply(img[:,:,0]) img = cv2.cvtColor(img, cv2.COLOR_LAB2RGB) return img / 255.0

5. 模型部署与车载实测技巧:如何把 .pt 转 ONNX 再部署到 Jetson Orin,附 latency 测量脚本

5.1 .pt → ONNX 转换:必须指定dynamic_axes与opset_version=16

YOLOv8 导出 ONNX 时若不设dynamic_axes,会导致输入尺寸固定(如 1280×720),无法适配车载 DVR 的动态分辨率(720p/1080p/4K)。正确命令:

yolo export \ model=cigar_v8n_rect/weights/best.pt \ format=onnx \ imgsz=1280,720 \ dynamic=True \ simplify=True \ opset=16 \ batch=1

生成的best.onnx中,输入images的 shape 为[1,3,720,1280],但dynamic_axes已声明:

{ "images": { "0": "batch", "2": "height", "3": "width" } }

这意味着你可以用onnxruntime动态 reshape 输入:

import onnxruntime as ort sess = ort.InferenceSession("best.onnx") # 输入 1080p 图像 inp = cv2.resize(frame, (1920, 1080)).transpose(2,0,1)[None] # [1,3,1080,1920] out = sess.run(None, {"images": inp.astype(np.float32)})

注意:opset=16是必须的——Jetson Orin 的 TensorRT 8.6.1 仅支持 ONNX opset ≤16;若用opset=17,trtexec会报Unsupported opset version。

5.2 TensorRT 引擎构建:trtexec命令与关键参数含义

在 Jetson Orin 上构建引擎(假设已安装 TensorRT 8.6.1):

trtexec \ --onnx=best.onnx \ --saveEngine=best.engine \ --fp16 \ --workspace=2048 \ --minShapes='images:1x3x720x1280' \ --optShapes='images:1x3x1080x1920' \ --maxShapes='images:1x3x2160x3840' \ --shapes='images:1x3x1080x1920' \ --avgRuns=100 \ --duration=30
  • --fp16:启用半精度,Orin 上 latency 降低 37%(实测从 18.2ms → 11.4ms);
  • --minShapes/--optShapes/--maxShapes:定义动态维度范围。--optShapes是推理时最常用尺寸,TensorRT 会对此尺寸做最优 kernel 选择;
  • --workspace=2048:GPU 显存分配上限(MB),低于 1024 会导致某些 layer 无法使用优化 kernel;
  • --avgRuns=100:warmup 后连续运行 100 次取平均 latency,比单次更稳定。

5.3 车载实测 latency 测量脚本:排除 USB 传输与显示开销,只测纯推理

很多教程测的是cv2.imshow()+yolo predict总耗时,这包含了 USB 摄像头读取(~12ms)、OpenCV decode(~8ms)、GUI 渲染(~15ms)——这些与模型无关。真实推理 latency 应只测session.run():

import time import numpy as np import onnxruntime as ort sess = ort.InferenceSession("best.engine", providers=['CUDAExecutionProvider']) # 预热 for _ in range(10): dummy = np.random.rand(1,3,1080,1920).astype(np.float32) _ = sess.run(None, {"images": dummy}) # 正式测量 latencies = [] for _ in range(1000): frame = cv2.imread("sample.jpg") # 用固定图避免 IO 波动 inp = cv2.resize(frame, (1920,1080)).transpose(2,0,1)[None].astype(np.float32) start = time.perf_counter_ns() _ = sess.run(None, {"images": inp}) end = time.perf_counter_ns() latencies.append((end - start) / 1e6) # ms print(f"Median latency: {np.median(latencies):.2f} ms") print(f"P99 latency: {np.percentile(latencies, 99):.2f} ms")

实测 Orin(JTOP 稳定 30W)上best.engine的 median latency 为11.3ms(88.5 FPS),P99 为14.7ms,满足车载 DMS 系统 ≥30FPS 的硬性要求。

5.4 从那以后我每次部署车载模型,都强制走一遍「三阶验证」:先用onnx-checker验证图结构,再用trtexec --verbose看 kernel 编译日志,最后用nvtop监控 GPU utilization 是否 ≥92%——如果 utilization < 85%,说明 TensorRT 没跑满,大概率是--workspace设太小或--minShapes范围过窄。这套流程帮我避开了 7 次现场 demo 翻车,其中 3 次是客户车上 NVDEC 解码器抢占显存导致 inference stall,靠nvtop一眼定位。希望帮到你。

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

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

医学图像分割实战:UNet与ResUNet在BUSI数据集上的训练与网页部署

简介&#xff1a;面向医学图像分割学习与研究者的超声乳腺疾病分割项目&#xff0c;基于BUSI数据集&#xff0c;提供ResUNet与UNet两种分割网络并可自行切换&#xff0c;实测Dice约0.82。代码已划分训练集与验证集&#xff0c;支持一键运行&#xff1b;训练采用cos余弦退火学习…

作者头像 李华
网站建设 2026/10/2 9:26:29

SQL Sentry 2024安装注册实战:深入SQL Server内部监控

上线第二天凌晨&#xff0c;DBA 的手机被告警轮番轰炸。某个核心库的 CPU 冲上 90%&#xff0c;阻塞作业全部卡死&#xff0c;前一天还在正常执行的 TOP SQL 一夜之间变成了慢 SQL。可回头翻系统自带的管理平台&#xff0c;上面只显示“数据库正在运行”&#xff0c;事件日志也…

作者头像 李华
网站建设 2026/10/2 9:25:38

SpringBoot+Vue+MySQL:阳光音乐厅订票系统从零到部署完整实战

一到毕设季&#xff0c;总有学弟学妹跑来问我&#xff1a;有没有一个既不算太复杂、又能把前端后端技术全部串起来的项目&#xff1f;每次我都会把“阳光音乐厅订票系统”从仓库里翻出来当例子讲。这是一个用SpringBoot做后端、Vue做前端、MySQL存数据的完整票务管理平台&#…

作者头像 李华
网站建设 2026/10/2 9:25:37

分布式计算原理深入解析:HDFS、MapReduce与YARN核心机制

1. 先说清楚&#xff1a;为什么你必须懂分布式计算原理 大数据这个领域这些年的热度一直没降过&#xff0c;但说实话&#xff0c;我接触过不少入行两三年的工程师&#xff0c;你要问他 Hadoop 是什么&#xff0c;他能给你背出“分布式存储 分布式计算”这套标准答案&#xff0…

作者头像 李华
网站建设 2026/10/2 9:25:24

泰拉瑞亚iOS版本怎么选?国际版与国服版详细对比

最近不少朋友私信问我&#xff0c;App Store苹果版的泰拉瑞亚到底该下哪个。搜索“泰拉瑞亚”出来的是免费中文版&#xff0c;搜索“Terraria”出来的是一个标价的外语版&#xff0c;名字像、图标也像&#xff0c;价格却完全不同&#xff0c;确实很容易买错。这篇文章不打算讲太…

作者头像 李华
网站建设 2026/10/2 9:24:47

Java后端+Agent防幻觉实战:n8n确定性工作流让Token直降80%

1. 当Java后端遇上会"编故事"的Agent&#xff0c;问题到底出在哪 做Java后端的兄弟这两年应该都有同感&#xff1a;业务系统里一旦接入大模型Agent&#xff0c;最头疼的不是接口调不通&#xff0c;而是它"一本正经地胡说八道"。你问它订单状态&#xff0c;…

作者头像 李华