First release: model, model card, methods, credits
Browse files- FUTO-SWIPE-DATA-LICENSE.txt +21 -0
- METHODS.md +223 -0
- NOTICE.md +61 -0
- README.md +218 -0
- swipe-model.bin +3 -0
FUTO-SWIPE-DATA-LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2025 FUTO
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
METHODS.md
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# How we measured everything
|
| 2 |
+
|
| 3 |
+
Draft, not published. Every number is traced to a file in the repository in an HTML comment next to it. Where a number does not exist in our records, this page says "not measured" instead of estimating one.
|
| 4 |
+
|
| 5 |
+
Models trained and released by Destin Moss via youcoded.ai, 2026. Project: https://github.com/itsdestin/swipe-keyboard. Model cards: [docs/models/](https://huggingface.co/youcoded).
|
| 6 |
+
|
| 7 |
+
## Why this page exists
|
| 8 |
+
|
| 9 |
+
We say our next-word and swipe models are good in some places and not in others. That is only believable if you can see exactly what was counted, on which text, against what, and what we got wrong along the way. This page is that account. It includes a measurement error we made and retracted ([the devhold incident](#the-devhold-contamination-incident)).
|
| 10 |
+
|
| 11 |
+
Plain rules we follow:
|
| 12 |
+
|
| 13 |
+
- Every figure says its denominator (how many sentences or swipes, and which ones).
|
| 14 |
+
- A change ships only if no language got worse on any scoreboard measure beyond noise: about 1 point on sets of roughly 700 words, wider sets where a decision hinges on a smaller gap.
|
| 15 |
+
- Test data never feeds training (see [safeguards](#data-leak-safeguards)).
|
| 16 |
+
- Results are reported with the places where we lose, not only where we win.
|
| 17 |
+
|
| 18 |
+
## The three tasks
|
| 19 |
+
|
| 20 |
+
| Task | What the user does | What we count |
|
| 21 |
+
|---|---|---|
|
| 22 |
+
| **Next word** | A sentence is partly typed; no letters of the next word yet. | The word the writer actually typed next is among the 3 suggestions ("top 3"). |
|
| 23 |
+
| **Completion after N letters** | The first N letters (1, 2 or 3) of the next word are typed. | The word is among the suggestions. We report **top 2** because the keyboard (and Gboard) show the typed letters themselves in one of the three slots. Words with N letters or fewer are skipped. |
|
| 24 |
+
| **Swipe decoding** | A finger path across the keyboard. | **First guess**: the first suggestion is the target word. **Top 3**: it is among the first three. |
|
| 25 |
+
|
| 26 |
+
Matching is case-insensitive for typing tasks (capitals are display, not prediction). For swipes, the ASCII benchmark compares letters only; the HeliBoard sets are case-insensitive with accents kept.
|
| 27 |
+
|
| 28 |
+
## Test sets
|
| 29 |
+
|
| 30 |
+
### Next word and completion
|
| 31 |
+
|
| 32 |
+
All three sets are built by `scripts/lm/make-nextword-testsets.py` with a fixed seed so every model is scored on the same text; 2,000 sentences each by default, 4 to 30 words per sentence, no URLs or code-like text. The routine scoreboard uses the **first 300 sentences** of each set (about 2,000 scored words per measure); blend tuning uses sentences 1000 and beyond so the reported ones stay untouched.
|
| 33 |
+
|
| 34 |
+
| Set | Source | Licence | Notes |
|
| 35 |
+
|---|---|---|---|
|
| 36 |
+
| **everyday** | Common Voice's community-written sentences, minus any that also appear in Tatoeba | CC0 | Read-aloud style, not texting. Never trained on. |
|
| 37 |
+
| **web** | Sentences from the FineWeb-2 official test split, at most one per web page (English: a FineWeb sample shard kept out of training) | ODC-By 1.0 | Partly "home ground" for models trained on web text. |
|
| 38 |
+
| **tatoeba** | Tatoeba sentences whose id ends in 0 | CC BY 2.0 FR | The tenth the packs never trained on. Home ground for models that train on the other nine tenths. |
|
| 39 |
+
|
| 40 |
+
No single source is neutral. A model built from web text should win on web text; we read a model as "better" only if it also wins on sets it was not built from. We say so next to each result.
|
| 41 |
+
|
| 42 |
+
### Swipes, English, real
|
| 43 |
+
|
| 44 |
+
FUTO's public swipe recordings (MIT licence; swipe.futo.org). Splits we use:
|
| 45 |
+
|
| 46 |
+
| Name | What it is | Use |
|
| 47 |
+
|---|---|---|
|
| 48 |
+
| `bench-2000` | 2,000 swipes spread evenly across FUTO's test split (every k-th line, so many different people; `bench/make-slice.py`) | final scoring only |
|
| 49 |
+
| `test-extra-10000` | 10,000 further swipes of the test split (how they were picked is not recorded in the repository) | final scoring only |
|
| 50 |
+
| `test.jsonl` | FUTO's full test split | clean3000 below is drawn from it |
|
| 51 |
+
| clean3000 | 3,000 swipes from `test.jsonl` excluding bench-2000 and test-extra-10000 | diagnostic; never trained on or tuned against |
|
| 52 |
+
| trv8k | 7,198 swipes: a 5 % session-level slice of FUTO's training file that keeps its sentence text | validation, and the sentence-context experiment |
|
| 53 |
+
| validation sessions | 10 % of `dev.jsonl` by whole recording session (6,637 swipes) | model selection |
|
| 54 |
+
|
| 55 |
+
bench-2000 is scored the same way for FUTO's engine and ours. Two denominators are always reported: **all swipes** (including those whose target is not in the word list and so can never be found) and **in-dictionary** (only swipes whose target is in the word list). FUTO's own tool skips about 3 % of swipes it cannot score; we state the count where we compare.
|
| 56 |
+
|
| 57 |
+
### Swipes, Spanish, French, German
|
| 58 |
+
|
| 59 |
+
- **HeliBoard real multilingual swipes** (from the HeliBoard project's gesture test data; CC BY-SA): 5,000 real swipes per language, with each swipe's real board geometry. **Test only. Never trained on** (the share-alike licence is the reason we kept it out of training).
|
| 60 |
+
- **Synthetic noisy swipes** (`bench/languages/synthetic-noisy-v1-{es,fr,de}.json`): 400 words each, sampled by frequency from our everyday and web test text, traced by a noise model fitted on real English swipes, then scaled so synthetic English matched real English on bench-2000 (92.3 vs 92.8 first guess). They only cover dictionary words and assume people swipe other languages like English. They are **not human swipes** and are never marked as reviewed by native speakers. A different generator (`scripts/swipe/synth_swipes.py`) makes training swipes, so the model is never scored on its own generator's output.
|
| 61 |
+
- **Real swipes from FUTO's `swipe-5`**: real French, German and Spanish swipes on their own layouts, used for training; validation slices of it are a development check only.
|
| 62 |
+
- **Hand-authored fixtures** (`synthetic-centered-v1.json`, 30 seeds): not reviewed by native speakers, no thresholds attached, used for code regression checks, not accuracy claims.
|
| 63 |
+
|
| 64 |
+
Real volunteer swipes for Spanish, French and German from people who speak them: **still missing**.
|
| 65 |
+
|
| 66 |
+
## How Gboard was measured from the outside
|
| 67 |
+
|
| 68 |
+
We compare with Gboard only by using the app, as a user would. Full procedure: `bench/gboard/README.md`.
|
| 69 |
+
|
| 70 |
+
- **What:** Gboard 14.2 (the copy built into Google's Android 35 x86_64 emulator image; the repository records no fuller build number), learning from typing **off**, one language at a time with multilingual typing off. Measured 2026-10-22.
|
| 71 |
+
- **Sentences:** 100 per language per set, from our own test sets (everyday and web).
|
| 72 |
+
- **Method:** for every word, the words before it plus its first 0, 1, 2 or 3 letters are put into a Messages text box, and the three suggestions are read off the screen. The three slots are recorded left, middle, right; middle is Gboard's best guess. This "text fill" method is much faster than tapping every key.
|
| 73 |
+
- **Check that text fill matches real typing:** 30 random phrases typed with real key taps gave the same suggestions as text fill in **27 of 30** cases; the 3 differences were single words with no direction (`validate_taps.py`).
|
| 74 |
+
- **Slot rule:** once letters are typed, Gboard spends one slot on the typed letters (95 to 100 % of rows), so the fair figure for us is "right word in our top 2". Before typing, both get 3. Sentence starts are not scored because Gboard shows shortcut chips there instead of words.
|
| 75 |
+
- **Frozen answers:** Gboard's replies are saved in `bench/gboard/reference/LANG-SET.tsv` (one row per query: sentence number, word number, letters typed, text before the word, the word, left / middle / right suggestion). `bench/scoreboard.sh` replays our predictor over exactly those queries, so anyone can compare without an Android device. English, Spanish, French and German references are committed.
|
| 76 |
+
- **Limits:** one Gboard version (current Gboard is newer and may differ); Gboard with learning on was not measured; learning off, so this is Gboard's out-of-the-box model, not what it does after weeks of use; 100 sentences per set gives roughly +-2 points of noise; the emulator is Google's and we have no view inside Gboard.
|
| 77 |
+
- **Gboard swipe typing: not measured.**
|
| 78 |
+
|
| 79 |
+
## How FUTO's engine was measured
|
| 80 |
+
|
| 81 |
+
FUTO's swipe engine is shipped with the keyboard as the default and used as the reference for swipe accuracy. We run it through two paths:
|
| 82 |
+
|
| 83 |
+
1. FUTO's own `infer_jsonl` program on the bench-2000 slice (beam width 100, top 3). With the stock dictionary this gave 92.50 first guess / 95.43 top 3 on 2,000 swipes.
|
| 84 |
+
2. Through our own recogniser harness with FUTO's models and our current dictionary: 93.32 first guess / 96.56 top 3 on bench-2000. This is the "FUTO 93.32 / 96.56" figure used in the model card.
|
| 85 |
+
|
| 86 |
+
The two differ because of the dictionary and ranking used, not the same code path; when we compare, we name which one. On clean3000, FUTO's tool scores the 2,909 swipes it can read: 92.5 / 96.3.
|
| 87 |
+
|
| 88 |
+
FUTO's code and model weights were **not used** in our own swipe engine (see below). FUTO's public swipe data (MIT) was used for training, with its licence text kept. FUTO's next-word model was the keyboard's English suggestion engine before 2026-10-22; we measured it as the "before" baseline for English (see results).
|
| 89 |
+
|
| 90 |
+
## Reproducing everything: the scoreboard
|
| 91 |
+
|
| 92 |
+
`bench/scoreboard.sh` is one command that rebuilds the typing table for all four languages: next word, completion after 1 and 3 letters, speed, pack size, and the same against Gboard's frozen answers. It appends rows to `bench/scoreboard.tsv`; `--check` fails if any accuracy measure fell more than 1 point below the previous run (about 2,000 scored words per measure, so smaller moves are noise). A full run takes a few minutes.
|
| 93 |
+
|
| 94 |
+
Rows in `bench/scoreboard.tsv` (commit and label are recorded per row):
|
| 95 |
+
|
| 96 |
+
| Label | Commit | What it is |
|
| 97 |
+
|---|---|---|
|
| 98 |
+
| installed packs (Tatoeba-only) | 7f53d8c | The keyboard's n-gram files before 2026-10-22 (es / fr / de) |
|
| 99 |
+
| new web+Tatoeba packs (mix30-S) | 7f53d8c | First web + Tatoeba packs |
|
| 100 |
+
| published language files 2026-10-22 (XS) | fd59e68 | The published XS n-gram files |
|
| 101 |
+
| open word lists 2026-10-22 | a2041d8 | Same, with the open (non-share-alike) word lists |
|
| 102 |
+
| AI models + open word lists 2026-10-23 | d63a2ce | The above plus the four neural next-word models |
|
| 103 |
+
|
| 104 |
+
Swipe accuracy comes from `tools/swipekb-swipenet-bench` (our engine) and `bench/score.sh` (FUTO's), described in the model card.
|
| 105 |
+
|
| 106 |
+
## Data-leak safeguards
|
| 107 |
+
|
| 108 |
+
1. **8-word-run exclusion (next word).** Any training sentence that shares a run of 8 consecutive words with any sentence of the three test sets is dropped, for both the n-gram files and the neural models. The same rule applies to the counts behind the word lists. This removes verbatim overlap, not paraphrases.
|
| 109 |
+
2. **Tatoeba tenths.** Test set = ids ending in 0; training uses the other nine tenths only.
|
| 110 |
+
3. **Test-only data stays test-only.** Common Voice sentences (CC0) and the HeliBoard swipes are never trained on.
|
| 111 |
+
4. **Tuning on other sentences.** Blend weights for the neural models were tuned on test-file sentences 1000 and beyond; reported scores use the first 300.
|
| 112 |
+
5. **Session-level splits (swipe).** Swipes from one person look alike, so a random split would leak that person into validation. Validation is 10 % of `dev.jsonl` by whole session (a stable SHA-1 of the session id).
|
| 113 |
+
6. **Overlap check against every evaluation file.** Before training on FUTO's other collections, every swipe whose (session, timestamp) key, or whose session, appears in bench-2000, test-extra-10000, `test.jsonl` or the validation sessions is dropped, with counts printed. Checked: 56,005 swipe keys and 768 sessions; no overlapping swipe or session occurred in any collection (counts kept: `swipe-1` 901,908; `swipe-2` 23,774; `swipe-3` 34,769; `swipe-4` 43,909; `swipe-5` 50,507).
|
| 114 |
+
7. **Different generators for training and test synthetic swipes.** (`synth_swipes.py` vs `make-noisy-swipes.py`.)
|
| 115 |
+
8. **Final sets are scored rarely.** bench-2000 and test-extra-10000 are scored once per final model, not used for selection.
|
| 116 |
+
|
| 117 |
+
## The devhold contamination incident
|
| 118 |
+
|
| 119 |
+
On 2026-10-22 we reported swipe results from validation sets called `devhold-5000`, `tune-2000` and `tune-10000`. They looked excellent: a first GPU-trained model scored 93.02 / 96.07, apparently tying FUTO's 93.3 / 96.6, and an earlier CPU model scored 91.5.
|
| 120 |
+
|
| 121 |
+
They were wrong. Those validation sets were **entirely contained in `dev.jsonl`, the training file** (100 % of ids and sessions). Every figure measured on them was a score on training swipes. We found it (the swipe helper noticed), verified it by comparing ids and sessions, and **retracted all devhold numbers**. The corrected first read, on 3,000 fresh swipes from `test.jsonl` that were never trained on, put our model at 88.6 / 93.9 (all swipes counted) versus FUTO's 92.5 / 96.3: a gap of roughly 2 to 4 points, not zero.
|
| 122 |
+
|
| 123 |
+
What we changed: validation is now whole recording sessions held out of `dev.jsonl`; model selection uses only that; bench-2000 and test-extra-10000 are final-only; and `split_by_session.py` documents the incident in its header so nobody reuses the old sets. The geometric decoder's 82.0 / 90.0 result never trained on `dev.jsonl` and stands.
|
| 124 |
+
|
| 125 |
+
## What we deliberately did not use
|
| 126 |
+
|
| 127 |
+
- **FUTO code.** The own swipe engine (CTC network, lexicon beam search, geometric fallback) was written from published literature (Graves et al. 2006 on CTC; Alsharif et al. 2015 and follow-ups on gesture decoding; Kristensson and Zhai 2004; dynamic time warping), by a writer who had not read FUTO's source. Our authorship audit separately marks which older files of the repository are FUTO-derived (53 files, mostly glue for calling FUTO's engine) so they can be removed.
|
| 128 |
+
- **FUTO model weights.** None are in our models. FUTO's engine is still the keyboard's default swipe engine for now and keeps its own licence and notice.
|
| 129 |
+
- **A Gboard study report.** Early in the project a static study of Gboard 18.5's app code was written. It was withdrawn at the owner's request on 2026-10-23 and removed from the current tree (it remains in older git history); nothing in our models, data or numbers depends on it. Gboard is compared only by using the app from the outside, as described above.
|
| 130 |
+
- **HeliBoard data for training.** Its gesture data is CC BY-SA (share-alike); we use it for testing only.
|
| 131 |
+
- **wordfreq.** Replaced by word lists counted from FineWeb / FineWeb-2 and Tatoeba (share-alike term removed).
|
| 132 |
+
- **Real users' typing.** Nothing is collected from users. The opt-in swipe recorder in the plugin exists but its recordings are not part of any model here.
|
| 133 |
+
|
| 134 |
+
## Results summary
|
| 135 |
+
|
| 136 |
+
All typing figures: percent, 300 sentences per set, `bench/scoreboard.tsv` commit d63a2ce (n-gram files plus neural models); "vs Gboard" = points ahead (+) or behind (-) Gboard 14.2 (the copy built into Google's Android 35 x86_64 emulator image, learning off, tested 2026-10-22) on its recorded queries, 100 sentences per set, top 3 before typing and top 2 after. Compare with caution: web and Tatoeba sets are partly home ground.
|
| 137 |
+
|
| 138 |
+
### Typing
|
| 139 |
+
|
| 140 |
+
| Language | Next word, top 3: everyday / web / Tatoeba | After 1 letter, top 2: everyday / web / Tatoeba | After 3 letters, top 2: everyday / web / Tatoeba | vs Gboard 14.2 (emulator copy, learning off), 1 letter: everyday / web |
|
| 141 |
+
|---|---|---|---|---|
|
| 142 |
+
| English | 29.36 / 31.62 / 43.83 | 51.96 / 52.89 / 67.82 | 71.97 / 73.53 / 88.97 | +11.95 / +12.87 |
|
| 143 |
+
| Spanish | 26.27 / 33.25 / 31.32 | 49.93 / 56.57 / 58.58 | 67.08 / 75.10 / 77.24 | +6.58 / +17.46 |
|
| 144 |
+
| French | 22.10 / 31.97 / 32.79 | 46.46 / 54.07 / 59.35 | 65.44 / 73.70 / 74.47 | +4.29 / +12.70 |
|
| 145 |
+
| German | 25.04 / 24.22 / 31.57 | 48.70 / 47.46 / 57.87 | 70.01 / 66.69 / 78.40 | +5.88 / +10.76 |
|
| 146 |
+
|
| 147 |
+
The neural models add (against the n-gram files alone, commit a2041d8): between +0.36 (English, Tatoeba, after 1 letter) and +9.32 (Spanish, web, after 3 letters) points depending on set and measure, largest on web text and after 3 letters; 3 of the 36 measures moved by less than 1 point, i.e. within noise. See each [model card](https://huggingface.co/youcoded) for the per-measure tables. Before the 2026-10-22 open files, the keyboard trailed or tied Gboard on several French and German web measures (French web: -5.11 points after 1 letter, -13.22 after 3 letters), and on the recorded 0- and 1-letter measures its lead over Gboard was never larger than 2.33 points (Spanish, French and German, everyday text).
|
| 148 |
+
|
| 149 |
+
### Swipe (model T1; English real swipes, FUTO's test split)
|
| 150 |
+
|
| 151 |
+
| Set | Denominator | Ours first / top 3 | FUTO first / top 3 |
|
| 152 |
+
|---|---|---|---|
|
| 153 |
+
| bench-2000 | all 2,000 swipes | 90.40 / 94.95 | 93.32 / 96.56 |
|
| 154 |
+
| bench-2000 | in-dictionary (1,958) | 92.34 / 96.99 | not restricted this way |
|
| 155 |
+
| test-extra-10000 | all 10,000 | 90.77 / 94.97 | not measured |
|
| 156 |
+
| test-extra-10000 | in-dictionary (9,781) | 92.80 / 97.10 | not measured |
|
| 157 |
+
| clean3000 | in-dictionary | 93.13 / 97.37 | 92.5 / 96.3 (2,909 swipes it can score) |
|
| 158 |
+
|
| 159 |
+
### Swipe, other languages (HeliBoard real swipes, test only, 5,000 each, first / top 3)
|
| 160 |
+
|
| 161 |
+
| Language | Ours (T1, 260k word lists) | FUTO engine today (older, smaller packs; not like-for-like) |
|
| 162 |
+
|---|---|---|
|
| 163 |
+
| English | 82.1 / 91.5 | 84.5 / 93.4 |
|
| 164 |
+
| Spanish | 81.1 / 89.8 | 77.7 / 85.1 |
|
| 165 |
+
| French | 71.7 / 85.9 | 64.6 / 76.9 |
|
| 166 |
+
| German | 73.3 / 82.3 | 69.7 / 76.4 |
|
| 167 |
+
|
| 168 |
+
### What is not measured
|
| 169 |
+
|
| 170 |
+
- Gboard swipe accuracy; Gboard English next word with its learning on; any newer Gboard.
|
| 171 |
+
- Real volunteer swipes for Spanish, French and German (HeliBoard's are real but from a different population; synthetic ones are model-made).
|
| 172 |
+
- Our swipe model on the synthetic Spanish, French and German sets (those sets were scored only with the older FUTO-engine keyboard: es 89.00 / 98.25, fr 83.25 / 93.00, de 87.75 / 97.00).
|
| 173 |
+
- FUTO's English next-word model on completion after letters; FUTO against the HeliBoard sets with the new open word lists.
|
| 174 |
+
- Validation perplexity and training curves of the next-word models.
|
| 175 |
+
- Speed on ARM or Steam Deck hardware (no device available).
|
| 176 |
+
- Texting-style text (all next-word sets are read-aloud, web or example-sentence text).
|
| 177 |
+
|
| 178 |
+
## Known limits of the whole method
|
| 179 |
+
|
| 180 |
+
- Small sets: 300 sentences (about 2,000 words) per typing measure, 100 sentences against Gboard. Differences under about 1 to 2 points are noise.
|
| 181 |
+
- One Gboard version (14.2, emulator copy), learning off, tested 2026-10-22; newer versions may differ and learning-on behaviour was not measured. We make no general claim about Gboard.
|
| 182 |
+
- Synthetic swipes are provisional; non-English real-swipe evidence comes from HeliBoard (test) and FUTO's `swipe-5` (training).
|
| 183 |
+
- The home-ground effect on web and Tatoeba sets.
|
| 184 |
+
- A single hardware setup: one desktop with an RTX 4070 Super for training; swipe speed measured on a loaded desktop CPU.
|
| 185 |
+
- We do not know a user's real-life accuracy; none of these are field trials.
|
| 186 |
+
- The incident above shows measurements here can be wrong. Corrections are recorded in git history and the roadmap.
|
| 187 |
+
|
| 188 |
+
## How to reproduce
|
| 189 |
+
|
| 190 |
+
From a checkout of https://github.com/itsdestin/swipe-keyboard, build the tools (the Qt build produces `build/tools/swipekb-nextword-eval` and `build/tools/swipekb-swipenet-bench`).
|
| 191 |
+
|
| 192 |
+
```
|
| 193 |
+
# Typing: build the three test sets (needs the Tatoeba export, Common Voice sentences, a FineWeb-2 test parquet)
|
| 194 |
+
python -I scripts/lm/make-nextword-testsets.py LANG TATOEBA.tsv.bz2 COMMONVOICE.txt FINEWEB2-TEST.parquet OUTDIR
|
| 195 |
+
|
| 196 |
+
# Typing: the scoreboard (all four languages; add --check to fail on a regression of more than 1 point)
|
| 197 |
+
SWIPEKB_NEXTWORD_EVAL=build/tools/swipekb-nextword-eval SWIPEKB_TESTSETS=<dir with LANG/test/*.txt> \
|
| 198 |
+
SWIPEKB_PACKS=<dir with LANG.ngram, LANG.vocab.tsv, LANG.nwp.bin> \
|
| 199 |
+
bench/scoreboard.sh --label "my run"
|
| 200 |
+
|
| 201 |
+
# Typing: one measure by hand, e.g. completion after 1 letter on the web set, first 300 sentences
|
| 202 |
+
build/tools/swipekb-nextword-eval --model es.ngram --vocab es.vocab.tsv --nwp es.nwp.bin \
|
| 203 |
+
--sentences OUTDIR/web.txt --limit 300 --letters 1
|
| 204 |
+
|
| 205 |
+
# Gboard: replay frozen answers (no device needed) -- run by the scoreboard; or by hand
|
| 206 |
+
build/tools/swipekb-nextword-eval --model es.ngram --vocab es.vocab.tsv --gboard bench/gboard/reference/es-everyday.tsv
|
| 207 |
+
|
| 208 |
+
# Gboard: re-record (needs the Android SDK emulator, uiautomator2; see bench/gboard/README.md)
|
| 209 |
+
python -I bench/gboard/gboard_probe.py LANG SENTENCES OUT.tsv --count 100 --serial emulator-5554
|
| 210 |
+
|
| 211 |
+
# Swipe: FUTO's data, filtered and overlap-checked, then score our engine
|
| 212 |
+
python -I scripts/swipe/holdout_ids.py holdout-final.json bench-2000.jsonl test-extra-10000.jsonl test.jsonl
|
| 213 |
+
python -I scripts/swipe/assemble_futo.py DATA_DIR OUT_DIR holdout-final.json holdout-val.json
|
| 214 |
+
build/tools/swipekb-swipenet-bench --model swipe-model.bin --words words.tsv --layout scripts/swipe/layouts/qwerty.tsv bench-2000.jsonl
|
| 215 |
+
|
| 216 |
+
# Swipe: FUTO's engine on the same slice (needs the FUTO build)
|
| 217 |
+
bench/score.sh --runner futo --label "FUTO reference"
|
| 218 |
+
|
| 219 |
+
# Synthetic noisy swipes for es / fr / de
|
| 220 |
+
python -I bench/languages/make-noisy-swipes.py gen --lang es --params bench/languages/noisy-params-v1.json --text-dir <dir> --out OUT.json
|
| 221 |
+
```
|
| 222 |
+
|
| 223 |
+
Inputs we cannot redistribute from the repository (download them yourself): Tatoeba exports (CC BY 2.0 FR), Common Voice sentences (CC0), FineWeb / FineWeb-2 parquet files (ODC-By 1.0), FUTO's swipe collections (MIT), HeliBoard's gesture sets (CC BY-SA). The language files and trained models are published as GitHub releases `language-files-2026-10-22-open-words` and `models-2026-10-23`, pinned by SHA-256 in `packaging/assets.lock.json`.
|
NOTICE.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Swipe Keyboard trained models, 2026-10-23
|
| 2 |
+
|
| 3 |
+
Models trained and released by Destin Moss via youcoded.ai, 2026.
|
| 4 |
+
SPDX-FileCopyrightText: 2026 Destin Moss <https://youcoded.ai>
|
| 5 |
+
|
| 6 |
+
Four neural next-word models (English, Spanish, French, German) and one swipe-recognition model. They sit beside the
|
| 7 |
+
language files published in release `language-files-2026-10-22-open-words` and are checked by SHA-256 against
|
| 8 |
+
`packaging/assets.lock.json` in github.com/itsdestin/swipe-keyboard before use. A missing or damaged file only turns
|
| 9 |
+
that model off (suggestions fall back to the n-gram files; swipes fall back to the geometric matcher); it never
|
| 10 |
+
disables a language.
|
| 11 |
+
|
| 12 |
+
| File | What it is | Declared licence |
|
| 13 |
+
|---|---|---|
|
| 14 |
+
| `LANG.nwp.bin` (en, es, fr, de) | next-word model: a small recurrent network (one LSTM layer, integer weights, about 4.7 MB), used together with `LANG.ngram` | ODC-By-1.0 AND CC-BY-2.0-FR |
|
| 15 |
+
| `swipe-model.bin` | swipe recognition: small convolution + recurrent network (about 0.5 million weights, 2.1 MB) shared by all four languages | MIT |
|
| 16 |
+
|
| 17 |
+
## How they were built
|
| 18 |
+
|
| 19 |
+
Scripts in github.com/itsdestin/swipe-keyboard (commit `14f9722` and its ancestors on branch `feature/179-engine-in-keyboard`):
|
| 20 |
+
|
| 21 |
+
- Next-word models: `scripts/lm/nwp/prepare.py` (tokenise, vocabulary), `train.py` (train), `tune.py` (blend with the
|
| 22 |
+
n-gram), `export.py` (write `LANG.nwp.bin`). Training text: the same FineWeb (English, sample-10BT) / FineWeb-2
|
| 23 |
+
(Spanish, French, German) text and Tatoeba sentences as the n-gram files, with test sentences held out (Tatoeba ids
|
| 24 |
+
ending in 0, and sentences sharing an 8-word run with the test sets).
|
| 25 |
+
- Swipe model: `scripts/swipe/prep_data.py`, `assemble_futo.py`, `synth_swipes.py`, `train.py`. Training data: real
|
| 26 |
+
swipes from FUTO's swipe.futo.org dataset (MIT) plus synthetic swipes generated from our open word lists
|
| 27 |
+
(our own noise model, no FUTO code or model weights). Sessions used for validation or final scoring were held out.
|
| 28 |
+
|
| 29 |
+
## Sources and licences
|
| 30 |
+
|
| 31 |
+
- **Web text** (next-word models) - FineWeb and FineWeb-2 by Hugging Face, Open Data Commons Attribution License v1.0
|
| 32 |
+
(`ODC-By-1.0.txt`); built from Common Crawl, whose terms of use also apply. The models contain learned weights, never text.
|
| 33 |
+
- **Short everyday sentences** (next-word models) - Tatoeba (tatoeba.org), CC BY 2.0 FR (`TATOEBA-CC-BY-2.0-FR.txt`).
|
| 34 |
+
The contributors are credited in `en-CONTRIBUTORS.txt`, `es-CONTRIBUTORS.txt`, `fr-CONTRIBUTORS.txt`,
|
| 35 |
+
`de-CONTRIBUTORS.txt` in release `language-files-2026-10-22-open-words`.
|
| 36 |
+
- **Real swipes** (swipe model) - the swipe.futo.org dataset, https://huggingface.co/datasets/futo-org/swipe.futo.org,
|
| 37 |
+
MIT licence, reproduced below and in `FUTO-SWIPE-DATA-LICENSE.txt`:
|
| 38 |
+
|
| 39 |
+
MIT License
|
| 40 |
+
|
| 41 |
+
Copyright (c) 2025 FUTO
|
| 42 |
+
|
| 43 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
| 44 |
+
documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
| 45 |
+
the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
| 46 |
+
to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
| 47 |
+
|
| 48 |
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions
|
| 49 |
+
of the Software.
|
| 50 |
+
|
| 51 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
| 52 |
+
THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 53 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
| 54 |
+
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
| 55 |
+
IN THE SOFTWARE.
|
| 56 |
+
|
| 57 |
+
- **Synthetic swipes** (swipe model) - generated by us from the open word lists above; no third-party terms.
|
| 58 |
+
|
| 59 |
+
Changes made: text was split into sentences and reduced to letter words before training; swipes were resampled and
|
| 60 |
+
normalised to key positions; the trained weights were converted to the compact formats the keyboard reads.
|
| 61 |
+
These models contain no FUTO model weights and no FUTO code. https://github.com/itsdestin/swipe-keyboard
|
README.md
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: mit
|
| 3 |
+
language:
|
| 4 |
+
- en
|
| 5 |
+
- es
|
| 6 |
+
- fr
|
| 7 |
+
- de
|
| 8 |
+
library_name: custom
|
| 9 |
+
pipeline_tag: other
|
| 10 |
+
tags:
|
| 11 |
+
- swipe-typing
|
| 12 |
+
- gesture-typing
|
| 13 |
+
- keyboard
|
| 14 |
+
- on-device
|
| 15 |
+
- ctc
|
| 16 |
+
- gru
|
| 17 |
+
- swipe-keyboard
|
| 18 |
+
model-index:
|
| 19 |
+
- name: swipe-typing (T1)
|
| 20 |
+
results:
|
| 21 |
+
- task:
|
| 22 |
+
type: other
|
| 23 |
+
name: Swipe decoding, English, first guess right (all swipes)
|
| 24 |
+
dataset:
|
| 25 |
+
name: bench-2000 (2,000 real English swipes, FUTO MIT test split)
|
| 26 |
+
type: custom
|
| 27 |
+
metrics:
|
| 28 |
+
- type: accuracy
|
| 29 |
+
value: 90.40
|
| 30 |
+
name: first guess right, all swipes
|
| 31 |
+
- task:
|
| 32 |
+
type: other
|
| 33 |
+
name: Swipe decoding, English, right word in top 3 (all swipes)
|
| 34 |
+
dataset:
|
| 35 |
+
name: bench-2000 (2,000 real English swipes, FUTO MIT test split)
|
| 36 |
+
type: custom
|
| 37 |
+
metrics:
|
| 38 |
+
- type: accuracy
|
| 39 |
+
value: 94.95
|
| 40 |
+
name: right word in top 3, all swipes
|
| 41 |
+
---
|
| 42 |
+
|
| 43 |
+
# youcoded/swipe-typing ("T1"): swipe-typing decoder for English, Spanish, French and German
|
| 44 |
+
|
| 45 |
+
> **Headline:** on 2,000 real English swipes (bench-2000, all swipes) the first guess is right 90.40 % of the time against 93.32 % for FUTO's engine, 2.9 points behind; no Gboard swipe comparison was made (Gboard swipe typing was not measured).
|
| 46 |
+
|
| 47 |
+
A small neural network that turns the path of a finger across an on-screen keyboard into a ranked list of words, for the Swipe Keyboard: an open-source swipe-typing and word-prediction add-on for KDE Plasma's on-screen keyboard. One model serves all four languages and any layout, because the keys are given to it as positions.
|
| 48 |
+
|
| 49 |
+
Models trained and released by Destin Moss via youcoded.ai, 2026.
|
| 50 |
+
|
| 51 |
+
Code, scripts and tests: https://github.com/itsdestin/swipe-keyboard/tree/feature/179-engine-in-keyboard (development branch; it moves to the main branch when merged). How every number below was measured: [methods page](METHODS.md) (published copy: METHODS.md).
|
| 52 |
+
|
| 53 |
+
**Status: an opt-in alternative engine.** In the keyboard it is used only when the user creates an `own-engine` file; FUTO's engine remains the default. On English it is **not yet as accurate** as FUTO's engine (see the numbers below).
|
| 54 |
+
|
| 55 |
+
## What it is, and what it is not
|
| 56 |
+
|
| 57 |
+
- A 1-D convolution stack followed by a 2-layer bidirectional GRU, trained with the CTC loss (Graves et al., 2006) on the sequence of keys the finger passes over. Read from the shipped file's header: 2 convolution layers of width 96 (kernel 5), a 2-layer bidirectional GRU with hidden size 128, a pointer head of width 32, 64 time steps of 8 features, float32 weights. That is about **529,000 parameters** and a **2.1 MB** file (2,115,260 bytes).
|
| 58 |
+
- Layout independent: the network does not have a fixed output per key. For every time step it scores each key from the finger's offset to that key (in key widths) plus the key's size, with one small shared scoring network ("pointer head"). A QWERTY, AZERTY, QWERTZ or Spanish keyboard with an n-tilde key therefore use the same weights.
|
| 59 |
+
- It outputs probabilities over keys, not words. Words come from a **lexicon beam search** over a word list (a trie of key sequences), so every answer is a word in the list, scored as network evidence + word frequency + the n-gram sentence prior when previous words are known + a **geometric cross-check** (a separate, classical shape-matching decoder, blended in with weight 40).
|
| 60 |
+
- **Fallback:** with no model file, a damaged one, or an empty result, the geometric decoder alone answers; swiping never depends on the network.
|
| 61 |
+
- It is **not** a handwriting or general gesture recogniser, and it cannot output a word that is not in the word list (words missing from the list are always misses; see limitations).
|
| 62 |
+
|
| 63 |
+
## Intended use
|
| 64 |
+
|
| 65 |
+
On-device swipe typing. The keyboard supplies: the finger path (x, y, time), the live rectangles of the keys, a verified word list for the language, and, when available, the previous words of the sentence. Settings used for all reported results: frequency weight 0.06, geometric cross-check weight 40, beam width 48.
|
| 66 |
+
|
| 67 |
+
Speed on one CPU thread: about 3.5 ms per swipe (measured on a loaded desktop, plain `-O3` build).
|
| 68 |
+
|
| 69 |
+
Not intended for: security-sensitive input, identifying people, or any use that stores or sends a user's swipes. The keyboard does not record swipes unless a user switches on a separate opt-in recorder.
|
| 70 |
+
|
| 71 |
+
## File format
|
| 72 |
+
|
| 73 |
+
File `swipe-model.bin`, read by our own plain C++ runner (`engine/src/swipe_net.cpp`, no machine-learning library). Magic `SKNN`, version 1, little-endian.
|
| 74 |
+
|
| 75 |
+
| Part | Content |
|
| 76 |
+
|---|---|
|
| 77 |
+
| Magic | the 4 bytes `SKNN` |
|
| 78 |
+
| Header (u32 each) | version (1); data type (0 = float32, 1 = float16); time steps (64); input features per step (8); key features (4); number of convolution layers; kernel size; GRU hidden size; GRU layers; pointer-head width |
|
| 79 |
+
| Convolution widths | one u32 per convolution layer |
|
| 80 |
+
| Tensors | in order: for each convolution layer weight [out][in][kernel] and bias; for each GRU layer and direction (forward, then reverse) input weights, recurrent weights and both biases (PyTorch gate order r, z, n); pointer head: A (weight, bias), B (weight, bias), w (weight, bias); blank head (weight, bias) |
|
| 81 |
+
|
| 82 |
+
Because the layer sizes are stored in the file, a bigger or smaller network needs no code change. The loader validates every header field against fixed ranges and refuses a file that is too short for the tensors it declares. **There is no checksum inside this file**, unlike the next-word models; integrity comes from the SHA-256 the keyboard pins (`941272a7017229a73e07d1c0bd766757e739174db3a42fb622c26256b8c46110`), checked before the engine loads it. A mismatch means geometry-only mode.
|
| 83 |
+
|
| 84 |
+
Input per step (64 steps resampled by arc length): x, y, dx, dy, log elapsed time, fraction of the path done, step length, log path length.
|
| 85 |
+
|
| 86 |
+
## Training data and licences
|
| 87 |
+
|
| 88 |
+
| Source | What was taken | Licence |
|
| 89 |
+
|---|---|---|
|
| 90 |
+
| FUTO's public swipe collections (swipe.futo.org: `swipe-1` training split, `swipe-2` to `swipe-5`) | real swipes, English QWERTY; `swipe-5` also holds real German, French and Spanish swipes on their own layouts | MIT (Copyright (c) 2025 FUTO; text kept in `FUTO-SWIPE-DATA-LICENSE.txt`) |
|
| 91 |
+
| Our own synthetic swipes | 100,000 each for Spanish, French and German, generated by `scripts/swipe/synth_swipes.py` on approximate layouts; no synthetic English in T1 | ours; MIT |
|
| 92 |
+
| Word lists (used at run time, not part of the model file) | the benchmarks used 260,000-word lists counted from FineWeb / FineWeb-2 and Tatoeba; the keyboard plugin loads the language profile's verified `.combined` list instead (top 100,000 words for es/fr/de) | ODC-By 1.0 and CC BY 2.0 FR, see the language-pack notices |
|
| 93 |
+
|
| 94 |
+
What exactly went into T1: about 317,000 swipes from a session-level 35 % subset of `swipe-1` to `swipe-4`, `dev.jsonl` (54,000 English swipes from FUTO's MIT recordings; about 47,600 left for training after 10 % of its sessions were held out for validation), all `swipe-5` groups (French, German and Spanish slices repeated three times, each on its own layout), plus the synthetic swipes. 30 epochs, batch 512.
|
| 95 |
+
|
| 96 |
+
**Never trained on:**
|
| 97 |
+
- `bench-2000`, `test-extra-10000` and `test.jsonl` (FUTO's MIT test split) and the validation sessions: an overlap check dropped any swipe whose id or session appeared in them; no overlapping swipe or session was found in any collection (56,005 swipe keys and 768 sessions checked).
|
| 98 |
+
- The HeliBoard gesture test sets (CC BY-SA): used for **testing only**. No HeliBoard data is in the training set, which is why the model's licence is not share-alike.
|
| 99 |
+
- No FUTO model weights were used or fine-tuned; the architecture and code are our own, written from published literature (CTC, lexicon-constrained gesture decoding, SHARK2, dynamic time warping).
|
| 100 |
+
|
| 101 |
+
## Training procedure and hardware
|
| 102 |
+
|
| 103 |
+
- Script: `scripts/swipe/train.py` (PyTorch, CTC loss on the collapsed key sequence; AdamW, one-cycle learning rate). Recipe "R2": dropout 0.2, board-geometry augmentation and speed augmentation, random whole-trace shifts of about 0.2 key.
|
| 104 |
+
- Hardware: one desktop NVIDIA RTX 4070 Super. **Training time for T1: 16 minutes** for 30 epochs.
|
| 105 |
+
- Model selection: search settings (frequency weight, cross-check weight, beam) were fixed on the clean validation split before scoring. `bench-2000` and `test-extra-10000` were scored once for the earlier model F1 and a second time for T1, the final model only; T1 was chosen using other data (trv8k, `swipe-5` slices, clean3000), see below.
|
| 106 |
+
- Not recorded in the repository: the exact command line of the T1 run and the random seed (the script default is 1).
|
| 107 |
+
|
| 108 |
+
## Evaluation
|
| 109 |
+
|
| 110 |
+
All figures are percentages. "First guess" = the top suggestion is the target word; "top 3" = it is among the first three. **Denominators matter:** "all swipes" counts every swipe, including those whose target word is not in the word list (those can never be right); "in-dictionary" counts only swipes whose target is in the word list.
|
| 111 |
+
|
| 112 |
+
### English, real swipes (FUTO's MIT test split), scored once for the final model
|
| 113 |
+
|
| 114 |
+
| Test set | Swipes | All swipes: first / top 3 | In-dictionary: first / top 3 |
|
| 115 |
+
|---|---|---|---|
|
| 116 |
+
| bench-2000 | 2,000 (1,958 in-dictionary) | 90.40 / 94.95 | 92.34 / 96.99 |
|
| 117 |
+
| test-extra-10000 | 10,000 (9,781 in-dictionary) | 90.77 / 94.97 | 92.80 / 97.10 |
|
| 118 |
+
| clean3000 (3,000 swipes, diagnostic) | 3,000 | not stated in the source | 93.13 / 97.37 |
|
| 119 |
+
|
| 120 |
+
### Against FUTO's engine (English)
|
| 121 |
+
|
| 122 |
+
| Set | FUTO engine, first / top 3 | This model, first / top 3 | Denominator |
|
| 123 |
+
|---|---|---|---|
|
| 124 |
+
| bench-2000 | 93.32 / 96.56 | 90.40 / 94.95 | all 2,000 swipes (FUTO figure: all 2,000 through our recogniser harness) |
|
| 125 |
+
| bench-2000 | 93.32 / 96.56 | 92.34 / 96.99 | ours: in-dictionary swipes only; the FUTO figure is not restricted this way, so this row is not like-for-like |
|
| 126 |
+
| clean3000 | 92.5 / 96.3 (2,909 swipes FUTO's tool can score) | 93.13 / 97.37 | ours: in-dictionary only (97.5 % of the 3,000) |
|
| 127 |
+
|
| 128 |
+
Plainly: on all swipes of bench-2000 the model is **2.9 points behind FUTO on first guess and 1.6 behind on top 3** (90.40 vs 93.32; 94.95 vs 96.56). On the swipes whose word is in the dictionary the gap on bench-2000 is about 1 point on first guess and 0 on top 3 (92.34 vs 93.32; 96.99 vs 96.56), but FUTO's number does not exclude out-of-dictionary swipes, so do not read that row as a win. The stated target (match FUTO's 93.3 / 96.6 on all swipes of bench-2000) was **not reached**.
|
| 129 |
+
|
| 130 |
+
### Other languages: real swipes from HeliBoard (test only)
|
| 131 |
+
|
| 132 |
+
HeliBoard gesture test sets: 5,000 real swipes per language, case-insensitive, accents kept, per-swipe real board geometry, 260,000-word lists. First guess / top 3, all 5,000 swipes. "FUTO engine today" used the older, smaller word packs, so the two columns do **not** use the same dictionary and are not like-for-like.
|
| 133 |
+
|
| 134 |
+
| Language | This model (T1) | FUTO engine today (old packs) |
|
| 135 |
+
|---|---|---|
|
| 136 |
+
| English | 82.1 / 91.5 | 84.5 / 93.4 |
|
| 137 |
+
| Spanish | 81.1 / 89.8 | 77.7 / 85.1 |
|
| 138 |
+
| French | 71.7 / 85.9 | 64.6 / 76.9 |
|
| 139 |
+
| German | 73.3 / 82.3 | 69.7 / 76.4 |
|
| 140 |
+
|
| 141 |
+
Dictionary coverage of the HeliBoard targets with the 260,000-word lists: Spanish 97.5 %, French 98.2 %, German 91.9 % (English: not stated for this list). With the older 100,000-word lists the coverage was Spanish 90.5 %, French 83.0 %, German 80.0 %, which caps accuracy.
|
| 142 |
+
|
| 143 |
+
Two common HeliBoard English boards with near-identical geometry differ by 5 to 7 points for every decoder tested, so the spread between rows is partly the swipers, not the layout handling.
|
| 144 |
+
|
| 145 |
+
### Real multilingual swipes from FUTO's `swipe-5`, on their own layouts (validation slices)
|
| 146 |
+
|
| 147 |
+
| Model | French | German | German (QWERTZ) |
|
| 148 |
+
|---|---|---|---|
|
| 149 |
+
| F1 (previous model, English + synthetic only) | 79.8 | 84.7 | 81.6 |
|
| 150 |
+
| T1 (this model) | 83.2 | 90.2 | 83.2 |
|
| 151 |
+
|
| 152 |
+
First guess. The source calls these "val slices" of the collection; it does not describe how they were separated from training in that table, so treat them as a development comparison, not a final test.
|
| 153 |
+
|
| 154 |
+
### Synthetic Spanish, French and German (not human)
|
| 155 |
+
|
| 156 |
+
The synthetic noisy sets (`bench/languages/synthetic-noisy-v1-*.json`, 400 words each) were scored with the **older FUTO-engine keyboard**, not with this model: Spanish 89.00 / 98.25, French 83.25 / 93.00, German 87.75 / 97.00 (first / top 3). We have **no synthetic-set score for T1 in the sources**. Synthetic English calibration: real 92.8 / 96.4 against synthetic 92.3 / 96.0. These sets only cover dictionary words and assume people swipe other languages like English.
|
| 157 |
+
|
| 158 |
+
### Sentence-context prior (experiment)
|
| 159 |
+
|
| 160 |
+
When the keyboard knows the previous words, the English n-gram prior lifts T1 on a 7,198-swipe set (trv8k) from 92.19 / 95.79 to 93.10 / 95.92 (first / top 3, all swipes; in-dictionary 95.28 / 98.17). That is +0.9 first guess. The set is a held-back 5 % slice of FUTO's `train.jsonl` that still has sentence text. Single-word swipes (bench-2000) carry no sentence, so the headline numbers above do not include this gain.
|
| 161 |
+
|
| 162 |
+
### Gboard
|
| 163 |
+
|
| 164 |
+
Gboard's swipe typing was **not measured** (any version, learning on or off).
|
| 165 |
+
|
| 166 |
+
## Known limitations
|
| 167 |
+
|
| 168 |
+
- **English is about 1 to 3 points behind FUTO's engine** on single in-dictionary words and about 3 on all swipes; the target was not met. More real English data barely helped: six times more real English swipes moved the clean English numbers by +0.4 on one set and 0 on another, so we stopped (agreed stopping rule).
|
| 169 |
+
- **French and German are lower than English** on HeliBoard (71.7 and 73.3 first guess vs 82.1). The sources do not isolate the cause. One measured factor is dictionary coverage of the targets (German 91.9 % even with the 260,000-word list; compounds are the likely reason, not verified). The spread between swipers on the same layout is also large (5 to 7 points).
|
| 170 |
+
- **Accent twins** (Spanish que / qué, como / cómo; French ou / où) share one swipe path. The shape cannot decide between them; the sentence prior has to, and without previous words the choice is frequency only.
|
| 171 |
+
- **Short words (3 letters or fewer)** were the other common miss when the older FUTO-engine keyboard was scored on synthetic Spanish, French and German swipes; we have not repeated that breakdown for T1.
|
| 172 |
+
- **Out-of-dictionary words are always misses.** About 2.5 % of English targets are not in the word list (bench-2000: 42 of 2,000).
|
| 173 |
+
- **Spanish, French and German training is partly synthetic** (100,000 each) plus the real `swipe-5` slices. Only English has large real recordings. Real volunteers' swipes per language are still missing, so non-English numbers are less certain than English ones.
|
| 174 |
+
- **Layout handling is approximate where we had no real key rectangles.** The AZERTY/QWERTZ/Spanish layouts used for synthetic training are approximations (`make_layouts.py`); the real keyboard supplies live rectangles at run time. Key pitch, not drawn key width, is the unit, because boards with gaps between keys were 20 % off otherwise.
|
| 175 |
+
- **An earlier validation error was found and corrected** (see the incident below). Every number on this page comes from the corrected, clean sets.
|
| 176 |
+
- No bias or fairness evaluation was done. The training swipers are volunteers on FUTO's collection; their handedness, device and language mix are not documented here.
|
| 177 |
+
|
| 178 |
+
### The inflated-validation incident (2026-10-22)
|
| 179 |
+
|
| 180 |
+
For a day, the validation sets named `devhold-5000`, `tune-2000` and `tune-10000` were believed to be held out. They were not: all of their swipes were contained in `dev.jsonl`, the training set. Every "devhold" figure was therefore measured on training swipes, including 91.5 % for the first CPU model and the 93.02 / 96.07 that looked like a tie with FUTO for the first GPU model ("gpu1"). **Those numbers are retracted.** The swipe helper found it; the coordinator verified it (100 % of ids and sessions overlapped); the fix was to hold out whole recording sessions from `dev.jsonl` as validation (`scripts/swipe/split_by_session.py`) and to select only on that, keeping `bench-2000` and `test-extra-10000` as final-only sets. The honest first read on fresh swipes put the model 2 to 4 points behind FUTO, not level.
|
| 181 |
+
|
| 182 |
+
## How to reproduce
|
| 183 |
+
|
| 184 |
+
From a checkout of https://github.com/itsdestin/swipe-keyboard/tree/feature/179-engine-in-keyboard. You need FUTO's public swipe data (MIT, from swipe.futo.org) and a CUDA GPU; scoring needs the Qt build.
|
| 185 |
+
|
| 186 |
+
```
|
| 187 |
+
# 1. Collect the evaluation keys so training data can be checked against them
|
| 188 |
+
python -I scripts/swipe/holdout_ids.py holdout-final.json bench-2000.jsonl test-extra-10000.jsonl test.jsonl
|
| 189 |
+
python -I scripts/swipe/holdout_ids.py holdout-val.json <validation sessions>.jsonl
|
| 190 |
+
# 2. Filter FUTO's collections (drops two-finger and invalid swipes and anything overlapping the evaluation files)
|
| 191 |
+
python -I scripts/swipe/assemble_futo.py DATA_DIR OUT_DIR holdout-final.json holdout-val.json
|
| 192 |
+
# 3. Synthetic swipes for es / fr / de (own generator, different from the test generator)
|
| 193 |
+
python -I scripts/swipe/synth_swipes.py --words words.tsv --layout scripts/swipe/layouts/azerty.tsv --n 100000 --out synth-fr.jsonl
|
| 194 |
+
# 4. Convert and train (see the script header for all options; recipe R2 flags: --dropout 0.2 --geo-aug ... --time-aug ...)
|
| 195 |
+
python -I scripts/swipe/prep_data.py ...
|
| 196 |
+
python -I scripts/swipe/train.py --train real.npz --train synth-fr.npz:scripts/swipe/layouts/azerty.tsv --val val.npz \
|
| 197 |
+
--out run --epochs 30 --batch 512 --conv 96,96 --hidden 128 --layers 2 --dropout 0.2 --device cuda
|
| 198 |
+
# 5. Score (first guess / top 3, ms per swipe)
|
| 199 |
+
build/tools/swipekb-swipenet-bench --model run/model.bin --words words.tsv --layout scripts/swipe/layouts/qwerty.tsv bench-2000.jsonl
|
| 200 |
+
```
|
| 201 |
+
|
| 202 |
+
The exact flag values of the shipped T1 run were not recorded; the sizes above follow the run table in `docs/active/specs/2026-10-23-own-swipe-engine.md`, and the geometry and speed augmentation strengths should be taken from the script's help text. Expect to need a few attempts to match the published numbers. More commands, and the Gboard and FUTO measurements, are on the [methods page](METHODS.md).
|
| 203 |
+
|
| 204 |
+
## Licence of the model file
|
| 205 |
+
|
| 206 |
+
`swipe-model.bin`: **MIT**. Training data: real swipes from FUTO's swipe.futo.org collections (MIT, Copyright (c) 2025 FUTO) plus our own synthetic swipes; the file contains no FUTO model weights.
|
| 207 |
+
|
| 208 |
+
Required credits when redistributing:
|
| 209 |
+
|
| 210 |
+
- **Models trained and released by Destin Moss via youcoded.ai, 2026**
|
| 211 |
+
- The MIT licence text of FUTO's swipe data (`FUTO-SWIPE-DATA-LICENSE.txt`, shipped with the model).
|
| 212 |
+
- The release notice `MODELS-NOTICE.md` (release `models-2026-10-23`).
|
| 213 |
+
|
| 214 |
+
The word lists the model is used with carry their own attribution terms (FineWeb / FineWeb-2: ODC-By 1.0; Tatoeba: CC BY 2.0 France; for English also the Android LatinIME word list, Apache-2.0). They are separate files and not part of the model.
|
| 215 |
+
|
| 216 |
+
## Credit
|
| 217 |
+
|
| 218 |
+
Models trained and released by Destin Moss via youcoded.ai, 2026.
|
swipe-model.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:941272a7017229a73e07d1c0bd766757e739174db3a42fb622c26256b8c46110
|
| 3 |
+
size 2115260
|