I take a recording device to client meetings. The recordings come back to the laptop sounding like someone had a conversation in a server room while a hoover ran in the background — which, in a couple of cases, is exactly what happened. Single-model Whisper does its best and produces something coherent, but "something coherent" and "accurate verbatim transcript with speaker attribution" are rather different things, and when I'm trying to reconstruct who said what about a project deadline, the distinction matters.
The current setup — one faster-whisper CPU container on the laptop, single model, no diarisation, no word-level timestamps — was always a temporary measure. It was time to do it properly: GPU-accelerated, multiple independent models cross-checking each other, speaker diarisation for attribution, word-level timestamps, and a local LLM to reconcile the disagreements and produce a consultancy summary. All of it running in a Proxmox LXC on PVE2 (four idle RTX 5060 Ti cards, ~16 GB VRAM each), audio stored on TrueNAS.
Before writing a single line of pipeline code, I spent a session researching the current state of the art. This post documents what I found, including the wrong turns. Part 2 goes deeper on how those benchmarks are actually constructed and what we found when we looked harder. Part 3 has the results of running the ensemble on real recordings.
A quick glossary
This post uses some ASR-specific jargon. For those not already immersed in it:
WER (Word Error Rate) — the standard accuracy metric: the percentage of words that were substituted, deleted, or inserted by the model compared to the correct transcript. Lower is better. 5% WER means 5 words in every 100 were wrong.
RTFx (Real-Time Factor, multiplied) — how many times faster than real-time the model processes audio. RTFx 3,380 means a one-hour recording finishes in about one second once the model is warm.
CTC (Connectionist Temporal Classification) — a training objective that lets a model align audio frames to text without needing pre-labelled boundaries. Produces fast, accurate models without an autoregressive decoder.
TDT (Token-and-Duration Transducer) — a variant of the RNN-Transducer architecture that predicts both the output token and how many frames to skip simultaneously, giving very high throughput while preserving timestamp accuracy.
GER (Generative Error Correction) — using a large language model to post-process ASR output, fixing errors by leveraging the LLM's understanding of language rather than acoustic signal.
ROVER (Recogniser Output Voting Error Reduction) — a 1997 algorithm that combines multiple ASR hypotheses by aligning them word-by-word and picking the most-voted word at each position.
Diarisation — segmenting audio into speaker turns and labelling them ("who spoke when"). Anonymous labels only (Speaker 1, Speaker 2); speaker identification by name is a separate problem.
VAD (Voice Activity Detection) — detecting which portions of audio contain speech vs silence or noise, so ASR engines don't waste compute on empty segments.
Forced alignment — matching an already-known transcript back to the audio to produce word-level timestamps. Used when a model doesn't natively output timestamps.
NeMo — NVIDIA's open-source toolkit for training and serving speech and language models. Most NVIDIA ASR models (Parakeet, Canary) are NeMo-native.
Why multiple models?
The core idea is simple: each ASR engine makes different mistakes. A Conformer-based model misreads differently to a Transformer-based one; a model fine-tuned on read speech falls apart on spontaneous conversation differently to one trained on telephone calls. If you run three or four architecturally distinct engines on the same audio and then ask a local LLM to reconcile the differences — rather than doing a naive majority vote — you get something closer to what was actually said than any single engine produces alone.
The alternative, ROVER, aligns N-best hypotheses and picks the most frequent word at each position. It's fast and deterministic. It's also twenty-five years old and, as the research notes, often performs worse than the ASR baseline when the hypotheses aren't already good — the bad guesses vote each other up rather than out. LLM-based generative error correction (GER) is the more interesting approach: rather than voting on words, you feed all the hypotheses to a language model and ask it to infer what was most likely said, with the constraint that it shouldn't invent content. The GenSEC challenge at IEEE SLT 2024 (Yang et al., arXiv:2409.09785) puts this on a proper footing as a benchmark task.
The catch: the LLM has to be constrained. A zero-shot prompt-only LLM will hallucinate fluent text that sounds plausible but was never spoken — which is worse than any of the raw transcripts. Low temperature, an explicit "do not generate content not present in at least one hypothesis" instruction, and [inaudible] for segments where no engine agrees, helps keep it honest.
Finding the leaderboard
My first stop was the Open ASR Leaderboard — a collaboration between Hugging Face, NVIDIA, Mistral AI, and the University of Cambridge that evaluates 86 open-source and commercial models across 12 datasets. If a model is genuinely competitive for English speech recognition, it's on here. Part 2 goes into how the leaderboard is constructed and what its numbers actually mean for noisy meeting recordings.
The dedicated ASR family
These are models built specifically for speech recognition, without the overhead of a general-purpose language model backbone.
NVIDIA NeMo Canary-Qwen-2.5B
HuggingFace repo: nvidia/canary-qwen-2.5b
Leaderboard: #1 average WER, 5.63% on English
A Conformer encoder paired with a Qwen 2.5B LLM decoder — an interesting architecture because you get a language model on the output side without running a separate reconciliation step. CC-BY-4.0 licence, English-focused on the published benchmarks. It needs forced alignment for word-level timestamps, since the LLM decoder doesn't output them natively.
NVIDIA NeMo Parakeet-TDT-0.6b-v2
HuggingFace repo: nvidia/parakeet-tdt-0.6b-v2
WER: 6.05% average; LibriSpeech test-clean 1.69%
A Conformer-TDT hybrid at 600M parameters producing native word-level timestamps — no forced alignment step needed. RTFx 3,380 with batch size 128: in practice a one-hour recording processes in about one second once the model is warm. English-only, CC-BY-4.0, around 2 GB VRAM. There's now a v3 (nvidia/parakeet-tdt-0.6b-v3) covering 25 European languages at 6.32% WER, worth considering if recordings include anything other than English.
The model card confirms it's optimised for NVIDIA Ampere, Blackwell, Hopper, and Volta architectures — so the 5060 Ti (sm_120) should be fine, though I'll verify that before trusting it.
WhisperX with openai/whisper-large-v3
HuggingFace repo: openai/whisper-large-v3
WER: ~7.4% average English
WhisperX (github.com/m-bain/whisperX, v3.8.6) wraps faster-whisper with wav2vec2 forced alignment for word-level timestamps and pyannote-audio speaker diarisation. Despite not being the accuracy leader, it stays in the ensemble for two reasons: (1) Whisper large-v3 was trained on a vast, diverse dataset and handles UK accents and background noise better than cleaner-trained models; (2) it's the only engine here that provides speaker diarisation natively, making it the timing and attribution backbone. WhisperX's assign_word_speakers attaches speaker labels to every word; the other engines' text hypotheses anchor to that skeleton.
Pyannote requires accepting a gated model licence on HuggingFace — the HF token in ~/.cache/huggingface/token needs to be present before first run.
CrisperWhisper
HuggingFace repo: nyrahealth/CrisperWhisper
WER: ~6.67% average
A fine-tuned Whisper variant optimised for verbatim transcription, including disfluencies like "um", "uh", and false starts that standard Whisper smooths over. Timestamp-specialised models tend to be more useful on messy real-world audio than their leaderboard numbers suggest — meetings have rather a lot of filler words.
IBM Granite Speech 3.3
HuggingFace repo: ibm-granite/granite-speech-3.3-8b
WER: ~5.74% (8B), ~6.00% (2B variant)
Apache-2.0 licence
IBM's entry, sitting near the top of the leaderboard. Apache-2.0 is a more permissive licence than CC-BY for anything commercial. The 2B variant fits alongside the rest of the ASR pack on a single GPU; the 8B needs its own card.
The voice-LLM family
Large language models that accept audio as a direct input modality. Architecturally very different to the dedicated ASR engines — they make different mistakes — which is precisely why they're useful in an ensemble.
Mistral Voxtral-Mini-3B-2507
HuggingFace repo: mistralai/Voxtral-Mini-3B-2507
Released: 15 July 2025
Apache-2.0 licence
Max audio: 30 minutes per call
The most practical voice-LLM for this pipeline. Runs in vLLM with the Mistral tokenizer mode and exposes an OpenAI-compatible /v1/audio/transcriptions endpoint natively:
vllm serve mistralai/Voxtral-Mini-3B-2507 \
--tokenizer_mode mistral \
--config_format mistral \
--load_format mistral
The pipeline can POST audio files to it exactly as it would to OpenAI Whisper's API — no bespoke client code. Outperforms Whisper large-v3 on transcription benchmarks, runs in ~9.5 GB VRAM in bf16/fp16. A 90-minute meeting needs chunking into three overlapping segments; the preprocessing step handles this.
Microsoft Phi-4-multimodal-instruct
HuggingFace repo: microsoft/Phi-4-multimodal-instruct
WER: 6.14%
MIT licence
Max audio per ASR call: 40 seconds
A 5.6B-parameter multimodal model with a 128K token context window. The 40-second ASR audio cap means chunking is required for long meetings — similar to Gemma 4's 30-second limit, which I'll come back to. MIT licence, architecturally completely different from the dedicated ASR engines. Fits on a single 16 GB card.
Gemma 4 E4B (experimental)
HuggingFace repo: google/gemma-4-E4B-it
Released: 2 April 2026
Apache-2.0 licence
Max audio: 30 seconds
I want to address the naming confusion here because it took a while to resolve. There are two different Google model families that sound similar:
- Gemma 3n (
google/gemma-3n-E4B-it) — the predecessor, ASR-capable - Gemma 4 (
google/gemma-4-E4B-it) — released April 2026, genuinely separate architecture, also ASR-capable
Google has a history of reusing model family names in confusing ways (the Gemma 1/2/3/3n/4 progression is not linear). Gemma 4 does exist as a distinct series. Its 30-second audio window is designed for on-device/phone deployment; for a 90-minute meeting that means 25-second chunks with overlapping boundaries. Whether the architectural diversity it adds to the ensemble justifies the chunking complexity is a build-time decision. I'm including it as optional.
Kyutai STT-2.6b-en
HuggingFace repo: kyutai/stt-2.6b-en
WER: 6.4% on Open ASR Leaderboard
CC-BY-4.0 licence
A streaming decoder-only Transformer from Kyutai using Mimi audio tokenization. 2.6B parameters, handles audio up to 2 hours in a single pass with a 2.5-second streaming delay. Word-level timestamps require a 2.5-second offset adjustment. Small enough to co-reside with other models. A cheap extra vote if VRAM headroom allows.
The models I chose not to include
Ultravox — audio understanding and instruction-following, not verbatim transcription. Different job.
GLM-4-Voice, Moshi, Step-Audio — speech output / dialogue systems. They produce speech, not text.
Kimi-Audio — Moonshot AI's audio model, competitive on Chinese benchmarks, questionable data practices for anything touching client-confidential material.
Qwen3-Omni-30B-A3B — genuinely impressive (LibriSpeech test-clean 1.22%), but needs two GPUs and doesn't have native word timestamps. Too complex for the return at this stage.
I'll admit Part 2 has one addition I missed here — there's a model that belongs in this ensemble and wasn't on my initial radar. More on that there.
The Blackwell trap: CTranslate2 and sm_120
PVE2's GPUs are RTX 5060 Ti — Blackwell architecture, compute capability sm_120. This was the most important discovery of the research phase, because it affects every model using CTranslate2 as its inference backend (which includes faster-whisper, and therefore WhisperX).
The error when running INT8 compute on sm_120:
cuBLAS failed with status CUBLAS_STATUS_NOT_SUPPORTED
Blackwell's INT8 tensor cores require specific padding that the current cuBLAS API version used by CTranslate2 doesn't supply. The fix: use float16 instead of INT8. Straightforward to configure, but it means VRAM estimates for faster-whisper models are higher than documentation suggests — whisper-large-v3 in float16 is roughly twice the VRAM of int8. There's a fix merged (CTranslate2 issue #1865, PR #1937), but I'll test before assuming it's resolved.
For PyTorch itself, PyTorch 2.7 is the first stable release with sm_120 kernel support, via the cu128 wheel index:
uv pip install torch==2.7.0 --index-url https://download.pytorch.org/whl/cu128
Any model that pulls in an older torch without specifying the index will fail at runtime with "no kernel image available for device 0". The vLLM stack (Voxtral, summary LLM) and the ASR stack (WhisperX/CTranslate2) have conflicting torch pins — they go into two separate isolated venvs. Phase 3 of the build clears this gate before touching pipeline code.
SubtitleEdit users hit this first and documented it well (issue #10180).
The session rate limit, and why I mention it
At one point during the research phase, the agent session hit the hourly rate limit and had to pause until it reset. Both research agents — one covering dedicated ASR, one covering voice-capable LLMs — completed their full reports after the limit cleared. I'm mentioning it partly because the blog post is meant to be honest about the process, and partly because it had a consequence: one significant model was entirely absent from the initial draft and only surfaced in the follow-up review. That's in Part 2.
The initial ensemble
GPU layout, models loaded per-job rather than all resident at once:
| GPU | Role | Models |
|---|---|---|
| GPU 0 | Voice LLM transcription | Voxtral-Mini-3B-2507 (~9.5 GB bf16) |
| GPU 1 | Voice LLM transcription | Phi-4-multimodal-instruct (~12 GB) |
| GPU 2 | Dedicated ASR pack | WhisperX (large-v3) + Parakeet-TDT-0.6b-v2 + whisper-large-v3-turbo |
| GPU 3 | Reconciliation + summary | Qwen3-14B-AWQ via vLLM |
WhisperX provides diarisation and the timing backbone. Parakeet and Whisper turbo add two more dedicated-ASR hypotheses. Voxtral and Phi-4 contribute two architecturally distinct voice-LLM hypotheses. All five go to the reconciliation LLM on GPU 3.
Outputs per job: transcript.json (words + timestamps + speaker labels + all per-segment hypotheses for auditing), transcript.md (human-readable, speaker turns with [mm:ss] markers), summary.md (exec summary, decisions, action items by speaker). Both .md files mirrored into the KnowledgeBase for RAG.
Part 2 covers how the ensemble got revised once I looked at the benchmarks more carefully. Part 3 has what it actually produced on real recordings.
References
- Open ASR Leaderboard
- Open ASR Leaderboard paper (arXiv:2510.06961)
- HuggingFace blog: Open ASR Leaderboard trends
- NVIDIA Canary-Qwen-2.5B model card
- NVIDIA Parakeet-TDT-0.6b-v2 model card
- NVIDIA Parakeet-TDT-0.6b-v3 model card
- WhisperX GitHub (m-bain/whisperX) — v3.8.6
- openai/whisper-large-v3 model card
- nyrahealth/CrisperWhisper model card
- ibm-granite/granite-speech-3.3-8b model card
- Mistral Voxtral announcement
- mistralai/Voxtral-Mini-3B-2507 model card
- Voxtral with vLLM example (AashiDutt)
- microsoft/Phi-4-multimodal-instruct model card
- google/gemma-4-E4B-it model card
- Google Gemma 4 announcement
- Gemma 4 model card (Google AI for Developers)
- kyutai/stt-2.6b-en model card
- CTranslate2 issue #1865: RTX 50XX cuBLAS INT8 NOT_SUPPORTED
- SubtitleEdit issue #10180: faster-whisper crashes on RTX 50-series
- PyTorch issue #164342: official sm_120 support
- PyTorch 2.7 release blog
- Fix PyTorch sm_120 on Blackwell GPUs (Harishkumar Pillai, Medium)
- GenSEC challenge paper (arXiv:2409.09785)
- Whispering LLaMA GER framework (arXiv:2310.06434)
- pyannote-audio (GitHub)
Ta ta for now — Part 2 looks at what the benchmarks actually measure, and where the initial model list fell short.