ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于YOLOv8的跌倒检测模型训练:数据集、源码与部署全流程

基于YOLOv8的跌倒检测模型训练:数据集、源码与部署全流程 简介这份资源面向计算机视觉入门与进阶开发者、安防监控及健康看护方向的算法实践者提供一套可直接复现的跌倒检测训练方案解决从零搭建行为识别模型时数据匮乏、流程繁琐的问题。压缩包共1438个文件约78.41MB其中1428张jpg为跌倒场景标注图像构成训练与验证主体6个py脚本负责数据加载、模型训练与推理2个md文档说明使用流程另含1个pt权重与1个onnx导出模型便于直接部署或二次微调。资源基于YOLOv8实现特征提取采用CSPDarknet结构通过跨阶段部分连接降低参数量并提升特征提取效率检测头借鉴YOLOv4-Head设计并采用Anchor-Free方式直接预测目标中心点与宽高比例减少先验框数量在速度与精度间取得平衡。目前已有1020人学习适合希望快速跑通跌倒检测全流程、积累数据集与源码经验的读者参考。1. 跌倒检测为什么值得用 YOLOv8 重做一遍跌倒检测这件事做过的人都知道难点从来不在「有没有模型」而在「模型能不能在真实场景里稳住」。传统做法要么用可穿戴传感器要么用姿态估计加时序判断前者用户不愿意戴后者在遮挡、逆光、多人场景下经常翻车。而把跌倒当成一个目标检测问题来做用 YOLOv8 直接框出「人跌倒」这个类别反而绕开了骨架点抖动和时序建模的玄学工程上更好落地。这套「基于 YOLOv8 训练跌倒检测模型 数据集 源码」的思路本质是把跌倒检测降维成单阶段检测任务输入一帧图像输出跌倒框和置信度再接一个简单的持续帧判定就能报警。它适合两类人一类是想快速跑通一个能演示、能部署的跌倒检测原型的开发者另一类是想拿它当模板迁移到工地安全、养老监护、医院病房等场景的工程师。下面我按自己实际训练和调参的顺序把数据集、训练、验证、踩坑一条线讲清楚。2. 数据集怎么准备从标注格式到 YOLOv8 目录结构2.1 跌倒检测数据集的类别设计与来源跌倒检测数据集最容易被低估的是类别定义。很多人一上来就标「跌倒」和「未跌倒」两类结果训练出来的模型把「蹲下」「弯腰捡东西」「坐下」全判成跌倒误报率高得没法用。我一般会分成三类fall跌倒、person正常站立或行走的人、lying躺卧但非跌倒比如床上休息。这样模型学到的是「跌倒」和「躺下」的边界而不是简单的人形检测。数据来源上公开的跌倒数据集通常规模不大常见做法是拿 UR Fall Detection Dataset、Le2i 这类公开数据打底再自己用手机在走廊、卧室、卫生间门口补拍。补拍时注意三点一是模拟跌倒要真的倒地不要半蹲二是要覆盖不同光照尤其是夜间红外或弱光三是每个场景至少拍 20 段每段 3 到 5 秒抽帧后能得到几百张有效图。抽帧不要每秒都抽跌倒过程前后 1 秒内抽 5 到 8 帧就够否则大量静止帧会让模型偏向「人站着」这个多数类。2.2 用 Labelme 标注并转成 YOLO 格式标注工具用 Labelme 或 labelImg 都行关键是要输出 YOLO 需要的归一化 txt。Labelme 默认输出 JSON需要转一道。下面这个脚本是我常用的转换逻辑输入是 Labelme 的 JSON 目录输出是 YOLO 的 images 和 labels 分离结构。import json import os from pathlib import Path # 类别顺序必须和训练时 data.yaml 里的 names 一致 CLASS_MAP {fall: 0, person: 1, lying: 2} def labelme_to_yolo(json_dir, out_img_dir, out_lbl_dir): json_dir Path(json_dir) out_img_dir Path(out_img_dir) out_lbl_dir Path(out_lbl_dir) out_img_dir.mkdir(parentsTrue, exist_okTrue) out_lbl_dir.mkdir(parentsTrue, exist_okTrue) for js_file in json_dir.glob(*.json): with open(js_file, r, encodingutf-8) as f: data json.load(f) img_w data[imageWidth] img_h data[imageHeight] lines [] for shape in data[shapes]: label shape[label] if label not in CLASS_MAP: continue cls_id CLASS_MAP[label] # Labelme 是两点矩形取左上和右下 (x1, y1), (x2, y2) shape[points] x_min, x_max min(x1, x2), max(x1, x2) y_min, y_max min(y1, y2), max(y1, y2) # YOLO 格式中心点 x,y 和宽高全部除以图像尺寸归一化 cx (x_min x_max) / 2.0 / img_w cy (y_min y_max) / 2.0 / img_h bw (x_max - x_min) / img_w bh (y_max - y_min) / img_h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) # 没有有效标注的图直接跳过避免空标签文件干扰训练 if not lines: continue txt_path out_lbl_dir / (js_file.stem .txt) with open(txt_path, w) as f: f.write(\n.join(lines)) # 图片复制到 images 目录保持同名 src_img json_dir / data[imagePath] if src_img.exists(): import shutil shutil.copy(src_img, out_img_dir / src_img.name) if __name__ __main__: labelme_to_yolo(./raw_json, ./dataset/images, ./dataset/labels)这段代码的关键点有三个。第一CLASS_MAP的 id 必须和后面data.yaml里的names顺序严格对应错一位模型就全乱。第二坐标归一化用的是图像原始宽高不是缩放后的尺寸Labelme 的imageWidth和imageHeight就是原图尺寸直接用。第三空标签文件一定要跳过YOLOv8 遇到没有目标的图会当成背景样本少量可以大量会让召回率掉得很难看。2.3 划分训练集验证集与 data.yaml 写法转换完之后按 8:1:1 划分 train、val、test。我一般写个小脚本随机抽但要注意同一个视频抽出来的帧不能同时出现在 train 和 val否则验证指标虚高。正确做法是按视频段划分而不是按帧随机划分。目录结构最终长这样dataset/ images/ train/ val/ test/ labels/ train/ val/ test/对应的fall_data.yamlpath: ./dataset train: images/train val: images/val test: images/test nc: 3 names: 0: fall 1: person 2: lyingnc是类别数names的 key 必须从 0 开始连续。很多人在这里写错比如写成1: fall训练不报错但类别全偏。写完 yaml 后建议用yolo checks先跑一遍环境自检确认路径能被正确解析。3. 用 YOLOv8 训练跌倒检测模型参数、命令与损失曲线3.1 环境配置与模型选型环境这块Ubuntu 20.04 和 Windows 都能跑CPU 版本也能训练只是慢。如果手头是 GTX 1660 Ti 这类 6G 显存的卡建议用yolov8s而不是yolov8x输入尺寸设 640batch 设 8 到 16基本能稳住。安装就一条命令pip install ultralytics装完yolo version能打印出版本号就说明环境通了。模型权重不用自己找yolov8n.pt、yolov8s.pt在首次训练时会自动下载。如果网络受限可以提前把 pt 文件放到项目根目录训练时用绝对路径指定。选型上我的经验是跌倒检测的类内差异其实不大都是人形倒地yolov8n在数据量 3000 张以上时就能到可用的 mAPyolov8s是精度和速度的平衡点。如果部署到 RK3588 或 Hi3516 这类边缘板优先选yolov8n后面转 ONNX 和量化都更省事。3.2 训练命令与关键参数含义训练命令本身很短但参数决定成败yolo detect train \ datafall_data.yaml \ modelyolov8s.pt \ epochs150 \ imgsz640 \ batch16 \ lr00.01 \ lrf0.01 \ patience30 \ workers8 \ projectruns/fall \ nameexp1逐个说。epochs150是上限真正停在哪由patience30决定30 轮验证指标不升就早停避免过拟合。lr00.01是初始学习率跌倒数据量不大时我会降到 0.005否则前期 loss 震荡明显。lrf0.01是最终学习率系数配合余弦退火让后期微调更稳。imgsz640是输入分辨率如果跌倒目标在画面里占比很小比如监控远景可以提到 960但显存和速度要重新权衡。workers8是数据加载线程Windows 下建议设 0 或 2否则容易卡死。训练启动后重点看三个东西box_loss是否稳定下降、mAP50是否在涨、cls_loss有没有突然飙高。cls_loss飙高通常意味着类别标注有冲突比如同一张图里fall和lying框重叠严重这时候要回去查标注。3.3 画损失函数曲线和混淆矩阵训练完runs/fall/exp1/下会有results.csv里面记录了每轮的 loss 和指标。想单独画损失曲线用下面这段import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/fall/exp1/results.csv) df.columns [c.strip() for c in df.columns] # 列名可能带空格 fig, ax1 plt.subplots(figsize(10, 5)) ax1.plot(df[epoch], df[train/box_loss], labeltrain box_loss) ax1.plot(df[epoch], df[val/box_loss], labelval box_loss) ax1.set_xlabel(epoch) ax1.set_ylabel(box loss) ax1.legend(locupper right) ax2 ax1.twinx() ax2.plot(df[epoch], df[metrics/mAP50(B)], colorgreen, labelmAP50) ax2.set_ylabel(mAP50) ax2.legend(loclower right) plt.title(YOLOv8 fall detection training curve) plt.tight_layout() plt.savefig(fall_loss_curve.png, dpi150)逻辑说明左轴画 box_loss右轴画 mAP50这样能直观看到 loss 下降和指标上升是否同步。如果 loss 一直降但 mAP 不涨多半是过拟合或者验证集分布和训练集差太多。参数上dpi150够发报告用figsize按需调。混淆矩阵 YOLOv8 会自动生成在exp1/confusion_matrix.png重点看fall被误判成lying的比例这个数高就说明两类边界没学好需要补「半躺」「侧倒」这类难样本。4. 推理、验证与部署前必须做的几件事4.1 用验证集跑指标并逐类看 P/R训练完不要只看一个总 mAP要逐类看。命令yolo detect val \ modelruns/fall/exp1/weights/best.pt \ datafall_data.yaml \ imgsz640 \ conf0.25 \ iou0.5输出里会分别列出fall、person、lying的 precision、recall、mAP50。跌倒检测里fall的 recall 比 precision 更重要漏报一次跌倒的代价远大于误报。如果fall的 recall 低于 0.85优先补数据而不是调阈值。conf0.25是推理置信度阈值验证阶段先用默认部署时再按场景调。4.2 单张图和视频推理的最小代码验证通过后用 Python 跑单张图确认效果from ultralytics import YOLO model YOLO(runs/fall/exp1/weights/best.pt) # 单张图推理saveTrue 会把带框结果存到 runs/detect/predict results model.predict( sourcetest_fall.jpg, imgsz640, conf0.3, iou0.45, saveTrue ) for r in results: for box in r.boxes: cls_id int(box.cls[0]) conf float(box.conf[0]) print(model.names[cls_id], round(conf, 3))conf0.3比验证时略高是为了减少演示时的误报。iou0.45控制 NMS 合并程度跌倒场景里人和跌倒框可能重叠iou 设太高会把两个框都留下设太低会误合并0.45 是我试下来比较稳的值。视频推理把source换成视频路径即可YOLOv8 会自动逐帧处理并输出视频。4.3 从检测到报警持续帧判定逻辑单帧检测出fall不代表真跌倒可能只是弯腰。工程上要加一个持续帧判定连续 N 帧中至少 M 帧检出fall才触发报警。常见做法是 N15、M10按 25fps 算大约 0.6 秒。这个逻辑不复杂但能大幅降低误报。如果部署到边缘设备建议把这段判定放在后处理里而不是塞进模型方便按场景调参。5. 跌倒检测训练里最容易翻车的几个坑5.1 现象mAP 很高但实际误报不断原因验证集和训练集来自同一批视频按帧随机划分导致同一段视频的相邻帧同时进了 train 和 val模型其实在「背答案」。解决按视频段划分数据集确保同一段视频只出现在一个子集里重新训练后 mAP 通常会掉几个点但那个数才是真实的。5.2 现象训练到一半 loss 变成 nan原因学习率过高或者标注里有宽高为 0 的框。Labelme 转换时如果两个点重合bw或bh会是 0YOLOv8 计算 loss 时除零。解决在转换脚本里加一行过滤if bw 0 or bh 0: continue同时把lr0从 0.01 降到 0.005。5.3 现象模型把「蹲下」全判成跌倒原因数据集里缺少蹲下、弯腰这类负样本模型没见过这些姿态只能往最近的fall类靠。解决专门补拍蹲下捡东西、系鞋带、坐下的片段标成person每类至少 200 张重新训练后误报会明显下降。5.4 现象GPU 显存够但训练报 CUDA out of memory原因batch设太大或者imgsz提到 960 后没同步降 batch。解决6G 显存下imgsz640配batch16是上限提到 960 就把 batch 降到 4 或 8。也可以用yolo detect train ... ampFalse关掉混合精度排查是不是 AMP 引起的显存异常。5.5 现象转 ONNX 后推理结果和 PyTorch 不一致原因导出时没指定opset或动态轴或者预处理归一化方式不同。解决导出命令加opset12和dynamicFalse并在 ONNX 推理端严格复用 YOLOv8 的预处理BGR 转 RGB、除以 255、letterbox 填充。这三步错一步框的位置就会整体偏移。6. 把跌倒检测推到边缘设备量化与阈值联调的一个实用技巧模型训练完只是半成品真正落地到 RK3588、Hi3516 这类板子上量化是绕不过去的。我的习惯是先在 PC 上用 ONNX Runtime 验证 FP32 精度再做 INT8 量化对比量化前后fall类的 recall 掉了多少。如果掉超过 5 个点就回到训练阶段补数据而不是硬调量化参数。具体做法是导出一份 ONNX用onnxruntime跑一遍验证集记录每类的 P/Rimport onnxruntime as ort import numpy as np import cv2 sess ort.InferenceSession(best.onnx, providers[CPUExecutionProvider]) input_name sess.get_inputs()[0].name def preprocess(img_path, size640): img cv2.imread(img_path) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img cv2.resize(img, (size, size)) img img.astype(np.float32) / 255.0 img np.transpose(img, (2, 0, 1)) # HWC - CHW return np.expand_dims(img, axis0) out sess.run(None, {input_name: preprocess(test_fall.jpg)}) print(np.array(out[0]).shape) # 确认输出维度符合预期这段代码的重点是预处理必须和训练时一致尤其是BGR2RGB和/255.0少一个结果就偏。量化时用板子厂商的工具链校准集从验证集里抽 200 张覆盖白天、夜间、多人场景。量化完在板端跑一遍重点看fall的 recall 和单帧耗时如果 recall 掉太多优先检查校准集是不是偏了。阈值联调有个实用技巧不要只调conf把conf和持续帧判定的 M 值一起调。比如板端算力有限只能跑 10fps那 N15 就对应 1.5 秒太慢改成 N8、M6同时把conf从 0.3 提到 0.4用置信度换响应速度。这个组合我在实际项目里调过很多次比单独调一个参数有效得多。最后说个我自己的习惯每次训练完我都会把best.pt、data.yaml、results.csv和当时的训练命令一起存进一个带日期的文件夹命名比如fall_yolov8s_20240612。跌倒检测这行数据一换、参数一改结果就完全不同没有后悔药只能靠记录复现。希望帮到你。本文还有配套的精品资源点击获取
返回列表