YOLOv5异常行为检测毕设资源包:从环境到调参全解析

发布时间:2026/10/13 20:01:35
YOLOv5异常行为检测毕设资源包:从环境到调参全解析
简介基于YOLOv5的异常行为检测本科毕业设计完整实战资料面向计算机专业学生、毕业设计开发者及目标检测入门者。资源提供从环境搭建到模型训练、推理验证的全流程内容适合用于课程设计、毕设答辩准备或作为工程项目参考。压缩包共212个文件以105个yaml配置、45个Python脚本、20张jpg图片样本及md/txt说明文档为主体整体仅2.81MB结构紧凑、便于下载与二次开发。已有637人学习使用。资料中包含容器化部署配置、交互式教程笔记、真实场景检测样例以及带标签与不带标签的Mosaic数据增强对比图可帮助读者直观理解YOLOv5预处理流程与检测效果。训练脚本与配置项按模块划分依赖关系清晰便于定位和修改。文档细节较完整代码注释与目录结构清楚既能支撑本科毕业设计的完整复现也可为后续算法改进与工程落地提供参考。1. YOLOv5异常行为检测这个毕设资源包不只是一个模型上一届答辩现场某同学调的检测模型在演示时忽然崩了起因是换了台电脑后 torch 和 CUDA 版本对不上整个环境重装了三个小时。做毕业设计、课程设计或者计算机专业的课程作业最怕的不是模型不收敛而是环境跑不通、数据没查过、效果没法复现。这份基于 YOLOv5 的异常行为检测毕设资源打包的是一整套工程外壳而不只是一个权重文件里面有 Dockerfile 负责固化环境setup.cfg 锁定依赖tutorial.ipynb 做交互式教程还有 bus.jpg 和两张 mosaic 增强对比图用于自检。它能帮你把「模型能跑」变成「演示能过、代码可复现、答辩有逻辑」。下面按工程落地的顺序拆开讲。2. 环境构建与工程结构从 Dockerfile 到 tutorial.ipynb 的完整闭环先看工程外壳是因为在我修过的大量毕设项目里异常行为检测翻车的第一现场几乎都在环境torch 版本不兼容、opencv 装错渠道、权重文件路径写死。代码本身反而问题不大。这个资源包把环境相关的文件放在显眼位置说明它在设计时就考虑了「换机器可复现」这件事。2.1 文件清单与工程骨架这几个文件各管一段压缩包解压后目录结构不算复杂但每个文件都不是摆设。我用表格梳理一下各自职责文件职责在毕设里的意义setup.cfg声明依赖与打包配置锁定 torch、opencv、numpy 等版本避免「在我电脑上能跑」Dockerfile构建一致的运行镜像答辩前把环境固化成容器换机器不重装.dockerignore / .gitignore / .gitattributes排除无关文件、统一换行符让工程可以干净提交、增量复制tutorial.ipynb交互式推理教程演示环境里逐格跑出问题能定位到哪一步bus.jpg通用样例图快速验证前向推理链路mosaic_with_label.jpg增强后带标注框的合成图检查 mosaic 增强逻辑是否正确画框mosaic_without_label.jpg增强后不带标注框的合成图与原图对比确认拼接与缩放没失真bus.jpg 在 YOLO 系列里是出现频率很高的样例图适合先用它跑通全流程再换自己的视频而两张 mosaic 对比图是资源包设计得很聪明的地方训练时增强逻辑是否生效单看 loss 曲线看不出来直接看增强后的可视化图才知道拼接采样有没有把目标裁坏。这也是下面 3.2 节要写脚本自查的原因。2.2 Dockerfile把环境变成可复现的镜像很多同学习惯在本机把依赖装好就直接训练但到了答辩现场换一台机器就傻眼。常见做法是用 Dockerfile 把环境固化镜像里装什么版本的 torch、什么版本的 cuda 依赖都由文件描述而不是靠某个人脑记。资源包里既然带了 Dockerfile就按这个思路用# 基础镜像按本机显卡驱动选择示例标签对应 cuda 11.7 环境 FROM pytorch/pytorch:1.13.0-cuda11.7-cudnn8-runtime # 安装系统级依赖比如 libgl1 是 opencv 读图需要的 RUN apt-get update apt-get install -y libgl1 libglib2.0-0 # 把项目代码拷进镜像保持容器内路径与工作目录一致 COPY . /app WORKDIR /app # 使用 setup.cfg / requirements 安装 Python 依赖 RUN pip install -e . # 默认跑推理source 和 weights 可被 docker run 覆盖 CMD [python, detect.py, --source, bus.jpg, --weights, yolov5s.pt]逐层解释一下FROM行的镜像标签决定了 torch 和 CUDA 的基准版本这是整个环境是否一致的地基如果本机显卡驱动只支持 CUDA 11.3这里就要换对应的标签否则容器起来后 GPU 不可用。RUN apt-get解决的是 opencv 在精简镜像里常见的libGL.so.1报错这个问题几乎每个用容器跑 YOLOv5 的人都会撞上一次。WORKDIR /app让后续命令都在项目根目录执行pip install -e .会把当前目录的包以可编辑模式装进环境正好对应资源包里的 setup.cfg。CMD指定默认启动命令方便演示时只敲一条docker run。实际操作时先构建再运行docker build -t yolo_demo . docker run --gpus all -v $(pwd)/runs:/app/runs yolo_demo注意-v把本机的 runs 目录挂载进容器这样容器里产生的推理结果能实时落到宿主机答辩时直接打开宿主机目录给评委看图片。如果机器没配 GPU把--gpus all去掉就能纯 CPU 跑但速度会慢不少建议演示前先用 bus.jpg 确认能出结果再上视频。2.3 setup.cfg 与依赖锁定让 pip 安装行为可预期setup.cfg 在工程里的作用是把「我需要哪些依赖」变成机器可读的声明。YOLOv5 本身依赖链不算短torch、opencv-python、numpy、matplotlib 缺一不可而且版本之间互相有约束。写一份最小可用的 setup.cfg 长这样[metadata] name abnormal-behavior-detect version 0.1.0 [options] packages find: python_requires 3.8 [options.extras_require] dev jupyter pytest逻辑说明packages find:会让 setuptools 自动扫描项目里的包目录不需要手工列文件名python_requires限定解释器版本防止在 Python 3.6 上装了新版 torch 直接报「unsupported」。依赖版本要区分两种情况写下限能让 pip 有更大挑选空间但也会让不同机器装出不同版本做毕设演示更稳妥的做法是把精确版本写在 requirements 里例如torch1.13.0。我一般会给这个资源包补一个精简的 requirements.txttorch1.13.0 opencv-python4.8.0.76 numpy1.24.3 matplotlib3.7.2装依赖的两种命令各有用处pip install -r requirements.txt快、直接适合训练前一次性装好pip install -e .会基于 setup.cfg 注册包入口适合要反复改代码、跑python -m的场景。对课程设计和毕设来说先用 requirements 把环境装通后面有时间再折腾 setup.cfg 的打包功能就行。2.4 用 tutorial.ipynb 跑通第一个推理闭环notebook 的价值不在「能跑」而在「分段跑、每段能解释」。答辩演示时如果推理从头到尾一把梭中途报错很难定位但 notebook 里每格一个动作卡在哪一格就是哪一格的依赖或路径问题。资源包里的 tutorial.ipynb 是现成的演示脚本拿到后先按这个顺序自检conda activate yolo python -m jupyterlab tutorial.ipynb python detect.py --weights yolov5s.pt --source bus.jpg --conf-thres 0.4第一条命令启动 JupyterLab在浏览器里打开 tutorial.ipynb 逐格执行第二条命令是为了验证命令行推理链路是否正常跟 notebook 里调用的是同一套底层代码。如果detect.py跑完在runs/detect/exp下出现带标注框的 bus.jpg说明权重加载、图像解码、NMS 后处理都没问题。这里有两个参数值得展开--conf-thres 0.4表示置信度低于 0.4 的框直接丢弃值调低能看到更多低置信度目标调高则结果更干净但容易漏检--iou-thres 0.45是 NMS 的去重阈值同一个目标重叠框超过这个比例会被合并。做异常行为检测时这两个值直接决定了「报警」的准与漏后续第 6 章还会讲怎么用网格搜索把它们调到平衡点。3. Mosaic 数据增强与标签可视化增强参数和画框逻辑异常行为检测训练里数据增强不是玄学而是提高模型对小目标和密集场景召回率的直接手段。资源包里的两张 mosaic 对比图恰好是理解增强逻辑的最好入口一张带标注框一张不带放在一起看就知道拼接采样干了什么。3.1 Mosaic 增强原理四张图拼一张小目标不再隐身Mosaic 增强的核心做法是把 4 张训练图片各取一部分随机拼成一张 640×640 的新图。每张子图先按随机比例裁剪再经过缩放、平移拼接对应到标签上每个目标的框坐标也要跟着做同样的仿射变换。之所以叫「mosaic」就是因为最终效果像马赛克拼贴。资源包里的mosaic_with_label.jpg和mosaic_without_label.jpg我理解是同一张增强结果的两种可视化带标注框的图用来确认变换后框是否仍然贴合目标不带标注框的图用来观察拼接边界和缩放是否自然。对毕设而言这两张图还有一个用途——写进论文的「数据增强」章节作为实验现象佐证比贴一行干巴巴的代码有说服力得多。Mosaic 为什么有效核心论点有两个。第一拼接图里包含多个不同场景的碎片等于每张训练图的信息量翻了 4 倍变相减小了对数据集规模的依赖第二原图里的目标可能只占几十个像素缩放拼接后目标尺寸分布更丰富小目标的检出率会明显上升。代价是训练时的数据加载变重epoch 数不变的情况下每个 step 的时间会增加。3.2 标签可视化脚本用 OpenCV 检查每一张标注标注质量决定了模型上限这句话我重复过很多次但真正动手检查标注的人并不多。YOLO 训练用的标签是 txt 文件每行格式是class cx cy w h其中 cx、cy、w、h 都是归一化到 [0, 1] 的浮点数。很多同学用标注软件导出的坐标没问题但中途自己写脚本转换时最容易出错的就是忘记把归一化坐标乘回图像宽高。写一个通用的可视化检查脚本import cv2 import glob import os def yolo_label_to_boxes(label_path, img_w, img_h): boxes [] with open(label_path, r) as f: for line in f: parts line.strip().split() if len(parts) ! 5: continue # 格式不对直接跳过防止解析崩溃 cid, cx, cy, bw, bh map(float, parts) x1 int((cx - bw / 2) * img_w) y1 int((cy - bh / 2) * img_h) x2 int((cx bw / 2) * img_w) y2 int((cy bh / 2) * img_h) boxes.append((cid, (x1, y1, x2, y2))) return boxes def draw_boxes(image_path, label_path, class_names): img cv2.imread(image_path) h, w img.shape[:2] for cid, (x1, y1, x2, y2) in yolo_label_to_boxes(label_path, w, h): color (0, 255, 0) # BGR 格式绿色框 cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) cv2.putText(img, class_names[cid], (x1, y1 - 6), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 1) return img # 按需修改成自己的路径 image_dir dataset/images/train label_dir dataset/labels/train for img_path in glob.glob(os.path.join(image_dir, *.jpg))[:200]: label_path os.path.join(label_dir, os.path.basename(img_path).replace(.jpg, .txt)) if not os.path.exists(label_path): print(missing label, img_path) continue vis draw_boxes(img_path, label_path, [person, fall, fight]) out_path check_ os.path.basename(img_path) cv2.imwrite(out_path, vis)逻辑说明脚本逐行解析 txt把归一化坐标换算成像素坐标后画框如果某个图片的 label 文件缺失直接打印missing label而不是继续跑这样能一次性暴露数据集目录配对问题。cv2.putText里的坐标(x1, y1 - 6)把类别名写在框上方避免文字压住目标。参数说明color (0, 255, 0)是 OpenCV 的 BGR 绿色线宽2在 640 分辨率下肉眼可见分辨率更大时可调到 3[:200]限制只检查前 200 张是为了快速定位问题全量检查时去掉切片。跑完脚本后把生成的检查图按文件名排序扫一遍重点看两类问题框是否明显偏离目标中心以及重叠目标是否漏框。这两个问题不解决后续训练都是白费时间。3.3 把增强开关写进训练配置什么时候关掉 mosaicMosaic 不是越强越好。YOLOv5 的训练配置里mosaic 开关和概率一般在 hyp 超参文件里控制常见写法如下mosaic: 1.0 mixup: 0.0mosaic: 1.0表示每个 batch 里的数据都走 mosaic 增强mixup是另一种混合增强默认不开开了会进一步增加训练成本。实际训练时还有个细节YOLOv5 在训练后期会自动降低 mosaic 概率因为最后几轮模型已经接近收敛过度拼接的失真数据反而会让精度震荡。我自己的习惯是如果数据集里小目标占比高全程保持mosaic: 1.0直到最后 10 个 epoch如果目标本身都很大、场景单一中期就可以把 mosaic 降到 0.5让模型多看看原图分布。调整配置有两种方式直接改hyp.scratch.yaml里的数值或者在训练命令里用--hyp指定另一份配置。毕设建议单独复制一份 hyp 文件改这样跑多组对比实验时有据可查论文里也能写清楚「哪组参数对应哪份配置」。4. 异常行为检测落地从检测框到行为判别的两条路线环境通了、数据查过、增强逻辑也验证过接下来才是这个毕设的核心把 YOLOv5 的检测框变成「异常行为报警」。这一步没有标准答案但有一条基本边界要拎清——YOLOv5 负责「看到什么、在哪」行为是否异常需要额外的判定逻辑。4.1 异常行为的检测边界YOLOv5 负责看到规则负责判断常见的异常行为包括跌倒、打架/聚集、闯入禁区、吸烟、攀爬等。一类行为能不能用 YOLOv5 直接检测取决于它是否有相对固定的视觉外观。跌倒和打架这类行为姿态特征明显可以通过标注「跌倒姿态」「挥拳动作」让模型直接分类而「闯入禁区」本质是位置判断模型只需要检测人位置关系交给规则去算。毕设里我见过两种路线各有适用场景。路线 A 是纯检测把异常行为本身作为一个类别标注进数据集模型输出直接就是「某个目标属于跌倒/打架」。优点是简单直观、训练和推理代码都好写缺点是行为外观变化大的时候比如跌倒的侧躺、蜷缩、趴地差异很大单一类别内样本要够多。路线 B 是检测加规则模型只检测 person 和关键姿态行为判定在外部用几何规则或时序逻辑完成。优点是行为定义灵活改规则不用重训模型缺点是要写额外的判定代码调阈值需要点耐心。对本科毕设来说我一般建议路线 B因为可解释性强、答辩时能讲清楚「检测模型做了什么、规则做了什么」也更容易用视频片段做逐步演示。4.2 数据组织与 YOLO 标签格式从视频抽帧到 txt不管选哪条路线数据都要先整理成 YOLO 能吃的格式。目录结构按官方惯例组织dataset/ images/ train/ val/ labels/ train/ val/ data.yamlimages 和 labels 下要一一对应同一张图的名字必须相同只是扩展名不同。label 文件里每行对应一个目标五个数值分别是类别 id、中心点 x、中心点 y、框宽、框高全部除以原图宽高做归一化。如果原图是 1920×1080一个 x1960、w480 的框存进去就是 cx0.5、w0.25。从视频构造数据集时常写的抽帧脚本大致如下import cv2 import os def extract_frames(video_path, output_dir, interval30): os.makedirs(output_dir, exist_okTrue) cap cv2.VideoCapture(video_path) frame_id 0 saved 0 while True: ret, frame cap.read() if not ret: break if frame_id % interval 0: out_path os.path.join(output_dir, fframe_{saved:06d}.jpg) cv2.imwrite(out_path, frame) saved 1 frame_id 1 cap.release()逻辑说明每隔interval帧保存一张图避免连续帧高度相似导致数据集冗余。对跌倒检测这类时序场景间隔 30 帧既能保留「倒地前-倒地后」的差异又不会让相邻帧几乎一样。抽完帧后用标注工具人工框目标导出时选择 YOLO 格式就会生成对应的 txt。之后在项目根目录放一个 data.yamltrain: dataset/images/train val: dataset/images/val nc: 3 names: 0: person 1: fall 2: fight注意nc必须和names的数量一致这是训练启动时最常见的不一致报错。路径建议用相对路径并且和训练脚本的工作目录保持一致我见过有人用绝对路径写死/home/xxx/dataset换到答辩机器上就全废了。4.3 训练脚本与关键参数一张能直接抄的命令数据备好后训练命令并不复杂真正要理解的是那几个参数为什么这么设python train.py \ --img 640 \ --batch 8 \ --epochs 100 \ --data data.yaml \ --cfg yolov5s.yaml \ --weights yolov5s.pt \ --device 0逐个参数说--img 640是训练分辨率越大保留的细节越多但显存占用按平方增长异常行为检测通常 640 够用。--batch 8在 8GB 显存左右的卡上是安全值显存小就降到 4不要硬顶。--epochs 100对中小规模数据集来说能收敛但如果用预训练权重迁移学习可能到 60 轮就已经平台期。--cfg yolov5s.yaml选的是 s 版本模型小、训练快适合毕设答辩追求精度可以换yolov5m.yaml但显存和训练时间都会涨。--weights yolov5s.pt表示加载预训练权重不是随机初始化这一步对收敛速度和最终精度影响非常大。--device 0指定第一块 GPU。这一组参数能直接抄但注意一个原则batch size 变化时学习率理论上要跟着调整。如果你把 batch 从默认的 16 改成 8最好把初始学习率也稍微降低或者直接用 YOLOv5 自带的自动学习率调度不要手动乱改。4.4 推理与行为判定检测框怎么变成报警信号训练的最终产物是best.pt。推理阶段拿到每帧的检测框后写一个简单的跌倒判定逻辑import torch import cv2 model torch.hub.load(yolov5, custom, pathbest.pt, sourcelocal) model.conf 0.4 model.iou 0.45 cap cv2.VideoCapture(test_fall.mp4) height int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) fall_frames 0 threshold_bottom height * 0.85 while True: ret, frame cap.read() if not ret: break results model(frame) boxes results.xyxy[0].cpu().numpy() # [x1, y1, x2, y2, conf, class] person_boxes boxes[boxes[:, 5] 0] # 类别 0 是 person if len(person_boxes) 0: continue bottom_y person_boxes[:, 3].max() # 取所有人体框的最大底边 y if bottom_y threshold_bottom: fall_frames 1 else: fall_frames max(0, fall_frames - 1) if fall_frames 5: print(fall detected, send alert) fall_frames 0逻辑说明results.xyxy[0]是当前帧的检测结果每行形如[x1, y1, x2, y2, confidence, class]第 5 列是类别 id用boxes[:, 5] 0筛出 person。bottom_y取所有人体框底边的最大值可以粗略看作画面中离镜头最近的人的位置当它接近画面底部且连续 5 帧成立认为发生了倒地。fall_frames的增减逻辑里加了一个衰减分支防止瞬时误检直接触发报警。参数说明threshold_bottom height * 0.85是经验值具体取决于摄像头安装高度和角度fall_frames 5表示连续 5 帧满足条件才报警大约对应 0.2 秒的持续状态。这两个值建议先跑一段正常行走的视频统计正常情况下的bottom_y分布再回推阈值不要拍脑袋定。检测加规则的路线最花时间的往往就是这一步的调参。5. 避坑从环境到训练翻车率最高的五个细节这一章写的每一条我都见过不止一个人踩进去。现象、原因、解决按三段式放在一起方便你快速对照。5.1 环境相关算子崩溃与依赖版本冲突坑 1现象训练跑到第 500 个 step 左右日志报CUDA error: device-side assert triggered紧接着训练进程卡死。第一次遇到这个报错的人十有八九会怀疑显卡坏了其实是标签问题。原因GPU 上某个算子对标签类别做了越界检查比如模型nc3但某个 txt 里出现了类别 id4前向传播不会炸到反向计算 loss 时才炸出来。解决先停掉训练用 3.2 节的脚本把所有标签文件扫一遍把cid大于nc-1的标注全部修正如果是从某个转换脚本导出的数据优先检查转换脚本里的类别映射表。坑 2现象pip install torch之后import torch报OSError: libcudnn.so.8: cannot open shared object file。原因torch 版本对应的 cuDNN 和当前机器上的 CUDA 驱动不匹配常见于直接pip install torch装到了 CPU 版本或错误的 CUDA 配套包。解决统一用资源包里的 Dockerfile 构建环境或者在安装前先确认本机驱动版本再选择对应的torch1.13.0cu117这类带cu后缀的安装包。做法没有玄学版本对齐就稳定。5.2 数据相关mosaic 震荡与标签坐标溢出坑 3现象训练后期 loss 曲线下降趋缓但验证集 mAP 在最后 20 轮出现明显震荡每次震荡幅度超过两个百分点。原因mosaic 增强产生的拼接图里有大量半目标和交叉遮挡模型一直用这些失真数据更新权重在最后阶段反复偏移。解决训练进入最后 10 轮时把 mosaic 概率从 1.0 逐步降到 0或者干脆在 hyp 文件里把mosaic设为 0.5。我现在的习惯是直接修改hyp.scratch.yaml在最后 10 轮前手动停掉 mosaic这个操作几乎每次都能让验证集精度稳一点。坑 4现象训练刚开始没几个 steploss 直接变成nan或者日志里出现box loss为负值的异常数据。原因标签 txt 里有坐标越界比如归一化后的cx大于 1或者bw、bh等于 0。这类标签多半是标注时点了同一点或者用脚本转换时坐标系搞反了。解决写一个标签清洗函数把所有cx、cy用clip(0, 1)裁剪把bw 0.005或bh 0.005的框直接剔除。坐标越界的框本身就是无效样本留到训练里只会增加一个 nan。5.3 演示相关notebook 路径与相对路径规范坑 5现象答辩前两小时tutorial.ipynb 在讲台上报FileNotFoundError: dataset/images/train/xxx.jpg代码在自己的电脑上明明能跑。原因notebook 里用了硬编码的绝对路径比如/Users/某同学/dataset/...换了工作目录就找不到文件另一种常见情况是detect.py默认从项目根目录找best.pt但启动 Jupyter 时工作目录在子文件夹。解决把代码里的路径全部改成相对路径数据集和权重统一放在项目根目录下在每个关键文件读取前加一行断言import os assert os.path.exists(dataset/data.yaml), data.yaml 不在当前工作目录这个断言在答辩演示时的价值巨大路径有问题它会在读取前直接报出明确提示而不是等模型加载到一半才崩。从那以后我每到一个新环境跑项目第一件事就是执行一遍所有断言确认路径、权重、依赖三项都通过再继续。6. 进阶技巧用 conf_thres 阈值扫描与自检验证模型模型训练完不要急着打包。在最终版本里conf_thres这个参数往往是精度与误报的平衡杆。检测框的置信度在 0.2 到 0.6 之间分布很广阈值定低了正常走路会被当成跌倒报警阈值定高了真跌倒又可能漏报。用一个脚本在验证集上做阈值扫描比拍脑袋定 0.4 可靠得多for conf in 0.15 0.25 0.4 0.6; do python detect.py --weights best.pt \ --source dataset/images/val \ --conf-thres $conf \ --save-txt done跑完四组之后统计每组输出目录里生成的 txt 文件数量以及人为抽查中误检和漏检的次数。常见结果类似conf_thres检出框数明显误检漏检目标0.1586600.2578210.469130.65206对这次异常行为检测任务来说0.25 或 0.4 之间的某个值通常是较好的选择既不会漏掉大多数风险目标又不会让误检淹没整个演示过程。这个表可以直接放进论文的实验章节作为「阈值对性能影响」的支撑数据。除阈值扫描外养成把检测结果可视化存档的习惯比多训十轮模型还重要。跑完验证集后把所有带框图片统一放进一个目录按文件名排序快速浏览重点看三类场景目标重叠、目标较小、目标在画面边缘。这三类场景最容易暴露出标注遗漏和模型误检也是答辩评委最喜欢追问的地方。从那以后我每次训练完都强制自己走一遍「阈值扫描加可视化自检」的流程把这一套当作收尾的地基。很多看起来神秘的模型表现问题其实在验证集图片上扫一眼就能猜到原因。希望帮到你。本文还有配套的精品资源点击获取