ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于YOLOv5的灯光检测自训练数据全流程:从tfevents日志解析到模型部署

基于YOLOv5的灯光检测自训练数据全流程:从tfevents日志解析到模型部署 简介这份资源面向计算机视觉入门与进阶开发者提供一套基于YOLOv5的灯光检测自训练数据与工程代码可用于自动驾驶、安防监控、无人机导航等场景下的灯光目标识别与定位练习。压缩包共1580个文件约603.83MB其中696张jpg图像与18张png构成训练与验证样本630个txt为标注文件65个yaml与14个yml负责数据集与模型配置54个py脚本和15个pt权重支撑训练、推理与微调流程另有sh、md、xml、mp4等辅助文件覆盖数据采集、标注、增强到模型训练的完整链路。资源还包含TensorBoard事件日志便于复盘训练过程与调参思路。目前已有252人学习下载适合希望掌握YOLOv5自定义数据集训练、灯光检测任务落地及模型微调技巧的读者参考实践。1. 灯光检测自训练数据从 tfevents 日志到 YOLOv5 可复现流程手里拿到一份灯光检测的训练产物目录里躺着events.out.tfevents.1619227857.DESKTOP-24QA30N.9876.0这类 TensorBoard 事件文件还有2.0、2.4.1、0.11.0几个版本号标记第一反应往往是「这堆东西到底能不能直接拿来接着训」。答案是能但前提是你得先搞清楚这些 tfevents 记录的是哪一轮、哪个模型规模、对应哪份数据配置。灯光检测这个任务本身不复杂难的是自训练数据的闭环——采集、标注、增强、训练、验证每一步都会在日志里留下痕迹而 YOLOv5 恰好是把这条链路串起来最顺手的框架之一。这篇笔记面向的是手里已经有部分训练产物、想接着往下做或者想复现一套灯光检测流程的从业者新手能照着步骤走熟手能直接看参数边界和踩坑点。2. 灯光检测任务拆解YOLOv5 选型与自训练数据准备2.1 为什么灯光检测优先考虑 YOLOv5 而不是其他检测器灯光检测的本质是「小目标 高对比度 类别少」的目标检测问题。路灯、车灯、室内照明这类目标在图像里往往只占几十个像素但亮度和颜色特征非常突出。YOLOv5 在这个场景下的优势不是精度天花板最高而是「训练快、部署轻、调参直观」。它的 anchor 机制对中小目标友好配合--img-size放大输入分辨率后小灯光的召回率能明显拉起来。对比几个常见选择Faster R-CNN 精度稳但推理慢不适合实时灯光检测DETR 系列需要更长的训练周期和更多数据YOLOv8 虽然更新但如果你手里的历史产物是 YOLOv5 的 tfevents强行迁移反而增加变量。常见做法是先用 YOLOv5s 跑通全流程确认数据标注质量没问题再考虑换更大模型或者升级版本。选型确定后真正决定效果的是数据。自训练数据的核心不是「多」而是「覆盖场景」。灯光检测至少要覆盖白天逆光、夜晚强光、雨天反光、隧道明暗交替这四类环境。每类场景至少 200 张有效标注图否则模型很容易在某一类上翻车。2.2 从 tfevents 反推训练配置日志里到底记了什么events.out.tfevents是 TensorBoard 的事件文件YOLOv5 训练时默认写到runs/train/exp目录下。文件名里的DESKTOP-24QA30N是主机名后面那串数字是进程 ID 和时间戳。你拿到的这几个文件时间戳从1619227857到1619330590跨度大约 28 小时说明至少跑了不止一轮。想从这些日志里恢复出训练配置最直接的方式是用 TensorBoard 加载# 把 tfevents 所在目录挂到 TensorBoard 上 tensorboard --logdir runs/train --port 6006 # 如果目录结构混乱可以指定单个文件所在文件夹 tensorboard --logdir ./logs/exp1 --port 6007启动后在浏览器打开对应端口重点看几个曲线train/box_loss、train/obj_loss、metrics/mAP_0.5、metrics/precision、metrics/recall。如果obj_loss一直不降大概率是标注框有问题如果mAP在某个 epoch 后突然掉下去通常是学习率或数据增强参数过激。日志里看不到的东西——比如具体用的哪个data.yaml、--img-size设了多少、--batch-size是多少——需要结合opt.yaml或者hyp.yaml来确认。YOLOv5 每次训练都会在 exp 目录下存一份opt.yaml里面记录了完整的命令行参数。如果这份文件丢了只能靠 tfevents 里的曲线形态去猜这就很被动了。提示拿到别人的训练产物第一件事是找opt.yaml和hyp.yaml没有这两个文件复现基本靠运气。2.3 自训练数据标注规范灯光检测的四个标注边界灯光检测的标注有几个容易扯皮的地方提前定好规则能省掉大量返工。第一灯光边界怎么框。路灯的光晕是渐变的框太紧会丢掉边缘框太松会把背景吃进去。我一般会框到「肉眼能明确识别为灯源」的范围光晕部分不纳入。如果灯源本身被遮挡只标注可见部分不要脑补完整形状。第二多灯重叠怎么处理。车灯组、路灯阵列这类场景如果两个灯源在图像上明显分离就分别标注如果已经糊成一团合并成一个框类别取主要的那一类。第三类别定义要克制。灯光检测常见类别就分「路灯」「车灯」「室内灯」「信号灯」四类不要一上来就分十几类。类别越多每类的样本量越少模型越难收敛。第四负样本要专门收集。没有灯光的夜景、反光地面、月亮这些容易被误检的图要单独放一批作为背景负样本比例大概占总数据的 5% 到 10%。标注格式用 YOLO 的 txt 格式每行class_id x_center y_center width height坐标全部归一化到 0 到 1 之间。转换脚本网上很多但建议自己写一遍方便加校验逻辑import os from PIL import Image def convert_to_yolo(label_path, img_path, class_map): 把自定义标注转成 YOLO 格式带边界校验 img Image.open(img_path) w, h img.size lines [] with open(label_path, r) as f: for line in f: cls_name, x1, y1, x2, y2 line.strip().split() # 校验坐标是否越界 x1, y1, x2, y2 max(0, float(x1)), max(0, float(y1)), min(w, float(x2)), min(h, float(y2)) if x2 x1 or y2 y1: print(f跳过无效框: {label_path}) continue xc (x1 x2) / 2 / w yc (y1 y2) / 2 / h bw (x2 - x1) / w bh (y2 - y1) / h lines.append(f{class_map[cls_name]} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}) return lines这段代码的关键在坐标裁剪和无效框过滤。实际标注数据里经常出现框超出图像边界的情况不处理的话训练时会被 YOLOv5 的 dataloader 直接丢掉导致某些图实际参与训练的框比标注的少模型学到的信息就残缺了。2.4 数据增强参数怎么设灯光检测的 hyp 配置YOLOv5 的数据增强参数集中在data/hyps/hyp.scratch-low.yaml里。灯光检测场景下有几个参数需要特别调整参数默认值灯光检测建议值原因hsv_v0.40.3亮度扰动太强会让灯源过曝或消失hsv_s0.70.5饱和度变化过大会改变灯光颜色特征degrees0.05.0轻微旋转提升对倾斜灯杆的适应translate0.10.15灯光位置分布广平移增强有帮助mosaic1.00.8mosaic 太强会让小灯光在拼接图里更难学mixup0.00.1少量 mixup 提升抗遮挡能力这些值不是拍脑袋定的是拿几轮实验对比出来的。hsv_v从 0.4 降到 0.3 之后夜晚场景的漏检率大概降了两个点。mosaic从 1.0 降到 0.8小目标的 AP 反而涨了因为拼接图里灯光目标被缩得更小模型学起来更吃力。改完 hyp 文件后训练命令里用--hyp指定python train.py \ --img 640 \ --batch 16 \ --epochs 100 \ --data data/light.yaml \ --weights yolov5s.pt \ --hyp data/hyps/hyp.light.yaml \ --name light_exp--img 640是起点如果灯光目标普遍小于 32x32 像素建议提到 1280但显存占用会翻倍batch 要相应降到 8 或 4。--weights用预训练权重比从头训收敛快很多灯光检测这种类别少的任务预训练权重的迁移效果很明显。3. 训练过程监控与 tfevents 日志分析实战3.1 用 TensorBoard 定位训练异常三条曲线定生死训练跑起来之后TensorBoard 是你唯一能实时看到模型状态的地方。灯光检测任务里我重点盯三条曲线第一条是train/obj_loss。这条线反映模型对「这里有没有目标」的判断能力。正常情况是前 10 个 epoch 快速下降之后缓慢收敛。如果它一直在高位震荡先检查标注文件里有没有空 txt再检查data.yaml里的nc和类别名是否对得上。第二条是metrics/mAP_0.5。灯光检测的 mAP 通常在前 30 个 epoch 就能到 0.7 以上如果 50 个 epoch 还在 0.3 以下大概率是数据问题而不是模型问题。这时候别急着调参回去看标注。第三条是val/box_loss和train/box_loss的差值。如果验证集 loss 明显高于训练集说明过拟合了需要加数据或者加增强。如果两者都高那是欠拟合检查学习率和模型规模。# 训练过程中实时查看日志尾部 tail -f runs/train/light_exp/results.txt # 训练结束后用 results.csv 画图 python -c import pandas as pd df pd.read_csv(runs/train/light_exp/results.csv) df.columns df.columns.str.strip() print(df[[epoch, metrics/mAP_0.5, metrics/precision, metrics/recall]].tail(10)) results.csv是 YOLOv5 训练结束后自动生成的每行一个 epoch列名带空格读的时候要strip()一下。看最后 10 行的 precision 和 recall 是否平衡如果 precision 高 recall 低说明模型太保守可以适当降低置信度阈值反过来则是模型太激进需要提高阈值。3.2 从 tfevents 恢复中断的训练断点续训的坑训练跑到一半机器断电或者显存爆了想接着上次的权重继续训YOLOv5 支持--resume参数。但这里有个坑--resume依赖last.pt和opt.yaml同时存在而且opt.yaml里的路径必须和当前环境一致。# 标准续训命令 python train.py --resume runs/train/light_exp/weights/last.pt # 如果 opt.yaml 路径失效手动指定关键参数 python train.py \ --resume runs/train/light_exp/weights/last.pt \ --data data/light.yaml \ --epochs 100 \ --img 640如果last.pt损坏或者丢失只能从best.pt重新开始但best.pt不包含优化器状态相当于用预训练权重重新训学习率调度会重置。这时候建议把初始学习率调低一点比如从 0.01 降到 0.005避免把已经学好的特征打乱。tfevents 文件本身不能直接用来续训它只是记录曲线不包含模型权重。但你可以通过 tfevents 里的 epoch 数判断上次跑到哪了然后决定这次从哪个权重接着跑。3.3 灯光检测的验证集构建别拿训练集当验证集自训练数据最容易犯的错误是训练集和验证集来自同一批采集数据。灯光检测场景下如果训练集全是白天路灯验证集也是白天路灯mAP 会很好看但模型一到夜晚就瞎。验证集必须覆盖训练集没有的场景哪怕只有几十张。我一般按「采集批次」划分而不是随机划分。比如今天拍的路灯放训练集明天拍的路灯放验证集这样能真实反映模型在新数据上的表现。如果数据量实在少至少保证验证集里有 20% 的夜晚图和 10% 的逆光图。import os import random import shutil def split_by_scene(img_dir, label_dir, val_ratio0.2): 按场景文件夹划分训练集和验证集 scenes os.listdir(img_dir) for scene in scenes: scene_imgs os.listdir(os.path.join(img_dir, scene)) random.shuffle(scene_imgs) val_count max(1, int(len(scene_imgs) * val_ratio)) for i, img_name in enumerate(scene_imgs): src_img os.path.join(img_dir, scene, img_name) src_label os.path.join(label_dir, scene, img_name.replace(.jpg, .txt)) if i val_count: dst datasets/val else: dst datasets/train shutil.copy(src_img, os.path.join(dst, images)) if os.path.exists(src_label): shutil.copy(src_label, os.path.join(dst, labels))这段脚本按场景文件夹划分保证每个场景都有图进验证集。val_ratio0.2是经验值数据量少于 500 张时可以降到 0.1但不能再低了否则验证指标波动太大没法判断模型好坏。4. 避坑与排查灯光检测自训练数据的五个血泪教训4.1 现象mAP 一直上不去obj_loss 不降原因标注文件里有大量空 txt 或者坐标全为 0 的无效框。YOLOv5 的 dataloader 遇到无效框会跳过导致某些图实际参与训练的框数为零模型把这些图当成纯背景学但验证时又期望它们有输出。解决训练前跑一遍标注校验脚本统计每张图的框数和坐标范围。空 txt 要么补标要么从训练集里删掉。坐标全为 0 的框直接过滤。# 快速统计空标注文件 find datasets/train/labels -name *.txt -empty | wc -l # 统计框数少于 1 的文件 for f in datasets/train/labels/*.txt; do count$(grep -c . $f) if [ $count -lt 1 ]; then echo $f; fi done4.2 现象夜晚灯光漏检严重白天正常原因训练集里夜晚样本太少或者hsv_v增强参数把夜晚图的亮度扰动到模型学不到稳定特征。灯光检测的夜晚场景和白天场景差异极大模型需要足够的夜晚样本才能泛化。解决单独收集一批夜晚灯光图至少 300 张加入训练集。同时把hsv_v从 0.4 降到 0.25 到 0.3 之间减少亮度扰动。如果夜晚图还是不够可以用--img 1280放大输入让小灯光在特征图上占更多像素。4.3 现象验证集 mAP 很高实际部署漏检多原因验证集和训练集同分布模型只是在「背答案」。灯光检测的实际场景比验证集复杂得多比如雨夜反光、隧道出口强光这些情况验证集里根本没有。解决重新划分验证集确保验证集包含训练集没有的场景类型。如果数据量允许单独留一个「测试集」只在最终评估时用一次平时不参与任何调参。4.4 现象训练到一半 loss 突然变成 nan原因学习率太高或者某批数据里有异常值。灯光检测里常见的是标注框宽高为 0计算 loss 时除零导致 nan。解决先把学习率降到 0.001 以下试一轮。如果还是 nan用脚本过滤掉宽高小于 2 像素的框。YOLOv5 的--hyp里有个fl_gamma参数设成 1.5 可以缓解异常 loss 的影响。4.5 现象tfevents 文件打不开或者曲线空白原因TensorBoard 版本和 tfevents 写入时的版本不兼容或者文件被截断。你拿到的2.0、2.4.1、0.11.0这几个版本号如果和当前环境的 TensorBoard 版本差距太大可能读不出来。解决用tensorboard --logdir时加--reload_multifiletrue或者升级 TensorBoard 到 2.4 以上。如果文件确实损坏只能从results.csv里恢复曲线数据tfevents 本身没有修复价值。5. 进阶技巧用 tfevents 反推最优 epoch 与模型导出验证训练跑完不是终点从 tfevents 里还能挖出一个关键信息哪个 epoch 的模型最适合部署。results.csv里记录了每个 epoch 的 mAP但 mAP 最高的 epoch 不一定是最适合部署的因为还要看模型大小和推理速度。我一般会做一张「epoch-mAP-模型大小」对照表选 mAP 在峰值 95% 以上、epoch 数最小的那个权重。比如第 60 个 epoch mAP 是 0.82第 80 个 epoch 是 0.83那就选第 60 个因为后面 20 个 epoch 只涨了 0.01但模型可能过拟合了。import pandas as pd df pd.read_csv(runs/train/light_exp/results.csv) df.columns df.columns.str.strip() best_map df[metrics/mAP_0.5].max() # 找 mAP 达到峰值 95% 的最早 epoch threshold best_map * 0.95 candidates df[df[metrics/mAP_0.5] threshold] best_epoch candidates[epoch].min() print(f峰值 mAP: {best_map:.4f}, 推荐 epoch: {best_epoch})选好 epoch 后从weights/目录里找到对应的epoch_{n}.pt导出 ONNX 做部署验证python export.py \ --weights runs/train/light_exp/weights/epoch_60.pt \ --include onnx \ --img 640 \ --batch 1导出后拿几张实际场景图跑一遍推理重点看夜晚和逆光场景的漏检情况。如果 ONNX 推理结果和 PyTorch 推理结果差异大检查--img和--batch是否和训练时一致。灯光检测的输入分辨率对结果影响很大训练用 640 导出用 1280框的位置会偏。还有一个容易忽略的点tfevents 里记录的metrics/mAP_0.5是在验证集上算的验证集的置信度阈值默认是 0.001实际部署时阈值通常设 0.25 到 0.5。所以 mAP 高不代表实际漏检少一定要用部署阈值重新跑一遍验证集看 precision 和 recall 的平衡点在哪。从那以后我每次拿到新的训练产物都强制走一遍「tfevents 看曲线 → results.csv 选 epoch → ONNX 导出验证 → 实际场景抽检」这四步少一步都可能把有问题的模型推上线。希望帮到你。本文还有配套的精品资源点击获取
返回列表