File size: 6,020 Bytes
9313a90 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | ---
license: cc-by-nc-sa-4.0
language:
- vi
library_name: pytorch
pipeline_tag: video-classification
tags:
- computer-vision
- fall-detection
- pose-estimation
- mediapipe
- temporal-convolution
---
# Phát hiện té ngã từ video dựa trên tư thế cơ thể
Project code hoàn chỉnh theo pipeline:
`Video RGB → MediaPipe (33 điểm khớp) → chuẩn hóa tư thế → cửa sổ 4 giây → Pose-TCN/Pose-GRU → làm trơn → cảnh báo`
Project đã chạy trên bộ UR Fall Detection (URFD). Kết quả cố định với seed 42 trên tập test gồm 41 cửa sổ thuộc 13 video:
| Mô hình | Accuracy | Precision | Recall | Specificity | F1 | ROC-AUC |
|---|---:|---:|---:|---:|---:|---:|
| Random Forest | 97,56% | 100,00% | 87,50% | 100,00% | 93,33% | 1,000 |
| Logistic Regression | 95,12% | 80,00% | 100,00% | 93,94% | 88,89% | 1,000 |
| Pose-TCN (CUDA) | 95,12% | 80,00% | 100,00% | 93,94% | 88,89% | 1,000 |
| Pose-GRU (CUDA) | 90,24% | 70,00% | 87,50% | 90,91% | 77,78% | 0,989 |
Đây là kết quả theo **cửa sổ video**, không phải theo người. URFD không cung cấp ánh xạ danh tính đủ rõ để chia subject-independent, vì vậy không dùng bảng trên để tuyên bố khả năng tổng quát hóa lâm sàng.
## Chạy nhanh
Project dùng Python 3.10–3.12. Tạo môi trường và cài thư viện:
```bash
python -m venv .venv
source .venv/bin/activate
pip install -e '.[dev]'
```
Để chạy Pose-GRU trên GPU NVIDIA, cài wheel PyTorch phù hợp trước. Máy đã dùng cho kết quả trong project chạy CUDA 12.8:
```bash
pip install torch --index-url https://download.pytorch.org/whl/cu128
python -c "import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0))"
```
Chạy lại toàn bộ thí nghiệm URFD. Lệnh sẽ tự tải khoảng 70 video từ nguồn chính thức nếu chưa có dữ liệu:
```bash
python scripts/run_all.py
```
Chạy demo trên video:
```bash
python scripts/demo_video.py \
--input data/videos/fall/fall-01/fall-01-cam0.mp4 \
--model artifacts/experiments/urfd/pose_tcn/model.pt \
--output artifacts/demo_fall01.mp4
```
## Chạy từng bước
```bash
# 1. Tải 30 video té và 40 video sinh hoạt thường ngày
python scripts/download_urfd.py
# 2. Trích keypoint và tạo dataset .npz
python scripts/prepare_dataset.py
# 3. Huấn luyện hai baseline
python scripts/train_baselines.py
# 4. Huấn luyện hai mô hình sâu
python scripts/train_gru.py
python scripts/train_tcn.py
# 5. Tổng hợp bảng và biểu đồ
python scripts/compare_models.py
# 6. Kiểm thử mã
pytest -q
```
Kết quả nằm tại `artifacts/experiments/urfd/`. Mỗi mô hình có trọng số, `metrics.json`, dự đoán từng mẫu, confusion matrix và ROC. File `results.csv` và `model_comparison.png` tổng hợp một lần chạy.
## Dữ liệu riêng
Sắp xếp mỗi video trong một thư mục nhóm riêng. Nhóm có thể là mã người hoặc mã video; nếu có mã người, nên dùng mã người để phép chia không rò rỉ danh tính.
```text
data/videos/
├── fall/
│ ├── person01/video01.mp4
│ └── person02/video02.mp4
└── normal/
├── person01/video03.mp4
└── person02/video04.mp4
```
Với dữ liệu không phải URFD và không có annotation frame, mọi cửa sổ trong `fall/` được gán nhãn té. Nên cắt video để mỗi clip té thực sự chứa sự kiện té. Sửa tham số trong [configs/default.yaml](configs/default.yaml).
## Thiết kế thí nghiệm
- Mỗi cửa sổ dài 40 frame ở 10 FPS, tương đương 4 giây; stride 10 frame.
- Pose được tịnh tiến về tâm hông và chia theo chiều dài thân/độ rộng vai.
- Pose-GRU dùng 140 chiều/frame: 33 × `(x, y, z, visibility)` và 8 đặc trưng hình học/chuyển động.
- Pose-TCN dùng 60 chiều/frame: 13 khớp cốt lõi × 4 kênh và 8 đặc trưng bổ sung, giúp giảm overfit trên URFD nhỏ.
- Chia train/validation/test theo group với tỷ lệ 60/20/20; các cửa sổ cùng video luôn ở cùng tập.
- Ngưỡng xác suất tối ưu F1 chỉ được chọn trên validation. Test không tham gia chọn mô hình/ngưỡng.
- GRU và TCN dùng BCE có trọng số lớp, AdamW, early stopping; hai baseline dùng cùng dữ liệu và phép chia.
## Chạy lặp nhiều seed
Lệnh sau chạy cả bốn mô hình với 5 seed, mỗi seed có phép chia theo video riêng. Pose-GRU và Pose-TCN tự dùng CUDA nếu có; hai mô hình scikit-learn chạy CPU.
```bash
python scripts/run_repeated_experiments.py --seeds 13 21 42 84 123 --device cuda
```
Kết quả từng lần nằm trong `artifacts/experiments/urfd_repeated/seed_*/`. Bảng tổng hợp mean, standard deviation, min và max nằm tại `aggregate_results.csv`.
Kết quả trên 5 seed đã chạy:
| Mô hình | Accuracy mean ± std | Recall mean ± std | F1 mean ± std | ROC-AUC mean ± std |
|---|---:|---:|---:|---:|
| Random Forest | 0,968 ± 0,026 | 0,885 ± 0,114 | **0,907 ± 0,061** | 0,997 ± 0,007 |
| Logistic Regression | **0,969 ± 0,021** | **0,955 ± 0,062** | 0,904 ± 0,095 | 0,991 ± 0,015 |
| Pose-TCN (CUDA) | 0,961 ± 0,040 | 0,915 ± 0,132 | 0,901 ± 0,069 | 0,983 ± 0,035 |
| Pose-GRU (CUDA) | 0,942 ± 0,043 | 0,865 ± 0,139 | 0,842 ± 0,098 | 0,996 ± 0,006 |
URFD có 70 chuỗi (30 fall, 40 ADL), phát hành theo CC BY-NC-SA 4.0 cho nghiên cứu phi thương mại tại [trang dữ liệu chính thức](https://fenix.ur.edu.pl/~mkepski/ds/uf.html). Khi sử dụng, trích dẫn bài của Kwolek và Kępski, DOI `10.1016/j.cmpb.2014.09.005`.
Repository công khai chứa code, checkpoint và kết quả thí nghiệm. Video URFD gốc, pose dataset đã trích và video demo không được đóng gói cùng repository; dùng `scripts/download_urfd.py` để tải dữ liệu từ nguồn chính thức.
|