|
| 1 | +# Multitalker Parakeet Streaming 0.6B v1 |
| 2 | + |
| 3 | +NVIDIA's [`nvidia/multitalker-parakeet-streaming-0.6b-v1`](https://huggingface.co/nvidia/multitalker-parakeet-streaming-0.6b-v1) |
| 4 | +ported to transcribe.cpp. A 0.6B-parameter cache-aware streaming |
| 5 | +FastConformer encoder with an RNN-T transducer decoder, fine-tuned from |
| 6 | +[`nvidia/nemotron-speech-streaming-en-0.6b`](https://huggingface.co/nvidia/nemotron-speech-streaming-en-0.6b). |
| 7 | + |
| 8 | +## What it's for |
| 9 | + |
| 10 | +Offline and cache-aware **streaming** English speech-to-text with greedy |
| 11 | +RNN-T decoding. Outputs cased, punctuated transcripts. Token- and |
| 12 | +word-level timestamps are available. |
| 13 | + |
| 14 | +Upstream this is a **multitalker (speaker-attributed)** checkpoint: it can |
| 15 | +transcribe several overlapping speakers into per-speaker channels. That |
| 16 | +path depends on machinery this port does **not** ship (see |
| 17 | +[Known limitations](#known-limitations)). transcribe.cpp exposes only the |
| 18 | +model's `single_speaker_mode` ASR path, which disables the multitalker |
| 19 | +machinery and runs the checkpoint as a cache-aware streaming RNN-T with |
| 20 | +the base model's frontend, encoder backbone, decoder, and tokenizer plus |
| 21 | +the checkpoint's always-on layer-0 speaker-kernel injection. |
| 22 | + |
| 23 | +This port runs the model in both **offline** and **cache-aware streaming** |
| 24 | +modes. |
| 25 | + |
| 26 | +See NVIDIA's [model card](https://huggingface.co/nvidia/multitalker-parakeet-streaming-0.6b-v1) |
| 27 | +for training data, intended use, the multitalker methodology, and the full |
| 28 | +latency-vs-accuracy table. |
| 29 | + |
| 30 | +Licensed under the [NVIDIA Open Model License](https://www.nvidia.com/en-us/agreements/enterprise-software/nvidia-open-model-license/). |
| 31 | +Ported from upstream commit |
| 32 | +[`8749fc7`](https://huggingface.co/nvidia/multitalker-parakeet-streaming-0.6b-v1/commit/8749fc71fd6e2d88ef230159bbf2aea69b524ee1), |
| 33 | +pinned 2026-07-12. |
| 34 | + |
| 35 | +## Download |
| 36 | + |
| 37 | +| Quantization | Download | Size | WER (LibriSpeech test-clean, offline) | |
| 38 | +| --- | --- | ---: | ---: | |
| 39 | +| F32 | [multitalker-parakeet-streaming-0.6b-v1-F32.gguf](https://huggingface.co/handy-computer/multitalker-parakeet-streaming-0.6b-v1-gguf/resolve/main/multitalker-parakeet-streaming-0.6b-v1-F32.gguf) | 2.49 GB | 2.19% | |
| 40 | +| F16 | [multitalker-parakeet-streaming-0.6b-v1-F16.gguf](https://huggingface.co/handy-computer/multitalker-parakeet-streaming-0.6b-v1-gguf/resolve/main/multitalker-parakeet-streaming-0.6b-v1-F16.gguf) | 1.25 GB | 2.19% | |
| 41 | +| Q8_0 | [multitalker-parakeet-streaming-0.6b-v1-Q8_0.gguf](https://huggingface.co/handy-computer/multitalker-parakeet-streaming-0.6b-v1-gguf/resolve/main/multitalker-parakeet-streaming-0.6b-v1-Q8_0.gguf) | 734 MB | 2.18% | |
| 42 | +| Q6_K | [multitalker-parakeet-streaming-0.6b-v1-Q6_K.gguf](https://huggingface.co/handy-computer/multitalker-parakeet-streaming-0.6b-v1-gguf/resolve/main/multitalker-parakeet-streaming-0.6b-v1-Q6_K.gguf) | 604 MB | 2.20% | |
| 43 | +| Q5_K_M | [multitalker-parakeet-streaming-0.6b-v1-Q5_K_M.gguf](https://huggingface.co/handy-computer/multitalker-parakeet-streaming-0.6b-v1-gguf/resolve/main/multitalker-parakeet-streaming-0.6b-v1-Q5_K_M.gguf) | 542 MB | 2.18% | |
| 44 | +| Q4_K_M | [multitalker-parakeet-streaming-0.6b-v1-Q4_K_M.gguf](https://huggingface.co/handy-computer/multitalker-parakeet-streaming-0.6b-v1-gguf/resolve/main/multitalker-parakeet-streaming-0.6b-v1-Q4_K_M.gguf) | 478 MB | 2.18% | |
| 45 | + |
| 46 | +WER is measured on the full LibriSpeech test-clean split (2620 utterances) |
| 47 | +in `single_speaker_mode` with greedy RNN-T decoding, whisper-normalizer |
| 48 | +scoring (PnC-stripped), and no external LM. F32 reference baseline: 2.19%. |
| 49 | +The measured NeMo `single_speaker_mode` reference on the same split is |
| 50 | +2.19%, and NVIDIA's self-reported number is 2.19% (from the |
| 51 | +[HF model card](https://huggingface.co/nvidia/multitalker-parakeet-streaming-0.6b-v1)). |
| 52 | + |
| 53 | +## Streaming parity |
| 54 | + |
| 55 | +Cache-aware streaming was validated tensor-by-tensor against NeMo's |
| 56 | +`conformer_stream_step` reference via `scripts/validate_streaming.py`. On |
| 57 | +`samples/jfk.wav` at `--backend cpu --threads 1`, the always-on layer-0 |
| 58 | +speaker-kernel injection is applied per chunk on the post-drop block-0 |
| 59 | +input (matching the offline path), and the harness reports **150/150 |
| 60 | +streaming-tensor pairs within tolerance and the transcript byte-exact vs |
| 61 | +NeMo at R=13** (`att_context_size=[70, 13]`, 1.12s chunk). Streaming |
| 62 | +`enc_out` drift (observed 5.5e-6) is tighter than the offline C++ |
| 63 | +`enc.final` drift (1.9e-3) on the same audio, because clean per-chunk |
| 64 | +caches accumulate less error than a single 24-block offline pass. |
| 65 | + |
| 66 | +Reproduce: |
| 67 | + |
| 68 | +```bash |
| 69 | +uv run --project scripts/envs/parakeet scripts/validate_streaming.py \ |
| 70 | + --hf-model nvidia/multitalker-parakeet-streaming-0.6b-v1 \ |
| 71 | + --gguf models/multitalker-parakeet-streaming-0.6b-v1/multitalker-parakeet-streaming-0.6b-v1-F32.gguf \ |
| 72 | + --audio samples/jfk.wav \ |
| 73 | + --out build/validate_streaming/multitalker/jfk \ |
| 74 | + --right 13 6 1 0 \ |
| 75 | + --backend cpu --threads 1 \ |
| 76 | + --tolerances tests/tolerances/multitalker-parakeet-streaming-0.6b-v1.streaming.json |
| 77 | +``` |
| 78 | + |
| 79 | +## Quick Start |
| 80 | + |
| 81 | +```bash |
| 82 | +cmake -B build |
| 83 | +cmake --build build |
| 84 | + |
| 85 | +build/bin/transcribe-cli \ |
| 86 | + -m models/multitalker-parakeet-streaming-0.6b-v1/multitalker-parakeet-streaming-0.6b-v1-Q8_0.gguf \ |
| 87 | + samples/jfk.wav |
| 88 | +``` |
| 89 | + |
| 90 | +If your audio is not already 16 kHz mono WAV, convert it first: |
| 91 | + |
| 92 | +```bash |
| 93 | +ffmpeg -i input.mp3 -ar 16000 -ac 1 output.wav |
| 94 | +``` |
| 95 | + |
| 96 | +## Performance |
| 97 | + |
| 98 | +Cells are wall-clock latency (mean over 3 iterations after 1 warmup), |
| 99 | +with speedup over realtime in parentheses. Units: `ms` below 1 s, `s` |
| 100 | +above (2 decimal places). |
| 101 | + |
| 102 | +### Apple M4 Max |
| 103 | + |
| 104 | +| Backend | Sample | Q8_0 | Q4_K_M | |
| 105 | +| ------- | ------------ | ------------: | ------------: | |
| 106 | +| Metal | jfk (11.0s) | 67 ms (164×) | 69 ms (159×) | |
| 107 | +| Metal | dots (35.3s) | 184 ms (192×) | 185 ms (191×) | |
| 108 | +| CPU | jfk (11.0s) | 310 ms (36×) | 307 ms (36×) | |
| 109 | +| CPU | dots (35.3s) | 1.05 s (34×) | 1.03 s (34×) | |
| 110 | + |
| 111 | +macOS 26.5.1, transcribe.cpp `c55a09d`. |
| 112 | + |
| 113 | +### AMD Ryzen 7 4750U Pro |
| 114 | + |
| 115 | +| Backend | Sample | Q8_0 | Q4_K_M | |
| 116 | +| ------- | ------------ | ------------: | ------------: | |
| 117 | +| Vulkan | jfk (11.0s) | 466 ms (24×) | 475 ms (23×) | |
| 118 | +| Vulkan | dots (35.3s) | 1.36 s (26×) | 1.39 s (26×) | |
| 119 | +| CPU | jfk (11.0s) | 751 ms (15×) | 816 ms (13×) | |
| 120 | +| CPU | dots (35.3s) | 2.99 s (12×) | 3.12 s (11×) | |
| 121 | + |
| 122 | +Fedora 43, transcribe.cpp `c55a09d`. Vulkan device: `AMD Radeon |
| 123 | +Graphics (RADV RENOIR)`. |
| 124 | + |
| 125 | +Benchmark reproduction: |
| 126 | + |
| 127 | +```bash |
| 128 | +uv run scripts/bench/run.py \ |
| 129 | + --models multitalker-parakeet-streaming-0.6b-v1 \ |
| 130 | + --quants q8_0,q4_k_m \ |
| 131 | + --samples jfk,dots \ |
| 132 | + --backends metal,cpu,vulkan \ |
| 133 | + --iters 3 --warmup 1 \ |
| 134 | + --name multitalker-parakeet-streaming-0.6b-v1-publication |
| 135 | +``` |
| 136 | + |
| 137 | +## Numerical Validation |
| 138 | + |
| 139 | +transcribe.cpp is validated tensor-by-tensor against NeMo on |
| 140 | +`samples/jfk.wav` via `scripts/validate.py`. Per-tensor tolerances live |
| 141 | +in a per-variant file |
| 142 | +([`tests/tolerances/multitalker-parakeet-streaming-0.6b-v1.json`](../../tests/tolerances/multitalker-parakeet-streaming-0.6b-v1.json)) |
| 143 | +rather than the family-shared one because the unnormalised log-mel |
| 144 | +(NeMo's `normalize="NA"` no-op) lands on a different magnitude scale than |
| 145 | +the per-feature-normalised siblings, and because the layer-0 |
| 146 | +speaker-kernel injection is unique to this variant. The family-level |
| 147 | +forward map at |
| 148 | +[`reports/porting/parakeet/forward-map.md`](../../reports/porting/parakeet/forward-map.md) |
| 149 | +documents the per-stage divergence sources. |
| 150 | + |
| 151 | +| Field | Value | |
| 152 | +| --- | --- | |
| 153 | +| Reference | NeMo, `nvidia/multitalker-parakeet-streaming-0.6b-v1` (`single_speaker_mode`) | |
| 154 | +| Dump script | `scripts/dump_reference_parakeet_nemo.py` | |
| 155 | +| Manifest | `tests/golden/parakeet/multitalker-parakeet-streaming-0.6b-v1.manifest.json` | |
| 156 | +| Command | `uv run scripts/validate.py all --family parakeet --variant multitalker-parakeet-streaming-0.6b-v1` | |
| 157 | + |
| 158 | +## Batch |
| 159 | + |
| 160 | +The model ships an explicit `run_batch()` parallel fast path. Batch output |
| 161 | +is WER-neutral: byte-equal to the serial single-stream path at batch sizes |
| 162 | +2 / 4 / 8 (golden frozen at |
| 163 | +`tests/golden/batch/multitalker-parakeet-streaming-0.6b-v1.cpu.json`), |
| 164 | +CPU same-length tensor parity is bit-exact (max_abs 0.0) at batch=4 on |
| 165 | +`jfk.wav`, diverse-length flash tensor parity is bit-exact across arbitrary |
| 166 | +length mixes, and full test-clean batch-8 WER equals batch-1 (2.19%). |
| 167 | + |
| 168 | +## Known limitations |
| 169 | + |
| 170 | +- **Single-speaker only. The multitalker / speaker-attributed ASR path is |
| 171 | + not ported.** Upstream, this checkpoint transcribes several overlapping |
| 172 | + speakers into per-speaker channels. That path requires (1) an external |
| 173 | + streaming speaker-diarization model |
| 174 | + ([`nvidia/diar_streaming_sortformer_4spk-v2.1`](https://huggingface.co/nvidia/diar_streaming_sortformer_4spk-v2.1), |
| 175 | + a separate Sortformer checkpoint that this repo does not ship), (2) |
| 176 | + per-frame speaker-kernel injection driven by that diarizer's supervision, |
| 177 | + (3) one encoder+decoder instance per speaker (up to 4), and (4) a |
| 178 | + speaker-tagged SegLST output contract. None of these exist in |
| 179 | + transcribe.cpp today, so the port runs `single_speaker_mode` and produces |
| 180 | + a single flat transcript. It does **not** separate speakers, diarize, or |
| 181 | + emit speaker turns. |
| 182 | +- **English only.** The model is English-only by training. |
| 183 | +- **No translation and no language detection.** |
| 184 | + |
| 185 | +## Reproduction |
| 186 | + |
| 187 | +### Convert |
| 188 | + |
| 189 | +```bash |
| 190 | +uv run --project scripts/envs/parakeet \ |
| 191 | + scripts/convert-parakeet.py nvidia/multitalker-parakeet-streaming-0.6b-v1 |
| 192 | +``` |
| 193 | + |
| 194 | +### Quantize |
| 195 | + |
| 196 | +Run `transcribe-quantize` once per target quant. Example for Q8_0; repeat |
| 197 | +with `F16`, `Q6_K`, `Q5_K_M`, `Q4_K_M`: |
| 198 | + |
| 199 | +```bash |
| 200 | +build/bin/transcribe-quantize \ |
| 201 | + models/multitalker-parakeet-streaming-0.6b-v1/multitalker-parakeet-streaming-0.6b-v1-F32.gguf \ |
| 202 | + models/multitalker-parakeet-streaming-0.6b-v1/multitalker-parakeet-streaming-0.6b-v1-Q8_0.gguf \ |
| 203 | + --quant Q8_0 |
| 204 | +``` |
| 205 | + |
| 206 | +### Validate |
| 207 | + |
| 208 | +```bash |
| 209 | +uv run scripts/validate.py all --family parakeet --variant multitalker-parakeet-streaming-0.6b-v1 |
| 210 | +``` |
0 commit comments