news 2026/10/11 22:58:44

YOLOv5异常行为检测毕设实战:从训练到树莓派部署

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
YOLOv5异常行为检测毕设实战:从训练到树莓派部署

简介:本资源是一套面向计算机专业本科生的毕业设计实战项目,聚焦基于YOLOv5的异常行为检测系统开发与部署,适用于毕业设计选题、课程设计实践及AI视觉方向技能进阶学习。压缩包共212个文件,涵盖105个配置与模型定义yaml文件、45个核心训练与推理py脚本、20张实测场景jpg图像、6个Linux部署sh脚本及5个说明性md文档,辅以Dockerfile、.gitignore等工程化支持文件,整体仅2.81MB,轻量但结构完整,便于快速复现与二次开发。目前已有637人学习下载,反映出较强的教学适配性与工程参考价值。读者可直接获取从数据预处理、模型训练、可视化评估到容器化部署的全流程代码与文档,包含带标签/无标签图像示例、mosaic增强实现、bus场景测试用例及jupyter交互式教程,所有内容均来自真实毕设项目,逻辑连贯、注释详尽,显著降低AI视觉项目落地门槛。

1. 为什么本科毕设选“基于YOLOv5的异常行为检测”不是跟风,而是稳扎稳打的落地选择?

你打开 GitHub 搜索“yolov5 异常行为检测”,会刷出上百个 fork 和 clone——但真正能跑通、能调参、能部署到树莓派4B或RK3568开发板上、还能在毕业答辩现场实时演示的,不到一成。很多同学卡在第一步:train.py报KeyError: 'data',或者训练完 mAP 0.02,又或者 Docker build 卡在apt-get update,再或者.dockerignore漏写了runs/导致镜像体积暴涨 3GB。这不是玄学,是没理清 YOLOv5 在行为检测场景下的三重错位:目标检测模型 ≠ 行为识别模型;单帧检测 ≠ 时序建模;本地训练脚本 ≠ 工业级部署流水线。这个毕设标题看似平平无奇,实则是一条贯穿数据构建、模型轻量化、容器化封装、边缘推理验证的完整工程链路。它不考你能不能复现 SOTA,而考你能不能把 YOLOv5 这个黑匣子,拆成可调试、可解释、可交付的模块——尤其适合想进安防、智能硬件、工业视觉方向的同学。如果你正被“怎么让模型认出跌倒”“怎么把训练好的权重塞进树莓派”“Dockerfile 写完却 build 失败”这些问题卡住,这篇笔记就是你答辩前最后一份可抄、可改、可 debug 的实战手记。


2. 从零搭起检测 pipeline:YOLOv5 为何必须定制化改造才能做异常行为?

YOLOv5 原生是为通用目标检测设计的:输入一张图,输出 bbox + class + conf。但“异常行为”本质是短时序语义事件——比如“跌倒”需要连续 3~5 帧中人体姿态剧烈变化,“打架”需多人交互距离突变,“攀爬围栏”需人体与静态结构的空间关系持续偏移。直接拿detect.py跑单帧,等于用尺子量温度:工具对,问题错。必须在 YOLOv5 基础上叠加轻量时序建模能力,且不能破坏其部署友好性。常见做法是“两段式”:YOLOv5 提特征(bbox + pose keypoint),后接 LSTM/TCN 或手工规则引擎。本科毕设不必硬上 Transformer,我一般会选YOLOv5 + OpenPose 关键点 + 状态机规则——它不依赖大量标注视频,推理快(<30ms/frame on Jetson Nano),且所有模块都支持 ONNX 导出和 TensorRT 加速。下面分三步落地:

2.1 数据准备:不是标“person”,而是标“person+状态标签”

YOLOv5 默认只训class_id=0(person)。但异常行为检测需要区分正常站立、弯腰、蹲下、躺倒、奔跑、拖拽等状态。因此你的 label 文件不能只有0 x_center y_center width height,而要扩展为:

0 x_c y_c w h posture_id motion_flag

其中posture_id∈ {0: upright, 1: bending, 2: squatting, 3: lying, 4: running},motion_flag是二值标记(0=静止,1=运动)。
你不需要重新标注 COCO,而是用 OpenPose 预处理视频帧,提取 18 个关键点坐标,再用几何规则自动打posture_id:

  • lying: 骨盆中心 y 坐标 < 膝盖平均 y 坐标 × 0.7
  • bending: 髋角 < 90° 且膝角 > 120°
  • running: 脚踝速度 > 15 px/frame 且双臂摆动幅度 > 30°

提示:不要手动标 posture!写个 Python 脚本批量生成.txt标签,比用 LabelImg 点 10000 帧高效 100 倍。脚本核心逻辑如下:

# gen_labels_from_openpose.py import numpy as np from pathlib import Path def calc_hip_angle(landmarks): # landmarks: (18, 2), hip=[11,12], knee=[13,14], ankle=[15,16] hip = (landmarks[11] + landmarks[12]) / 2 knee = (landmarks[13] + landmarks[14]) / 2 ankle = (landmarks[15] + landmarks[16]) / 2 vec1 = knee - hip vec2 = ankle - knee cos_a = np.dot(vec1, vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2) + 1e-8) return np.degrees(np.arccos(np.clip(cos_a, -1, 1)) def assign_posture(kp): hip_ang = calc_hip_angle(kp) pelvis_y = (kp[11,1] + kp[12,1]) / 2 knee_y = (kp[13,1] + kp[14,1]) / 2 if pelvis_y < knee_y * 0.7: return 3 # lying elif hip_ang < 90 and (kp[13,1] + kp[14,1])/2 - (kp[11,1] + kp[12,1])/2 > 50: return 1 # bending else: return 0 # upright (default)

这段代码输出的是posture_id,你再结合光流法算motion_flag,就能生成带行为语义的 YOLO 标签。注意:.txt文件名必须与图像同名,存放在labels/train/下,路径结构严格遵循 YOLOv5 官方要求(images/和labels/平行)。

2.2 模型改造:在 detect.py 中注入行为逻辑,而非重训整个网络

YOLOv5 的detect.py是推理入口,但它默认只画 bbox。我们要在这里插入行为判断逻辑——不改模型结构,只改后处理。修改detect.py的run()函数末尾:

# detect.py line ~200, after 'pred = model(img, augment=augment)[0]' if len(pred) > 0: pred[:, :4] = scale_coords(img.shape[2:], pred[:, :4], im0.shape).round() # --- 新增:提取 bbox 内关键点并判断行为 --- for *xyxy, conf, cls in pred: x1, y1, x2, y2 = map(int, xyxy) crop = im0[y1:y2, x1:x2] # 裁出 person ROI if crop.size == 0: continue # 调用轻量 OpenPose(如 lightweight-openpose-pytorch) keypoints = get_keypoints(crop) # 返回 (18,2) numpy array if keypoints is not None: posture = assign_posture(keypoints) if posture == 3: # lying → 异常 cv2.putText(im0, "ABNORMAL: Lying", (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0,0,255), 2) elif posture == 1 and conf > 0.7: # bending + high confidence # 可加运动分析:对比前后帧关键点位移 pass

关键点检测用lightweight-openpose(PyTorch 版,<5MB 模型),不是 full OpenPose。它能在树莓派4B 上以 8fps 运行,且支持 ONNX 导出。你不需要训练它,直接pip install lightweight-openpose即可调用。这样做的好处是:YOLOv5 仍负责定位人,OpenPose 负责姿态估计,规则引擎负责行为判决——三者解耦,debug 时可单独验证每一步输出。

2.3 训练配置:超参数不是调出来的,是按硬件反推的

YOLOv5 的hyp.yaml里一堆超参,但本科毕设最常翻车的是batch_size和imgsz。很多人盲目设batch_size=64,结果显存爆掉;或设imgsz=1280,导致树莓派部署时 OOM。正确做法是按目标设备反推:

设备推荐 imgsz最大 batch_sizeepoch备注
RTX 306064032100可开 mosaic/augment
Jetson Nano4168200关闭 mosaic,lr ×0.5
Raspberry Pi 4B (4GB)3204300必须用 FP16,关闭 all augment

imgsz不是越大越好:YOLOv5 的精度增益在 640 之后急剧衰减,但推理耗时呈平方增长。实测imgsz=416在 Nano 上比 640 快 2.3 倍,mAP 仅降 0.8%。batch_size要根据nvidia-smi实时看显存占用调整——启动训练后watch -n 1 nvidia-smi,看到Memory-Usage接近 90%,就该降 batch。另外,warmup_epochs: 3必须保留,否则小数据集容易 early stop。


3. Docker 封装:为什么.dockerignore比Dockerfile更决定毕设成败?

很多同学写完Dockerfile就以为万事大吉,结果docker build花 40 分钟,镜像体积 8GB,push 到树莓派后docker run直接 OOM。根源不在FROM选错,而在.dockerignore没写对——它决定了哪些文件不该进镜像层。YOLOv5 项目根目录下有这些“隐形炸弹”:

  • runs/:训练日志和权重,动辄 2GB,且含绝对路径,进镜像毫无意义
  • datasets/:原始视频和标注,应只 COPY 处理后的images/和labels/
  • venv/或env/:本地虚拟环境,Docker 内重装依赖即可
  • *.log,*.pyc,__pycache__/:全部排除

一个可靠的.dockerignore必须包含:

** !requirements.txt !Dockerfile !setup.cfg !models/ !utils/ !detect.py !train.py !data/ !weights/ !images/ !labels/ !.dockerignore !.gitignore

注意:**开头表示全局忽略,后面用!白名单放行必要文件。漏掉runs/是毕设最常见翻车点——某次我见一个同学的镜像里塞了 3 个runs/train/exp10/weights/best.pt,每个 150MB,光这一项就占镜像 450MB。

3.1 Dockerfile 编写:用多阶段构建砍掉 70% 体积

别用FROM pytorch/pytorch:latest—— 它带 CUDA Toolkit 全家桶,镜像 4GB。毕设部署只需推理,用FROM nvidia/cuda:11.3.1-runtime-ubuntu20.04(精简运行时)+ 手动装torch==1.10.0+cu113(非pip install torch,后者会装 dev 版)。完整Dockerfile如下:

# 第一阶段:构建环境(build stage) FROM nvidia/cuda:11.3.1-runtime-ubuntu20.04 AS builder RUN apt-get update && apt-get install -y python3-pip python3-dev && rm -rf /var/lib/apt/lists/* WORKDIR /app COPY requirements.txt . RUN pip3 install --no-cache-dir torch==1.10.0+cu113 torchvision==0.11.1+cu113 -f https://download.pytorch.org/whl/torch_stable.html RUN pip3 install --no-cache-dir -r requirements.txt # 第二阶段:运行环境(runtime stage) FROM nvidia/cuda:11.3.1-runtime-ubuntu20.04 RUN apt-get update && apt-get install -y libglib2.0-0 libsm6 libxext6 libxrender-dev libglib2.0-dev && rm -rf /var/lib/apt/lists/* WORKDIR /app # 只复制第一阶段装好的包,不复制源码 COPY --from=builder /usr/local/lib/python3.8/site-packages /usr/local/lib/python3.8/site-packages COPY --from=builder /usr/local/bin/pip3 /usr/local/bin/pip3 # 复制本项目必要文件 COPY models/ ./models/ COPY utils/ ./utils/ COPY data/ ./data/ COPY weights/ ./weights/ COPY detect.py ./ COPY images/ ./images/ COPY labels/ ./labels/ COPY requirements.txt . # 创建非 root 用户(安全基线) RUN useradd -m -u 1001 -G root appuser && chown -R appuser:root /app USER appuser CMD ["python3", "detect.py", "--weights", "weights/best.pt", "--source", "images/test.jpg"]

关键点:

  • --from=builder只复制 site-packages,不复制/root/.cache或编译中间文件
  • libglib2.0-0等是 OpenCV GUI 依赖,漏装会导致cv2.imshow报错
  • USER appuser是答辩加分项:体现安全意识,避免 root 权限滥用

构建命令必须加--no-cache和--progress=plain:

docker build --no-cache --progress=plain -t yolo-abnormal:v1.0 .

--no-cache防止 Docker 复用旧层导致依赖错乱;--progress=plain让你看到每一层实际耗时,快速定位卡点(比如apt-get update卡住,说明国内源没配好)。

3.2 setup.cfg:不是可有可无,而是定义 pip install 行为的契约

setup.cfg决定别人pip install .时安装什么。很多毕设 repo 里没有它,导致pip install -e .失败,或import yolov5报ModuleNotFoundError。标准setup.cfg应包含:

[metadata] name = yolov5-abnormal version = 1.0.0 description = YOLOv5-based abnormal behavior detection for graduation project author = Your Name requires-python = >=3.8 [options] packages = find: include_package_data = True package_dir = = . [options.packages.find] where = . exclude = tests, docs, examples [options.package_data] * = *.yaml, *.pt, *.jpg, *.png

重点:

  • packages = find:让 setuptools 自动发现models/utils/等包
  • include_package_data = True+package_data确保data/coco.yamlweights/best.pt被打包进去
  • exclude = tests, docs避免把测试代码打进生产镜像

验证方法:

python3 -m build # 生成 dist/yolov5_abnormal-1.0.0-py3-none-any.whl pip install dist/yolov5_abnormal-1.0.0-py3-none-any.whl python3 -c "import models; print('OK')"

如果import models成功,说明setup.cfg生效;否则检查package_dir是否指向错误路径。


4. 避坑指南:那些让答辩前夜崩溃的 5 个真实问题与血泪解法

YOLOv5 异常行为检测毕设的坑,90% 都集中在环境、数据、部署三环。以下是我在指导 12 届本科生过程中,高频出现、当场卡死、但解决后能立刻推进的 5 个典型问题。每一条都按「现象 → 原因 → 解决」给出可执行动作,不讲原理,只给答案。

4.1 现象:train.py报FileNotFoundError: No labels found in ...,但ls labels/train/明明有 200 个.txt文件

原因:YOLOv5 要求 label 文件名必须与 image 文件名完全一致(包括大小写和扩展名),且images/train/xxx.jpg对应labels/train/xxx.txt。常见错误是视频抽帧生成xxx_001.jpg,但 label 写成xxx001.txt(少下划线)或XXX_001.txt(大写)。
解决:

# 统一转小写并标准化命名 cd images/train && rename 'y/A-Z/a-z/' *.jpg && cd - cd labels/train && rename 'y/A-Z/a-z/' *.txt && cd - # 检查是否一一对应 diff <(ls images/train | sed 's/.jpg//') <(ls labels/train | sed 's/.txt//') | grep "^<"

如果输出为空,说明全部匹配;否则< xxx行就是缺失 label 的图片名。

4.2 现象:训练 loss 不下降,val_loss 持续震荡,mAP@0.5 停在 0.002

原因:data.yaml中nc: 1写成了nc: 5(你只标了 person 一类,但 yaml 说有 5 类),或names: ['person']写成names: ['person', 'car', 'dog', ...](names 数量 ≠ nc)。YOLOv5 会强制按nc初始化分类头,导致 logits 维度错乱。
解决:

# 检查 data.yaml grep -A5 "nc:" data/custom.yaml grep -A10 "names:" data/custom.yaml # 必须满足:len(names) == nc,且 names[0] == 'person' # 修正后删掉 runs/ 目录重训 rm -rf runs/

4.3 现象:Docker build 卡在Step 5/12 : RUN pip3 install --no-cache-dir -r requirements.txt,10 分钟不动

原因:requirements.txt里有torch或tensorflow,触发 pip 从 PyPI 源下载(国内慢),或opencv-python-headless未指定版本导致编译耗时。
解决:

# requirements.txt 必须写死版本,并换清华源 torch==1.10.0+cu113 torchvision==0.11.1+cu113 numpy==1.21.6 opencv-python-headless==4.5.5.64 # 其他包...

并在Dockerfile的 pip install 行加源:

RUN pip3 install --no-cache-dir -i https://pypi.tuna.tsinghua.edu.cn/simple/ -r requirements.txt

4.4 现象:detect.py在 PC 上正常,但docker run后报cv2.error: OpenCV(4.5.5) ... error: (-215:Assertion failed) size.width>0 && size.height>0 in function 'cv::imshow'

原因:cv2.imshow()在无 GUI 的 Docker 容器内不可用,且--display参数未传入。
解决:

  • 方案 A(推荐):禁用 GUI,改用cv2.imwrite()保存结果图
    # detect.py 中注释掉 cv2.imshow(),换成 cv2.imwrite(f"output/{Path(source).stem}_result.jpg", im0)
  • 方案 B:用 X11 转发(仅限 Linux 主机)
    xhost +local:docker docker run -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix yolo-abnormal:v1.0

4.5 现象:树莓派4B 上docker run启动后立即退出,docker logs显示Illegal instruction (core dumped)

原因:镜像基于 x86_64 构建(如nvidia/cuda:11.3-runtime),但树莓派是 arm64/v8 架构,CPU 指令集不兼容。
解决:

  • 重写Dockerfile,基础镜像换为arm64v8/ubuntu:20.04
  • PyTorch 改用torch-1.10.0-cp38-cp38-linux_armv7l.whl(官网提供 ARM 轮子)
  • OpenCV 用opencv-python-headless==4.5.5.64(已支持 armv7l)
  • 构建时加--platform linux/arm/v7:
    docker build --platform linux/arm/v7 -t yolo-rpi:v1.0 .

5. 边缘部署实战:在树莓派4B上跑通 YOLOv5 异常检测的 4 个硬核技巧

树莓派4B(4GB RAM + USB3.0)不是玩具,而是真实的边缘 AI 平台。它跑 YOLOv5 的瓶颈不在算力,而在内存带宽和 I/O 延迟。很多同学把 PC 上跑通的模型直接scp过去,结果detect.py启动就卡住——不是模型太大,而是 OpenCV 读图方式错了。下面这 4 个技巧,是我压测 37 次后总结出的必调项,每一条都能提升 2~5 fps,且让系统稳定运行 72 小时不 crash。

5.1 图像加载:放弃cv2.imread(),改用PIL.Image.open().convert('RGB')

cv2.imread()在树莓派上会触发额外的色彩空间转换和内存拷贝,实测比 PIL 慢 3.2 倍。且cv2的 JPEG 解码器在 ARM 上有 bug,偶发cv2.error: bad argument。替换方法:

# 替换 detect.py 中的 cv2.imread() from PIL import Image import numpy as np def pil_loader(path): with open(path, 'rb') as f: img = Image.open(f).convert('RGB') return np.array(img) # 转为 numpy array,保持与 cv2 一致 # 在 run() 函数中 im0 = pil_loader(source) # source 是 jpg 路径

注意:pil_loader返回的是 RGB 顺序,而 YOLOv5 的letterbox()期望 BGR,所以要在letterbox()前加im0 = im0[..., ::-1](RGB→BGR)。

5.2 模型加载:用 TorchScript 代替torch.load(),提速 40%

torch.load()在树莓派上解析.pt文件要 1.8 秒,而 TorchScript 的.ts文件加载只要 0.3 秒。导出命令:

# 在 PC 上导出 python export.py --weights weights/best.pt --include torchscript --img 320 --device cpu # 生成 best.torchscript

然后修改detect.py的模型加载部分:

# 替换 model = torch.load(...) 为 model = torch.jit.load('weights/best.torchscript') model.eval()

TorchScript 模型体积更小(best.pt150MB →best.torchscript85MB),且无需 CUDA context,纯 CPU 运行更稳。

5.3 推理优化:关闭torch.backends.cudnn.benchmark,启用torch.set_num_threads(2)

树莓派是 4 核 CPU,但默认torch会启 4 线程,导致 cache thrashing。实测set_num_threads(2)+ 关闭 cudnn benchmark 后,单帧耗时从 210ms 降到 145ms:

# detect.py 开头添加 import torch torch.backends.cudnn.benchmark = False torch.set_num_threads(2) # 必须在 model.load 前设置

同时,在Dockerfile中设置环境变量,防止被覆盖:

ENV OMP_NUM_THREADS=2 ENV OPENBLAS_NUM_THREADS=2

5.4 内存管理:用psutil监控并主动释放缓存

树莓派内存紧张,长时间运行后docker stats显示内存使用率 >90%,detect.py开始 OOM。解决方案不是重启容器,而是每 100 帧主动清理:

# detect.py 中 import psutil import gc frame_count = 0 for path, im, im0s, vid_cap, s in dataset: frame_count += 1 if frame_count % 100 == 0: # 清理 Python 垃圾 gc.collect() # 清理系统 page cache(需 root 权限) try: with open('/proc/sys/vm/drop_caches', 'w') as f: f.write('1\n') except PermissionError: pass # 非 root 容器跳过

注意:drop_caches需要容器以--cap-add=SYS_ADMIN启动,或在Dockerfile中加RUN chmod u+s /sbin/sysctl(不推荐,安全风险)。更稳妥的做法是gc.collect()+ 控制batch_size=1,避免内存累积。

最后说一句血泪经验:答辩前 48 小时,务必在树莓派上跑满 2 小时压力测试——用ffmpeg循环推流 1080p 视频,观察docker stats的 MEM % 是否稳定在 75% 以下。如果波动超过 ±10%,说明还有内存泄漏,这时别碰代码,只做一件事:把cv2.VideoCapture()改成cv2.CAP_GSTREAMER后端,并加-v参数输出日志定位卡点。
希望帮到你。

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

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

Cursor Agent工作流:重构软件开发全生命周期的实践指南

1. 项目概述&#xff1a;当写代码变成“发指令”&#xff0c;开发者的角色正在被重定义 “写代码只是第一步”——这句话放在五年前&#xff0c;大概率会被当成一句玩笑&#xff1b;放在今天&#xff0c;它已经成了某实验室里三位工程师围坐白板前反复推演的共识。我参与过多个…

作者头像 李华
网站建设 2026/10/11 22:54:52

OFDM星座图与2RC-4CPFSK仿真:从离散星座点到连续相位轨迹

简介&#xff1a;这份OFDM仿真资源以2rc-4CPFSK信号为对象&#xff0c;展示星座图生成与循环前缀、加窗等关键环节的MATLAB实现&#xff0c;适合通信工程初学者理解多载波调制原理并模仿仿真流程。压缩包共12个文件&#xff0c;包含5个.m脚本、5个.asv自动备份及1个网页说明与1…

作者头像 李华
网站建设 2026/10/11 22:54:19

智能赛车道红绿灯分类:高动态场景鲁棒性实战指南

简介&#xff1a;本资源是面向计算机视觉初学者与智能交通项目开发者的红绿灯图像分类数据集&#xff0c;专为训练轻量级图像分类模型&#xff08;如YOLOv5分类模式&#xff09;设计&#xff0c;解决交通信号识别场景中高质量标注数据稀缺问题。数据集共2000个文件&#xff0c;…

作者头像 李华
网站建设 2026/10/11 22:47:48

基于 PostgreSQL 和 pgvector 构建轻量级 RAG 混合检索系统

前一阵做企业知识库的 RAG 检索系统&#xff0c;遇到一个特别现实的问题&#xff1a;数据量不算大&#xff0c;几百 GB 的文本和文档&#xff0c;日常并发也就几十 QPS&#xff0c;但商业向量数据库的授权费算下来&#xff0c;一年接近两个后备开发的人力成本。更重要的是&…

作者头像 李华
网站建设 2026/10/11 22:46:55

数据库表结构设计实战指南:从字段类型到索引的避坑原则

我记得很清楚&#xff0c;自己第一次独立设计数据库表结构的时候&#xff0c;满脑子都是“字段齐了就行”。结果表是建出来了&#xff0c;上线一个月就开始难受&#xff1a;用户要按时间筛选&#xff0c;发现日期存的是字符串&#xff1b;要做数据统计&#xff0c;发现状态字段…

作者头像 李华