☰
YOLOv8跌倒检测实战:数据集标注、模型训练与部署全流程解析
2026/9/28 12:08:46 网站建设 项目流程

简介:基于YOLOv8的跌倒检测毕业设计资源,适合高校学生完成相关课题或开发者快速搭建安防监控原型。压缩包共1437个文件,核心包含1428张带标注的跌倒与非跌倒图像,覆盖多种室内外场景和姿态,为训练提供充分数据;6个Python脚本按模块划分,涵盖数据预处理、YOLOv8模型构建、训练循环、验证评估等关键步骤;另附ONNX格式推理模型、训练完成的权重文件和Markdown说明文档,可离线加载、直接测试。整包约78.41MB,下载快,部署门槛低。目前已有93人学习使用。通过该资源,读者能系统掌握YOLOv8从数据准备到模型导出的完整流程,理解数据增强、学习率调度、损失函数配置等实际调参技巧;同时,整洁的代码结构与详尽标记也便于扩展为智能看护、医院病房或社区养老等场景的跌倒预警系统,是毕业设计答辩与工程实践的高质量参考。

1. 用 YOLOv8 训练自己的跌倒检测模型:这份资源到底能直接拿来干什么

跌倒检测这几年在毕业设计里出现频率越来越高,原因很直接:场景真实、数据可获取、模型选型成熟,而且能讲出一个完整的工程故事。这份基于 YOLOv8 的跌倒检测资源,包含图片数据集和完整训练源码,核心就是让你绕过数据采集和代码重写的重复劳动,直接进入训练、调参、评估、部署这条主线。适合三类人:想快速出成果的应届生、需要落地老人监护demo的开发者、以及刚接触 YOLO 系列想用真实数据集练手的学习者。我从数据集命名、标注格式、训练参数到常见坑位完整拆一遍,看完你大致能判断这份资源值不值得下载,以及拿到手后每一步该怎么走。

2. 先看清数据集和标注格式:fall_xxx.jpg 的命名规律与 YOLO txt 对齐方式

2.1 数据集构成:正负样本怎么分、命名规律说明了什么

打开数据集目录,你会看到一批以 fall_ 开头的图片文件,比如 fall_249.jpg、fall_324.jpg、fall_1277.jpg。这个命名规律说明数据集作者把跌倒正样本统一归入了 fall 前缀,文件名里的数字大概率是采集时的帧序号或者样本编号,并没有额外的时间戳信息,所以不能直接从文件名还原视频流的时间顺序。

但注意一个关键点:这份资源里看到的列表全是 fall 命名,实际完整数据集通常应该还包括 normal 或者背景负样本。因为摘要描述里明确提到“包含了各种跌倒和非跌倒场景”,如果你的压缩包里确实只有 fall_ 前缀的图片,那正负样本很可能被分别放在了不同目录,比如 fall/ 和 normal/,或者标注文件里通过类别 id 来区分。拿到资源后第一步别急着训练,先把目录结构列一遍。

我一般会习惯性地把图片按类别数量做个统计,这直接关系到后面模型能不能收敛。跌倒检测本质上是个二分类目标检测问题,如果正样本(跌倒)有几千张、负样本(正常行走/坐下/躺下)只有几百张,训练出来的模型会把所有水平姿态的人都判成跌倒,因为模型学到的只是“横着=跌倒”的粗浅特征。

2.2 标注文件到底长什么样:YOLO 格式的坐标换算

YOLOv8 使用的标注格式和 YOLOv5 完全一致,每张图片对应一个同名的 txt 文件,放在 labels 目录下。txt 里每一行代表一个目标框,格式是:

class_id cx cy w h

注意这里 cx、cy、w、h 全部是归一化坐标,即相对于图片宽度和高度的比例值,取值范围 0 到 1。比如一张 1280x720 的图片里,一个人跌倒 bounding box 的左上角是 (320, 180),右下角是 (960, 540),那么:

  • cx = (320 + 960) / 2 / 1280 = 0.5
  • cy = (180 + 540) / 2 / 720 = 0.5
  • w = (960 - 320) / 1280 = 0.5
  • h = (540 - 180) / 720 = 0.5

对应的 txt 行就是0 0.5 0.5 0.5 0.5。

很多人第一次转换标注时容易把像素坐标直接写进 txt,导致训练时边框超出图片边界,损失直接变成 NaN。如果这份资源的标注是自己转换的,你最好抽几张图,用 Python 脚本把标注框画回去核对一下,这个步骤十几分钟就能完成,能省掉后面几天排查问题的精力。

2.3 动手检查数据集:用 Python 脚本核对图片和标签是否一一对应

标注缺失是目标检测训练里最常见的翻车原因。有的图片漏标、有的标注文件是空的、有的图片损坏打不开,这些都会让训练过程出现诡异的 loss 波动或者 mAP 异常。建议先跑一遍这个核对脚本:

import os from pathlib import Path from PIL import Image img_dir = Path("datasets/fall/images") label_dir = Path("datasets/fall/labels") imgs = sorted(img_dir.glob("*.jpg")) missing_labels = [] empty_labels = [] broken_images = [] for img_path in imgs: label_path = label_dir / (img_path.stem + ".txt") if not label_path.exists(): missing_labels.append(img_path.name) continue if label_path.stat().st_size == 0: empty_labels.append(img_path.name) try: with Image.open(img_path) as img: img.verify() except Exception: broken_images.append(img_path.name) print(f"总图片数: {len(imgs)}") print(f"缺失标注: {len(missing_labels)} -> {missing_labels[:10]}") print(f"空标注: {len(empty_labels)} -> {empty_labels[:10]}") print(f"损坏图片: {len(broken_images)} -> {broken_images[:10]}")

这段脚本做的事情很直接:遍历 images 目录下所有 jpg,检查同名 txt 是否存在、是否为空、图片本身能否正常打开。逻辑上分了三类问题分别输出,方便你定位是数据拷贝丢了文件还是标注环节写漏了。如果发现大量空标注,大概率是标注工具导出时把没有目标的图片也生成了空文件,这些文件训练时会被 YOLOv8 当作背景样本,少量没关系,多了会干扰正样本学习。

3. 搭建 YOLOv8 训练环境并跑通完整流程:从依赖安装到参数设置

3.1 环境搭建:Ubuntu 20.04 CPU 版和 GPU 版两条路径

YOLOv8 官方推荐用 Python 3.8 以上版本配合 PyTorch。如果是 Ubuntu 20.04 系统,先装 CUDA 版的 PyTorch,再通过 pip 安装 ultralytics 包:

# GPU 版本(推荐,训练速度快 10 倍以上) pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics # CPU-only 版本(数据集小于 2000 张可以勉强跑) pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu pip install ultralytics

这里要说明一下:GTX 1660 Ti 或者 RTX 3060 这类显卡跑 YOLOv8n 或者 YOLOv8s 完全够用,跌倒检测是单类别任务,不需要上 YOLOv8x 这种大模型。如果只有 CPU,也不是不能跑,但要把图片尺寸降到 416、epochs 控制在 50 以内,不然一个 epoch 可能要跑十几分钟,整体时间成本不划算。

装完后先验证一下环境是否可用:

yolo predict model=yolov8n.pt source="https://ultralytics.com/images/bus.jpg"

这一步会下载官方预训练权重并跑一次推理,能正常打印出检测结果说明环境没问题。很多人卡在这块是因为网络原因下载超时,可以把权重文件手动下载后放到项目目录下再指定路径。

3.2 准备训练配置:data.yaml 与模型选择

训练前需要准备一个 data.yaml 文件,这是 YOLOv8 读取数据集的入口。文件内容如下:

train: datasets/fall/images/train val: datasets/fall/images/val nc: 1 names: 0: fall

参数说明:train 和 val 分别指向训练集和验证集的图片目录,YOLOv8 会自动去同名 labels 目录找标注文件;nc 是类别数量,跌倒检测只有 1 类;names 列表里 0 对应 fall。这里最容易出问题的就是路径写错,尤其是相对路径和绝对路径混用导致数据集加载失败。

模型选择上,我一般建议从 YOLOv8n 或者 YOLOv8s 开始。n 是最轻量的版本,参数量只有 3.2M,适合 CPU 训练和快速验证流程通不通;s 版本参数量 11.2M,精度更高但训练时间约为 n 的 2 到 3 倍。跌倒是单类目标检测,正样本特征相对固定,n 和 s 的精度差距在实际场景里大约 1 到 2 个 mAP 点,并不值得为了这点精度去跑更大的模型。先把流程跑通,再用 s 版本做最终精调,是效率最高的路径。

3.3 启动训练:关键参数含义与常见设置

训练命令本身不复杂,复杂的是参数怎么调。一条典型的训练命令长这样:

yolo detect train \ model=yolov8n.pt \ data=data.yaml \ epochs=100 \ imgsz=640 \ batch=16 \ optimizer=AdamW \ lr0=0.001 \ lrf=0.01 \ patience=20 \ seed=42 \ device=0

逐项拆开说明:

  • model=yolov8n.pt:加载 COCO 预训练权重做迁移学习。跌倒在 COCO 里没有专门类别,但预训练模型已经学会了通用特征提取,迁移学习后收敛速度远快于从零训练。
  • epochs=100:训练轮数。跌倒数据集通常在 5000 张以内,100 轮足够,多了容易过拟合。
  • imgsz=640:输入图片尺寸。跌倒检测的 bounding box 通常比较大(人体占画面主体),不需要像小目标检测那样用 1280 分辨率,640 在精度和显存占用之间比较均衡。
  • batch=16:批大小。显存不够就降到 8 或者 4,但 batch 太小会导致 BN 层统计不稳定,损失曲线会抖得厉害。
  • optimizer=AdamW:YOLOv8 默认用 SGD 也能收敛,但 AdamW 对学习率的敏感度低一些,新手调参用 AdamW 更容易出稳定结果。
  • lr0=0.001:初始学习率。用迁移学习时 0.001 是安全值,太大容易破坏预训练权重,太小收敛慢。
  • patience=20:早停轮数。连续 20 轮验证集 mAP 没有提升就自动停止,避免无效训练浪费时间。

训练启动后,终端会实时打印每个 epoch 的 loss、P、R、mAP50 和 mAP50-95。这里有个经验值:正常训练到 30 到 50 轮时 mAP50 应该能到 0.85 以上,如果一直在 0.5 左右徘徊说明数据集或标注有问题,不要盲目加 epochs。

4. 训练完怎么验证效果:从损失曲线到 PR 曲线再到模型导出

4.1 训练过程日志怎么看:loss、mAP、P、R 的含义

训练结束后,ultralytics 会在runs/detect/train/目录下生成完整的过程记录,包括results.png、confusion_matrix.png、PR_curve.png等图表。很多人只看最后的 mAP 数字,其实过程曲线暴露的问题更多。

results.png里包含 box_loss、cls_loss、dfl_loss 三条下降曲线,以及 precision、recall、mAP50、mAP50-95 四条上升曲线。重点看两点:

  • 训练集 loss 和验证集 loss 的差距。如果训练集 loss 持续下降而验证集 loss 在第 60 轮后开始回升,说明过拟合已经发生,早停机制应该会在 patience 范围内触发,如果没触发就要手动检查。
  • mAP50 的收敛位置。单类别检测如果 mAP50 最终低于 0.8,基本可以判定标注质量或数据多样性有问题,不是训练轮数不够的问题。

4.2 模型评估与导出:best.pt、last.pt 转 ONNX

训练完成后会生成两个权重:best.pt和last.pt。best.pt 是验证集 mAP 最高的权重,last.pt 是最后一个 epoch 的权重,部署时只用 best.pt。可以用官方命令直接评估:

yolo detect val model=runs/detect/train/weights/best.pt data=data.yaml

这条命令会在 val 集上跑完整评估,输出每个类别的 P、R、mAP50、mAP50-95。紧接着把模型导出 ONNX,方便后续部署到手机端或者边缘设备:

yolo export model=runs/detect/train/weights/best.pt format=onnx imgsz=640

导出后会在同目录生成 best.onnx。ONNX 格式的意义在于脱离 PyTorch 环境,可以用 ONNX Runtime 在 CPU 上跑推理,也可以转换为 NCNN/TensorRT 部署到嵌入式设备。如果你在 RK3588 这类板子上做部署,这一步是必经之路。

4.3 可视化推理验证:画框看置信度

数值评估只能给你一个整体印象,真正的效果要拉到图片上看。用下面这个脚本跑一批样本:

from ultralytics import YOLO model = YOLO("runs/detect/train/weights/best.pt") results = model.predict("datasets/fall/images/val", conf=0.3, save=True, project="val_vis") for r in results: boxes = r.boxes if len(boxes) > 0: cls = boxes.cls.tolist() conf = boxes.conf.tolist() print(f"{r.path}: class={cls}, conf={conf}")

conf=0.3是置信度阈值,低于该值的检测框会被过滤掉。这个值直接影响直观效果:阈值设太高会漏检(比如把跌倒的人漏掉),设太低会误检(比如把蹲下的人也算跌倒)。我的习惯是先看 0.3 和 0.5 两组结果,结合真正要部署的场景去定阈值。做一个独居老人监护系统,宁可误报多也要减少漏报,阈值就压低;做公共场所监控,报警会惊动安保人员,阈值就适当提高。

这个可视化步骤极其重要,因为 mAP 是统计指标,它无法告诉你模型在特定角度、特定光照下会不会翻车。建议选几个极端场景测试:部分遮挡的跌倒、夜间画面、多个同时出现的人。

5. 跌倒检测训练避坑指南:数据、标注、显存和过拟合的常见问题

这一章直接给结论,每一条都是我实际踩过或者见证别人踩过的坑。

5.1 全正样本导致模型对“躺着的人”误检

现象:训练时 mAP 很高,但拿一段正常行走的人在长椅上躺下的视频测试,模型直接报警“跌倒”。

原因:数据集里负样本严重不足,模型只学到了“水平姿态 + 人体”这个组合特征,没有学到“水平姿态下的日常行为”也属于正常。

解决:补充至少 30% 的负样本,包括躺下休息、蹲下系鞋带、跪姿擦拭地面、睡觉翻身这些容易和跌倒混淆的场景。标注时负样本直接留空,YOLOv8 会把它当成背景参与训练。

5.2 标注框坐标算错导致 loss 直接 NaN

现象:训练启动后第一个 epoch 的 loss 是 NaN,终端直接爆掉。

原因:标注 txt 里写的是像素坐标而不是归一化坐标,或者归一化时除以了错误的宽高。

解决:立即抽查 3 到 5 张图片的标注文件,写一个小脚本把标注框画到图片上肉眼核对。标注是按像素框(x1 y1 x2 y2)给的,就用公式cx = ((x1+x2)/2)/W逐项转换,不要手算。

5.3 显存溢出 OOM 后盲目调小 batch

现象:训练中断报 CUDA out of memory,但把 batch 从 16 调到 4 之后 mAP 怎么都上不去。

原因:batch 过小导致 BN 层统计量不稳定,模型训练过程剧烈抖动,收敛质量下降。

解决:优先调小 imgsz 而不是 batch。例如从 640 降到 512,显存占用下降约 36%,对精度的影响远小于 batch 从 16 降到 4。如果 512 仍然溢出,再考虑 batch 降到 8 并配合workers=4加速数据加载。

5.4 训练集和验证集数据来源重叠

现象:训练时 mAP50 最后到了 0.95 以上,但一测视频就频繁漏报。

原因:数据集划分时用了随机划分,同一个视频序列的连续帧被同时分到训练集和验证集,模型实际上“背过”了验证集内容。

解决:按视频片段划分而不是按单帧随机划分。理想做法是把采集的每个视频作为一个整体单位,将其中几个完整视频放入验证集,确保验证集帧和训练集帧来自不同视频。

5.5 CPU 训练到崩溃也没跑完一个 epoch

现象:用纯 CPU 跑 YOLOv8s,一个 epoch 要 30 分钟,100 轮要 50 个小时。

原因:没有版本概念,一上来就选了大模型和 640 分辨率。

解决:CPU 用户直接换 YOLOv8n,imgsz 设 416,epochs 设 50。代码逻辑上只需要在训练命令里改model=yolov8n.pt imgsz=416 epochs=50,其他配置不用动。这个组合在 4 核 CPU 上单 epoch 大约 5 分钟,能跑通全流程。如果数据集只有几百张,效果也能出一个可用的 demo。

6. 把模型接进实时监控:一个可跑的摄像头推理脚本加上跟踪优化

训练完模型只是第一步,毕业设计想拿高分,或者实际部署到老人监护场景,还得让模型“动”起来。这里给一个可以直接用的摄像头实时推理脚本:

import cv2 from ultralytics import YOLO model = YOLO("runs/detect/train/weights/best.pt") cap = cv2.VideoCapture(0) alert_cooldown = 0 while True: ret, frame = cap.read() if not ret: break results = model(frame, conf=0.4, verbose=False) fall_detected = False for r in results: for box in r.boxes: conf = float(box.conf[0]) if conf >= 0.4: fall_detected = True x1, y1, x2, y2 = map(int, box.xyxy[0].tolist()) cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.putText(frame, f"FALL {conf:.2f}", (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 2) if fall_detected and alert_cooldown <= 0: print("ALERT: Fall detected!") alert_cooldown = 30 elif alert_cooldown > 0: alert_cooldown -= 1 cv2.imshow("Fall Detection", frame) if cv2.waitKey(1) & 0xFF == ord("q"): break cap.release() cv2.destroyAllWindows()

补充两个最实用的进阶技巧。

技巧一:加一个简单的帧间确认机制,避免单帧误报。跌倒动作有一个从站立到躺地的过程,连续两帧都检测到fall类才触发报警,误报率能降一半左右。你可以用一个fall_count变量累积计数,连续超过 3 帧才触发。

技巧二:判断框高宽比辅助过滤。跌倒后人体框的高宽比会从站立时的接近 1 变成躺倒时的 0.5 以下。在模型输出后加一个判断:h / w < 0.6才视为有效跌倒,这样能把模型本身对“蹲”和“躺坐”的误判过滤掉相当一部分。

我最早做这个项目时犯过一个低级错误,把conf=0.4写死死在代码里。后来在评测环境发现白天 0.4 没问题,晚上噪点多了之后框就全部消失了,这才意识到阈值必须跟场景绑在一起调。从那以后我每次训练完都会多留一组推理参数调优环节,而不是只看 mAP 收敛就完事。

这份资源适合作为起点,但真正拉开差距的是你拿到数据后自己做的数据处理和验证工作:先把标注画回图片逐张看一遍,再按视频维度划分数据集,最后部署时记得把阈值做成外部参数而不是写死在代码里。希望这轮拆解对你有点帮助,把每一步踩实,跌到检测这个项目其实并没有想象中那么复杂。

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

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

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

立即咨询