Gramscii commited on
Commit
acc30fd
·
verified ·
1 Parent(s): 2e46ec9

Release v22: requests behind an opening no, bare topics, what's new in X, lowercase names

Browse files
.gitattributes CHANGED
@@ -36,3 +36,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
36
  tokenizer.json filter=lfs diff=lfs merge=lfs -text
37
  grpo-best-q8_0.gguf filter=lfs diff=lfs merge=lfs -text
38
  sft-v19-q8_0.gguf filter=lfs diff=lfs merge=lfs -text
 
 
36
  tokenizer.json filter=lfs diff=lfs merge=lfs -text
37
  grpo-best-q8_0.gguf filter=lfs diff=lfs merge=lfs -text
38
  sft-v19-q8_0.gguf filter=lfs diff=lfs merge=lfs -text
39
+ sft-v22-q8_0.gguf filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -89,19 +89,20 @@ These are real outputs from the released weights, greedy:
89
  | in | out |
90
  |---|---|
91
  | `Spanish: no busques la tienda de ropa, dime la dosis de paracetamol` | `dime la dosis de paracetamol` |
92
- | `Italian: scusa il disturbo, mi diresti che tempo fa domani a Bologna?` | `dimmi che tempo fa domani a Bologna` |
93
  | `English: book me a table for friday and also cancel my dentist` | `book me a table for friday`<br>`cancel my dentist` |
 
94
  | `Italian: guarda un po', questo sacchetto della spesa è tutto rotto.` | `NO_REQUEST` |
 
95
 
96
- A negation is dropped, an apology is dropped, one message asking for two
97
- things becomes two lines, and something that is not a request at all
98
- answers with the sentinel.
99
 
100
  ## What is in this repository
101
 
102
  | file | size | what it is |
103
  |---|---|---|
104
- | `sft-v19-q8_0.gguf` | 300 MB | what the engine serves, through llama-server |
105
  | `model.safetensors` | 536 MB | the same weights fused, BF16, 236 tensors |
106
  | `model.safetensors.index.json` | | the index over that single file |
107
  | `tokenizer.json`, `tokenizer_config.json` | 33 MB | the tokenizer as the fuse wrote it |
@@ -109,127 +110,82 @@ answers with the sentinel.
109
  | `chat_template.jinja` | | present because the fuse writes it — **not the surface this model reads**, see above |
110
 
111
  The GGUF's sha256 is
112
- `33b6cc73c7d306c9c81aa96c5a8ddb9dbfd46a5ac5d0388a2de45b5229928c56`.
113
  The engine pins it and refuses anything else, which is what makes a routing
114
  decision reproducible.
115
 
116
- Both files carry the same weights: the fused final adapter of training run
117
- v19, adapter sha256 `1082985953ed6c33…`, quantised to Q8_0. Q8_0 and not
118
- Q4: measured on this seat, at temperature 0 a Q8_0 is stable to the byte
119
- across runs and a Q4 is not.
120
 
121
  ## What it is measured to do
122
 
123
- Measured against the two things worth measuring against: the model it was
124
- fine-tuned from, and doing no repair at all. Two benches over different
125
- corpora, because a model that wins one of them is a model chosen by which
126
- table got printed.
 
127
 
128
- **400 routing tasks over 343 graphs**, of which 78 ask for more than one
129
- capability and 160 name a day. These exact released weights against the
130
- untrained base, every column the bench reports:
 
131
 
132
- | | this model | [`gemma-3-270m`](https://huggingface.co/google/gemma-3-270m), untrained |
133
  |---|---|---|
134
- | **exact**, every capability the question asks for, and no other | **32** | 24 |
135
- | **safe**, a proper subset reached, nothing wrong run | 6 | 1 |
136
- | **abstained**, nothing executed at all | 298 | 197 |
137
- | **wrong execution**, something ran that should not have | **1** | 0 |
138
- | **answered in the wrong language** | **6** | **123** |
139
- | **lost the day** the question named, of 160 | 57 | 55 |
140
- | **echoed the question back** instead of restating it | 64 | 106 |
141
- | of those echoes, ones that still routed exactly | 9 | 20 |
142
- | **compound questions answered whole**, of 78 | 0 | 0 |
143
-
144
- Read the columns together rather than one at a time.
145
-
146
- The **language** column is what the fine-tune buys and it is the largest
147
- effect in any table here: 123 becomes 6.
148
-
149
- The **abstention** column is the honest cost. This model refuses far more
150
- often than the base does, 298 against 197. It abstains rather than guess,
151
- and abstaining is why its wrong executions stay at one. A rewriter that
152
- guesses would score better on exact and worse on everything that matters.
153
-
154
- The one wrong execution is worth reading whole. *Vorrei sapere quanto devo
155
- per la visita di martedì scorso. Non ho ricevuto la fattura.* — gold
156
- `pagamento_fattura` — came back as *dimmi quanto devo per la visita di
157
- martedì scorso*: the date kept, the second sentence gone, and with it the
158
- one word that decided. `visita` then carried the line confidently to
159
- `prenota_visita` (top 0.392, margin 0.148, both over the served bars),
160
- where the original message had put `pagamento_fattura` first but without
161
- the margin to execute (0.086) — which is why it was in repair at all. The
162
- failure is a dropped clause, not an invented action: the model wrote
163
- nothing the person did not say. Recovered by re-running the bench, which
164
- is greedy and seeded, so the same 400 tasks reproduce every column of
165
- this table to the digit.
166
-
167
- The **echo** column says how often the model gave the question back
168
- unchanged. It halves, 106 to 64, which is the fine-tune learning that
169
- restating is the job.
170
-
171
- The **date** column barely moves, 55 to 57, and the **compound** column does
172
- not move at all: neither the base nor this model answers a single one of
173
- the 78 questions asking for two capabilities on this bench. Those are the
174
- two things the training did not buy.
175
-
176
- What bounds the compound number: in the engine, every line of the
177
- restatement is routed on its own, and nothing decides where to split
178
- except the router's own scores on each line. A message restated into one
179
- right line and one missing one still reaches the capability it named —
180
- that is what the **safe** row counts. *Answered whole* is the
181
- all-or-nothing reading of that; the seat's failure mode on a compound is
182
- a partial answer, not a wrong one.
183
-
184
- **39 held-out questions on a live workspace**, written by three blind
185
- judges against the capabilities in it, in two languages:
186
-
187
- | | exact |
188
- |---|---|
189
- | **this model** | **16** |
190
- | routing the question as written, no repair | 12 |
191
- | `google/gemma-3-270m`, untrained | 9 |
192
 
193
- The base model scoring **below** "no repair at all" is the whole argument
194
- for fine-tuning something for this seat: an untrained 270M put here makes
195
- routing worse than leaving the question alone. Of the 10 compound questions
196
- in that set — one message asking for two things — this model answers 2
197
- whole.
198
 
199
- **Its own training gate**, on 1000 held-out examples: 261 exact (26.1%),
200
- 927 of 1000 answers well formed, and the language-balance gate passed with
201
- a 7-point gap between English and Italian against a 10-point bar.
 
202
 
203
- ## What it does not fix, which a card naming only the gains would hide
 
 
204
 
205
- **The sentinel does not catch every non-request.** `guarda un po', questo
206
- sacchetto della spesa è tutto rotto` answers `NO_REQUEST`, but `ciao come
207
- stai` comes back verbatim rather than refused. If nothing downstream checks
208
- that the restatement is a request, a greeting will be routed.
209
-
210
- **It sometimes rewrites a word rather than restating a sentence.** Measured:
211
- `Bitte reserviere mir einen Platz im Klettergarten für Freitag` comes back
212
- as `reserviere mir einen Platz im Kletterpark für Freitag` — `Klettergarten`
213
- became `Kletterpark`. The restatement is only ever compared against
214
- capability descriptions and never executed, which is why this is tolerable
215
- here; in any design where the rewrite is acted on, it is not.
216
-
217
- **Dates.** In the 400-task run above, 160 of the tasks name a day. This
218
- model loses the day in **57 of them** — more than a third. It is the
219
- weakest column it has, and it is weak in a way that does not announce
220
- itself: the restatement reads as a clean request, with the "yesterday" or
221
- the "before Easter" simply gone. If the day matters to your routing,
222
- measure that before you serve this.
223
-
224
- **It is not distinguishable from its own neighbours.** Ten checkpoints of
225
- this run were compared on the same 400 tasks pair by pair rather than by
226
- totals — counting only the tasks where two checkpoints disagree, which are
227
- the only ones carrying information. Not one difference reaches
228
- significance: the widest gap in the table is 7 tasks to 1, p = 0.07. With
229
- around thirty exact answers out of four hundred the natural fluctuation is
230
- about five, which is most of the ranking. Treat the order inside a run as
231
- noise: a checkpoint one or two points ahead of another inside the same run
232
- has not been shown to be better than it.
233
 
234
  ### What bounds all of this
235
 
@@ -250,8 +206,8 @@ restatement's to lose.
250
 
251
  **A restatement that does not win by enough margin routes nothing.** The
252
  router applies a margin and a floor, and below them the system abstains and
253
- asks for a rephrasing. That is why the wrong-execution column is 1 in 400
254
- while the abstention column is 298: the failure mode is refusing, not acting
255
  wrongly.
256
 
257
  **The descriptions are the other half.** What a question is matched against
@@ -276,7 +232,7 @@ handed an answer with no account of how it was reached.
276
  Served with llama-server, reached by the engine as one of four model seats:
277
 
278
  ```
279
- llama-server -m sft-v19-q8_0.gguf --host 127.0.0.1 --port 9250 -ngl 99 -c 2048 --jinja
280
  ```
281
 
282
  It is loaded only when routing is genuinely unsure, never as the default
@@ -284,7 +240,7 @@ path, and released after an idle window.
284
 
285
  ### On CPU alone
286
 
287
- Measured on an Apple M-series machine with `-ngl 0 -t 4`: no GPU offload at
288
  all, four threads, and nothing in the server log naming Metal or a GPU.
289
 
290
  | | latency | tokens/s |
@@ -296,7 +252,7 @@ all, four threads, and nothing in the server log naming Metal or a GPU.
296
  **762 MB resident** while serving.
297
 
298
  ```
299
- llama-server -m sft-v19-q8_0.gguf --host 127.0.0.1 --port 9250 -ngl 0 -t 4 -c 2048
300
  ```
301
 
302
  What this does and does not establish: it runs usefully with no accelerator,
@@ -311,7 +267,21 @@ under heat while these did not.
311
  **[`Gramscii-IT/semantic-repair-routing`](https://huggingface.co/datasets/Gramscii-IT/semantic-repair-routing)**
312
  — published, and everything below can be recounted from it.
313
 
314
- **84,819 pairs**: 82,819 train, 1,000 validation, 1,000 test. Each pair is a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
315
  message somebody could plausibly write and the requests inside it restated
316
  plainly, one per line.
317
 
@@ -389,9 +359,10 @@ and where they stopped being.
389
 
390
  ## Training
391
 
392
- Fine-tuned from [`google/gemma-3-270m`](https://huggingface.co/google/gemma-3-270m) with `mlx_lm lora`, full fine-tune.
393
- The released weights are the run's final adapter, chosen by a gate on 1,000
394
- held-out examples rather than by the best number on a validation curve.
 
395
 
396
  ## Where all of this happened
397
 
@@ -409,16 +380,15 @@ One desktop machine, and nothing left it.
409
  | the fine-tune | |
410
  |---|---|
411
  | method | `mlx_lm lora`, full fine-tune |
412
- | iterations | 20,704 |
413
- | tokens seen | 2,383,728 |
414
- | peak memory | 7.3 GB |
415
- | speed | 5.6 iterations/s, 610 tokens/s |
416
- | wall clock | 11:15 to 12:42, about 90 minutes |
417
 
418
  Generators and judge ran on that same machine as local llama.cpp servers on
419
  loopback. No message here was written by a hosted API, and none was sent to
420
- one to be judged. The unified memory is why: a 35B generator and a
421
- fine-tune only share a desk when CPU and GPU read the same 64 GB.
422
 
423
  A model that decides where a question goes does not need a cluster or a
424
  month. It needs a narrow job, data built for it, and a bench honest enough
 
89
  | in | out |
90
  |---|---|
91
  | `Spanish: no busques la tienda de ropa, dime la dosis de paracetamol` | `dime la dosis de paracetamol` |
 
92
  | `English: book me a table for friday and also cancel my dentist` | `book me a table for friday`<br>`cancel my dentist` |
93
+ | `Italian: no aspetta, riassumimi cosa ci siamo detti` | `riassumi cosa ci siamo detti` |
94
  | `Italian: guarda un po', questo sacchetto della spesa è tutto rotto.` | `NO_REQUEST` |
95
+ | `Italian: ciao come stai` | `NO_REQUEST` |
96
 
97
+ A negation is dropped, one message asking for two things becomes two lines,
98
+ a request behind an opening "no" is kept, and something that is not a
99
+ request at all answers with the sentinel.
100
 
101
  ## What is in this repository
102
 
103
  | file | size | what it is |
104
  |---|---|---|
105
+ | `sft-v22-q8_0.gguf` | 292 MB | what the engine serves, through llama-server |
106
  | `model.safetensors` | 536 MB | the same weights fused, BF16, 236 tensors |
107
  | `model.safetensors.index.json` | | the index over that single file |
108
  | `tokenizer.json`, `tokenizer_config.json` | 33 MB | the tokenizer as the fuse wrote it |
 
110
  | `chat_template.jinja` | | present because the fuse writes it — **not the surface this model reads**, see above |
111
 
112
  The GGUF's sha256 is
113
+ `58b750b4bba4ed9cf1ea30316f1c5ad131316efaedd56cfd9440b488b2ae88f4`.
114
  The engine pins it and refuses anything else, which is what makes a routing
115
  decision reproducible.
116
 
117
+ Both files carry the same weights: checkpoint 21,000 of training run v22,
118
+ chosen on the validation split, quantised to Q8_0. Q8_0 and not Q4:
119
+ measured on this seat, at temperature 0 a Q8_0 is stable to the byte across
120
+ runs and a Q4 is not.
121
 
122
  ## What it is measured to do
123
 
124
+ Every number below compares these weights with the previous release of this
125
+ model (training run v19), both served by the same llama-server build with
126
+ the same greedy call, on the same day. Pairs are counted where the two
127
+ disagree, which is where the information is, with an exact two-sided sign
128
+ test.
129
 
130
+ **481 real questions people asked the engine**, in Italian, held out from
131
+ every training and selection step and routed through the full path the
132
+ engine takes (the router, the repair when the route is unsure, admission
133
+ only when every line is confident):
134
 
135
+ | | this model | previous release |
136
  |---|---|---|
137
+ | **exact**, every capability asked and no other | **159** | 138 |
138
+ | **safe**, a proper subset reached, nothing wrong run | 10 | 10 |
139
+ | **wrong execution** | 12 | 12 |
140
+ | questions where only this model is right / only the previous one is | **23 / 2** | p = 0.00002 |
141
+
142
+ The gain is where it was aimed: requests behind an opening "no", "ok" or
143
+ "I didn't get it", bare statistical topics, "what's new in X", and names
144
+ written in lowercase, which the previous release answered with
145
+ `NO_REQUEST`. Of the 118 questions it still fails on a capability it can
146
+ reach, 66 are decided by the router, not the rewrite: the right capability
147
+ comes first but below the bars. 38 route elsewhere and 13 are still
148
+ answered with the sentinel.
149
+
150
+ **900 routing tasks over graphs from another corpus**, five languages, two
151
+ in five naming a day:
152
+
153
+ | | this model | previous release |
154
+ |---|---|---|
155
+ | exact | 56 | 59 |
156
+ | compound questions answered whole | 4 | 5 |
157
+ | safe | 17 | 11 |
158
+ | abstained | 696 | 713 |
159
+ | wrong execution | **4** | 4 |
160
+ | answered in the wrong language | 2 | 1 |
161
+ | **lost the day** the question named | **125** | 112 |
162
+ | echoed the question back | 123 | 150 |
163
+
164
+ Disagreements split 26 to 39 against this model, p = 0.14: no difference
165
+ on this bench is significant, and the day column is the one to read.
166
+
167
+ **100 probes written before training**, 20 per family, none equal to a
168
+ training row or to a real question above: 52 of 80 requests routed to the
169
+ right capability with every name kept (previous release 43), and 20 of 20
170
+ non-requests answered `NO_REQUEST` (previous 20).
171
+
172
+ **The held-out test split** of the training data, 963 rows, whole
173
+ completion equal to the target: 263 (previous 260).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
 
175
+ ## What it does not fix, which a card naming only the gains would hide
 
 
 
 
176
 
177
+ **Dates.** On the 900-task bench it loses the day the question named more
178
+ often than the previous release, 125 against 112, and the restatement reads
179
+ as a clean request with the day simply gone. If the day matters to your
180
+ routing, measure that before you serve this.
181
 
182
+ **It can drop the verb of a request.** `Italian: scusa il disturbo, mi
183
+ diresti che tempo fa domani a Bologna?` comes back as `dimmi se domani a
184
+ Bologna è previsto`: "che tempo fa" is gone.
185
 
186
+ **It still refuses some requests.** `Italian: che novità ci sono in Django
187
+ 6?` answers `NO_REQUEST`. Of the 80 request probes, 10 still come back as
188
+ the sentinel, 15 route to another capability and 3 lose a name.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
 
190
  ### What bounds all of this
191
 
 
206
 
207
  **A restatement that does not win by enough margin routes nothing.** The
208
  router applies a margin and a floor, and below them the system abstains and
209
+ asks for a rephrasing. That is why the wrong-execution column is 4 in 900
210
+ while the abstention column is 696: the failure mode is refusing, not acting
211
  wrongly.
212
 
213
  **The descriptions are the other half.** What a question is matched against
 
232
  Served with llama-server, reached by the engine as one of four model seats:
233
 
234
  ```
235
+ llama-server -m sft-v22-q8_0.gguf --host 127.0.0.1 --port 9250 -ngl 99 -c 2048 --jinja
236
  ```
237
 
238
  It is loaded only when routing is genuinely unsure, never as the default
 
240
 
241
  ### On CPU alone
242
 
243
+ Measured on this architecture at this size, on an Apple M-series machine with `-ngl 0 -t 4`: no GPU offload at
244
  all, four threads, and nothing in the server log naming Metal or a GPU.
245
 
246
  | | latency | tokens/s |
 
252
  **762 MB resident** while serving.
253
 
254
  ```
255
+ llama-server -m sft-v22-q8_0.gguf --host 127.0.0.1 --port 9250 -ngl 0 -t 4 -c 2048
256
  ```
257
 
258
  What this does and does not establish: it runs usefully with no accelerator,
 
267
  **[`Gramscii-IT/semantic-repair-routing`](https://huggingface.co/datasets/Gramscii-IT/semantic-repair-routing)**
268
  — published, and everything below can be recounted from it.
269
 
270
+ The base is that dataset's **84,819 pairs** (82,819 train, 1,000 validation,
271
+ 1,000 test), cleaned by deterministic rules before training: template
272
+ leaks, changed values, English targets for other languages, repeated lines
273
+ and generic "category" lines removed, which leaves 80,297 train, 966
274
+ validation and 963 test rows. To them this release adds **2,515 rows** in
275
+ Italian and English, generated by Qwen3.6-35B-A3B and kept only when every
276
+ line's top capability on the engine's own roster was the one the row was
277
+ written for, every number and name of the message survived, and no row
278
+ shared most of its trigrams with a probe, a real question or another row.
279
+ They cover a request about the conversation itself, a bare statistical
280
+ topic, "what's new in X", names in lowercase or with a typo, long noisy
281
+ messages carrying two or three requests, and acknowledgements that ask for
282
+ nothing. Each is repeated twice in training, about 6% of it.
283
+
284
+ The base dataset, as published: Each pair is a
285
  message somebody could plausibly write and the requests inside it restated
286
  plainly, one per line.
287
 
 
359
 
360
  ## Training
361
 
362
+ Fine-tuned from [`google/gemma-3-270m`](https://huggingface.co/google/gemma-3-270m) with `mlx_lm lora`, full fine-tune, all
363
+ 18 blocks. The released weights are checkpoint 21,000, chosen among the
364
+ run's checkpoints by exact answers on the validation split (301 of 1,077),
365
+ never on the test split or the benches above.
366
 
367
  ## Where all of this happened
368
 
 
380
  | the fine-tune | |
381
  |---|---|
382
  | method | `mlx_lm lora`, full fine-tune |
383
+ | iterations | 21,276 |
384
+ | tokens seen | 2,327,566 |
385
+ | peak memory | 5.4 GB |
386
+ | speed | about 6 iterations/s |
387
+ | wall clock | 08:27 to 09:30, about an hour |
388
 
389
  Generators and judge ran on that same machine as local llama.cpp servers on
390
  loopback. No message here was written by a hosted API, and none was sent to
391
+ one to be judged.
 
392
 
393
  A model that decides where a question goes does not need a cluster or a
394
  month. It needs a narrow job, data built for it, and a bench honest enough
model.safetensors CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:f3a2d08287ab45528b19d6fa512f7bbcd2e6718d7264d0fce4d955c1a140af40
3
  size 536222768
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:eb85980247d466cb2b5a6e1b32d40a35f6b0551b968c344a19449656cfda3005
3
  size 536222768
sft-v19-q8_0.gguf → sft-v22-q8_0.gguf RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:33b6cc73c7d306c9c81aa96c5a8ddb9dbfd46a5ac5d0388a2de45b5229928c56
3
- size 299748064
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:58b750b4bba4ed9cf1ea30316f1c5ad131316efaedd56cfd9440b488b2ae88f4
3
+ size 291545056