Align documentation with the verified Swedish-form evidence

#1
Files changed (1) hide show
  1. README.md +102 -84
README.md CHANGED
@@ -18,12 +18,14 @@ datasets:
18
  - precisit/one-pass-sv-forms-synthetic
19
  ---
20
 
21
- # One-Pass SV-Forms (SV0) — a Swedish one-pass form specialist (research checkpoint)
22
 
23
  **This is a research checkpoint, not a product.** It is a 706 048-parameter model that scores a
24
- supplied list of options in **one forward pass** — the "Jev"/System One shape — trained from
25
- scratch on **synthetic** Swedish forms. It generates no text, needs no tokenizer, and answers in
26
- about a millisecond on an Apple device (Core ML: 1.4 MB fp16, 787 KB int8).
 
 
27
 
28
  | | |
29
  | --- | --- |
@@ -31,26 +33,29 @@ about a millisecond on an Apple device (Core ML: 1.4 MB fp16, 787 KB int8).
31
  | Architecture | byte-level embeddings + 2-layer Transformer encoder (width 128, 4 heads) + option-attention head; `tinyx` |
32
  | Parameters | 706 048 |
33
  | Context / option budget | 224 bytes of context, 96 bytes per option, **up to 40 options** |
34
- | Training data | 10 000 synthetic Swedish form episodes (234 921 decisions); **no real form, person or customer data** |
35
  | Licence | MIT (weights and code) |
36
- | Lineage | independent implementation of the same interface as [Cua's CUA-S1](https://huggingface.co/cua-ai/cua-s1-forms) and [jevlike](https://github.com/vinnylarouge/jevlike); trained from scratch, not a fine-tune of either |
37
 
38
  ## Measured results (our harness, Apple M4)
39
 
40
- | Run | decisions | top-1 | majority-class baseline | ECE | silently skipped a required fill |
41
  | --- | ---: | ---: | ---: | ---: | ---: |
42
- | Held-out synthetic test (form-signature disjoint) | 2 310 | **99.29 %** | 47.36 % | 0.0014 | **1** |
43
- | Hand-written out-of-distribution demo | 50 | **100.00 %** | 64.00 % | — | 0 |
44
- | Shuffled-context control (same test rows) | 2 310 | 31.99 % | 47.36 % | — | — |
45
-
46
- The shuffled-context control is the number to look at first: rotating contexts between rows drops
47
- the model to 31.99 %, well below the majority baseline, so it is reading the element label and the
48
- document rather than exploiting option statistics. Without that control a 100 % demo set means
49
- nothing.
50
-
51
- For comparison, the released English checkpoint of the same family scores **20.75 %** on the same
52
- 29 839 rows (`results-english-reference.json`) — far below the 47.36 % majority baseline, with
53
- 5 412 of 13 844 required fills silently skipped. The language was the barrier, not the interface.
 
 
 
54
 
55
  ### Data-size curve (same 4-epoch schedule, same seed, corrected generator)
56
 
@@ -60,51 +65,48 @@ For comparison, the released English checkpoint of the same family scores **20.7
60
  | 4 000 | 94 405 | 98.94 % | 6 | 0.0014 | 56 min |
61
  | **10 000** | **234 921** | **99.29 %** | **1** | 0.0014 | 163 min |
62
 
63
- This checkpoint is the 10 000-episode point. The curve is published because it is the useful
64
- part: at 900 episodes the same pipeline sits at 77 %, so a single small run would have been
65
- misread as a statement about the method rather than about the data.
66
 
67
  ## Changelog
68
 
69
- - **v2 (2026-09-21)** — this release. Two fixes and a scale-up, all three visible above:
70
- 1. **Corpus correctness.** The Swedish catalogue's `personnummer` generator emitted nine digits
71
- formatted `DDDDDDDD-DD` and `organisationsnummer` emitted `DDDDD-DDDDD`; both are now the
72
- real Swedish shape `YYMMDD-XXXX`. As a side effect the models can no longer identify those
73
- two concepts from the *shape of the value* alone — the bug had been an accidental
74
- giveaway — so per-action accuracy on `fill` is the honest kind now.
75
- 2. **Scale.** 900 → 10 000 episodes, which moved top-1 from 77 % to 99.29 % and silent skips
76
- from 127 to 1.
77
- 3. **Correction of our own first explanation.** An intermediate 900-episode run on the
78
- corrected corpus scored 83.02 % (v1) versus 77.10 % (corrected), and we initially attributed
79
- that six-point drop to the removed giveaway. The 4 000- and 10 000-episode points show the
80
- dominant factor was data size, not corpus correctness. The measurement is recorded here
81
- because we published the wrong explanation for part of a working day.
82
- 4. **Correction of our Core ML claim.** We published that 4-bit palettisation destroys this
83
- model. Scored per compute-unit path, 4-bit weights keep 99.27 % top-1 with 32 changed
84
- decisions in 29 839 on the **CPU**, while the **Neural Engine** path for the same package
85
- returns 49.92 % with 15 017 changes and reports `ANECCompile() FAILED`. The collapse was an
86
- artefact of scoring int4 only with `CPU_AND_NE`: a broken accelerator path looked like a
87
- broken quantiser. int8 still ships, for the better reason that it is identical to fp16 on
88
- both paths, and the follow-up investigation is in the vault at
89
- `ideas/2026-09-21-int4-investigation-one-pass.md`.
90
- - **v1 (2026-09-21)** — first release: 900 synthetic episodes, 83.02 % top-1, 7.5 % silent skips,
91
- 787 KB int8. Superseded; kept in the history of this repository rather than hidden.
92
 
93
  ## What it is NOT
94
 
95
- - **Not trained or tested on real Swedish forms.** The corpus is synthetic by construction:
96
- fictional names, `.invalid` e-mail domains, generated personnummer-shaped identifiers that pass
97
- their checksum but belong to nobody. Two sets carry the non-synthetic evidence, and both are
98
- small: a 50-decision set we wrote by hand, and a 270-decision set built from two of our own
99
- shipped forms (Kanslist's and Pratsam's lead forms, real labels and option lists, synthetic
100
- values, hand-written entity-to-field mapping). **On those real forms the model scores 52.8 % and
101
- 77.3 % top-1**, against 99.29 % on synthetic held-out rows — the gap is the most important number
102
- in this card. The failure mode is abstention rather than invention (on the Kanslist form it
103
- answers "skip" for 57 of 65 required fills), and the cause is vocabulary and label length: the
104
- training catalogue's element labels are short concept names, these forms' labels are sentences.
 
 
 
105
  - **Not an agent.** It does not generate text, cannot invent a value it was not given, and does
106
- not decide execution order — the option list and the sequence come from ordinary code around it.
107
- - **Not safe unsupervised.** One required fill out of 29 839 was still answered "skip": a silent
 
108
  failure. Any real integration must check outcomes outside the model (fail closed, dry run, one
109
  submit, human review before consequential actions).
110
  - **Not tuned for throughput.** One decision per `predict` call is what the latency numbers
@@ -112,30 +114,43 @@ misread as a statement about the method rather than about the data.
112
 
113
  ## Core ML export (same checkpoint, coremltools 9.0, Apple M4)
114
 
115
- | Variant | package | CPU top-1 | CPU parity vs PyTorch (mismatches) | ANE top-1 | ANE parity (mismatches) |
116
  | --- | ---: | ---: | ---: | ---: | ---: |
117
- | fp16 | 1.44 MB | 99.28 % | 0.999531 (14) | 99.29 % | 0.999497 (15) |
118
- | **int8** | **787 KB** | **99.31 %** | 0.999598 (12) | 99.29 % | 0.999564 (13) |
119
- | int4 | 481 KB | **99.27 %** | 0.998928 (32) | **49.92 %** | 0.496732 (15 017) |
120
-
121
- Scored per compute-unit path on the same 29 839 held-out decisions, same encoding, same masked
122
- argmax. The reading matters more than the table:
123
-
124
- - **4-bit weights are nearly lossless on the CPU path** (32 changed decisions in 29 839) and the
125
- package is 481 KB.
126
- - **The Neural Engine path for that palettised graph is silently wrong**: 49.92 % top-1, 15 017
127
- changed decisions, while the graph also reports `ANECCompile() FAILED`. It does not raise an
128
- error, it substitutes a different computation — which is why this model's large margins (median
129
- 12.1 logits) did not protect it.
130
- - **We first published this as "int4 destroys the model".** That was our measurement artefact:
131
- int4 had only ever been scored with `CPU_AND_NE`, so a broken accelerator path looked like a
132
- broken quantiser. Corrected here, and the wrong explanation is kept in the changelog rather than
133
- deleted.
134
- - **int8 ships** because it is identical to fp16 on *both* paths — not because it survives
135
- quantisation better.
136
- - **int4 + ANE is achievable for this architecture**: the released English conversion of the same
137
- model runs 4-bit on the Neural Engine at 99.93 % in our own verification, so the difference is in
138
- the export. Levers and open questions: `ideas/2026-09-21-int4-investigation-one-pass.md`.
 
 
 
 
 
 
 
 
 
 
 
 
 
139
 
140
  ## Usage
141
 
@@ -152,15 +167,18 @@ hf_hub_download("precisit/one-pass-sv-forms", "sv0-forms.json", local_dir=weight
152
 
153
  The context string and options must be built exactly as in training (byte ids = UTF-8 byte + 1,
154
  zero padded; `UPPGIFT fyll i formuläret från dokumentet och skicka sedan in` / `FORM <titel>` /
155
- `ELEMENT <roll> "<etikett>" value="…"`). A mismatch there is the most likely cause of poor output —
156
- the generator, the catalogue and the scoring harness are in the toolkit repository.
 
157
 
158
  ## Building your own
159
 
160
  [`precisit/one-pass-specialists`](https://github.com/precisit/one-pass-specialists) is the public
161
  toolkit that produced this checkpoint: catalogue, synthetic generator with form-disjoint splits,
162
  trainer, evaluation (including the shuffled-context control and the silent-skip count), Core ML
163
- export with a bit-identity proof before anything is written, and the SV0 recipe with all receipts.
 
 
164
  The synthetic corpus itself is published as
165
  [`precisit/one-pass-sv-forms-synthetic`](https://huggingface.co/datasets/precisit/one-pass-sv-forms-synthetic).
166
 
@@ -170,5 +188,5 @@ MIT. The architecture, training loop and evaluation metrics are vendored unmodif
170
  MIT-licensed [`libs/cua-s1`](https://github.com/trycua/cua/tree/main/libs/cua-s1) (which credits
171
  `jevlike` for the option-attention head design). The Swedish catalogue, synthetic generator,
172
  training runs, measurements and Core ML tooling are Precisit's. **No TypeSafe AI code, weights,
173
- data or API output was used** — "Jev" and "System One" are their names for a similar interface, and
174
  this is an independent implementation. See `THIRD_PARTY_NOTICES.md`.
 
18
  - precisit/one-pass-sv-forms-synthetic
19
  ---
20
 
21
+ # One-Pass SV-Forms (SV0): a Swedish one-pass form specialist (research checkpoint)
22
 
23
  **This is a research checkpoint, not a product.** It is a 706 048-parameter model that scores a
24
+ supplied list of options in **one forward pass**, using a System One-style interface.
25
+ It was trained from scratch on **synthetic** Swedish forms. It generates no text, needs no tokenizer, and answers in
26
+ a measured median of 1.314 ms per prediction on an Apple M4 with `CPU_AND_NE`
27
+ (Core ML packages: about 1,472 KiB fp16, 787 KiB int8). This excludes input encoding,
28
+ model loading and warm-up; it is not an end-to-end form completion time.
29
 
30
  | | |
31
  | --- | --- |
 
33
  | Architecture | byte-level embeddings + 2-layer Transformer encoder (width 128, 4 heads) + option-attention head; `tinyx` |
34
  | Parameters | 706 048 |
35
  | Context / option budget | 224 bytes of context, 96 bytes per option, **up to 40 options** |
36
+ | Training data | 10 000 synthetic Swedish form episodes (234 921 decisions); **generated rather than collected from people or customers** |
37
  | Licence | MIT (weights and code) |
38
+ | Lineage | uses vendored [Cua-S1](https://github.com/trycua/cua/tree/main/libs/cua-s1) architecture and training code, with an option-attention head credited to [jevlike](https://github.com/vinnylarouge/jevlike); new weights trained from scratch, not fine-tuned from Cua weights |
39
 
40
  ## Measured results (our harness, Apple M4)
41
 
42
+ | Run | decisions | top-1 | majority-class baseline | ECE | silently skipped an expected fill |
43
  | --- | ---: | ---: | ---: | ---: | ---: |
44
+ | Held-out synthetic test (form-signature disjoint) | 29 839 | **99.29 %** | 47.36 % | 0.0014 | **1** |
45
+ | Hand-written out-of-distribution demo | 50 | **100.00 %** | 64.00 % | n/a | 0 |
46
+ | Shuffled-context control (same test rows) | 29 839 | 31.99 % | 47.36 % | n/a | n/a |
47
+
48
+ The shuffled-context control rotates contexts between rows while retaining their options
49
+ and labels. Accuracy falls to 31.99%, showing that the model uses the context rather than
50
+ only option statistics. It does not identify which context clues the model has learned.
51
+ The synthetic test contains 13,844 expected fill decisions; one is answered skip. This
52
+ count excludes choosing a wrong fill value. Fill accuracy is 99.00%.
53
+
54
+ For comparison, the unchanged released English checkpoint scores **20.75%** on the same
55
+ 29,839 rows, with 5,412 of 13,844 expected fills skipped. Labels, action strings and the
56
+ generated distribution all change; the result does not isolate language as the cause.
57
+ The 50 handwritten decisions comprise 32 fills, 12 skips, three checks and three clicks.
58
+ They are a small diagnostic set, not a broad test of Swedish forms.
59
 
60
  ### Data-size curve (same 4-epoch schedule, same seed, corrected generator)
61
 
 
65
  | 4 000 | 94 405 | 98.94 % | 6 | 0.0014 | 56 min |
66
  | **10 000** | **234 921** | **99.29 %** | **1** | 0.0014 | 163 min |
67
 
68
+ This checkpoint is the 10,000-episode point. Each run has its own generated test set.
69
+ At a fixed four epochs, the larger training sets also receive more optimization steps.
70
+ These runs do not isolate the effect of data size or establish convergence.
71
 
72
  ## Changelog
73
 
74
+ - **v2 (2026-09-21)**: corrected synthetic identifier formats and increased the corpus
75
+ to 10,000 episodes. The generator previously emitted malformed personnummer- and
76
+ organisationsnummer-shaped values. Tests now check the intended formats and checksums.
77
+ Such formatting differences could provide shortcuts, but the runs do not measure how
78
+ much the model used them. Comparing the earlier 83.02% run with the corrected
79
+ 900-episode run at 77.10% does not establish a cause for the difference: the generated
80
+ training and test examples changed. Larger subsequent runs also used more training steps.
81
+ - **Core ML clarification**: int4 was initially evaluated with `CPU_AND_NE` and described
82
+ as losing too much weight precision. The same package reaches 99.27% on CPU, versus
83
+ 49.92% with CPU and Neural Engine allowed. Actual operation placement and the root
84
+ cause remain unknown. Int8 and fp16 are not prediction-identical. See the public
85
+ [execution investigation](https://github.com/precisit/one-pass-specialists/blob/9240818b2f9221ecce9e27af11eab9816dfc51f9/examples/sv-forms/COREML-EXECUTION.md) for the full M4 comparison, M1 Max follow-up,
86
+ decompression control and remaining tests.
87
+ - **v1 (2026-09-21)**: earlier 900-episode release, 83.02% top-1 and a reported 7.5%
88
+ silent-skip rate. Its artifacts remain in repository history. Use each revision's
89
+ own result files and denominators when comparing releases.
 
 
 
 
 
 
 
90
 
91
  ## What it is NOT
92
 
93
+ - **Not validated for real form completion.** Training data are generated, not collected
94
+ from people or customer submissions. Names are constructed and email addresses use
95
+ `.invalid`. Generated identifiers are not checked against registries; coincidental
96
+ matches with real identifiers cannot be ruled out. The external checks are small:
97
+ 50 handwritten decisions and 270 decisions in simplified fixtures based on Kanslist
98
+ and Pratsam forms. Their labels and controls differ from the current sites. They use
99
+ synthetic scenarios and hand-mapped expected actions, not real submissions or browser runs.
100
+ The fixture results are **52.8% and 77.3%**, with 57 of 65 expected Kanslist fills
101
+ answered skip. These are expected fills, not necessarily HTML-required fields.
102
+ Pratsam's fixture also has a gold-label defect: its scenario uses `mig själv`, while
103
+ the radio mapping checks for `ja`, labelling all 15 radio rows skip. Those results
104
+ are provisional. Vocabulary, input lengths, roles and fixture conventions need
105
+ investigation; the current evidence does not isolate one cause.
106
  - **Not an agent.** It does not generate text, cannot invent a value it was not given, and does
107
+ not decide execution order: the option list and the sequence come from ordinary code around it.
108
+ - **Not safe unsupervised.** One expected fill out of 13,844 was answered "skip" in the
109
+ synthetic test: a silent
110
  failure. Any real integration must check outcomes outside the model (fail closed, dry run, one
111
  submit, human review before consequential actions).
112
  - **Not tuned for throughput.** One decision per `predict` call is what the latency numbers
 
114
 
115
  ## Core ML export (same checkpoint, coremltools 9.0, Apple M4)
116
 
117
+ | Variant | package | CPU top-1 | CPU parity vs PyTorch (mismatches) | CPU + NE allowed top-1 | CPU + NE allowed parity (mismatches) |
118
  | --- | ---: | ---: | ---: | ---: | ---: |
119
+ | fp16 | 1,472 KiB | 99.28 % | 0.999531 (14) | 99.29 % | 0.999497 (15) |
120
+ | **int8** | **787 KiB** | **99.31 %** | 0.999598 (12) | 99.29 % | 0.999564 (13) |
121
+ | int4 | 481 KiB | **99.27 %** | 0.998928 (32) | **49.92 %** | 0.496732 (15 017) |
122
+
123
+ All 29,839 held-out decisions are included, with the same encoding and masked argmax.
124
+ `CPU_AND_NE` allows CPU and Neural Engine use; it does not report which operations ran
125
+ on which processor. Package sizes sum the files, not runtime memory. One KiB is 1,024 bytes.
126
+
127
+ The int8 recipe uses a uniform 256-entry palette per tensor with float16 computation.
128
+ Int4 uses grouped-channel K-means palettes, groups of 32, and a different deployment
129
+ target: iOS 18, versus iOS 17 for fp16 and int8. These are different export recipes,
130
+ not only different bit widths.
131
+
132
+ The same int4 package preserves 99.27% top-1 on CPU but falls to 49.92% when CPU and
133
+ Neural Engine are allowed. That is an execution-dependent discrepancy, not evidence
134
+ that these rounded weights cannot represent the task. Int8's rounded top-1 matches
135
+ fp16 under `CPU_AND_NE`, but it changes 13 choices versus PyTorch; it is not lossless
136
+ or prediction-identical to fp16.
137
+
138
+ A follow-up on M1 Max, macOS 26.5.1, used 512 deterministic samples spread across the
139
+ test set. Int4 scored 511/512 on CPU and 266/512 with `CPU_AND_NE`. Decompressing its
140
+ palettes to dense constants retained exactly those choices under each setting. This
141
+ removes the palette-expansion operations but keeps the rounded weights and iOS 18
142
+ target. It also runs conversion passes, so it is not proof of an otherwise identical graph.
143
+ `ANECCompile() FAILED` messages were observed, but the buffered output could not be
144
+ attributed to individual calls. Neither these messages nor the predictions establish
145
+ operation placement, fallback or a faulty operation.
146
+
147
+ See the [public investigation](https://github.com/precisit/one-pass-specialists/blob/9240818b2f9221ecce9e27af11eab9816dfc51f9/examples/sv-forms/COREML-EXECUTION.md) for pinned data, scripts, artifact hashes
148
+ and the remaining target-matched export and graph-inspection work. The chip and OS
149
+ both differ between the M4 and M1 Max tests; their effects are not isolated.
150
+
151
+ The original M4 latency run excluded three warm-up rows, leaving 29,836 predictions.
152
+ Int8 with `CPU_AND_NE` had median 1.314 ms and p95 1.411 ms; fp16 on CPU had median
153
+ 1.727 ms. These time `MLModel.predict`, not preprocessing, model loading or a full form.
154
 
155
  ## Usage
156
 
 
167
 
168
  The context string and options must be built exactly as in training (byte ids = UTF-8 byte + 1,
169
  zero padded; `UPPGIFT fyll i formuläret från dokumentet och skicka sedan in` / `FORM <titel>` /
170
+ `ELEMENT <roll> "<etikett>" value="…"`). An encoding mismatch is one possible source of poor output; vocabulary, truncation,
171
+ fixture labels and runtime behavior also need checking. The generator, catalogue and
172
+ scoring harness are in the toolkit repository.
173
 
174
  ## Building your own
175
 
176
  [`precisit/one-pass-specialists`](https://github.com/precisit/one-pass-specialists) is the public
177
  toolkit that produced this checkpoint: catalogue, synthetic generator with form-disjoint splits,
178
  trainer, evaluation (including the shuffled-context control and the silent-skip count), Core ML
179
+ export with a 512-example check of the export-friendly eager implementation against
180
+ its trace, followed by Core ML decision comparisons, and the SV0 recipe. The trace
181
+ check does not establish bit identity with the original unmodified forward pass.
182
  The synthetic corpus itself is published as
183
  [`precisit/one-pass-sv-forms-synthetic`](https://huggingface.co/datasets/precisit/one-pass-sv-forms-synthetic).
184
 
 
188
  MIT-licensed [`libs/cua-s1`](https://github.com/trycua/cua/tree/main/libs/cua-s1) (which credits
189
  `jevlike` for the option-attention head design). The Swedish catalogue, synthetic generator,
190
  training runs, measurements and Core ML tooling are Precisit's. **No TypeSafe AI code, weights,
191
+ data or API output was used**: "Jev" and "System One" are their names for a similar interface, and
192
  this is an independent implementation. See `THIRD_PARTY_NOTICES.md`.