尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于YOLO的安防异常行为检测:9100张真实监控数据集训练与部署全流程

基于YOLO的安防异常行为检测:9100张真实监控数据集训练与部署全流程 1. 安防场景下的异常行为检测这个数据集到底能干什么安防监控这个领域做算法的人都有一个共同的痛点公开数据集太干净了。学术数据集里的人物姿态标准、光照均匀、背景简洁模型跑出来的mAP漂亮得不行一上真实场景就拉胯。我前两年接手过一个园区安防的项目用COCO预训练的YOLO直接推理结果摄像头装在高处俯拍人在画面里只有几十个像素模型连人都框不准更别提判断行为了。这次拿到的这个数据集9100张YOLO格式的安防监控图像核心价值就在于它贴近真实监控场景。它不是那种摆拍式的学术数据而是包含了监控视角下的人体目标、异常行为标注。你可以用它来训练一个能识别摔倒、攀爬、徘徊、聚集、闯入等异常行为的检测模型也可以单纯当作一个监控视角下的人体检测数据集来用。适合谁来参考如果你正在做以下事情这个数据集值得花时间研究安防算法工程师需要快速验证异常行为检测的baseline计算机视觉方向的学生想做一个落地的目标检测项目嵌入式部署方向的开发者需要监控场景的数据来测试模型在边缘设备上的表现想学习YOLO训练全流程的新手需要一个真实场景的数据集来练手我拿到数据集之后第一件事不是直接开训而是先做数据探查。这个习惯救过我很多次——曾经有个项目标注文件里的类别索引和data.yaml对不上白跑了两天训练。所以下面我会从数据集的解构开始一步步拆到训练、调优、部署把整个链路讲透。2. 数据集解构与训练前的关键检查2.1 YOLO格式标注的目录结构与字段含义YOLO格式的数据集标准结构是这样的dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yaml每张图片对应一个同名的.txt标注文件每行代表一个目标框格式为class_id center_x center_y width height这里有个新手最容易踩的坑所有坐标都是归一化到0到1之间的不是像素值。比如一张1920x1080的图一个人体框在像素坐标下是(960, 540, 200, 400)归一化后就是0 0.5 0.5 0.104 0.370计算方式很简单center_x 960/1920 0.5width 200/1920 0.104。我见过有人直接把像素坐标写进标注文件训练loss直接爆炸排查了半天才发现是格式问题。9100张图的数据集如果按7:2:1划分大概是6370张训练、1820张验证、910张测试。但具体划分要看数据集本身的组织方式有些数据集已经预分好了你直接用就行。2.2 数据探查训练前必须做的三件事第一件事类别分布统计。写个脚本统计每个类别的标注数量import os from collections import Counter label_dir dataset/labels/train counter Counter() for txt_file in os.listdir(label_dir): if txt_file.endswith(.txt): with open(os.path.join(label_dir, txt_file), r) as f: for line in f: class_id int(line.strip().split()[0]) counter[class_id] 1 print(类别分布, dict(sorted(counter.items())))如果发现某个类别的样本数只有几十个而其他类别有几千个那就要考虑类别不平衡的问题了。安防场景下摔倒这种异常行为的样本天然就少这是正常的但训练时需要做处理。第二件事可视化抽查。随机抽20张图把标注框画上去看看import cv2 import random def visualize_annotation(img_path, label_path): img cv2.imread(img_path) h, w img.shape[:2] with open(label_path, r) as f: for line in f: cls, cx, cy, bw, bh map(float, line.strip().split()) x1 int((cx - bw/2) * w) y1 int((cy - bh/2) * h) x2 int((cx bw/2) * w) y2 int((cy bh/2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) return img这一步的目的是检查标注质量。我遇到过标注框偏移、漏标、错标的情况如果不提前发现模型学到的就是错误的信息。第三件事检查图片尺寸分布。监控摄像头的分辨率五花八门有1080P的、有720P的、还有D1分辨率的。统计一下尺寸分布决定训练时的输入分辨率。from PIL import Image import os sizes [] for img_file in os.listdir(dataset/images/train): img Image.open(os.path.join(dataset/images/train, img_file)) sizes.append(img.size) from collections import Counter print(Counter(sizes).most_common(10))注意如果图片尺寸差异很大建议统一resize到640x640再训练。YOLO系列默认输入就是640这个分辨率在精度和速度之间取得了不错的平衡。2.3 data.yaml的正确写法与常见错误data.yaml是YOLO训练的核心配置文件格式如下path: /home/user/dataset train: images/train val: images/val test: images/test nc: 5 names: 0: person 1: fall 2: climb 3: loiter 4: intrusion这里有几个容易出错的地方path必须是绝对路径或者相对于训练脚本运行目录的路径。我建议用绝对路径省得后面找不到文件。nc是类别数量必须和names的长度一致。names的索引必须从0开始且和标注文件里的class_id对应。有个朋友曾经把nc写成6但names只列了5个类别训练的时候直接报索引越界的错误。这种低级错误看起来可笑但赶项目的时候真的会发生。3. YOLO模型选型与训练策略设计3.1 从YOLOv5到YOLOv8安防场景该选哪个版本YOLO系列发展到现在版本多得让人眼花缭乱。我按实际项目经验给个选型建议版本优势劣势适用场景YOLOv5生态成熟文档丰富部署工具链完善精度相对落后快速验证、嵌入式部署YOLOv7精度高训练策略先进代码结构较复杂对精度要求高的场景YOLOv8精度和速度均衡API简洁部分部署工具链还在完善新项目首选YOLOv9/v10最新架构精度领先生态不够成熟研究性质的项目对于安防异常行为检测这个场景我的建议是如果追求快速落地选YOLOv8n或YOLOv8s如果追求极致精度选YOLOv8m或YOLOv7。为什么安防场景通常需要实时推理模型不能太大。YOLOv8n只有300万参数在V100上跑640x640的图batch size 1的情况下能到300FPS完全满足实时性要求。而且YOLOv8的ultralytics库封装得非常好几行代码就能完成训练和推理。3.2 预训练权重的选择与迁移学习策略千万不要从零开始训练。除非你有几十万张标注数据否则从零训练的效果一定不如用预训练权重做迁移学习。YOLOv8的预训练权重在COCO数据集上训练过已经学到了通用的特征提取能力。COCO里有人这个类别和安防场景下的人体检测有很强的相关性。所以from ultralytics import YOLO # 加载预训练权重 model YOLO(yolov8s.pt) # 开始训练 model.train( datadata.yaml, epochs100, imgsz640, batch16, device0, workers4, patience20, lr00.01, lrf0.01, momentum0.937, weight_decay0.0005, warmup_epochs3, augmentTrue, cacheTrue )这里解释几个关键参数epochs1009100张图的数据集100轮足够了。如果验证集loss在20轮内没有下降patience20会自动停止训练。batch16根据显存调整。V100 32G显存跑YOLOv8sbatch可以开到32甚至64。lr00.01初始学习率。迁移学习时这个值比较合适如果loss震荡厉害可以降到0.001。cacheTrue把图片缓存到内存加速训练。9100张图大概占几个G内存如果内存够大就开着。3.3 数据增强安防场景的针对性策略YOLOv8默认开启了Mosaic、MixUp、HSV增强等策略。但安防场景有它的特殊性需要针对性调整Mosaic增强把4张图拼成1张增加小目标检测能力。安防场景下人体目标通常较小这个增强很有用保持默认开启。HSV增强调整色调、饱和度、亮度。监控画面在不同光照条件下差异很大白天、夜晚、逆光、阴影这个增强能提升模型的鲁棒性。建议把hsv_h调到0.02hsv_s调到0.8hsv_v调到0.5。随机翻转安防场景下人体左右翻转是合理的但上下翻转不合理人不会倒着走。所以flipud0.0fliplr0.5。随机裁剪监控画面中人体通常不在画面正中央随机裁剪能模拟这种偏移。但裁剪比例不要太大否则会把目标裁掉。model.train( ... hsv_h0.02, hsv_s0.8, hsv_v0.5, flipud0.0, fliplr0.5, mosaic1.0, mixup0.1, scale0.5, translate0.1 )实操心得数据增强不是越多越好。我曾经把MixUp开到0.5结果模型收敛极慢验证集精度反而下降了。后来降到0.1效果就正常了。增强策略要根据数据集大小来定数据少就多增强数据多就少增强。4. 训练过程监控与调优实战4.1 训练日志解读loss曲线告诉你的真相YOLOv8训练时会输出三个lossbox_loss、cls_loss、dfl_loss。box_loss边界框回归损失衡量预测框和真实框的差距cls_loss分类损失衡量类别预测的准确度dfl_loss分布焦点损失YOLOv8特有的用于优化边界框的分布正常的训练曲线应该是三个loss都稳步下降最后趋于平稳。如果出现以下情况就要注意了情况一box_loss下降但cls_loss不降。说明模型能定位到目标但分不清类别。可能原因是类别不平衡或者某些类别的特征太相似。解决办法是检查标注质量或者给稀有类别加权。情况二loss震荡剧烈。学习率太大了。把lr0降到0.001试试或者开启余弦退火调度。情况三验证集loss先降后升。过拟合了。增加数据增强、加Dropout、或者减少模型参数量。我习惯用TensorBoard或者WandB来监控训练过程model.train( ... projectsecurity_detection, nameyolov8s_exp1, plotsTrue )训练完成后runs/detect/security_detection/yolov8s_exp1/目录下会有loss曲线图、混淆矩阵、PR曲线等这些图能直观反映模型的训练情况。4.2 学习率调度与超参数调优YOLOv8默认使用线性预热余弦退火的学习率调度。前3个epoch是预热阶段学习率从0线性增加到lr0然后按余弦函数逐渐降低到lrf * lr0。这套策略在大多数情况下都work但安防场景可以微调如果数据集较小比如只有几千张把warmup_epochs增加到5让模型更平稳地进入训练状态。如果发现模型在后期震荡把lrf从0.01降到0.005让学习率降得更低。momentum保持0.937这是经过大量实验验证的值。weight_decay保持0.0005防止过拟合。有个技巧是用YOLOv8自带的超参数搜索功能model.tune( datadata.yaml, epochs50, iterations30, optimizerAdamW, plotsTrue )它会自动搜索最优的学习率、动量、权重衰减等参数。但这个过程很耗时30次迭代可能要跑好几天。建议在项目时间充裕的情况下使用。4.3 类别不平衡的处理方案安防异常行为检测中摔倒、攀爬这些异常行为的样本通常远少于正常行走。如果直接训练模型会偏向于预测多数类导致异常行为的召回率很低。方案一过采样。把稀有类别的图片复制多份让各类别样本数接近。缺点是容易过拟合。方案二focal loss。YOLOv8默认用的是BCE loss可以改成focal loss让模型更关注难分类的样本。但YOLOv8没有直接暴露这个接口需要改源码。方案三类别权重。在计算loss时给稀有类别更高的权重。这个最实用# 在data.yaml同级目录下创建weights.yaml # 或者在训练时通过回调函数修改实操心得我试过最简单有效的方法是分层采样。在构建DataLoader时保证每个batch里稀有类别的样本占比不低于某个阈值。这样不用改loss函数也能缓解类别不平衡的问题。5. 模型评估与部署落地5.1 安防场景该看哪些评估指标mAPmean Average Precision是目标检测的通用指标但安防场景不能只看mAP。mAP0.5IoU阈值为0.5时的平均精度。这个指标比较宽松适合评估模型的整体检测能力。mAP0.5:0.95IoU阈值从0.5到0.95步长0.05取平均。这个指标更严格反映模型的定位精度。召回率Recall安防场景最看重的指标。漏检一个异常行为可能意味着一次安全事故。所以召回率比精确率更重要。误报率False Positive Rate安防场景下误报太多安保人员会疲于奔命最后干脆忽略报警。所以要在保证召回率的前提下尽量降低误报率。我通常这样评估模型metrics model.val( datadata.yaml, splitval, conf0.25, iou0.5 ) print(fmAP0.5: {metrics.box.map50}) print(fmAP0.5:0.95: {metrics.box.map}) print(f各类别AP: {metrics.box.ap})然后根据业务需求调整置信度阈值。如果业务要求高召回率就把conf降到0.1如果要求低误报率就把conf提高到0.5。5.2 模型导出与推理加速训练好的模型需要导出成部署格式。YOLOv8支持多种导出格式# 导出ONNX model.export(formatonnx, opset12, simplifyTrue) # 导出TensorRT model.export(formatengine, halfTrue, device0) # 导出OpenVINO model.export(formatopenvino, halfTrue)ONNX通用性最好几乎所有的推理框架都支持。适合跨平台部署。TensorRTNVIDIA GPU上的推理加速神器。FP16精度下推理速度能提升2-3倍。但只能在NVIDIA设备上用。OpenVINOIntel CPU和集成显卡上的推理加速方案。适合没有独立GPU的边缘设备。我实测过YOLOv8s在V100上的推理速度格式精度推理时间640x640PyTorchFP328msONNXFP326msTensorRTFP163msTensorRTINT81.5msINT8量化需要校准数据集精度会有一定下降但速度提升明显。如果对精度要求不是极致INT8是边缘部署的首选。5.3 边缘设备部署的实操要点安防摄像头通常搭配边缘计算盒子比如Jetson Nano、Jetson Xavier NX、RK3588等。这些设备的算力有限部署时要注意第一模型要小。YOLOv8n是最低要求YOLOv8s在Jetson Xavier NX上能跑到30FPS左右YOLOv8m就只能到15FPS了。第二输入分辨率要降。640x640在边缘设备上可能跑不动可以降到416x416甚至320x320。精度会下降但速度能提升一倍。第三用TensorRT加速。Jetson系列对TensorRT的支持很好导出engine文件后推理速度能提升2-3倍。第四多线程处理。视频解码、预处理、推理、后处理可以放在不同的线程里用流水线的方式并行处理提升整体吞吐量。import tensorrt as trt import pycuda.driver as cuda import pycuda.autoinit # TensorRT推理示例 def infer(engine_path, input_image): # 加载engine with open(engine_path, rb) as f: engine_data f.read() runtime trt.Runtime(trt.Logger(trt.Logger.WARNING)) engine runtime.deserialize_cuda_engine(engine_data) # 创建执行上下文 context engine.create_execution_context() # 分配显存 # ... 省略具体代码 # 执行推理 context.execute_v2(bindings) return output注意TensorRT的版本兼容性很坑。训练时的CUDA版本、TensorRT版本、部署时的版本必须匹配否则engine文件加载会失败。我建议在部署设备上直接导出engine而不是在训练服务器上导出后再拷贝。6. 常见问题与排查技巧实录6.1 训练不收敛的排查清单现象可能原因排查方法解决方案loss为nan学习率太大检查lr0降到0.001或更低loss不下降标注格式错误可视化标注修正标注文件loss震荡batch size太小检查显存占用增大batch或降低lr验证集loss上升过拟合对比训练/验证曲线增加增强、减少epochmAP为0类别索引不匹配检查data.yaml修正nc和names6.2 推理时检测框偏移或漏检的处理检测框偏移通常是预处理和后处理不一致导致的。训练时图片resize到640x640推理时也要做同样的resize。如果推理时用了letterbox后处理时要把框映射回原图坐标。漏检可能原因有几种。一是置信度阈值太高降到0.1试试。二是NMS的IoU阈值太高密集场景下框被抑制了把iou降到0.5。三是模型本身能力不足需要更多数据或更大的模型。误检监控画面中的树影、灯光、旗帜等容易被误检为人。解决办法是在训练数据中加入这些负样本让模型学会区分。6.3 模型部署后的性能优化技巧批处理如果边缘设备需要同时处理多路视频可以把多帧拼成一个batch一起推理提升GPU利用率。异步推理用CUDA Stream实现异步推理让数据拷贝和计算重叠减少等待时间。模型剪枝去掉模型中不重要的通道减小模型体积和计算量。YOLOv8可以用torch-pruning库做剪枝。知识蒸馏用大模型教师指导小模型学生训练让小模型获得接近大模型的精度。YOLOv8的官方仓库里有蒸馏的示例代码。我在实际项目中的体会是部署阶段的优化80%的收益来自TensorRT和FP16量化剩下20%来自模型剪枝和蒸馏。所以优先把TensorRT跑通再考虑其他优化手段。6.4 数据集扩展与持续迭代策略9100张图的数据集对于安防异常行为检测来说规模不算大。如果实际场景中误报漏报较多需要持续收集数据来迭代模型。主动学习让模型对未标注的数据做推理挑出置信度低或不确定的样本人工标注后加入训练集。这样能用最少的标注成本获得最大的精度提升。难例挖掘把误报和漏报的样本单独拿出来分析原因针对性地补充数据。数据合成用3D渲染或GAN生成合成数据扩充稀有类别的样本。但合成数据和真实数据有domain gap需要做domain adaptation。实操心得我做过一个项目初始模型在测试集上mAP0.5是0.85但上线后误报率很高。后来把误报的样本收集起来重新标注加入训练集迭代了3轮之后误报率下降了60%。数据迭代比模型调参更重要这是我在多个项目中反复验证的结论。最后再分享一个小技巧训练YOLO的时候把save_period设成10每10个epoch保存一次权重。这样如果训练中途崩溃不至于从头再来。而且可以对比不同epoch的权重在验证集上的表现有时候最佳模型并不是最后一个epoch的。
返回列表