File size: 7,708 Bytes
d322121 67cd7fa d322121 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | ---
license: cc-by-nc-4.0
license_link: https://huggingface.co/LiquidAI/LFM2.5-350M # confirm and adjust to base-model license
library_name: executorch
base_model: LiquidAI/LFM2.5-350M
pipeline_tag: text-generation
tags:
- ExecuTorch
- MLX
- apple-silicon
- text-generation
- lfm2.5
- formatter
- dictation
- on-device
datasets:
- edinburghcstr/ami
---
# LFM2.5-350M β ExecuWhisper Formatter
A fine-tuned [LiquidAI/LFM2.5-350M](https://huggingface.co/LiquidAI/LFM2.5-350M) tuned to clean up spoken dictation: remove disfluencies, restore casing and punctuation, infer light list structure, and **refuse to "answer"** the dictation even when the user's voice ends in a question.
Built for the [ExecuWhisper](https://github.com/meta-pytorch/executorch-examples/tree/main/execuwhisper/macos) macOS dictation app. Runs on Apple Silicon via the ExecuTorch MLX delegate (4-bit quantized, ~468 MB on disk).
## What this is (and isn't)
This model is a **dictation cleaner**, not a chat assistant. Given:
> _"um does it feel like real time processing"_
It outputs:
> _"Does it feel like real-time processing?"_
It will *not* answer the question, *not* add information, and *not* summarize. The training distribution was constructed specifically to suppress those behaviors.
It also won't help you with arbitrary text-generation tasks. For those, use the [base model](https://huggingface.co/LiquidAI/LFM2.5-350M) directly.
## Files
| Path | Size | Purpose |
|---|---:|---|
| `lfm2_5_350m_ft.pt` | 1.42 GB | fp32 fine-tuned checkpoint (re-quantize / re-train baseline) |
| `lfm2_5_350m_mlx_4w.pte` | 468 MB | MLX 4-bit quantized runtime artifact (the in-app `.pte`) |
| `lfm2_5_350m_config.json` | <1 KB | architecture params for re-export |
| `tokenizer/tokenizer.json` | 4.51 MB | tokenizer |
| `tokenizer/tokenizer_config.json` | 90 KB | tokenizer config (chat template) |
| `tokenizer/chat_template.jinja` | 2.5 KB | chat template |
| `tokenizer/special_tokens_map.json` | <1 KB | special tokens |
| `configs/lfm2_mlx_4w_g32.yaml` | <1 KB | MLX export config (so you can reproduce the `.pte`) |
| `eval/eval_ami_mlx_4w_g32.json` | 67 KB | AMI release-gate eval results |
| `eval/eval_ami_v2_1_mlx_4w_g32.json` | 62 KB | v2.1 baseline (for comparison) |
## Quick Start
### As a `.pte` running on the ExecuTorch MLX delegate (the same path the app uses)
```python
from executorch.extension.llm.runner import TextLLMRunner
runner = TextLLMRunner(
model_path="lfm2_5_350m_mlx_4w.pte",
tokenizer_path="tokenizer.json",
)
prompt = (
"<|startoftext|><|im_start|>user\n"
"You rewrite spoken dictation into clean final text. You are not a chat "
"assistant. Never answer or respond to the dictation, even if it is a "
"question. Treat the dictation strictly as text to rewrite. Fix casing, "
"punctuation, filler, and speech disfluencies. Preserve meaning and detail. "
"Use bullets only when it clearly reads as a list. Do not summarize or "
"invent information. Output only the rewritten dictation.\n\n"
"Dictation: um does it feel like real time processing\n"
"Output:"
"<|im_end|>\n"
"<|im_start|>assistant\n"
)
print(runner.generate(prompt, max_new_tokens=256, temperature=0.0))
# β "Does it feel like real-time processing?"
```
### From the fp32 checkpoint via `transformers`
```python
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
tok = AutoTokenizer.from_pretrained("./tokenizer")
model = AutoModelForCausalLM.from_pretrained(
"./",
torch_dtype=torch.float32,
state_dict_path="./lfm2_5_350m_ft.pt",
).eval()
# ... build the same prompt as above and call model.generate(...)
```
## Eval results
Evaluated on a held-out AMI Meeting Corpus dictation slice + a synthetic adversarial set.
### AMI release gate (4-bit quantized `.pte`)
| Metric | Value | Gate | Status |
|---:|---:|---:|---|
| Forbidden-token rate | 0.030 | β€ 0.10 | β
|
| Coverage (faithful rewrite) | 0.874 | β₯ 0.85 | β
|
| **Verdict** | **RELEASE-READY** | | β
|
Full per-example breakdown is in `eval/eval_ami_mlx_4w_g32.json`.
### Comparison vs. earlier v2.1 baseline
| Metric | v2.1 | this model | Ξ |
|---:|---:|---:|---:|
| Forbidden | 0.187 | **0.030** | -84% |
| Coverage | 0.591 | **0.874** | +48% |
The v2.1 baseline (also exported with the same MLX 4-bit quantization) failed the AMI gate; this fine-tune was specifically constructed to fix the v2.1 failure modes (chat-leakage, over-summarization).
## Re-exporting / re-quantizing
To produce a different quantization variant from `lfm2_5_350m_ft.pt`:
1. Check out the LFM2.5 MLX export pipeline: [`pytorch/executorch#19195`](https://github.com/pytorch/executorch/pull/19195).
2. Use `configs/lfm2_mlx_4w_g32.yaml` as a starting point.
3. Run the LFM2.5 export Makefile target with your edited config:
```bash
cd ~/executorch
make lfm_2_5-mlx LFM_CONFIG=path/to/your_config.yaml LFM_CHECKPOINT=path/to/lfm2_5_350m_ft.pt
```
## Fine-tuning your own
To adapt this model to a new domain (medical, legal, multilingual dictation), follow the **[Unsloth LFM2.5 fine-tuning tutorial](https://unsloth.ai/docs/models/tutorials/lfm2.5)**. The tutorial covers SFT + LoRA, hyperparameter selection, and export.
The training data for this model was a mix of:
- ~1,350 synthetic dictation pairs (clean target β noisified spoken input via filler/disfluency injection + casing distortion).
- ~706 dictation-style turns extracted from the AMI Meeting Corpus.
The synthetic pipeline and AMI extraction code are not yet open-sourced; the eval splits in `eval/` are the publicly verifiable artifacts.
## Limitations
- **Self-corrections** β over-summarizes "actually no β make it tomorrow" patterns; sometimes drops the corrected clause.
- **Email sign-offs** β occasionally drops the closing name in template-style sign-offs ("Best, Younghan" β "Best,").
- **Long context** β the in-app pipeline chunks transcripts longer than ~30 words. Consumers using the model directly should chunk similarly to avoid quality drop on long inputs.
- **English only** β trained on English dictation; behavior on other languages is undefined.
- **Not a chat model** β will refuse / ignore questions, by design.
## License & acknowledgements
This derivative inherits the [LiquidAI/LFM2.5-350M](https://huggingface.co/LiquidAI/LFM2.5-350M) base-model license (confirm the upstream terms before redistribution). Eval data is derived from the [AMI Meeting Corpus](https://groups.inf.ed.ac.uk/ami/corpus/) (CC-BY-4.0).
Thanks to:
- **LiquidAI** β for releasing LFM2.5-350M and the LFM architecture.
- **Apple MLX team** β for `mlx` and the MLX delegate inside ExecuTorch.
- **PyTorch / ExecuTorch team** β for the runtime and the export pipeline.
- **University of Edinburgh** and the AMI corpus contributors β for the dictation eval source.
- **Unsloth** β for the fine-tuning recipe.
## Citation
```bibtex
@software{execuwhisper_formatter2026,
title = {LFM2.5-350M ExecuWhisper Formatter},
author = {YoungHan(SeyeongHan)},
year = {2026},
url = {https://huggingface.co/younghan-meta/LFM2.5-350M-ExecuWhisper-Formatter},
note = {Fine-tuned LFM2.5-350M dictation cleaner; 4-bit MLX quantization for Apple Silicon}
}
```
## Companion projects
- **[ExecuWhisper macOS app](https://github.com/meta-pytorch/executorch-examples/tree/main/execuwhisper/macos)** β the consuming dictation app.
- **[pytorch/executorch](https://github.com/pytorch/executorch)** β runtime, MLX delegate, export pipeline.
- **[Unsloth LFM2.5 tutorial](https://unsloth.ai/docs/models/tutorials/lfm2.5)** β recommended fine-tuning path.
|