news 2026/10/6 5:45:02

吸烟检测YOLOv8训练全流程:数据清洗、格式转换与调参避坑

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
吸烟检测YOLOv8训练全流程:数据清洗、格式转换与调参避坑

简介:吸烟数据集带标注是一份面向人工智能与机器学习场景的监督学习数据集,主要服务于目标检测、图像分类等模型训练任务。包内含1567个文件,其中783个jpg图像与783个xml标注文件一一对应,xml采用通用标注格式记录吸烟目标类别与位置信息,可直接用于YOLO、Faster R-CNN等常见检测框架;另有1个txt文件用于归纳类别或说明。压缩包整体大小31.71MB,样本规模适中,适合入门练习与算法验证。数据特征覆盖个人信息、生活习惯、健康状况、社会经济状态与环境因素等多维度信息,样本已由专家或自动系统标记为吸烟者与非吸烟者,便于开展监督学习。目前已有159人学习下载,适合AI初学者、算法工程师及数据科学从业者用于吸烟行为识别、风险预测等方向的研究与实践,也可帮助开发者快速验证模型性能。

1. 拿到“吸烟数据集带标注”,先别急着开训:先确认这三件事

做禁烟场景的人,搜索“吸烟数据集带标注”,十有八九是要给摄像头后面的模型补粮草。把数据集解压之后,你会发现里面要么是 images 加 XML,要么是 images 加 TXT,运气好点还带一份 JSON。但带标注不等于能直接训练,这个标题里的“带标注”只是说明标注文件存在,没说明标注质量、格式和类别定义。拿到这份数据,先确认三件事:标注框住的是“烟体”还是“正在吸烟的人”,这两条路对应的模型行为完全不同;标注格式是 VOC、COCO 还是 YOLO TXT,决定你要不要写转换脚本;以及类别有没有统一,我见过一份数据里 smoking 和 cigarette 混着标,后面清洗花了两天。这篇笔记就把这三件事按实操顺序讲透:格式转换、目录组织、超参数、数据清洗、高频坑和上线前的调参。

2. 先看清标注格式:VOC、COCO 与 YOLO TXT 的差异和转换脚本

2.1 拿到目录结构,先判断是哪一种标注格式

解压数据集后,第一步不是打开图片看效果,而是扫一遍目录结构。标注格式决定了你后续要写多少转换代码,也决定了能不能直接丢给训练框架。常见的三种格式,判断方法都很直接。

第一种是 Pascal VOC,典型特征是每张图片对应一个同名 XML 文件,XML 里有<object>节点,节点下是<name>和<bndbox>,<bndbox>里是xmin、ymin、xmax、ymax四个整数像素坐标。第二种是 COCO,整个数据集打包成一个annotations.json,里面categories数组定义类别,annotations数组记录每个框的bbox和area。第三种是 YOLO TXT,每张图对应一个同名 txt,每行五个数字:类别ID cx cy w h,中心点和宽高都归一化到 0 到 1 之间的小数。

判断方法不需要打开文件,直接在终端里数文件就行。如果 XML 文件数量等于图片数量,大概率是 VOC;如果只有一个 JSON 文件,是 COCO;如果 txt 数量和图片数量一致,且每行都是五个小数,那就是 YOLO 格式。这里有一个很容易踩的坑:COCO 的bbox是x, y, width, height的绝对值,而 YOLO 的cx, cy, width, height是归一化相对值,转换时容易把坐标原点搞混。另一个坑是类别 ID 的顺序,YOLO txt 里的0到底对应cigarette还是smoking,完全取决于你训练时 yaml 文件里的names列表顺序,和 XML 里的类别字符串没有半毛钱关系。

还有一个值得注意的点:看 txt 里数值的范围。如果 txt 里出现0.5 0.5 0.02 0.02这种小数值,是归一化后的 YOLO 格式;如果出现234 567 12 34这种大整数,大概率是某种不规范的自定义格式,需要先查清楚坐标是不是像素值。我自己习惯先跑一个统计脚本,把每张图的框坐标范围、框数量、宽高比都打出来,一眼就能看出格式和数据质量问题。

2.2 把 VOC XML 批量转成 YOLO TXT:一份可以抄的 Python 脚本

如果数据集是 VOC 格式,而你又打算用 YOLOv8 或 YOLO11 训练,转换脚本绕不开。这里的转换逻辑不复杂:从 XML 读出像素坐标,算出中心点坐标和宽高,再分别除以图片宽高做归一化。需要注意两个细节:一是 XML 里的坐标可能越界,裁剪到图片尺寸范围内再算;二是类别名称必须映射到训练时定义的 ID,一个字符都不能错。

import os import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, out_path, classes): tree = ET.parse(xml_path) root = tree.getroot() # 读取图片宽高,用于归一化 size_node = root.find('size') img_w = int(size_node.find('width').text) img_h = int(size_node.find('height').text) lines = [] for obj in root.iter('object'): name = obj.find('name').text if name not in classes: continue class_id = classes.index(name) 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) # 防止坐标越界,把框裁剪回图片范围内 xmin = max(0, min(xmin, img_w)) xmax = max(0, min(xmax, img_w)) ymin = max(0, min(ymin, img_h)) ymax = max(0, min(ymax, img_h)) box_w = xmax - xmin box_h = ymax - ymin cx = (xmin + xmax) / 2 / img_w cy = (ymin + ymax) / 2 / img_h n_w = box_w / img_w n_h = box_h / img_h lines.append(f"{class_id} {cx:.6f} {cy:.6f} {n_w:.6f} {n_h:.6f}") if lines: with open(out_path, 'w') as f: f.write('\n'.join(lines))

脚本的核心逻辑是:遍历 XML 里的每个object,跳过不在classes列表里的类别,把像素坐标转成归一化坐标,最后写入 txt。参数里最关键的是classes这个列表,它的顺序必须和你后续训练 yaml 里的names顺序一致。比如classes = ['cigarette', 'smoking'],那 ID 0 就是 cigarette,ID 1 就是 smoking。顺序搞反了,训练出来的模型输出的类别标签就是反的,查错会查到你怀疑人生。

批量调用的时候,要注意源目录和目标目录的对应关系。常见做法是保持相对路径一致,比如把datasets/voc/images下的每张图对应的 XML 转换成datasets/yolo/labels下的 txt。转换完成后务必抽查 5 到 10 个 txt,用一个可视化脚本把框画回图片上,确认框位置没有发生平移或拉伸。这一步看着笨,但能救回你后面几天的训练时间。

2.3 标注类别只有一类怎么办:用标注工具补样本

很多吸烟数据集的类别定义只有一条,比如只有smoking一类,框住的是完整的人或人的上半身。这种标注策略有一个结构性问题:模型学到的是“人的姿态”而不是“烟”。当你部署到真实场景,只要有人把手抬到嘴边,哪怕手里拿的是笔,也会被误判成吸烟。更麻烦的是,smoking框住整个人时,正样本的尺寸和位置变化极大,模型要花大量参数去拟合人体形状,留给烟体细节的容量就少了。

常见做法是拆成两类:cigarette框住烟体,smoking框住吸烟行为,或者干脆只保留cigarette。如果你拿到的数据集只有一类,就需要自己补标一部分。标注工具我一般用 CVAT 和 X-AnyLabeling,两个都是开源工具。CVAT 适合需要多人协作、按团队流程管理的场景,导出格式可以直接选 YOLO 或 Pascal VOC;X-AnyLabeling 更轻,适合单机快速补几百张,它能直接加载 YOLO 格式目录,标注完保存就是 txt,省去二次转换。

补标时记住一个原则:标注烟体时宁缺毋滥。烟体被手遮挡超过一半、模糊到人眼都看不清、或者距离远到只有十几个像素,这些都不要标。标注框的噪声比漏标更伤训练,模型会被部分遮挡的框带着走,学到错误的中心点。另外,如果数据集里本身没有负样本图片,也就是完全没有烟的正常场景,你需要单独准备一个negative目录放背景图。这个目录不需要标注文件,但要在训练配置里作为背景来源参与训练,否则模型在真实场景里的误检率会非常难看。

3. 用 YOLOv8 训练自己的吸烟数据集:目录结构、配置与超参数

3.1 数据集目录怎么摆:train/val 分离和 names 顺序的坑

格式转换完了,下一步是把数据集整理成 YOLOv8 能直接识别的目录结构。这个结构有两套方案,我推荐用带images和labels双目录的方案,因为它的路径清晰,也符合大多数开源项目的惯例。结构长这样:

datasets/smoking/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/

关键是images/train和labels/train下的文件名必须完全一致,YOLO 训练时按文件名前缀去找标签文件。如果文件名对不上,训练日志里会刷一堆警告,但不会报错终止,最后你会发现某个类别一个框都没参与训练。整理目录时用脚本批量重命名,不要手动拖文件。

然后写smoking.yaml配置文件,这是训练时的入口。常见错误是把路径写成绝对路径,换台机器就废了。我一般用相对path加train/val子路径的组合,训练时只要在数据集根目录下执行命令,路径就一定能对上。配置文件内容如下:

# smoking.yaml path: . # 相对于当前工作目录 train: images/train # 训练图片目录 val: images/val # 验证图片目录 names: 0: cigarette 1: smoking

names的顺序就是类别 ID 的映射表。前面 VOC 转换时classes的顺序,必须和这里的names顺序一致,否则标签错位。还有一个容易被忽略的细节:YOLO 格式的 txt 文件里不能有空行,也不能有多余空格,某些标注工具导出的 txt 会在末尾带一个空行,训练时虽然不报错,但会影响数据加载效率。清洗阶段顺手把空行去掉,后面会省很多事。

3.2 训练命令与四个必调参数:imgsz、batch、epochs、patience

目录和配置就绪后,训练命令本身不复杂。需要根据显卡显存和场景特点调整几个关键超参数。我用的是 YOLOv8 官方训练命令,模型用yolov8s作为起点,在标注质量和数据量都一般的情况下,s 级模型已经能覆盖大多数禁烟监控场景,没必要一上来就跑 x 级,训练时间成倍增加,精度提升却有限。

yolo detect train \ data=smoking.yaml \ model=yolov8s.pt \ epochs=120 \ imgsz=960 \ batch=16 \ patience=30 \ device=0

四个参数里,imgsz对吸烟检测的影响最大。烟体在监控画面里经常只有几十个像素,imgsz=640是 YOLO 默认值,但对小目标不友好。我一般起步就设960,显存足够的话可以试1024。代价是训练时间和显存占用上升,batch=16在 12GB 显存显卡上跑 960 分辨率基本是极限。

epochs设多少要看数据量。几千张图的数据集 100 到 120 轮足够收敛,patience=30表示验证集连续 30 轮指标不提升就提前终止。这个参数能避免过拟合,同时省时间。如果你发现训练在 80 轮就自己停了,也不用急着加 epochs,先去看验证集的 loss 是不是已经平稳。

batch如果调到训练卡顿或显存溢出,最简单的做法是减半。小 batch 在 BN 层统计上噪声大,但配合小学习率也能训出不错的结果。还有一个超参数容易被忽略,就是mosaic增强。YOLOv8 默认开启 mosaic,吸烟检测里烟体本来就小,mosaic 把四张图拼在一起后,烟体可能被裁掉一半或缩成一个点,反而干扰学习。训练到后半程我习惯把 mosaic 关掉或者降到 0.5,让模型在正常尺度下精调几轮。

3.3 训练完先别看 mAP:先看混淆矩阵和 F1-confidence 曲线

训练结束后,很多人第一件事是打开终端看 mAP 数值,这是一个习惯性错误。mAP 是一个聚合指标,它掩盖了类别间的差距。吸烟检测通常只有两三个类别,更应该看results/confusion_matrix.png和results/F1_curve.png。

混淆矩阵能告诉你每一类被误分成了什么。比如cigarette有一批框被分到了background,说明烟体特征不够强,可能需要更高输入分辨率,或者标注框里混入了大量半截烟;如果smoking被误分成cigarette,说明两类框的空间关系重叠严重,模型没能区分“烟体”和“吸烟行为”。

F1-confidence 曲线更实用,它能直接指导你部署时的置信度阈值。横轴是置信度,纵轴是 F1 分数,曲线最高点对应的阈值就是当前模型在训练集上的理论最优阈值。这个值后面部署时直接写进后处理代码。另外,打开results.csv,看最后一列metrics/precision(B)和metrics/recall(B)的差距。如果 precision 0.9 但 recall 只有 0.6,说明模型漏检多,宁可置信度调低一点,先保召回;反过来 recall 高 precision 低,就要拉高置信度,减少误报。实际禁烟场景里,误报比漏报更容易让人烦躁,因为你不想每天收到几百条对着水杯报警的消息。

4. 吸烟数据清洗四道工序:去重、查漏、调分布、补小目标

4.1 去重:用感知哈希把同一镜头的重复帧挑出来

吸烟数据集里有大量从监控视频抽帧得到的图片,连续帧之间内容高度相似。如果这些相似帧同时出现在训练集里,模型会对这个固定场景过拟合,验证集上指标虚高,换一个现场就失效。去重最实用的方法是感知哈希。

import os import imagehash from PIL import Image folder = 'datasets/smoking/images/train' seen = {} for filename in os.listdir(folder): path = os.path.join(folder, filename) try: img = Image.open(path) except Exception: continue h = imagehash.phash(img) for old_h, old_name in seen.items(): if h - old_h <= 8: print(f'duplicate: {filename} vs {old_name}') break else: seen[h] = filename

感知哈希的原理是把图片缩成固定大小的灰度图,计算像素均值后生成一串二值指纹,汉明距离越小说明图片越相似。这里阈值取8,能过滤掉同一镜头下的细微运动差异,又不会把光照变化大的不同场景误判为重复。跑完脚本后,把输出结果里成对出现的文件手动确认一遍,删除其中一张。

注意事项:数据集如果是按视频抽帧得到的,不要只做一层去重。抽帧间隔本身要检查,如果每隔 1 帧抽一张,即使感知哈希阈值调到 5,重复率依然很高。常见做法是先按时间轴每 N 帧取一张,再做哈希去重,双保险。

4.2 查漏标:统计每张图的框数,找出“应该有很多目标却只标了一个”的图

漏标问题在吸烟数据集里太常见了。一张多人聚会的照片里,三个人在抽烟,标注员只框了一个人手里的烟;或者远背景模糊处的烟头根本没标。模型看到标注过的正样本学出了特征,同一张图上没标注的目标就成了隐性的负样本,训练时会被当作背景,逻辑上直接把模型搞混乱。

查漏标靠肉眼逐张看太慢,先写一个统计脚本,把异常样本筛出来再人工复查。

import os for split in ['train', 'val']: img_dir = f'datasets/smoking/images/{split}' label_dir = f'datasets/smoking/labels/{split}' for name in os.listdir(img_dir): stem = os.path.splitext(name)[0] txt = os.path.join(label_dir, stem + '.txt') if not os.path.exists(txt) or os.path.getsize(txt) == 0: print(f'no label: {split}/{name}') continue with open(txt) as f: lines = [line.strip() for line in f if line.strip()] # 单张图框数异常,大概率是漏标或合并框 if len(lines) == 1: print(f'single box: {split}/{name}') if len(lines) > 20: print(f'many boxes: {split}/{name}, {len(lines)}')

脚本会打印两类文件:没有标注文件的图片,和只有单个框的图片。没有标注文件的情况,直接删图或者补标;单个框的情况需要人工打开图片确认,如果图里有好几个人但只标了一个框,这就是典型漏标。框数大于 20 的图片通常有几个目标被合并成了一个框,也需要打开看。

另外,检查一下 txt 里的归一化数值是否异常。比如宽度n_w小于 0.001,那是一个只有几个像素的噪声框,这种框会让模型去拟合噪声,建议过滤掉。取值范围超出[0, 1]的框更直接,说明转换脚本有 bug,回头查一下 2.2 里的xmin/xmax数值类型是不是被处理成了字符串拼接。

4.3 调分布:白天/黑夜、室内/室外都要有,别让模型只认识监控室

数据量上去了,分布不合理一样白搭。吸烟检测最常见的失败场景是:训练数据全来自某写字楼走廊的白天监控,结果模型拿到傍晚的食堂门口,检测率直接掉一半。光照、背景、距离、姿态四个维度,任何一个出现分布倾斜,模型就会学到偏置,而不是学到“烟”这个物体本身。

清洗阶段可以按下面这个表检查覆盖面。它不是硬性指标,而是在你决定要不要补数据时的一个对照:

维度覆盖场景经验建议
光照白天、黄昏、夜间、逆光每个大项至少 20% 的样本
背景室内、室外、车窗内、工地至少 4 种不同背景
距离近景、中景、远景近景和远景各留一批,避免全集中在中景
姿态夹烟、叼烟、弹烟灰、打电话时夹烟尽量多覆盖,姿态越丰富越好

如果你手里的数据集在黑夜场景几乎为空,有两个快速补法。一个是用公开的夜间吸烟视频抽帧,手工标注几十张就够启动;另一个是用图像增强工具把白天样本做色彩变换,模拟黄昏和夜间效果,包括降低亮度、加蓝色色偏。注意增强补出来的样本只能当辅助,不能全信,模型对真实夜间烟火点的敏感度还得靠真样本验证。

4.4 补小目标:烟体在画面里往往只有 20 像素,切图或 mosaic 增强

在 YOLO 模型中,输入图片要经过 32 倍的下采样,一个 20 像素的烟体,在深层特征图上只剩不到 1 个像素,几乎没有特征可言。这就是为什么很多模型在 mAP 上表现不错,一到实际远距离场景就漏检。

应对小目标的第一招是提高输入分辨率,imgsz=960或1024都值得试。第二招是切图。把 1920×1080 的监控帧切成四块 960×540 的图,每块单独推理,再按坐标映射回原图。切图推理时注意重叠区域,避免目标被切成两半而漏检,I OU 合并策略用 0.3 左右的重叠比较稳妥。SAHI 这类库就是干这个的,省得自己写坐标映射。

训练阶段的 mosaic 增强对小目标的效果要辩证看。它能把小目标和其他背景拼在一起,增加小目标的训练曝光次数,但切得太碎也会丢目标。我的习惯是前 80 轮开 mosaic,最后 20 轮关掉,让模型用完整的单图精调。同时把小目标样本的标注筛一遍,框尺寸小于三四个像素的直接删掉,这种标注即使保留也是噪声。

5. 吸烟检测训练避坑:五个高频问题,现象、原因、解决

5.1 坑一:电子烟、烟头、未点燃的烟全部漏检

现象:训练时模型 val 集 mAP 不错,部署后遇到有人抽电子烟,模型完全没反应;遇到会议桌上放着一根未点燃的烟,或烟灰缸里立着一根烟头,误检率反而飙升。

原因:数据集里绝大多数正样本是“点燃状态的白烟”,有烟灰、火星点、烟缕这些强视觉特征。电子烟没有烟灰和火星点,外形更像一支金属笔;未点燃的烟和烟头则特征微弱,尤其是烟头,高光反射后看起来像一个白色小方块。模型学到的是点亮状态的模板,而不是“烟形物体”的泛化特征。

解决:拆场景补样本。电子烟单独建立一个类别或者作为负样本,如果你的业务明确要求识别电子烟,至少补 500 张不同角度、不同光照的电子烟图;如果只识别传统卷烟,就把电子烟图放到负样本目录,让模型学会把它们归为背景。未点燃的烟和烟头,需要人工标注一批放在cigarette类别里,让模型明白没有火星点的烟也是烟。补样后重新训练时,建议把验证集里也加入等比例的这些难样本,否则你根本不知道改进有没有生效。

5.2 坑二:小目标在特征图上下采样后被“吞掉”

现象:近景测试全部通过,人离摄像头超过 8 米,烟体缩小到 30 像素以内,模型开始断断续续地漏检。单独剪出烟体的图片拿去推理,却能检测出来。

原因:前面提过的下采样问题,加上标注框太小导致正样本在ignore区域。YOLO 在计算损失时,会忽略某些小框或让它们不参与损失计算,默认配置下小目标的梯度贡献本来就弱。你单独剪图检测时,烟体已经被放大到几百个像素,当然能检出。

解决:最直接的是提高imgsz,配合切图推理。我一般把训练分辨率提到 960,训练完成后部署阶段再叠加切图逻辑。还有一个容易被忽略的参数,anchor相关配置,YOLOv8 已经自动学习 anchor,不需要手调,但如果你用的是 YOLOv5,必须确认小目标的 anchor 预设没有被裁剪。另外,在损失函数里可以考虑给小目标更高的权重,但这属于进阶调参,性价比不如切图来得快。

5.3 坑三:误检棒棒糖、铅笔和手指

现象:模型把叼在嘴边的棒棒糖、夹在指间的白色铅笔,甚至一根弯曲的手指,都当成香烟框了出来。置信度还不低,能到 0.6 以上。

原因:数据集中缺少“看起来像烟但不是烟”的负样本。棒棒糖的白棒和白色烟体外形高度相似,铅笔更是圆柱体加上深色笔芯,和香烟的横截面特征接近。模型在训练时没见过这些负样本,它的决策边界会无限制地扩到所有“细长白色物体”上。

解决:负样本策略要刻进工作流。整理一个negative目录,放上大量正常手势、持笔、持棒棒糖、喝水等场景图片,不需要标注文件,但要在训练数据配置里让模型看到它们。另一个办法是在类别里加一个other类,把误检对象框出来标成other,让模型学会区分。加了负样本后,重点看验证集上cigarette类别的 precision 是否提升,如果只提升了 recall 而 precision 没动,说明误检还是压在背后。

5.4 坑四:标注框漂移导致训练震荡

现象:训练 loss 曲线上下波动,val mAP 在 60 到 70 之间徘徊,怎么调超参都上不去。打开预测结果看,框总是偏左或偏右半个烟身。

原因:标注框本身没有对准烟体中心。很多标注员习惯用框包住“烟加手指”,框的中心点落在手指上,而不是烟体上。YOLO 的回归目标预测的是框中心偏移,中心点噪声会把学习方向带偏。加上烟体细长,框的宽高比和真实目标差距大,模型对边界回归的置信度自然低。

解决:清洗阶段用可视化工具把标注框画出来,逐张抽查中心点是否落在烟体上。发现问题重新标注,不要手动改 txt 里的数值。如果标注资源有限,至少把那些框宽高比大于 5 的异常框挑出来复查,这类框通常包含了手指或手掌。还有一个兜底方案:训练时用更强的数据增强,比如degrees=10和translate=0.1,让模型对轻微位置偏移更鲁棒,但这只能缓解,治不了根。

5.5 坑五:验证集泄露,val 曲线好看,现场一测就翻车

现象:训练时验证集 mAP 到 0.9,部署到现场实测,召回率直接腰斩。很多人第一反应是环境差异大,其实是数据划分出了问题。

原因:如果数据集来自连续视频抽帧,随机划分 train/val 时,同一段视频的相邻帧可能一边在训练集、一边在验证集。模型见过验证集里的画面,相当于开卷考试,分数自然虚高。更隐蔽的是,同一摄像头拍摄的不同时间段画面,背景相同、机位相同,只是人物和动作不同,随机划分也会让验证集包含训练集同场景的“影子”。

解决:划分数据前,按视频片段分组。同一段视频的所有帧必须放在同一个集里,绝不能跨集。如果数据集没有原始视频信息,可以按文件名前缀分组,监控视频抽帧通常文件名带时间戳或摄像头 ID,先按摄像头 ID 划分,再按时间段划分。划分完成后做个交叉验证,用训练集里拉出的样本和验证集算一下特征相似度,相似度太高就要调整划分粒度。这个坑不解决,后面所有调参都是在自欺欺人。

6. 模型上线前最后一调:NMS 阈值、置信度阈值与热力图验证

训练完不是终点,部署后能不能在实际场景里稳跑,最后一段调参决定了体验。先说 NMS 阈值。YOLO 默认的 IOU 阈值在 0.45 左右,适合目标稀疏的场景。吸烟检测里经常几个人并排站在一起,多个候选框叠在同一目标上,IOU 阈值设太低会把重复框都放出来;反过来,远距离小目标之间重叠很小,NMS 容易保留多个框,这时候把 IOU 阈值调到 0.6 到 0.7 能有效合并重复检测。我实际项目中一般会跑两组对比测试,一组 0.5,一组 0.65,看哪组在测试视频上的“框数量抖动”更小。

置信度阈值不要凭感觉拍,直接用训练时的F1_curve.png找最高点。YOLOv8 训练完后会在runs/detect/train目录下生成一组曲线图,F1_curve横坐标是置信度,纵坐标是 F1,曲线最高点对应的阈值就是理论最优。真实部署时还要结合业务取舍:禁烟告警场景容忍误报,阈值可以比理论值低 0.05 到 0.1,增加召回;如果告警会直接触发人工处理,阈值就调高一点,减少无效工单。

热力图验证是我保留的最后一个习惯。用 Grad-CAM 风格的工具跑几张典型测试图,看模型关注的热区是不是落在烟体上。如果热区覆盖了手指而没有烟,说明模型学到的还是“手部姿态”,数据策略需要往烟体细节上压。这个步骤不用每次训练都做,模型结构或数据集有重大调整时跑一轮就够。我自己的经验是,模型上限在数据不在结构,网络结构怎么换都只是锦上添花。标注质量差的吸烟数据集,YOLOv8s 和 YOLOv8x 的精度差不了几个点,但清洗过后的数据集,哪怕用轻量模型也能稳稳超过别人没洗过的重模型。希望帮到你。

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

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

旅游记录与分享APP:Android Studio原生开发实战

简介&#xff1a;这套基于Android Studio开发的旅游记录与分享APP源码&#xff0c;面向Android开发者、毕业设计学生及移动应用学习人群&#xff0c;完整实现了路线规划、位置追踪、日志记录、社交分享等核心功能闭环。项目整合Google Maps API地图集成、GPS实时定位、SQLite数…

作者头像 李华
网站建设 2026/10/6 5:43:35

跨客户端AI记忆共享系统的自研实践:从mem0对比到混合检索落地

先交代背景。我一直在做 AI 辅助日常工作的落地&#xff0c;桌面端、Web 端、手机端、编辑器插件轮着用。用了半年多&#xff0c;最烦的一个问题就是&#xff1a;同一个 AI 服务&#xff0c;在这个客户端里聊过的上下文&#xff0c;换到另一个客户端就全断了。比如我在电脑上让…

作者头像 李华
网站建设 2026/10/6 5:41:22

电气控制三图协同解读:原理图、布置图、接线图实战指南

1. 为什么这三张图是电气控制电路的“通关密钥”&#xff1f;干了十多年电气设计、调试和培训&#xff0c;我见过太多人卡在同一个地方&#xff1a;图纸看得懂字&#xff0c;却看不懂逻辑&#xff1b;元件认得全&#xff0c;一上手就接错线&#xff1b;老师傅讲半天&#xff0c…

作者头像 李华
网站建设 2026/10/6 5:41:22

电气控制三图原理:原理图、布置图、接线图协同解析

1. 为什么这三张图是电气控制电路的“通关密钥”干了十多年电气设计、调试和培训&#xff0c;我见过太多人卡在同一个地方&#xff1a;图纸看得懂字&#xff0c;却看不懂逻辑&#xff1b;元件认得全&#xff0c;一上手就接错线&#xff1b;PLC程序写得飞起&#xff0c;现场一通…

作者头像 李华
网站建设 2026/10/6 5:40:10

3D像素艺术轮廓线:先像素化再做边缘检测的稳定方案

我在给一个3D像素风项目做美术升级时&#xff0c;第一次认真研究"轮廓线"这件事。当时项目里所有角色和场景都是方块堆出来的体素风格&#xff0c;光照和贴图都调得差不多了&#xff0c;但整体画面总觉得"散的慌"&#xff0c;角色和背景糊在一起&#xff0…

作者头像 李华
网站建设 2026/10/6 5:39:40

基于机器学习的Webshell检测:从特征工程到生产部署实践

简介&#xff1a;面向信息安全方向的毕业设计/课设项目&#xff0c;围绕 PHP Webshell 检测开展完整机器学习实践&#xff1a;涵盖黑白样本采集、特征工程、多种算法训练与对比&#xff08;随机森林、XGBoost、K-近邻、决策树&#xff09;&#xff0c;并通过网格搜索与交叉验证…

作者头像 李华