Downloads · 30 days
0
christopherthompson81/granite-speech-4-1-2b-onnx-bf16
granite-speech-4-1-2b-onnx-bf16 is a automatic speech recognition model from christopherthompson81. Use it when you need speech turned into text. It is set up for onnxruntime. The card lists the license as apache-2.0.
ONNX export of ibm-granite/granite-speech-4.1-2b with the 1.84 B-parameter Granite-4.0 LLM decoder in bfloat16, packaged for use with Vernacula and ONNX Runtime on hardware with native BF16 acceleration.
Downloads · 30 days
0
Access
Public
Updated May 9, 2026
Repo size
5.6 GB
Likes
0
Public
Click a slice to open those files.
.data5.4 GB · 97%
From the Hugging Face model README
ONNX export of ibm-granite/granite-speech-4.1-2b
with the 1.84 B-parameter Granite-4.0 LLM decoder in bfloat16, packaged
for use with Vernacula
and ONNX Runtime on hardware with native BF16 acceleration.
scripts/granite_export/ibm-granite/granite-speech-4.1-2bchristopherthompson81/granite-speech-4-1-2b-onnxThis is the GPU bundle for hardware with NVIDIA Ampere or newer
(compute capability ≥ 8.0). On those parts the LM decoder runs through
BF16 tensor cores and the ASR loop is meaningfully faster than the FP32
sibling. On older GPUs and on CPU-only systems use the FP32 bundle —
ORT's CPU EP currently lacks a Where(BF16) kernel that this graph
needs at the audio merge, so the BF16 bundle does not load on CPU
regardless of whether the host CPU has avx512_bf16 or amx_bf16 in
hardware. See the FP32 sibling bundle linked above for that path.
Vernacula auto-detects this with HardwareInfo.SupportsBf16Acceleration
and pulls whichever bundle is appropriate.
| File | Purpose | Precision |
|---|---|---|
mel.onnx | Log-Mel spectrogram frontend (16 kHz waveform → mel features) | FP32 (DSP, dtype-invariant) |
encoder.onnx (+ .data) | Conformer acoustic encoder, full-attention rewrite | FP32 |
projector.onnx | BLIP-2 Q-Former audio-to-text projector | FP32 |
decoder.onnx (+ .data) | Unified prefill + step Granite-4.0 LM decoder with cumsum-gather audio merge; BF16 weights and KV | BF16 (FP32 audio_embeds in, FP32 logits out) |
tokenizer.json, vocab.json, merges.txt, added_tokens.json, special_tokens_map.json, tokenizer_config.json | GPT-2-family ByteLevel BPE tokenizer assets | text |
chat_template.jinja | Chat template (used to construct the ASR prompt) | text |
preprocessor_config.json, processor_config.json | Mel/preprocessor parameters from upstream | text |
export-report.json | Per-stage export timings + dtype/opset metadata | text |
manifest.json | Per-file MD5 hashes (used by Vernacula's download verifier) | text |
The ONNX export traces the model loaded at BF16 then casts the encoder and projector back to FP32 before tracing those graphs:
model = GraniteSpeechForConditionalGeneration.from_pretrained(repo, dtype=torch.bfloat16)
model.encoder = model.encoder.to(torch.float32)
model.projector = model.projector.to(torch.float32)
Two ORT BF16 gaps drove the encoder/projector → FP32 carve-out:
Where has no BF16 kernel registered — the audio merge
uses torch.where and would fail to load even on hardware that has
AVX-512 BF16 support, because the kernel isn't built into ORT's CPU EP
regardless of host capability.The decoder graph has FP32 boundary casts at exactly two places:
audio_embeds arrives as FP32 (projector output) and is cast to BF16 inside the decoder graph before the audio merge.logits is cast back to FP32 so the C# argmax stays cheap and dtype-uniform with the FP32 bundle.Past-KV stays in BF16 across the chained Run loop — GPU-resident, never read on the host. The C# side detects the dtype from the decoder's InputMetadata["past_key_0"].ElementDataType at session construction and creates the empty-prefill OrtValues via a switch on Float / BFloat16 / Float16.
Measured on an RTX 3090 with Vernacula's batched ONNX pipeline:
| Workload | Mode | FP32 wall | BF16 wall | FP32 RTF | BF16 RTF |
|---|---|---|---|---|---|
| 6.4 s VCTK clip | B=1 | 3.25 s | 2.50 s | 0.508 | 0.392 |
| 600 s (10 min) VAD-segmented | mixed B (≤16) | 23.9 s | 17.4 s | 0.043 | 0.032 |
Per-stage breakdown on the 10-min run (BF16):
| Stage | ms | % |
|---|---|---|
| mel | 534 | 3.4% |
| encoder | 5,191 | 33.4% |
| projector | 42 | 0.3% |
| prefill | 1,723 | 11.1% |
| step-loop | 7,755 | 49.9% |
| overhead | 300 | 1.9% |
Encoder is unchanged from FP32 (intentional — see Mixed-precision design above). The win is concentrated in prefill + step-loop, which together account for ~60% of total ASR time at this precision.
Apache-2.0, inherited from the upstream ibm-granite/granite-speech-4.1-2b model. Permissive — commercial use is allowed with attribution.
In Vernacula, the auto-detect picks this bundle when both bundles are present on disk and the host has CUDA EP available with an Ampere+ GPU. The CLI flag is --asr granite; force a specific bundle with --granite-model <path> if you need to override the heuristic.
Outside Vernacula, pull with huggingface_hub and load the four graphs with onnxruntime:
from huggingface_hub import snapshot_download
path = snapshot_download(repo_id="christopherthompson81/granite-speech-4-1-2b-onnx-bf16")
The contract on the decoder graph differs from the FP32 sibling in two places that callers need to handle:
audio_embeds is still declared as FP32 at the graph boundary (cast to BF16 internally). No caller change needed there.past_key_<L> and past_value_<L> are declared as BF16. The empty-prefill tensors at the start of decode must be BF16, not FP32. ORT C# exposes this via Microsoft.ML.OnnxRuntime.BFloat16; ORT Python's BF16-numpy round-trip is unhelpful (numpy lacks a native BF16 dtype) and ML callers should keep KV as OrtValue objects without ever materialising on the host.See scripts/granite_export/ for the full input/output tensor names and shapes, and docs/dev/granite_speech_bf16_investigation.md for the run-by-run journey including the ORT compatibility gaps that shaped the mixed-precision policy.
Where(BF16) kernel gap. For those use the FP32 sibling bundle.max_new_tokens=256). Pre-segment longer audio with VAD or diarization.granite-speech-4.1-2b-plus variant, which has not been exported.@misc{granite-speech-4-1,
author = { IBM Granite Team },
title = { Granite Speech 4.1 (2B) },
year = 2025,
url = { https://huggingface.co/ibm-granite/granite-speech-4.1-2b },
publisher = { Hugging Face }
}
Issues with the ONNX export specifically: open an issue on
the Vernacula repo.
Issues with the underlying model: see the upstream
ibm-granite/granite-speech-4.1-2b
model card.
granite-speech-4-1-2b-onnx — FP32 sibling bundle (default for non-Ampere GPUs and CPU)scripts/granite_export/) — the export pipeline that produced these filesibm-granite/granite-speech-4.1-2b — upstream model card