Downloads · 30 days
83
18% of all-time downloads
ntsrigaud/maestro-lstm-hybrid
maestro-lstm-hybrid is a machine learning model from ntsrigaud. Use it for the machine learning task on the model card, and read the license before you ship it in a product. The card lists the license as other.
A real-time hand gesture classifier trained on the LDJI hybrid gesture dataset (LD-ConGR swipes and fist, Jester zooms, IPN Hand pointing and background).
Downloads · 30 days
83
18% of all-time downloads
All-time downloads
457
Public
Repo size
129 MB
Likes
0
Public
Click a slice to open those files.
.pt129 MB · 100%
From the Hugging Face model README
A real-time hand gesture classifier trained on the LDJI hybrid gesture dataset (LD-ConGR swipes and fist, Jester zooms, IPN Hand pointing and background).
This model is part of the Maestro pipeline that enables touchless control of presentation and meeting software through hand gestures captured from a standard webcam using MediaPipe for landmark extraction.
(batch, 16, 147)
— 16-frame sliding window at 30 FPS ≈ 533 msfeature-schema-v5EnhancedTwoStreamLSTM splits the 147-dim feature vector into two parallel streams and
processes them through a BiLSTM + self-attention + MLP-gate pipeline:
Input (B, T=16, 147)
│
├─ Stream A — Pose/Shape (73 dims)
│ Linear+LN+GELU → 96
│ 2-layer BiLSTM (h=96) → (B, T, 192)
│ LayerNorm → Self-MHA (8 heads) + residual + post-LN
│ mean+max pool → pool_LN → ctx_a (B, 192)
│
├─ Stream B — Motion/Dynamics (74 dims)
│ (identical structure) → ctx_b (B, 192)
│
├─ MLP cross-stream gate
│ gate_a = Sigmoid(
│ Linear(96→192)(
│ Tanh(Linear(192→96)(ctx_b))))
│ ctx_a = LN(ctx_a × gate_a + ctx_a)
│ gate_b = Sigmoid(
│ Linear(96→192)(
│ Tanh(Linear(192→96)(ctx_a))))
│ ctx_b = LN(ctx_b × gate_b + ctx_b)
│
└─ cat(ctx_a, ctx_b) → (384,)
LN → Linear(384→192) → GELU → Dropout → Linear(192→10)
Design rationale:
| Class | Description |
|---|---|
unknown | Background / transition / no gesture |
point_one | Single-finger pointing gesture (continuous laser-pointer control) |
point_two | Two-finger pointing gesture (continuous annotation-pen control) |
fist | Closed fist (LD-ConGR class) |
swiping_down | Vertical swipe downward (LD-ConGR class) |
swiping_left | Horizontal swipe from right to left (LD-ConGR class) |
swiping_right | Horizontal swipe from left to right (LD-ConGR class) |
swiping_up | Vertical swipe upward (LD-ConGR class) |
zooming_in_full_hand | Pinch-open / spread fingers away from each other (Jester class) |
zooming_out_full_hand | Pinch-close / bring fingers together (Jester class) |
| Class | Mode | Command | Runtime handling |
|---|---|---|---|
unknown | discrete | no_action | No-op background class |
point_one | continuous | — | Continuous tracker: LaserPointerTracker (bypasses discrete dispatcher) |
point_two | continuous | — | Continuous tracker: AnnotationPenTracker (bypasses discrete dispatcher) |
fist | discrete | erase_annotations | Discrete command via GestureActivationController → CommandDispatcher |
swiping_down | discrete | stop_presentation | Discrete command via GestureActivationController → CommandDispatcher |
swiping_left | discrete | previous_slide | Discrete command via GestureActivationController → CommandDispatcher |
swiping_right | discrete | next_slide | Discrete command via GestureActivationController → CommandDispatcher |
swiping_up | discrete | start_presentation | Discrete command via GestureActivationController → CommandDispatcher |
zooming_in_full_hand | discrete | zoom_in_view | Discrete command via GestureActivationController → CommandDispatcher |
zooming_out_full_hand | discrete | zoom_out_view | Discrete command via GestureActivationController → CommandDispatcher |
feature-schema-v5)| Block | Dims | Description |
|---|---|---|
position | 0–62 | 21 wrist-relative, scale-normalised landmark positions (x, y, z) |
fingertip_spread | 63–67 | 5 inter-fingertip Euclidean distances |
wrist_trajectory | 68–70 | Net wrist displacement from oldest frame in the window |
velocity | 71–133 | 21 per-landmark wrist-relative velocity vectors (Δposition per unit time) |
joint_angles | 134–143 | 10 MCP + PIP joint angles in radians |
wrist_vel_raw | 144–146 | Camera-normalised wrist velocity (x, y, z) — key directional signal |
import torch
from huggingface_hub import hf_hub_download
from maestro.infrastructure.model.checkpoint_loader import load_inference_artifact
# Download the artifact (cached after first call)
local_path = hf_hub_download(
repo_id="ntsrigaud/maestro-lstm-hybrid",
filename="two_stream_attn_v1_2layer_ld_cong_finetune_20260515T134706Z_inference.pt",
)
# Load the artifact (includes model, class labels, and feature schema)
artifact = load_inference_artifact(
artifact_path=local_path,
device=torch.device("cpu"),
)
artifact.model.eval()
# Build a 147-dim feature vector using LandmarkFeatureTransformer
# and fill a 16-frame SlidingWindowSequenceBuffer, then:
with torch.no_grad():
# tensor shape: (batch=1, T=16, F=147)
window_tensor = torch.tensor(window_np, dtype=torch.float32).unsqueeze(0)
logits = artifact.model(window_tensor)
pred_class = artifact.class_labels[logits.argmax(dim=1).item()]
point_one, point_two, unknown)unknown background)Two-phase transfer learning pipeline:
| Parameter | Value |
|---|---|
| Architecture | EnhancedTwoStreamLSTM (BiLSTM h=96×2, MHA 8 heads, proj=96, mean+max pool, MLP gate) |
| Input size | 147 |
| Hidden size | 96/stream (BiLSTM output: 192) |
| Projection dim | 96 |
| Num layers | 2 per stream |
| MHA heads | 8 (head dim: 24) |
| Learning rate | 3e-05 |
| Weight decay | 0.001 |
| Batch size | 128 |
| Max epochs | 80 |
| Early stopping patience | 20 |
| Label smoothing | 0.05 |
| Class weighting | disabled |
| Max samples per class | 3000 |
| LR scheduler | ReduceLROnPlateau (factor=0.5, patience=10) |
| Metric | Value |
|---|---|
| Accuracy | 96.1% |
| Macro F1 | 95.9% |
| Class | Recall |
|---|---|
fist | 97.3% |
swiping_left | 98.3% |
swiping_right | 97.1% |
swiping_up | 98.2% |
swiping_down | 98.0% |
zooming_in_full_hand | 97.0% |
zooming_out_full_hand | 95.1% |
point_one | 97.4% |
point_two | 95.1% |
unknown | 85.7% |
| Version | Role | Test accuracy | Test macro F1 |
|---|---|---|---|
two_stream_attn_v1_2layer_ld_cong_finetune_20260515T134706Z | Production: default in the Maestro app and installers | 96.1% | 95.9% |
two_stream_attn_finetune_hybrid_10class_finetune_20260606T150031Z | Reference: the model whose results are reported in the ICKII 2026 manuscript | 96.4% | 96.6% |
Both share the same architecture (1,208,554 parameters, 16-frame window) and the LDJI training corpus. The reference model scores slightly higher offline but one swipe gesture was less reliable in live testing, so the production model remains the default. Other artifacts in this repository are earlier experiments.
| Feature | TwoStreamGestureLSTM | EnhancedTwoStreamLSTM |
|---|---|---|
| LSTM direction | Unidirectional | Bidirectional |
| Attention | Bahdanau (scalar) | MHA Q/K/V (8 heads) |
| Feature projection | No | Yes (→96) |
| Temporal pooling | Mean only | Mean + Max |
| Cross-stream fusion | Concat only | 2-layer MLP gate |
| Parameters | ~182 K | ~1,208,554 |
These weights are for academic and non-commercial research use only (see MODEL_LICENSE.md), because they were trained on LD-ConGR (academic research only), Jester (research-use license) and IPN Hand (CC BY 4.0). The Maestro source code is Apache-2.0.
unknown class represents background/transition frames. At runtime, predictions
are filtered through per-class confidence thresholds defined in production_hybrid.yaml.Training was performed on CPU/MPS. Estimated training time: ~10 minutes. Estimated CO₂ equivalent: negligible (<0.001 kg CO₂eq).
Generated by the Maestro training pipeline on 2026-05-13.