Le2i跌倒检测数据集实战:从关键点提取到LSTM时序分类

📅 发布时间:2026/9/17 1:52:30
Le2i跌倒检测数据集实战:从关键点提取到LSTM时序分类
跌倒检测这几年一直是从智能安防到养老监护里比较刚需的方向。Le2i Fall Detection Dataset 是我见过被引用最多、也最适合新手入门的视频跌倒数据集之一。这篇文章就围绕它来写怎么把数据集下载下来、怎么把视频预处理成能喂给模型的时间序列、怎么搭一个像样的分类器来训练以及训练过程中最容易踩的坑。如果你最近正好在看 YOLO、关键点提取或者时序模型相关的话题那这套流程其实是同一个思路。数据集本身不算大全部视频加起来一两百个片段但足够让你把“视频数据 - 特征 - 模型 - 评估”这条链路完整跑通。对新手来说它的好处有三个公开可下载、标注简单明确、场景相对可控。对老手来说它也是一个很好的 benchmark拿它做基线再迁移到自己的监控场景里改动成本很低。这篇教程我会尽量按实际操作的顺序来写代码也都是可以直接跑的。1. 先认识一下 Le2i Fall Detection Dataset1.1 这个数据集到底是什么Le2i 是法国一个实验室的缩写全称是 Laboratoire Electronique, Informatique et Image这个数据集由他们发布最早用在论文里做室内跌倒检测。它包含几个不同室内场景的视频常见版本有 Home家庭、Coffee Room咖啡间、Office办公室、Lecture Room教室等每个场景都有多个人做动作动作分为两类一类是跌倒Fall一类是日常活动Activity of Daily LivingADL比如坐下、起立、蹲下、走路、弯腰捡东西等等。注意这里的标注不是目标检测框而是行为标签这也是后续选择技术路线的重要依据。每个视频的时长几秒到几十秒不等分辨率通常在 320x240 左右帧率一般标 25fps。整体数据量不算大一共几十段到上百段视频具体版本不同数量略有差异。这么小的数据量直接拿它训练一个复杂的视频分类模型很容易过拟合因此后面我会引导大家先用关键点抽特征再喂给轻量级时序模型这也是绝大多数论文的实际做法。1.2 数据文件结构与标注格式拿到压缩包解压之后你会看到若干场景文件夹每个文件夹里是若干 .avi 视频。我见过的多个版本里标注信息有两种常见形式一种是每个视频旁边放一个 .txt 的标注文件另一种是单独一个表格文件汇总所有视频信息。不同版本字段命名不一样但核心信息就两件事这个视频里是否发生了跌倒以及跌倒发生在哪几帧。以常见的文本标注为例可能有这样几行fall 25 72 adl 0 24 stand 73 120含义大概是某个标签从第几帧到第几帧。也有版本直接标“视频名 起始帧 结束帧 类型”。拿到数据之后我强烈建议第一步先打开标注文件看看字段名不要想当然去写代码解析否则对不齐数据会浪费一整天。1.3 拿到数据后第一步的检查项这里分享一个我在拿到任何公开数据集之后都会做的检查清单视频是否能正常解码。用 OpenCV 读一遍看有没有读不满帧、花屏、最终帧数为 0 的问题。标注文件行数是否和视频长度匹配。有的版本标注会多出几行或者某些视频没有标注。区分场景信息。Le2i 数据集有多个场景如果混在一起训练模型可能学到的是“房间背景”而不是“人的动作”后面我会专门讲怎么切分训练集和验证集。检查是否有多人同时出现在画面里。Le2i 有些视频里其实不止一个人这会影响关键点提取需要想好是取置信度最高的那个还是干脆把这类样本剔除。我第一次用时没检查视频解码结果有个视频 OpenCV 读到一半直接崩了训练到一半才发现特别被动。建议你在预处理代码里加上 try-except 和日志输出哪个视频出错直接跳过去别把整个流程卡死。2. 数据集的获取与预处理从视频到关键点序列2.1 数据集下载途径与版本差异关于下载这里说明两个点。第一Le2i 的原始数据通常在项目主页或论文主页发布部分版本需要填写学术用途声明。如果你在学校或者公司内网直接搜“Le2i Fall Detection Dataset download”一般能找到官方入口GitHub 上也有一些学术项目把数据做成了镜像下载速度可能更快但注意比对文件清单是否完整。第二不同传播版本视频数量可能不同有的版本把标注合并成了一个 Excel有的则放在每个场景文件夹里。我建议优先选择带原始 .avi 文件的版本因为很多搬运版本为了压缩体积转成了 .mp4虽然也能用但帧率、编码格式可能和标注错位。下载完先解压看一眼文件夹结构记住视频和标注的存放位置后面预处理代码要按这个路径来写。这一步简单但很多人会忽略“版本一致性问题”后期训练集和标注对不上就会非常头疼。如果你发现自己手里的标注是 Excel 格式建议先转成统一的 .txt 或 CSV后面处理会省很多事。2.2 抽帧与关键点提取MediaPipe 和 OpenPose 怎么选跌倒检测要建模的是“动作随时间的变化”我们不能直接把一整段视频的所有原始像素塞进网络除非你有很深的显存和很大的数据量所以要先抽特征。最常用的做法是人体关键点序列。目前主流的人体关键点提取工具有两个OpenPose 和 MediaPipe。OpenPose 的精度高支持多人和手部、面部关键点但安装依赖重、运行时间长CPU 上速度很感人。MediaPipe 由 Google 出品安装一条命令搞定CPU 也能跑单人姿态估计的稳定性在 Le2i 这种室内场景里已经够用了。我个人的建议是如果你只是想快速跑通跌倒检测先选 MediaPipe如果你追求极致精度愿意为训练和推理速度付出成本再考虑 OpenPose。另外如果你本身对 YOLOv8 更熟也可以用 YOLOv8-pose 来做关键点提取效果也更符合日常检测流程但这里为了控制篇幅我以 MediaPipe 为例。下面是一段抽帧 提取关键点的示例代码它会遍历指定目录下的所有视频对每一帧提取 33 个关键点坐标和置信度然后保存成 .npy 文件。注意我这里为了演示删掉了很多日志和异常处理实际用的时候建议加上进度条和断点续传。import cv2 import mediapipe as mp import numpy as np from pathlib import Path mp_pose mp.solutions.pose pose mp_pose.Pose(static_image_modeFalse, model_complexity1, min_detection_confidence0.5) input_root Path(Le2i/) output_root Path(le2i_keypoints/) output_root.mkdir(exist_okTrue) for video_path in sorted(input_root.rglob(*.avi)): cap cv2.VideoCapture(str(video_path)) if not cap.isOpened(): print(fskip {video_path}) continue frames_kpts [] while True: ret, frame cap.read() if not ret: break frame_rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) results pose.process(frame_rgb) if results.pose_landmarks is None: # 没检测到人用全零占位 frames_kpts.append(np.zeros((33, 3), dtypenp.float32)) continue kpts [] for lm in results.pose_landmarks.landmark: kpts.append([lm.x, lm.y, lm.visibility]) frames_kpts.append(np.array(kpts, dtypenp.float32)) cap.release() # 保存为 (T, 33, 3) 的数组 arr np.stack(frames_kpts, axis0) out_path output_root / (video_path.stem .npy) np.save(out_path, arr) print(f{video_path.name}: {arr.shape})这段代码有三个值得注意的点。第一no detection 时用全零占位但后续训练时这些帧应该被特殊处理比如直接丢弃或通过插值补上不能让全零帧混进关键点序列里当有效信息。第二MediaPipe 的坐标是归一化到 [0,1] 的分辨率变化不影响这个值但对绝对位置敏感后期做中心化归一化时要注意。第三用 model_complexity1 在 CPU 上速度还能接受如果你显存足够可以用 2 提高精度。2.3 关键点清洗与降噪处理关键点提取完之后数据里往往会有一些噪声和缺失帧如果不处理就直接训练模型会被这些异常点带偏。我常用的清洗手段有三个。第一个是连续缺失帧的插值。如果某一帧或者连续几帧没检测到人可以用前后有效帧做线性插值。这里有个前提缺失帧不能太多如果连续丢了几百帧插出来的值也没什么意义这种情况下建议整段删掉。插值代码可以用 pandas 的 interpolate也可以自己写循环逻辑不复杂。第二个是坐标平滑。MediaPipe 在单帧上做姿态估计时间维度上可能会有轻微抖动比如手肘坐标跳来跳去。可以通过滑动窗口均值或者 Savitzky-Golay 滤波把这种高频抖动抹掉。窗口大小建议 3 到 5太大反而会把真实的快速动作给平滑没了。跌倒过程本身是迅速下坠过度平滑会让模型分不清“快速坐下”和“跌倒”。第三个是坐标归一化。在 Le2i 里摄像头位置固定人物在房间不同位置远近差异很大。如果我们直接拿原始像素坐标训练模型会学习到“靠近画面左侧的人更容易跌倒”这种错误规律。所以归一化非常关键。一般做法是取脖子和骨盆的中点作为原点然后除以肩宽左肩到右肩的欧氏距离。这样不管人站在画面哪个位置、离镜头是远是近关键点坐标都会被标准化到相似的空间。def normalize_pose(kpts): # kpts: (33, 3) x, y, visibility left_shoulder kpts[11] right_shoulder kpts[12] left_hip kpts[23] right_hip kpts[24] center_shoulder (left_shoulder[:2] right_shoulder[:2]) / 2.0 scale np.linalg.norm(left_shoulder[:2] - right_shoulder[:2]) 1e-6 normalized kpts.copy() normalized[:, 0] (kpts[:, 0] - center_shoulder[0]) / scale normalized[:, 1] (kpts[:, 1] - center_shoulder[1]) / scale return normalized用脖子和肩膀作为归一化锚点是因为上半身在跌倒过程里变化最明显如果用骨盆做锚点人在弯腰时骨盆位置也会移动反而引入额外偏移。我自己的建议是归一化做完后随机抽几段序列可视化一下确认不同人、不同位置的姿态在归一化后确实对齐了再进入下一步。2.4 构建带标签的训练样本数据清洗完下一步就是把连续的关键点序列变成“一段一段带标签的窗口”。为什么要切窗口因为 LSTM 或者 TCN 这类时序模型需要固定长度的输入而且整段视频太长直接丢进去既慢又难收敛。切窗口的时候标注怎么对齐是个核心问题。假设一个视频里有跌倒事件标注告诉你跌倒发生在第 25 到 72 帧。我们设定窗口长度 W24步长 S6那么从第 0 帧开始依次取 [0:24]、[6:30]、[12:36]……只要这个窗口的区间和 [25, 72] 有重叠就标记为正样本完全没有重叠就标记为负样本。def build_dataset_from_npy(video_keypoints, annot_events, window24, stride6): T len(video_keypoints) windows, labels [], [] t 0 while t window T: label 0 for ev in annot_events: if ev[label] fall and not (t window - 1 ev[start] or t ev[end]): label 1 break windows.append(video_keypoints[t: t window]) labels.append(label) t stride return np.array(windows), np.array(labels)构建样本的时候还有一个容易被忽视的点训练集和验证集怎么划分。如果直接把所有窗口随机切分到训练集和验证集同一个视频的相邻窗口会同时出现在两边模型相当于已经“看过”验证集的内容结果会虚高。正确的做法是先按视频编号划分比如把 80% 的视频归入训练20% 的视频归入验证然后再各自切窗口。如果能按人物 ID 划分就更严格不过 Le2i 并不总能提供人物 ID所以按视频切分是更常见的做法。3. 模型设计思路为什么选择“关键点 时序分类”而不是纯粹的 YOLO3.1 两条技术路线的对比最近 YOLOv8 很火很多人会问能不能直接用 YOLO 做跌倒检测其实可以但容易走进死胡同。YOLO 是目标检测模型输出的是“框”和“类别”。你可以在 Le2i 上重新训练 YOLO 检测 “person” 类别再结合跟踪、框宽高比变化去判断有没有跌倒。这个方案有一个前提你需要大量已经标注了人体框和跌倒状态的数据而 Le2i 的标注不是框是行为标签所以纯 YOLO 路线在 Le2i 上其实很别扭。相比之下“关键点 时序分类”这条路线和 Le2i 的数据特性天然匹配。跌倒本质上是一个动态过程人在跌倒前后关键点轨迹有明确规律重心先升高然后快速下移躯干从直立变成水平最后倒地静止。关键点序列可以很好地表达这种规律而且相比原始视频输入维度小很多模型也更容易学到动作本质不容易被背景干扰。我把两种方案放在表格里对比方案标注需求模型复杂度对背景鲁棒性推荐场景YOLO 检测 规则后处理需要检测框标注Le2i 需要自己标注中高中容易受其他物体干扰有现成检测框数据关键点 LSTM/TCN直接复用 Le2i 行为标签低较高关键点天然去掉背景信息在本数据集快速实验如果你确实想用 YOLO 思路做也不是不行但需要自己做两件事一是把 Le2i 的视频标注成人体框二是设计一套规则或者小分类器来判断“框的轨迹”是不是跌倒。第二步其实又绕回了时序分类问题所以对初学者来说直接走关键点路线会更顺。3.2 时间窗口和多帧组合的设计时序模型不是把一整段视频丢进去就好。Le2i 单个视频有几秒到几十秒把整段作为一个样本输入长度不定处理起来很麻烦而且动作类别比例也不均匀。更常规的做法是把序列切成固定长度的窗口比如 24 帧对应不到 1 秒25fps。一个完整的跌倒动作通常持续 1 到 2 秒所以 24 帧窗口不算太长但也足够看到“从站立到摔倒”的关键轨迹。如果你希望窗口覆盖完整跌倒动作可以选 32 帧或 48 帧但窗口越大会引入更多无关静态帧模型容易偷懒学“静止状态”反而不利于捕捉瞬间动作。步长stride决定相邻窗口的重叠程度。步长越小样本越多训练越稳定但相邻窗口高度相似有信息冗余步长太大又可能漏掉跌倒瞬间。我自己常用 W24、S6这样大概重叠 75%在一个 100 帧的视频里能切出 13 个左右的窗口对数据增强也有帮助。你也可以考虑用随机裁剪的方法做数据增强每个 epoch 对同一个视频随机切一个偏移量不同的窗口效果比固定切窗更抗过拟合。3.3 轻量级分类模型LSTM 与 TCN处理关键点序列最经典的模型是 LSTM。LSTM 的优点是能自动建模时间依赖但对长度很长的序列会慢而且容易过拟合。Le2i 数据量小所以 LSTM 隐藏层不宜太深一般一层或两层隐藏单元 64 到 128 就够。我在 PyTorch 里的实现大概这样import torch import torch.nn as nn class FallClassifier(nn.Module): def __init__(self, input_dim66, hidden_dim128, num_layers2, num_classes2, dropout0.5): super().__init__() self.lstm nn.LSTM(input_dim, hidden_dim, num_layers, batch_firstTrue, dropoutdropout) self.head nn.Sequential( nn.Linear(hidden_dim, 64), nn.ReLU(), nn.Dropout(dropout), nn.Linear(64, num_classes) ) def forward(self, x): # x: (B, T, input_dim) out, _ self.lstm(x) # 取最后时刻的输出 out out[:, -1, :] return self.head(out)这里 input_dim 我写的是 66意思是每个关键点只取 x 和 y 两个坐标33 个关键点就是 66 维。你也可以把 visibility 置信度拼进去变成 99 维但我在实验里发现提升不明显反而增加了过拟合风险所以默认就只用 x 和 y。除了 LSTMTCNTemporal Convolutional Network这两年也很推荐。它本质是一维因果卷积训练速度快梯度稳定在动作识别任务里经常能超过 LSTM。如果你愿意折腾可以把 LSTM 换成 TCN输入仍然是关键点序列输出一样是分类。在 Le2i 这种小数据集上我实测 TCN 往往比 LSTM 更容易收敛而且不太容易出现 LSTM 那种“训练集很好、验证集崩掉”的过拟合情况。3.4 损失函数与类别不平衡处理Le2i 的正负样本比例不均衡。一个视频里可能只有几秒是跌倒其余都是日常活动切窗之后正样本数量通常只有负样本的 1/5 到 1/10。如果不做处理模型会倾向于把所有样本都预测为“日常活动”因为这样准确率也能很高但跌倒检测里漏报是最危险的。处理办法有三个我建议组合使用类别加权交叉熵。给正样本更高的权重比如 class_weight [1.0, 5.0]。负样本下采样。让每个 batch 里正负样本数量接近比如正样本采样 50%负样本采样 50%。使用 Focal Loss。它能让模型更关注难分类样本对正负样本不平衡效果不错。我用得最多的是“类别加权 下采样”组合简单直接也不容易引入额外超参数。Focal Loss 在小数据上反而容易因为超参数选择不当而抖动。如果你想知道自己的模型到底是不是被不平衡害了可以打印每个 batch 的正负比例一目了然。4. 完整的训练流程实战4.1 环境准备动手之前先把环境装好。Le2i 数据量不大CPU 也能跑但如果你想快速迭代建议还是用 GPU。下面是我常用的环境版本Python 3.9 或 3.10PyTorch 2.xopencv-pythonmediapipescikit-learnpandasnumpy安装命令很简单pip install torch opencv-python mediapipe scikit-learn pandas numpy如果你有 GPU建议装对应 CUDA 版本的 PyTorch没有 GPU 也无所谓这个数据集的单次训练时间在 CPU 上也就十几分钟到半小时。4.2 模型核心代码前面已经给了 LSTM 模型定义这里补充 Dataset 和 DataLoader 的关键部分以及训练循环。先把窗口数据封装成 PyTorch 的 Datasetfrom torch.utils.data import Dataset, DataLoader class FallsDataset(Dataset): def __init__(self, windows, labels): # windows: (N, T, 33, 3) self.windows torch.FloatTensor(windows) self.labels torch.LongTensor(labels) def __len__(self): return len(self.labels) def __getitem__(self, idx): x self.windows[idx] # 只取 x, y 坐标拉平成 (T, 66) x x[:, :, :2].reshape(x.size(0), -1) return x, self.labels[idx]训练循环我习惯写得直白一点方便改东西from torch.utils.data import DataLoader train_dataset FallsDataset(train_windows, train_labels) val_dataset FallsDataset(val_windows, val_labels) train_loader DataLoader(train_dataset, batch_size32, shuffleTrue) val_loader DataLoader(val_dataset, batch_size64, shuffleFalse) model FallClassifier(input_dim66) optimizer torch.optim.Adam(model.parameters(), lr1e-3) scheduler torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max30) criterion nn.CrossEntropyLoss(weighttorch.tensor([1.0, 5.0])) for epoch in range(30): model.train() total_loss 0.0 for x, y in train_loader: optimizer.zero_grad() logits model(x) loss criterion(logits, y) loss.backward() optimizer.step() total_loss loss.item() * x.size(0) scheduler.step() # 验证集上算准确率简单看趋势 model.eval() correct 0 total 0 with torch.no_grad(): for x, y in val_loader: logits model(x) preds logits.argmax(dim1) correct (preds y).sum().item() total y.size(0) val_acc correct / total print(fepoch {epoch1:02d} | loss {total_loss/len(train_dataset):.4f} | val_acc {val_acc:.4f})这段代码是能直接跑的。唯一要注意的是我没有在训练循环里做类别下采样如果你想用下采样策略需要单独实现一个 WeightedRandomSampler 或者自定义 DataLoader让每个 batch 里正负样本比例更接近。我实际跑的时候光靠类别权重也能得到不错的效果如果你后面发现正样本召回率特别低再考虑上采样。4.3 训练参数与调优记录下面是我在 Le2i 上跑过的一组比较稳的参数你可以直接参考参数数值说明关键点数33MediaPipe Pose 的输出窗口长度 W24约 0.96 秒25fps步长 S6窗口重叠 75%输入维度66只使用 x、y 坐标LSTM 隐藏单元128单层也行两层更稳Dropout0.5防止小数据过拟合Batch Size32尽量别太大小数据下容易崩学习率1e-3配合 CosineAnnealingEpochs30~60多跑几轮早停更稳类别权重[1.0, 5.0]根据正负样本比例调整在这个配置下如果数据预处理和划分没出问题验证集 F1 通常能做到 0.85 到 0.95。不同版本数据集结果会有差异所以不用太纠结具体数值重点看训练曲线是否平稳、验证集有没有突然塌掉。4.4 评估指标怎么看很多初学者在训练完只看准确率这在类别不平衡的数据集上会骗人。比如负样本占 90%模型全预测负样本准确率也有 90%但一个跌倒都没检测出来这个模型毫无意义。所以我建议至少看三个东西混淆矩阵。能直观看到哪些正样本被漏掉了哪些负样本被误报成跌倒。召回率Recall。跌倒检测里最关键的是“漏报少”宁可误报也别漏报所以正类的召回率很重要。F1 Score。在召回率和精确率之间取平衡。如果你做的是帧级评估那每一帧都算一个判断如果你做的是事件级评估那只要在一次跌倒事件的时间范围内模型至少输出一次“跌倒”就算这个事件被检测到了。后者更贴近真实监控场景。下面是一个简单的评估代码from sklearn.metrics import confusion_matrix, classification_report y_true, y_pred [], [] model.eval() with torch.no_grad(): for x, y in val_loader: logits model(x) preds logits.argmax(dim1) y_true.extend(y.tolist()) y_pred.extend(preds.tolist()) print(confusion_matrix(y_true, y_pred)) print(classification_report(y_true, y_pred, target_names[ADL, Fall], digits4))打印出来的 classification_report 里Fall 那一行的 recall 和 f1-score 是你最需要盯住的两个数字。5. 常见坑与排查技巧实录5.1 容易踩的坑速查表我把操作中遇到的典型问题整理成了一张表方便你对照排查问题现象常见原因解决办法MediaPipe 漏检关键点数组出现大量全零帧人物太小、背对镜头或运动过快放大输入帧降低 min_detection_confidence对缺失帧做插值标注错位可视化时发现标注区间和画面动作对不上视频压缩转格式导致帧数变化用可视化脚本逐帧核对重写标注映射逻辑模型不收敛loss 基本不变准确率接近多数类比例输入特征未归一化或学习率过大先做坐标标准化用少量样本试跑一个 batch过拟合严重训练集 F1 很高验证集很低小数据 模型参数多提高 dropout改用 TCN增加窗口重叠做数据增强数据泄漏验证集分数虚高换新视频后暴跌同一视频的窗口同时出现在 train/val按视频文件划分数据集而不是按窗口随机划分5.2 详细排查思路先说 MediaPipe 漏检。Le2i 视频分辨率偏低有些帧人物比较小MediaPipe 确实会检测不到。你可以试两个方向一是把输入帧先放大一些再送进 pose 模型二是调低 min_detection_confidence 到 0.3 左右。如果连续十几帧都是全零那基本上不是小问题建议直接人工检查原视频看是不是画面里根本没有完整的人。再说标注错位。这个问题通常出现在你用非原始版本视频的时候。比如别人把 avi 转成 mp4 时丢了几帧或者做了裁剪帧号自然就对不上了。我的处理方式是写一个简单的可视化脚本把标注区间画在原视频上比如在跌倒区间给画面加一个红色边框。人眼扫一遍马上就能发现问题出在哪。最后说模型不收敛。如果你发现 loss 一直在很高的位置震荡先别急着调学习率把输入数据拿出来打印一下看看有没有 NaN 或者超大值。我遇到过一次是因为归一化分母除到了接近 0导致某些坐标值爆炸。另外建议训练前先拿一个 batch 的数据做一次 forward backward确认流程能走通再跑完整训练。5.3 如何判断一个模型是真的学到了“跌倒”而不是“背景”这个坑我特别想说。Le2i 场景固定为室内如果模型只记住了“这个房间”的样子换到另一个房间效果就会崩。所以训练时我建议做两件事。第一训练集和验证集尽量来自不同场景。比如训练用 Home、Coffee Room验证用 Office、Lecture Room这样能测出模型是否具备跨场景泛化能力。第二训练完之后写一个可视化脚本把模型对每个窗口的预测结果叠加到原视频上。很多时候你以为模型学到了“跌倒规律”其实它学的是“画面闪动”或“运动模糊”不可视化你是发现不了的。可视化脚本并不复杂就是把预测的标签按帧画到视频上然后保存成新的视频文件用播放器慢放看几遍。我当时就发现模型对“快速弯腰捡东西”特别敏感经常误判为跌倒原因就是关键点轨迹和跌倒太像了。后来我在后处理里加了一个“倒地后静止时间”的条件误报率立刻降下来不少。6. 一点个人体会与扩展建议我自己跑这个数据集时最大的感触是数据预处理比模型设计要费心得多。如果你正在入门跌倒检测建议先把“拿到视频 - 抽关键点 - 切窗 - 训练 - 可视化结果”这条链路完整跑通再考虑换更强的模型。Le2i 尺寸虽小但正因为小你才有机会把每个环节都弄明白而不是盲目堆数据。最后再分享一个小技巧训练完之后可以把手头的数据扩展一下比如在关键点序列里加入相邻帧的差分特征也就是速度和加速度信息。跌倒最明显的特征是垂直方向的重心加速度变化你不需要让模型凭空学会这一点直接把加速度作为额外输入特征模型会学得更快。我就是这样把验证集 F1 从 0.87 提到了 0.92。这个思路后续也可以迁移到自己的监控视频上把关键点模型换成你更熟悉的 YOLOv8-pose时序分类部分保持不变基本就能形成一套自己的跌倒检测原型了。