File size: 9,735 Bytes
e2d95ed | 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 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | # Setup and operation
Tested on: **Python 3.13.14, Linux x86_64, CPU-only (2 vCPU, ~2 GB RAM)** with the
pinned versions in `requirements.txt`. TensorFlow 2.21 + Keras 3, MediaPipe 1.0.1
(Tasks API only β that release has **no** `mediapipe.solutions`).
---
## 1. Install
```bash
git clone <your-fork> isl-recognition && cd isl-recognition
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install --upgrade pip
pip install -r requirements.txt
python run.py doctor # environment + asset self-check
```
Everything after this is driven by `python run.py <command>`; each command forwards
extra flags to the underlying script (`python run.py train --model gru --epochs 40`).
## 2. Get the data (required for audit/training)
The project trains on AI4Bharat's released **INCLUDE keypoint archive** (β0.66 GB), not
on the 56 GB raw video release.
```bash
# 1) official metadata (a few hundred KB) -> datasets/metadata/
python run.py metadata
# 2) keypoints. Download Pose_Signs.zip from the OpenHands/INCLUDE Zenodo record and
# place the extracted archive where the loader looks, or point the env var at it:
# https://zenodo.org/record/6674324/files/INCLUDE.zip (contains Pose_Signs.zip)
export ISL_KEYPOINTS_PATH=/path/to/Pose_Signs_fresh.zip
python run.py info # the "keypoint archive" line must say OK
```
The loader accepts either the `.zip` archive or an extracted `Pose_Signs/` folder and
records the resolved path in `docs/dataset_audit.md`.
MediaPipe Task bundles (needed only for webcam/video input, not for the dataset):
```bash
python scripts/download_models.py # holistic + pose + hand, with checksums
```
## 3. Reproduce the study (the whole pipeline)
```bash
python run.py audit # PHASE 2 -> docs/dataset_audit.md, results/dataset_audit_summary.json
python run.py preprocess # PHASE 4 -> datasets/processed/sequences_session_disjoint.npz (~37 MB)
python run.py train # PHASES 5-7 -> models/{lstm,gru,gru_mha}/ (~2-3 min/model on 2 vCPU)
python run.py evaluate # PHASE 7 -> results/summary_metrics.csv, per_class_comparison.csv, plots
python run.py robustness # PHASE 8 -> results/robustness_results.csv + degradation plot
python run.py threshold # -> results/threshold_sweep.csv + plot
```
Both split protocols are supported everywhere:
```bash
python run.py preprocess --protocol official
python run.py evaluate --protocol official # -> *_official.csv / *_official.png
python run.py robustness --protocol official
```
Environment overrides (all optional, `.env` is read automatically):
```bash
ISL_SEQUENCE_LENGTH=40 ISL_CONFIDENCE_THRESHOLD=0.8 ISL_SPLIT_PROTOCOL=official python run.py train
```
## 4. Run the system
```bash
# 1) API and browser dashboard (http://localhost:8000; API docs at /docs)
python run.py api
# or: uvicorn backend.main:app --host 0.0.0.0 --port 8000
# 2) Live webcam recognition (local machine, camera required)
python run.py realtime --model gru_mha --threshold 0.70
# keys: q quit | s speech | a accept | c correct | r reject | 1/2/3 model | x clear | b backspace
# 3) Offline / batch
python run.py batch --from-dataset --split test --limit 20
python run.py batch --video uploads/hello.mp4
python run.py batch --video-dir uploads/ --recursive
```
## 5. Tests
```bash
python run.py test # or: python -m pytest tests -v
python -m pytest tests/test_api.py -q
```
Tests that need the dataset or trained models **skip with an explicit reason** when
the artefact is absent, so the suite is meaningful on a fresh checkout and complete on
a full one. No test writes into the real logs (audit paths are redirected to a temp
dir) and no test writes into `models/personalized/`.
## 6. Docker
```bash
docker compose up --build # API + browser dashboard :8000
docker compose run --rm api python training/audit_dataset.py
docker compose run --rm api python -m pytest tests -q
```
Mount `models/`, `datasets/`, `results/`, `logs/` (compose does this) so artefacts and
audit data live on the host.
### Webcam limitations in Docker
A container normally has no `/dev/video0`, and a browser camera belongs to the host
machine, so **local webcam recognition is not available inside Docker**. Supported
alternatives:
1. **Run `backend/inference/realtime.py` on the host** against the same checkout β full camera
rate, the intended way to demo real-time behaviour.
2. **Use the browser dashboard** at `http://localhost:8000` for video upload,
dataset demos or browser-camera capture. Browser capture and network transfer add
latency compared with the local real-time camera loop.
3. **Run the API in Docker** for upload/dataset workflows. The Python real-time camera
loop still runs on the host because it needs direct camera access and local MediaPipe.
## 7. Why the webcam does not work
Run the dedicated check first β it measures the two things a webcam needs (a capture
device and, for the preview window, a display) and prints the matching fix:
```bash
python run.py camera # or: python scripts/camera_check.py --indices 0 1 2 3
```
Measured example from a headless container (this is what "not working" usually is):
```
platform : Linux 6.1.158+
capture devices : none (/dev/video* absent)
DISPLAY : <unset>
OpenCV GUI backend : Qt5
preview window : False (Available platform plugins are: xcb.)
[-- ] index 0: opened=False readable=False ... device could not be opened
* No /dev/video* device exists: this machine has no camera attached
* No usable display: cv2.imshow here aborts the process -> use --no-window
```
| symptom | cause | fix |
|---|---|---|
| `no /dev/video*` / `device nodes: none` | the machine has no camera: server, container, WSL, CI, cloud sandbox, or VM without USB passthrough | use the browser dashboard upload/dataset tabs, `backend/inference/batch.py`, or run on a desktop machine |
| `opened=False` on every index although a camera is attached | camera already in use by another app (Zoom/Teams/browser tab) | close the other app, then re-run |
| same, on macOS | the *terminal application* was never granted camera access | System Settings β Privacy & Security β Camera β enable Terminal/iTerm/VS Code, then restart it |
| same, on Windows | camera access blocked for desktop apps | Settings β Privacy & security β Camera β allow desktop apps |
| index 0 fails, another index works | laptop has an internal + external camera, or a virtual camera is registered first | `python run.py realtime --camera 1` (the script already falls back through indices 0-3) |
| WSL2: no device at all | WSL does not forward USB cameras by default | forward it: `usbipd list` β `usbipd attach --wsl --busid <id>`, then check `/dev/video0` |
| Docker: no device | containers do not get `/dev/video0` automatically | `docker run --device /dev/video0 ...` plus `--group-add video`, and run with `--no-window` (no X server) β see Β§6 |
| process **dies with no Python traceback** after printing `qt.qpa.xcb: could not connect to display` | `cv2.imshow` with no display aborts the process in the C++ layer | this is handled now: `realtime.py` probes the GUI in a subprocess and continues windowless (`--no-window` forces it). If you see it, you are running an older copy |
| `cv2.error: The function is not implemented ...` on `imshow` | OpenCV was installed as `opencv-python-headless` (the pinned default, which has no GUI) | `pip install opencv-python` (non-headless) for a desktop preview window; headless is fine for uploads, batch and dataset work |
| camera works but every sign is `UNCERTAIN` | detector is fine, model confidence is low (that is the gate working) | check the hand-detection rates in the UI/HUD, hold the sign for the full buffer, and tune `--threshold` after reading `docs/evaluation.md` Β§5 |
Reminder: the hosted/sandbox preview you may be looking at has **no camera device and
no display**, so real-time video cannot work there by construction β that is why the
live tab buffers browser captures and why `realtime.py` prints fallbacks instead of a
traceback. Use `python run.py batch --from-dataset`, a video upload, or a desktop
machine for camera-rate recognition.
## 8. Troubleshooting
| symptom | cause / fix |
|---|---|
| `keypoint archive ... --` in `run.py info` | keypoints not found; set `ISL_KEYPOINTS_PATH` (see Β§2) |
| `FileNotFoundError: trained model not found` | train first: `python run.py train` (or `--model gru_mha`) |
| `/predict` returns 503 | same cause; `/health` reports `model_loaded=false` with the reason |
| MediaPipe prints `cuInit`/`oneDNN`/`absl` noise | harmless on CPU builds; the scripts filter it in logging |
| `Could not open camera index 0` | headless/container environment β see Β§6 and Β§7 |
| TTS says unavailable | no `gtts`/`pyttsx3` or no audio player; recognition still works (`TTS_ENGINE=none` disables it explicitly) |
| frontend shows "Backend not reachable" | start the API first (`python run.py api`) β the UI never fakes a prediction |
| Docker build is slow | TensorFlow is a large wheel; the layer cache makes rebuilds cheap |
## 9. Housekeeping
* `logs/predictions.jsonl` and `logs/feedback/feedback.jsonl` grow append-only; delete
them to reset the error-review view (or use `backend.inference.audit.clear_logs()`).
* Evaluation results, trained model weights, the processed session-disjoint tensor
and MediaPipe task bundles are kept in the project for a reproducible demo.
* Raw recordings and uploaded videos are not included in the repository; uploads are
never retained unless `ISL_PERSIST_UPLOADS=true`.
|