Pre-encode weights are kept at F32 in both GGUFs (F16 causes 1.56 max accumulation error across the 4352-dim projection).
1# Auto-download (Q4_K, 458 MB)
2crispasr --backend nemotron -m auto --auto-download -f audio.wav
3
4# Or download manually
5huggingface-cli download cstr/nemotron-3.5-asr-streaming-GGUF \
6 nemotron-3.5-asr-streaming-0.6b-q4_k.gguf --local-dir models/
7
8# Transcribe (English, default)
9crispasr --backend nemotron \
10 -m models/nemotron-3.5-asr-streaming-0.6b-q4_k.gguf \
11 -f audio.wav
12
13# Transcribe in German
14crispasr --backend nemotron \
15 -m models/nemotron-3.5-asr-streaming-0.6b-q4_k.gguf \
16 -f audio.wav -l de-DE
17
18# Beam search (default is greedy)
19crispasr --backend nemotron -m auto --auto-download -f audio.wav --beam-size 4
20
21# Streaming from stdin
22ffmpeg -i audio.wav -f s16le -ar 16000 -ac 1 - | \
23 crispasr --backend nemotron -m auto --auto-download --stream
Four attention context presets trade latency for accuracy (published WER from NVIDIA's Open ASR Leaderboard):
The same GGUF works for all presets — the context window is a runtime knob, not a retraining artifact.
Audio (16kHz mono)
→ Mel spectrogram (128 bins, 10ms hop, no normalization)
→ Pre-encode (3x causal Conv2d, 8x downsample, Linear 4352→1024, F32 weights)
→ 24x Cache-Aware FastConformer block:
FFN1(½) → MHA(rel_pos, cache-aware) → DWConv(k=9, causal, LN) → FFN2(½) → LN
→ Prompt kernel (MLP: concat(enc[1024], lang_onehot[128]) → 2048 → ReLU → 1024)
→ RNN-T decoder:
Prediction: Embed(13088, 640) + 2-layer LSTM(640)
Joint: enc(1024→640) + pred(640→640) → ReLU → Linear(640→13088)
→ Greedy / beam search decode
1python models/convert-nemotron-to-gguf.py \
2 --nemo nvidia/nemotron-3.5-asr-streaming-0.6b \
3 --output nemotron-3.5-asr-streaming-0.6b-f16.gguf
4
5crispasr-quantize nemotron-3.5-asr-streaming-0.6b-f16.gguf \
6 nemotron-3.5-asr-streaming-0.6b-q4_k.gguf q4_k
F16 and Q4_K produce identical text. Streaming output has minor punctuation differences but same content.