☰
安防异常行为检测:9100张YOLO格式数据集训练与调优实战
2026/9/30 9:13:19 网站建设 项目流程

1. 安防异常行为检测数据集的核心价值拆解

1.1 为什么9100张这个量级值得单独拿出来说

做安防监控方向的目标检测,绕不开的一个现实问题就是:公开数据集要么太小、要么场景太单一,要么标注质量参差不齐。9100张这个体量,放在通用目标检测领域(比如COCO的十几万张)里不算大,但放在异常行为检测这个垂直细分场景里,已经属于能撑起一次完整训练迭代的实用规模了。

我自己的经验是,异常行为检测的数据集有个很尴尬的特点——真实场景里异常事件本身就是低频的。你在一段监控视频里蹲守一整天,可能就出现几次翻越围栏、人员聚集、摔倒这类行为。这就导致两个后果:一是数据采集成本极高,二是正负样本极度不均衡。所以一个已经整理好、标注好的9100张数据集,省掉的不是标注那点时间,而是前期采集和筛选的巨大成本。

这个数据集的核心定位很明确:面向安防监控场景的异常行为目标检测,采用YOLO格式标注,可以直接喂给YOLOv5、YOLOv8乃至更新的YOLO系列模型进行训练。它解决的核心问题是——让做安防算法的人能快速验证自己的检测方案,而不用从零开始攒数据。

适合谁来用?三类人:一是做安防产品原型验证的算法工程师,二是研究异常行为检测的学生和科研人员,三是想快速上手YOLO实战、找一个真实场景练手的开发者。不管你是哪一类,这个数据集都能帮你跳过最枯燥的数据准备阶段。

1.2 异常行为检测和普通目标检测的本质区别

很多人第一次接触这个方向,会下意识地把它当成普通的目标检测任务——不就是框出人、框出物体吗?实际上差别很大。

普通目标检测检测的是静态类别,比如人、车、狗,这些类别的外观特征相对稳定,模型学的是"这个东西长什么样"。而异常行为检测检测的是行为状态,比如"攀爬""摔倒""聚集""徘徊",同一个人的不同姿态可能对应完全不同的类别,类间差异小、类内差异大。这就导致模型不能只靠外观特征,还得理解一定的空间关系和姿态信息。

举个具体的例子:一个人正常站立和一个人准备翻越围栏,在单帧图像里可能上半身姿态非常接近,区别在于身体和围栏的相对位置关系、腿部动作。这就要求标注的时候不能只框个人头了事,得把行为发生的区域框准。这也是为什么异常行为数据集对标注质量的要求比通用数据集高得多——框偏一点,模型学到的特征就完全跑偏了。

所以拿到这个数据集之后,第一件事不是急着跑训练,而是先抽样看标注框的粒度。如果标注框只框了人,那模型学到的就是"人在哪",而不是"人在干什么"。真正可用的异常行为数据集,标注框应该覆盖行为发生的核心区域。

2. YOLO格式数据集的结构与标注规范解析

2.1 目录结构长什么样

一个标准的YOLO格式数据集,目录结构通常是这样的:

dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yaml

images下面放图片,labels下面放同名的.txt标注文件。注意这里有个新手最容易踩的坑:图片和标注文件必须同名,只是扩展名不同。比如images/train/001.jpg对应的标注就是labels/train/001.txt。如果名字对不上,训练的时候模型会直接报"找不到标签"或者更隐蔽地跳过这些样本,你以为在训练,实际上有一半数据没被用上。

data.yaml是整个数据集的配置文件,内容一般长这样:

path: ./dataset train: images/train val: images/val test: images/test nc: 5 names: ['fall', 'climb', 'gather', 'loiter', 'normal']

nc是类别数,names是类别名称列表。这里要特别注意:names的顺序必须和标注文件里的类别索引严格对应。标注文件里写的0对应names列表的第一个元素,写1对应第二个,以此类推。如果顺序搞反了,模型会把摔倒识别成攀爬,而且训练loss看起来还挺正常,这种错误极难排查。

2.2 YOLO标注格式的坐标计算

YOLO的标注格式是归一化的中心点坐标加宽高,一行代表一个目标:

class_id center_x center_y width height

这四个坐标值都是相对于图片宽高的归一化值,范围在0到1之间。举个例子,一张1920x1080的图,某个目标的边界框左上角在(960, 540),宽400高300,那么:

  • center_x = (960 + 400/2) / 1920 = 1160/1920 ≈ 0.604
  • center_y = (540 + 300/2) / 1080 = 690/1080 ≈ 0.639
  • width = 400/1920 ≈ 0.208
  • height = 300/1080 ≈ 0.278

最终标注行就是:0 0.604 0.639 0.208 0.278

这个计算看着简单,但实际标注过程中最容易出问题的就是归一化。有些标注工具导出的时候用的是绝对坐标,有些用归一化坐标,混用就会导致框全部跑到图片外面去。我建议拿到数据集后先写个脚本抽查一批标注,把框画回图片上看一眼,确认坐标没问题再开始训练。

提示:如果发现标注框全部挤在图片左上角或者完全看不见,八成是归一化和绝对坐标搞混了,先检查这一步再排查其他问题。

2.3 类别定义与标注粒度的一致性

异常行为检测数据集最怕的一件事就是类别定义模糊。什么叫"聚集"?三个人算不算?五个人算不算?"徘徊"和"正常行走"的边界在哪?如果标注的时候没有统一标准,不同标注员对同一个场景的判断可能完全不一样,模型学到的就是一堆自相矛盾的样本。

拿到数据集后,建议先做一件事:每个类别随机抽20到30张图,看看标注框的粒度是否一致。重点看三个地方:一是同类行为的框选范围是否统一(有的框全身,有的只框上半身);二是边界样本的处理方式(比如一个人既在行走又在打电话,算哪个类);三是漏标和误标的情况。

如果发现标注粒度不一致,有两个处理思路。一是重新清洗,把不一致的样本剔除或者重新标注,这个成本高但效果最好。二是合并类别,把容易混淆的细分类别合并成一个大类,比如把"快速行走"和"奔跑"合并成"快速移动",降低标注歧义带来的影响。具体选哪个,取决于你的项目对细粒度识别的需求有多高。

3. 从零跑通YOLO训练的关键步骤

3.1 环境搭建与依赖安装

训练YOLO的环境搭建本身不复杂,但版本兼容性是最大的坑。我踩过最典型的一次是PyTorch版本和CUDA版本对不上,报了一堆看不懂的错,排查了半天才发现是版本问题。

推荐的环境组合(以YOLOv8为例):

# 创建虚拟环境 conda create -n yolo python=3.10 conda activate yolo # 安装PyTorch(根据你的CUDA版本选择) pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 安装ultralytics pip install ultralytics

装完之后一定要验证一下GPU是否可用:

import torch print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0))

如果is_available()返回False,别急着往下走,先把GPU问题解决。用CPU训练9100张图,一个epoch可能要跑几个小时,完全不具备可操作性。

注意:显卡显存建议8G起步。9100张图如果用YOLOv8m这个量级的模型,batch size设16,显存占用大概在6到8G。显存不够就把batch size调小,或者用YOLOv8n这种轻量模型先跑通流程。

3.2 数据划分与配置文件编写

9100张图不能全部拿来训练,得划分训练集、验证集和测试集。常见的比例是7:2:1或者8:1:1。异常行为检测这个场景,我建议用8:1:1,因为异常样本本身就少,训练集多留一点能提升模型对稀有类别的学习效果。

划分的时候有个细节要注意:同一个视频序列抽出来的帧不能同时出现在训练集和验证集里。如果监控视频是连续抽帧的,相邻帧之间几乎一模一样,把它们分到不同集合会导致验证集指标虚高,模型看起来表现很好,实际部署时一塌糊涂。正确的做法是按视频源划分,同一个视频的所有帧要么全在训练集,要么全在验证集。

data.yaml写完之后,可以用一行代码验证配置是否正确:

from ultralytics import YOLO model = YOLO('yolov8n.pt') model.train(data='data.yaml', epochs=1, imgsz=640)

先跑1个epoch看看能不能正常启动,能跑起来再正式训练。这一步能帮你提前发现路径错误、类别数不匹配等问题,省得训练到一半才报错。

3.3 训练参数的选择逻辑

训练参数没有万能配置,但有几个关键参数值得展开说。

imgsz(输入尺寸):默认640。安防监控场景里,异常行为往往发生在画面中远处,目标比较小。如果直接把640作为输入,小目标可能只有几十个像素,特征提取会很吃力。我的建议是先用640跑一版baseline,看看小目标的检测效果,如果召回率明显偏低,再考虑提升到960甚至1280。但要注意,输入尺寸翻倍,显存占用大概翻四倍,得看你的硬件扛不扛得住。

batch size:在显存允许的前提下尽量往大了设。batch size太小会导致BN层的统计量不稳定,训练过程震荡明显。如果显存不够,可以用梯度累积来模拟大batch的效果:

model.train(data='data.yaml', epochs=100, batch=8, accumulate=4)

这样等效于batch size 32。

epochs:9100张图,我一般先设100个epoch跑一版看看收敛情况。如果验证集loss还在下降,就继续加;如果已经平稳甚至反弹,说明过拟合了,该停了。配合patience参数可以自动早停:

model.train(data='data.yaml', epochs=200, patience=30)

意思是30个epoch内验证指标没有提升就自动停止。

学习率:YOLO默认用的是带warmup的余弦退火策略,初始学习率0.01。这个默认值在大多数场景下都能用,但如果你的数据集类别极度不均衡,可以适当调低到0.001,让模型学得更稳一些。

3.4 训练过程的监控与指标解读

训练启动后,终端会实时打印每个epoch的loss和指标。重点盯这几个:

  • box_loss:边界框回归损失,反映框得准不准
  • cls_loss:分类损失,反映类别判断对不对
  • dfl_loss:分布焦点损失(YOLOv8特有),影响框的精细程度
  • mAP50:IoU阈值0.5时的平均精度,最直观的指标
  • mAP50-95:IoU从0.5到0.95的平均精度,更严格

正常情况下,三个loss应该整体呈下降趋势,mAP50稳步上升。如果出现loss突然飙升或者变成NaN,大概率是学习率太大或者数据里有脏样本(比如标注框宽高为0)。这时候先检查数据,再考虑调学习率。

训练完成后,runs/detect/train/目录下会生成一堆可视化结果,其中results.png是最有用的,把loss和mAP曲线都画在一起了。confusion_matrix.png能看出哪些类别容易混淆,对后续优化很有指导意义。

4. 异常行为检测的实战调优经验

4.1 类别不均衡的处理策略

异常行为数据集几乎必然面临类别不均衡的问题。"正常"样本可能占70%以上,而某些异常行为只有几百张。直接训练的话,模型会倾向于把所有样本都预测成多数类,因为这样loss最低。

处理这个问题有几个层次的手段。最直接的是过采样,把稀有类别的样本复制多份,让各类别数量接近。但简单复制容易导致过拟合,更好的做法是配合数据增强,让每次看到的稀有样本都有细微差异。

YOLO本身支持通过数据增强来缓解不均衡,在训练配置里可以调整:

model.train( data='data.yaml', epochs=100, mosaic=1.0, # 马赛克增强,默认开启 mixup=0.1, # 混合增强 copy_paste=0.1, # 复制粘贴增强,对小目标特别有效 degrees=10.0, # 随机旋转 translate=0.1, # 随机平移 scale=0.5 # 随机缩放 )

copy_paste这个增强对小目标和稀有类别特别有用,它会把一个样本里的目标抠出来贴到另一个样本上,相当于凭空造出更多稀有类别的样本。

另一个手段是调整损失权重。YOLO的分类损失默认对所有类别一视同仁,可以通过自定义损失函数给稀有类别更高的权重。不过这个改动比较深,新手建议先用数据增强和过采样,效果不够再考虑改损失。

4.2 小目标检测的优化思路

安防监控的视角决定了画面里大部分目标都不大。一个1080P的监控画面,远处的人可能只有50x100像素。YOLO默认的检测头在P3、P4、P5三个尺度上做预测,P3负责小目标,但如果目标实在太小,P3也力不从心。

提升小目标检测效果,我试过比较有效的几个方法。一是提升输入分辨率,前面说过了,从640提到960或1280,小目标的像素数直接翻倍。二是增加P2检测层,在更浅的特征图上做预测,专门抓小目标。YOLOv8可以通过修改模型配置文件来加P2层,但会增加计算量。

三是用SAHI切片推理。这个方法的思路是把大图切成小块分别检测,再把结果拼回去。对于超大分辨率(比如4K)的监控画面特别有效。SAHI可以和YOLO无缝配合:

from sahi import AutoDetectionModel from sahi.predict import get_sliced_prediction detection_model = AutoDetectionModel.from_pretrained( model_type='yolov8', model_path='best.pt', confidence_threshold=0.3, device='cuda:0' ) result = get_sliced_prediction( 'test.jpg', detection_model, slice_height=640, slice_width=640, overlap_height_ratio=0.2, overlap_width_ratio=0.2 )

切片推理的代价是速度变慢,因为要对多个切片分别推理。如果对实时性要求高,得在精度和速度之间做权衡。

4.3 误报抑制与后处理技巧

异常行为检测在实际部署中,误报率往往比漏报率更让人头疼。监控画面里人来人往,模型很容易把正常行为误判成异常,导致安保人员被大量无效告警淹没。

降低误报有几个实用手段。一是提高置信度阈值,默认0.25可能太低,可以提到0.4甚至0.5。代价是漏报会增加,需要根据实际场景调。二是时序滤波,单帧检测结果不可靠,可以要求连续N帧都检测到同一异常才触发告警。这个逻辑需要在部署层面实现,不是模型本身能解决的。

三是基于规则的二次过滤。比如"聚集"这个类别,模型可能把三个人站在一起就判为聚集,但实际业务里可能要求五个人以上才算。这种业务规则可以在检测结果之上再加一层判断:

def filter_gather(detections, min_persons=5): persons = [d for d in detections if d['class'] == 'person'] if len(persons) >= min_persons: return True return False

这种规则过滤虽然简单,但在实际项目里非常有效,能把误报率降下来一大截。

5. 常见问题排查与避坑指南

5.1 训练不收敛的排查路径

训练不收敛是最高频的问题,表现是loss震荡、mAP不涨甚至下降。排查思路按优先级来:

排查项检查方法常见原因
数据标注可视化抽查标注框坐标归一化错误、类别索引错位
学习率看loss曲线是否震荡学习率过大
数据划分检查训练/验证集是否重叠同源帧泄漏导致指标虚高
类别配置核对data.yaml的nc和names类别数与标注不匹配
预训练权重确认是否加载了预训练模型从零训练收敛慢

我遇到最多的情况是标注问题。有一次训练loss一直不降,排查了半天发现是标注文件里有一批用了绝对坐标,框全部跑到图片外面去了。模型看到的是"图片里没有目标"但标注说有目标,自然学不会。所以训练前一定要可视化抽查标注,这一步花十分钟,能省掉后面几小时的无效训练。

5.2 显存溢出与训练中断的处理

显存溢出(OOM)报错很直接:CUDA out of memory。解决办法按代价从低到高:

  • 降低batch size,从16降到8甚至4
  • 降低imgsz,从640降到512
  • 换更小的模型,从YOLOv8m换到YOLOv8n
  • 开启混合精度训练,amp=True(YOLO默认开启)
  • 用梯度累积模拟大batch

如果训练跑到一半突然中断,先看是不是OOM。如果是,把batch size调小重新开始。注意YOLO默认会保存last.pt,可以用resume=True从中断处继续:

model.train(data='data.yaml', resume=True)

但resume有时候会有玄学问题,如果resume后指标异常,建议还是从头训练。

5.3 部署阶段的性能优化

模型训练好了,部署到实际监控系统里还有一堆坑。最典型的是速度问题——训练时用的是高端显卡,部署时可能是边缘设备,算力差了一大截。

优化推理速度的手段有几个。一是模型量化,把FP32转成FP16甚至INT8,速度能提升2到4倍,精度损失通常在1%以内。YOLO支持导出多种格式:

model.export(format='onnx', half=True) # FP16量化 model.export(format='engine', half=True) # TensorRT

TensorRT在NVIDIA设备上的加速效果最明显,但导出过程比较折腾,需要环境里装好TensorRT。

二是降低输入分辨率,推理时用比训练更小的尺寸,比如训练用640,推理用416。速度提升明显,但小目标检测效果会下降,需要实测权衡。

三是跳帧推理。监控视频通常是25或30帧每秒,异常行为不需要每帧都检测,可以每3帧或5帧推理一次,中间帧用跟踪算法补上。这样等效速度提升3到5倍,对实时性要求不极端的场景完全够用。

提示:部署前一定要在目标设备上实测推理速度,别只看训练机器上的表现。我见过太多在服务器上跑得飞起、一到边缘设备就卡成幻灯片的案例。

5.4 数据集扩展与持续迭代

9100张图能撑起第一版模型,但要让模型在实际场景里真正好用,持续迭代是必须的。迭代的核心是收集bad case——模型在实际运行中判错的样本,把它们标注好加进训练集,重新训练。

这个流程叫主动学习,具体操作是:部署模型后开启一个低置信度记录机制,把置信度在0.3到0.6之间的检测结果保存下来,定期人工审核,确认是误报还是漏报,然后针对性补充标注。这样每一轮迭代都能精准补上模型的短板,比盲目扩充数据效率高得多。

扩充数据的时候要注意保持类别平衡。如果只补误报样本,模型会越来越保守,漏报越来越多。正确的做法是误报和漏报样本都补,让模型在两个方向上同步优化。

另外,如果实际场景和训练数据分布差异大(比如训练用的是白天画面,部署场景有大量夜间画面),需要考虑做域适应。最简单的做法是直接采集目标场景的数据重新训练,复杂一点可以用风格迁移把白天数据转成夜间风格来扩充训练集。具体选哪种,看你的数据采集成本和项目周期。

6. 一些个人实操体会

这个数据集我前后跑过几轮,有几个体会比较深。第一是别迷信大模型。YOLOv8x听起来比YOLOv8n强很多,但在异常行为检测这个场景里,如果数据质量不行,大模型照样学不会,反而因为参数多更容易过拟合。我建议先用YOLOv8n或YOLOv8s跑通全流程,确认数据和标注没问题,再换大模型冲精度。

第二是验证集指标好看不代表实际好用。mAP50到0.9不代表部署后就没问题,因为验证集和真实场景的分布差异可能很大。真正靠谱的评估方式是拿一段实际监控视频跑一遍,人工看检测结果,统计误报和漏报。这个过程很枯燥,但比盯着mAP数字有用得多。

第三是标注质量决定上限。模型再先进,标注错了就是学错。9100张图如果标注质量高,YOLOv8n都能跑出不错的效果;如果标注乱七八糟,YOLOv8x也救不回来。所以拿到数据集的第一件事永远是抽查标注,而不是急着跑训练。

最后分享一个实用小技巧:训练的时候把save_period设成10,每10个epoch存一个checkpoint。这样如果发现某个中间epoch的模型在实际场景里表现更好,可以直接拿来用,不用重新训练。YOLO默认只存best和last,中间状态是丢掉的,设了save_period就能保留更多选择。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询