v51: composite=88.68 — see model card for benchmark deltas vs v45
Browse files- README.md +31 -136
- config.json +1 -1
- model.safetensors +1 -1
README.md
CHANGED
|
@@ -18,102 +18,54 @@ datasets:
|
|
| 18 |
- juanquivilla/sotto-transcript-cleanup
|
| 19 |
---
|
| 20 |
|
| 21 |
-
# SottoASR Transcript Cleanup — LFM2.5-350M (Full Precision,
|
| 22 |
|
| 23 |
[sottoasr.app](https://sottoasr.app) · [MLX 5-bit (recommended)](https://huggingface.co/juanquivilla/sotto-cleanup-lfm25-350m-mlx-5bit) · [MLX 4-bit (smaller)](https://huggingface.co/juanquivilla/sotto-cleanup-lfm25-350m-mlx-4bit) · [Training Dataset](https://huggingface.co/datasets/juanquivilla/sotto-transcript-cleanup)
|
| 24 |
|
| 25 |
## Overview
|
| 26 |
|
| 27 |
-
|
| 28 |
|
| 29 |
-
|
| 30 |
|
| 31 |
-
|
| 32 |
|
| 33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
|
| 35 |
-
|
|
|
|
|
|
|
| 36 |
|
| 37 |
-
|
| 38 |
-
2. **GRPO (v40 → v42 → v43 → v44 → v45)** — five GRPO refinement passes that progressively tightened the reward shaping. The final v45 reward combines v36's substantive-deletion penalty + a number-accuracy term (digit-signature exact match, ±5.0) + an over-conversion penalty (penalize digits when reference has none) + an amplified filler penalty (6× multiplier). Each pass trained on a 6K-row mix (3K numbers + 2K flat + 1K preservation), batch=48, num_gen=8, 1000 steps, lr=5e-6 cosine.
|
| 39 |
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
| Capability | v23 baseline | v36 (preservation) | **v45 (this model)** |
|
| 43 |
|---|---:|---:|---:|
|
| 44 |
-
| Number accuracy (171-sample stratified
|
| 45 |
-
|
|
| 46 |
-
|
|
| 47 |
-
|
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
‡ Measured on a stricter eval — all 241 long inputs (>100 words) from `data_v23_paragraphs/val.jsonl`. On that same stricter eval v36 measures 13.3 %, so v45 is essentially tied with v36 on deletion behavior while gaining 83pp on number accuracy.
|
| 51 |
-
|
| 52 |
-
### Number conversion accuracy by category (171 stratified val samples)
|
| 53 |
-
|
| 54 |
-
| Category | v36 | **v45** |
|
| 55 |
-
|---|---:|---:|
|
| 56 |
-
| compound_2digit ("three sixty" → "360") | 10.0 % | **96.7 %** |
|
| 57 |
-
| sound_alike (sixteen vs sixty) | 0.0 % | **100.0 %** |
|
| 58 |
-
| hundred_form ("two hundred fifty" → "250") | 5.0 % | **100.0 %** |
|
| 59 |
-
| four_digit ("nineteen ninety nine" → "1999") | 6.7 % | **100.0 %** |
|
| 60 |
-
| time ("three pm" → "3 PM") | 0.0 % | **100.0 %** |
|
| 61 |
-
| decimal ("three point one four" → "3.14") | 10.0 % | 90.0 % |
|
| 62 |
-
| percent ("sixty percent" → "60 %") | 0.0 % | **100.0 %** |
|
| 63 |
-
| currency ("fifty dollars" → "$50") | 0.0 % | **100.0 %** |
|
| 64 |
-
| negative ("minus five" → "-5") | 0.0 % | **100.0 %** |
|
| 65 |
-
| digit_by_digit (phone) | 0.0 % | 60.0 % |
|
| 66 |
-
| ordinal ("twenty third" → "23rd") | 0.0 % | **100.0 %** |
|
| 67 |
-
| date ("july fourth" → "July 4") | 16.7 % | **100.0 %** |
|
| 68 |
-
| **preserve** (idioms, small cardinals) | 100.0 % | **100.0 %** |
|
| 69 |
-
|
| 70 |
-
12 of 13 categories at ≥90 %; preserve cases held at 100 % — v45 does not over-convert idiomatic uses of small cardinals.
|
| 71 |
-
|
| 72 |
-
## Key Specs
|
| 73 |
-
|
| 74 |
-
| Property | Value |
|
| 75 |
-
|----------|-------|
|
| 76 |
-
| **Size** | **676 MB** |
|
| 77 |
-
| **Number accuracy (stratified val)** | **95.9 %** ⭐ |
|
| 78 |
-
| **Filler-Free rate** | **97.0 %** ⭐ |
|
| 79 |
-
| **Architecture** | Hybrid: 10 conv + 6 GQA attention (354M params) |
|
| 80 |
-
| **Precision** | bf16 |
|
| 81 |
-
| **Training method** | SFT then chained GRPO (full fine-tune, no LoRA) |
|
| 82 |
-
| **Native context** | 32,768 tokens (128K base) |
|
| 83 |
-
| **Hardware** | 1× RTX PRO 6000 Blackwell (96 GB) |
|
| 84 |
-
|
| 85 |
-
## What It Does
|
| 86 |
-
|
| 87 |
-
Takes raw, unpunctuated ASR output and produces clean, readable text:
|
| 88 |
-
|
| 89 |
-
| Input (raw ASR) | Output (cleaned) |
|
| 90 |
-
|-----------------|------------------|
|
| 91 |
-
| so uh basically we need to fix the deployment pipeline | We need to fix the deployment pipeline. |
|
| 92 |
-
| the deadline is friday no monday we have until monday | The deadline is Monday. |
|
| 93 |
-
| talk about server three sixty | Talk about server 360. |
|
| 94 |
-
| schedule it for three fifteen pm | Schedule it for 3:15 PM. |
|
| 95 |
-
| we hit ninety eight percent uptime last month | We hit 98 % uptime last month. |
|
| 96 |
-
| transfer fifty dollars to billing | Transfer $50 to billing. |
|
| 97 |
-
| i'll be there in five | I'll be there in five. |
|
| 98 |
-
| we run twenty four seven | We run 24/7. |
|
| 99 |
-
|
| 100 |
-
### Paragraph emission on long dictations (inherited from v23)
|
| 101 |
-
|
| 102 |
-
Long, multi-topic input is restructured into paragraph-formatted prose with `\n\n` breaks at natural topic boundaries. See the [v36 model card archive](https://huggingface.co/juanquivilla/sotto-cleanup-lfm25-350m/tree/main) for a worked example.
|
| 103 |
|
| 104 |
-
|
| 105 |
|
| 106 |
-
##
|
| 107 |
|
| 108 |
```
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
|
|
|
|
|
|
| 114 |
```
|
| 115 |
|
| 116 |
-
##
|
| 117 |
|
| 118 |
```python
|
| 119 |
from transformers import AutoModelForCausalLM, AutoTokenizer
|
|
@@ -135,73 +87,16 @@ output = tokenizer.decode(out[0][inputs["input_ids"].shape[1]:], skip_special_to
|
|
| 135 |
if "###" in output:
|
| 136 |
output = output[:output.index("###")]
|
| 137 |
print(output.strip())
|
| 138 |
-
# → "Talk about server 360."
|
| 139 |
```
|
| 140 |
|
| 141 |
-
For long dictation that may need paragraph formatting, use a higher `max_new_tokens` (1024–2048).
|
| 142 |
-
|
| 143 |
-
## Training Details
|
| 144 |
-
|
| 145 |
-
### Pipeline
|
| 146 |
-
|
| 147 |
-
```
|
| 148 |
-
LiquidAI/LFM2.5-350M-Base
|
| 149 |
-
→ SFT (v23): 157,556 rows, LR 3e-5, 3 epochs, packed 4,096 ctx
|
| 150 |
-
→ GRPO R5/R6 (v23): paragraph emission tuned
|
| 151 |
-
→ GRPO v36: full FT, substantive-deletion-aware reward (no LoRA)
|
| 152 |
-
→ SFT v39: v36 + 12,757 number examples + 5K flat + 1K preservation, 2 epochs
|
| 153 |
-
→ GRPO v40-v45: chained refinement passes with combined reward
|
| 154 |
-
(ROUGE×5 - filler×6 + format + sub-del-pen + pres + num_term ±5)
|
| 155 |
-
```
|
| 156 |
-
|
| 157 |
-
### v45 reward function
|
| 158 |
-
|
| 159 |
-
A sum of:
|
| 160 |
-
|
| 161 |
-
1. **Quality**: `+5.0 × ROUGE-L F1` against the reference clean output.
|
| 162 |
-
2. **Filler penalty (amplified)**: `−min(count × 0.5, 2.0) × 6.0` per generation. v45 doubles v36's 3.0 multiplier — the boost that pushed filler-free past 95 %.
|
| 163 |
-
3. **Format bonus**: +0.2 each for capital-leading and terminal punctuation.
|
| 164 |
-
4. **Substantive-deletion penalty** (inherited from v36): strip filler words from input, compute multiset deletion ratio. If `> 0.10`, apply `−10.0 × ramp` linearly scaling from 0 at 0.10 to 1.0 at 0.35 deletion.
|
| 165 |
-
5. **Preservation bonus**: `+1.5` when output/input word ratio is in `[0.70, 0.95]`.
|
| 166 |
-
6. **Number-accuracy term (new in v40, fixed in v42)**: extract digit signatures from output and reference (after stripping commas/hyphens between digits). If they match, `+5.0`. If reference has digits but output disagrees, `−5.0`. **If reference has no digits but output adds them, `−5.0`** (v42's fix that solved v40's preserve-case over-conversion).
|
| 167 |
-
|
| 168 |
-
### Number-data generation
|
| 169 |
-
|
| 170 |
-
Programmatic generator covering 11 categories with **guaranteed ground truth** (digit form generated first, spoken form derived). Bedrock Claude Haiku 4.5 was the original augmentation target; replaced with a local Qwen3.6-27B-FP8 SGLang container (`enable_thinking: false` to disable reasoning mode). 3,229 programmatic seeds × 4 variants → 12,757 augmented examples after digit-signature acceptance filtering (98.4 % accept rate).
|
| 171 |
-
|
| 172 |
-
### Why chained GRPO
|
| 173 |
-
|
| 174 |
-
v40 (single-pass GRPO from v39 with the basic combined reward) hit 92.4 % num + 93.8 % filler-free — strong but with a regression on `preserve` and `time` categories (model over-converted idioms). v42 fixed the over-conversion penalty (recovering preserve to 100 %), v43 amplified the number term to 5/-5 (regaining num to 95.3 %), v44 chained one more epoch (recovering `time` to 100 %), and v45 finally amplified the filler penalty (97.0 % filler-free + 95.9 % num — final).
|
| 175 |
-
|
| 176 |
-
The chained approach proved more controllable than reaching the target in one shot: each pass corrected one specific failure mode without disturbing the others.
|
| 177 |
-
|
| 178 |
-
### Dataset
|
| 179 |
-
|
| 180 |
-
**157,556 train / 7,121 val rows** in [juanquivilla/sotto-transcript-cleanup](https://huggingface.co/datasets/juanquivilla/sotto-transcript-cleanup), plus the **1,352-sample preservation set** and a **3,400-sample programmatic ITN set** (3,229 train + 171 stratified val) augmented to 12,757 by Qwen3.6-27B with digit-signature validation.
|
| 181 |
-
|
| 182 |
## All Variants
|
| 183 |
|
| 184 |
| Variant | Size | Use Case |
|
| 185 |
|---------|------|----------|
|
| 186 |
| **[Full precision (this)](https://huggingface.co/juanquivilla/sotto-cleanup-lfm25-350m)** | 676 MB | Training, GPU inference |
|
| 187 |
| **[MLX 5-bit](https://huggingface.co/juanquivilla/sotto-cleanup-lfm25-350m-mlx-5bit)** | ~237 MB | **Recommended for Apple Silicon** |
|
| 188 |
-
| [MLX 4-bit](https://huggingface.co/juanquivilla/sotto-cleanup-lfm25-350m-mlx-4bit) | ~195 MB | Smallest
|
| 189 |
-
|
| 190 |
-
## Limitations
|
| 191 |
-
|
| 192 |
-
- Optimized for **English** conversational/meeting-style speech
|
| 193 |
-
- Domain-specific jargon (medical, legal) may not be corrected without additional fine-tuning
|
| 194 |
-
- `digit_by_digit` (phone numbers, account numbers spoken as individual digits with hyphens) is the weakest ITN category at ~60 % — produces correct digits but sometimes formats them differently from the reference
|
| 195 |
-
- Decimal conversion accuracy is 90 % (1/10 stratified val miss)
|
| 196 |
-
- The substantive-deletion metric is reference-free (compares output to input only, after filler-stripping) so it cannot catch *semantic* hallucinations — only word-level losses
|
| 197 |
-
- Not designed for formal written text — trained on spoken language patterns
|
| 198 |
|
| 199 |
## License
|
| 200 |
|
| 201 |
MIT
|
| 202 |
-
|
| 203 |
-
## Links
|
| 204 |
-
|
| 205 |
-
- **Application:** [sottoasr.app](https://sottoasr.app)
|
| 206 |
-
- **Source:** [github.com/juanqui/sottoasr](https://github.com/juanqui/sottoasr)
|
| 207 |
-
- **Dataset:** [juanquivilla/sotto-transcript-cleanup](https://huggingface.co/datasets/juanquivilla/sotto-transcript-cleanup)
|
|
|
|
| 18 |
- juanquivilla/sotto-transcript-cleanup
|
| 19 |
---
|
| 20 |
|
| 21 |
+
# SottoASR Transcript Cleanup — LFM2.5-350M (Full Precision, v51)
|
| 22 |
|
| 23 |
[sottoasr.app](https://sottoasr.app) · [MLX 5-bit (recommended)](https://huggingface.co/juanquivilla/sotto-cleanup-lfm25-350m-mlx-5bit) · [MLX 4-bit (smaller)](https://huggingface.co/juanquivilla/sotto-cleanup-lfm25-350m-mlx-4bit) · [Training Dataset](https://huggingface.co/datasets/juanquivilla/sotto-transcript-cleanup)
|
| 24 |
|
| 25 |
## Overview
|
| 26 |
|
| 27 |
+
Full-precision bf16 fine-tune of [LiquidAI/LFM2.5-350M-Base](https://huggingface.co/LiquidAI/LFM2.5-350M-Base) for on-device speech-to-text transcript cleanup. This is the **training artifact** — for on-device deployment on Apple Silicon, use the [5-bit MLX variant](https://huggingface.co/juanquivilla/sotto-cleanup-lfm25-350m-mlx-5bit).
|
| 28 |
|
| 29 |
+
## What's new in v51
|
| 30 |
|
| 31 |
+
v51 extends v45 with targeted training data covering five failure modes observed on real production transcripts:
|
| 32 |
|
| 33 |
+
- **Multi-number sentences** ("the score was 21 to 14")
|
| 34 |
+
- **Year-with-context drift** ("twenty eighteen and twenty twenty seven" → preserve both years)
|
| 35 |
+
- **Disconnected number lists** (no phone-number hallucination on "one two three eleven forty six")
|
| 36 |
+
- **Within-input duplicates** (same number stated twice — preserve consistency)
|
| 37 |
+
- **Long-form preservation** (multi-paragraph dictations with embedded numbers)
|
| 38 |
|
| 39 |
+
The v37+v47 training data (~30K examples) was re-audited end-to-end with a Qwen3.6-27B
|
| 40 |
+
judge and bad rows were dropped. A new 66-case adversarial benchmark drives objective
|
| 41 |
+
evaluation.
|
| 42 |
|
| 43 |
+
## Headline numbers
|
|
|
|
| 44 |
|
| 45 |
+
| Capability | v36 | v45 | **v51 (this model)** |
|
|
|
|
|
|
|
| 46 |
|---|---:|---:|---:|
|
| 47 |
+
| Number accuracy (171-sample stratified val) | 12.9% | 95.9% | **95.3%** |
|
| 48 |
+
| 66-case adversarial benchmark (greedy) | n/a | 76% | **86%** |
|
| 49 |
+
| 66-case adversarial benchmark (temp 0.7 × 4) | n/a | 77% | **84%** |
|
| 50 |
+
| Loops on 264 sampling-mode probes | n/a | 0 | **0** |
|
| 51 |
+
| Filler-free on 241 long inputs | 67.2% | 68.0% | **73.0%** |
|
| 52 |
+
| Sub-deletion >15% on 241 long inputs | 13.3% | 13.7% | **11.2%** |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
|
| 54 |
+
Composite score (0.35×num + 0.30×bench_greedy + 0.15×bench_sample + 0.10×filler_long + 0.05×(1-sub15) + 0.05×(1-loops/N)): **88.68**
|
| 55 |
|
| 56 |
+
## Training pipeline
|
| 57 |
|
| 58 |
```
|
| 59 |
+
LiquidAI/LFM2.5-350M-Base
|
| 60 |
+
→ SFT v23 → GRPO v23 (paragraph emission)
|
| 61 |
+
→ GRPO v36: full FT with substantive-deletion-aware reward
|
| 62 |
+
→ SFT v39: + 12.7K augmented number examples (ITN)
|
| 63 |
+
→ GRPO v40-v45: chained refinement, fixed reward + amplified filler penalty
|
| 64 |
+
→ SFT/GRPO v51: + 5.5K gap-filling examples (multi-number, year-context,
|
| 65 |
+
disconnected, duplicates, long-form), Qwen-audited and cleaned
|
| 66 |
```
|
| 67 |
|
| 68 |
+
## Usage
|
| 69 |
|
| 70 |
```python
|
| 71 |
from transformers import AutoModelForCausalLM, AutoTokenizer
|
|
|
|
| 87 |
if "###" in output:
|
| 88 |
output = output[:output.index("###")]
|
| 89 |
print(output.strip())
|
|
|
|
| 90 |
```
|
| 91 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
## All Variants
|
| 93 |
|
| 94 |
| Variant | Size | Use Case |
|
| 95 |
|---------|------|----------|
|
| 96 |
| **[Full precision (this)](https://huggingface.co/juanquivilla/sotto-cleanup-lfm25-350m)** | 676 MB | Training, GPU inference |
|
| 97 |
| **[MLX 5-bit](https://huggingface.co/juanquivilla/sotto-cleanup-lfm25-350m-mlx-5bit)** | ~237 MB | **Recommended for Apple Silicon** |
|
| 98 |
+
| [MLX 4-bit](https://huggingface.co/juanquivilla/sotto-cleanup-lfm25-350m-mlx-4bit) | ~195 MB | Smallest |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
|
| 100 |
## License
|
| 101 |
|
| 102 |
MIT
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
config.json
CHANGED
|
@@ -4,6 +4,7 @@
|
|
| 4 |
],
|
| 5 |
"block_auto_adjust_ff_dim": true,
|
| 6 |
"block_dim": 1024,
|
|
|
|
| 7 |
"block_ffn_dim_multiplier": 1.0,
|
| 8 |
"block_mlp_init_scale": 1.0,
|
| 9 |
"block_multiple_of": 256,
|
|
@@ -56,6 +57,5 @@
|
|
| 56 |
"use_cache": false,
|
| 57 |
"use_pos_enc": true,
|
| 58 |
"vocab_size": 65536,
|
| 59 |
-
"block_ff_dim": 6656,
|
| 60 |
"rope_theta": 1000000.0
|
| 61 |
}
|
|
|
|
| 4 |
],
|
| 5 |
"block_auto_adjust_ff_dim": true,
|
| 6 |
"block_dim": 1024,
|
| 7 |
+
"block_ff_dim": 6656,
|
| 8 |
"block_ffn_dim_multiplier": 1.0,
|
| 9 |
"block_mlp_init_scale": 1.0,
|
| 10 |
"block_multiple_of": 256,
|
|
|
|
| 57 |
"use_cache": false,
|
| 58 |
"use_pos_enc": true,
|
| 59 |
"vocab_size": 65536,
|
|
|
|
| 60 |
"rope_theta": 1000000.0
|
| 61 |
}
|
model.safetensors
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
size 708984464
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:48942a9e661298a8c531c901cca9d0dac8affc82fd06741f82599e0b3352ce8b
|
| 3 |
size 708984464
|