Mistral's mistralai/Voxtral-Mini-3B-2507
ported to transcribe.cpp. An offline audio-LLM: a Whisper-large-v3
bidirectional audio encoder (32 layers, d_model=1280, 20 heads) feeds
a 4-frame-group projector (375 audio tokens per 30 s chunk) into a
Ministral-3B causal LM (30 layers, hidden_size=3072,
intermediate_size=8192, GQA 32 q / 8 kv heads, NEOX RoPE, SwiGLU) via
audio-token injection at the audio_token_id=24 positions in the prompt.
Offline speech-to-text and speech-to-text translation. Takes a 16 kHz mono WAV and produces a transcript via greedy decoding.
- Transcription — auto language detection, or an explicit
--languagehint. Voxtral advertises English, French, German, Spanish, Italian, Portuguese, Dutch, and Hindi. - Translation —
--translate --target-language <code>runs the mistral-common instruct template ("Translate this to {Language}.") to translate non-English speech into the target language's text.
See Mistral's model card for training data, intended use, and upstream evaluation.
Licensed Apache-2.0. Ported from upstream commit
3060fe3,
pinned 2026-06-06.
| Quantization | Download | Size | WER (LibriSpeech test-clean) |
|---|---|---|---|
| BF16 | Voxtral-Mini-3B-2507-BF16.gguf | 9.37 GB | 1.88% |
| F16 | Voxtral-Mini-3B-2507-F16.gguf | 9.38 GB | 1.89% |
| Q8_0 | Voxtral-Mini-3B-2507-Q8_0.gguf | 5.00 GB | 1.87% |
| Q6_K | Voxtral-Mini-3B-2507-Q6_K.gguf | 3.87 GB | 1.87% |
| Q5_K_M | Voxtral-Mini-3B-2507-Q5_K_M.gguf | 3.46 GB | 1.91% |
| Q4_K_M | Voxtral-Mini-3B-2507-Q4_K_M.gguf | 2.98 GB | 1.94% |
WER measured on the full LibriSpeech test-clean split (2620 utterances)
with the Whisper-style English text normalizer, batch size 8 on an NVIDIA
L40S. The same-machine HuggingFace transformers reference run
(VoxtralForConditionalGeneration, BF16, attn_implementation=eager,
greedy) lands at 1.87%, and the BF16 GGUF matches it (1.87% at batch
1).
cmake -B build
cmake --build build
# transcription (auto language)
build/bin/transcribe-cli \
-m models/Voxtral-Mini-3B-2507/Voxtral-Mini-3B-2507-Q8_0.gguf \
samples/jfk.wav
# transcription with an explicit language hint
build/bin/transcribe-cli \
-m models/Voxtral-Mini-3B-2507/Voxtral-Mini-3B-2507-Q8_0.gguf \
--language de samples/german.wav
# speech translation (non-English audio -> English text)
build/bin/transcribe-cli \
-m models/Voxtral-Mini-3B-2507/Voxtral-Mini-3B-2507-Q8_0.gguf \
--translate --target-language en samples/german.wavIf your audio is not already 16 kHz mono WAV, convert it first:
ffmpeg -i input.mp3 -ar 16000 -ac 1 output.wavCLI flags:
--language <code>— BCP-47 hint. Omit for auto-detection.--translate --target-language <code>— speech translation via the instruct template.
Cells are wall-clock latency (mean over 3 iterations after 1 warmup), with
speedup over realtime in parentheses. Units: ms below 1 s, s above (2
decimal places).
| Backend | Sample | Q8_0 | Q4_K_M |
|---|---|---|---|
| Metal | jfk (11.0s) | 727.3 ms (15.1×) | 656.8 ms (16.7×) |
| Metal | dots (35.3s) | 2.40 s (14.7×) | 1.90 s (18.6×) |
| CPU | jfk (11.0s) | 6.06 s (1.8×) | 6.76 s (1.6×) |
| CPU | dots (35.3s) | 16.60 s (2.1×) | 15.31 s (2.3×) |
| Backend | Sample | Q8_0 | Q4_K_M |
|---|---|---|---|
| Vulkan | jfk (11.0s) | 9.57 s (1.2×) | 9.37 s (1.2×) |
| Vulkan | dots (35.3s) | 26.49 s (1.3×) | 23.82 s (1.5×) |
| CPU | jfk (11.0s) | 26.15 s (0.4×) | 19.39 s (0.6×) |
| CPU | dots (35.3s) | 63.96 s (0.6×) | 45.92 s (0.8×) |
Fedora Linux 43, transcribe.cpp 91af262. Vulkan device: AMD Radeon Graphics (RADV RENOIR).
Benchmark reproduction:
uv run scripts/bench/run.py \
--models Voxtral-Mini-3B-2507 \
--quants q8_0,q4_k_m \
--samples jfk,dots \
--backends metal,cpu,vulkan \
--iters 3 --warmup 1 \
--name voxtral-mini-3b-2507-publicationtranscribe.cpp is validated tensor-by-tensor against the HuggingFace
transformers reference (VoxtralForConditionalGeneration, BF16,
attn_implementation=eager) on samples/jfk.wav with the strict CPU
backend. All 43 checkpointed tensors fall within family tolerance, and
the BF16 transcript matches the reference verbatim
(And so, my fellow Americans, ask not what your country can do for you, ask what you can do for your country.).
The encoder mel frontend is computed in-process (not injected from the
reference), so enc.mel.in is the real frontend-parity gate and matches
the reference WhisperFeatureExtractor to 2.2e-5 max / 4.1e-8 mean.
The dominant remaining drift is not a bug: the reference casts the mel
to BF16 before conv1 and keeps BF16 activations through the whole stack,
while the C++ ggml graph runs F32 activations with BF16 weights — so the
C++ is the more accurate path, and the cpp-vs-BF16-reference drift is the
reference's own BF16 activation rounding (which compounds with depth). A
three-way decomposition confirmed this: cpp-vs-F32-reference is 3–4× tighter
than cpp-vs-BF16-reference on the encoder, and the transcript is byte-exact
against both the BF16 and F32 references. Tolerances and the full mechanism
are pinned in tests/tolerances/voxtral.json.
| Field | Value |
|---|---|
| Reference | HuggingFace transformers v4.57.6 (mistralai/Voxtral-Mini-3B-2507) |
| Dump script | scripts/dump_reference_voxtral_transformers.py |
| Manifest | tests/golden/voxtral/voxtral-mini-3b-2507.manifest.json |
| Tolerances | tests/tolerances/voxtral.json |
| Command | uv run scripts/validate.py all --family voxtral --variant voxtral-mini-3b-2507 |
Selected tensors (observed on CPU, strict backend; see tolerance file for budgets):
| Tensor | Shape | Max abs diff | Mean abs diff | Notes |
|---|---|---|---|---|
enc.mel.in |
[128,3000] |
2.229e-05 |
4.060e-08 |
In-process log-mel vs reference WhisperFeatureExtractor — the frontend-parity gate |
enc.out |
[1500,1280] |
1.414e+01 |
1.121e-02 |
Final encoder LayerNorm; the drift here is the reference's BF16 activation rounding (cpp-vs-F32-ref is ~4× tighter) |
proj.out |
[375,3072] |
3.493e-01 |
3.158e-03 |
Projector output (the audio embeddings injected into the LM) |