Skip to content

Commit ab4e20a

Browse files
committed
feat: recognise 238 LSE signs with a trained model
1 parent 9beeb16 commit ab4e20a

17 files changed

Lines changed: 1542 additions & 27 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ __pycache__
2222

2323
# Staged from node_modules by scripts/copy-wasm.mjs, never committed.
2424
public/wasm
25+
tools/train/artifacts

README.md

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Three engines answer through one port, so the app does not care which one produc
1515
| Engine | What it reads | Where it comes from |
1616
| --- | --- | --- |
1717
| **Alphabet** | Fingerspelled letters (dactilológico). Spell anything, letter by letter. | Geometric handshape rules — no training data needed. |
18-
| **Vocabulary** | Whole LSE signs, one word each. | ONNX model trained on [SWL-LSE](https://zenodo.org/records/13691887): 300 classes, ~180 concepts after merging variants. Health domain. **Not built yet.** |
18+
| **Vocabulary** | Whole LSE signs, one word each. | GRU trained on [SWL-LSE](https://zenodo.org/records/13691887): 238 health-domain concepts. **63% top-1, 83% top-3** on the dataset's own held-out test split. |
1919
| **Taught** | Any sign you record yourself, in any sign language. | Nearest-prototype match over 3+ recordings, stored in IndexedDB on your device. Working now. |
2020

2121
### What it does not do
@@ -27,6 +27,23 @@ Sign `[YO] [CABEZA] [DOLOR]` and you get "yo cabeza dolor", not "me duele la cab
2727
Continuous sentence-level sign language translation is an open research problem. Treating
2828
word-level output honestly is a design decision, not a missing feature.
2929

30+
### How good is the vocabulary model, really
31+
32+
63% top-1 and 83% top-3 on 598 held-out samples across 238 classes — against a 0.4% random
33+
baseline. Useful, not authoritative. The UI says so, and the transcript is editable.
34+
35+
Those numbers come from SWL-LSE's own train/val/test split, never from data the model saw.
36+
`tools/train/train.py` prints them on every run and writes them into the shipped manifest, so
37+
the figure in this README cannot drift from the model that is actually deployed.
38+
39+
**There is no inference runtime.** onnxruntime-web needs 13 MB of WASM to run a 2.4 MB model,
40+
and on GitHub Pages it cannot even use threads — Pages sends no COOP/COEP headers. The
41+
network is a fixed stack (LayerNorm → 2-layer bidirectional GRU → mean-pool → 2 linear
42+
layers), so `src/infrastructure/recognition/gru.ts` computes it directly and the weights ship
43+
as one flat float32 blob. `VocabularySignClassifier.test.ts` checks the whole stack against
44+
logits PyTorch produced for a fixed input, because a hand-written GRU that is subtly wrong
45+
still runs and still returns plausible numbers.
46+
3047
## Architecture
3148

3249
Hexagonal, with constructor injection and no DI framework — a plain `Container` wires
@@ -56,10 +73,17 @@ index point against a Y at 0.962 — no threshold separates those. Distance over
5673
normalised coordinates gives 0.10 and 0.25 for the same pairs. If taught-sign recognition
5774
ever starts matching everything, check that this has not been "simplified" back to cosine.
5875

59-
**Normalisation must match training.** `normalizeHand` mirrors what `tools/train` applies to
60-
the dataset. A model trained on normalised coordinates and fed raw ones predicts noise
61-
silently rather than failing — if recognition degrades for no visible reason, check this
62-
first.
76+
**Normalisation must match training.** `windowSignature` and `tools/train/features.py` must
77+
produce byte-identical layouts. A model trained on one and fed the other predicts noise
78+
silently rather than failing — the loader throws on a length mismatch, but a same-length
79+
reordering would slip through. If recognition degrades for no visible reason, diff those two
80+
files first.
81+
82+
**Known limitation in taught signs.** The signature carries the wrist position because LSE
83+
gives location meaning, but it is 3 floats out of 66 per hand, so plain distance matching
84+
barely weights it. The trained model learns its own weighting and copes; taught-sign matching
85+
does not, so two taught signs differing only in height will be confused. Covered by a test
86+
that asserts the real figure rather than a hoped-for one.
6387

6488
## Development
6589

public/models/lse-vocabulary.bin

2.38 MB
Binary file not shown.

0 commit comments

Comments
 (0)