Skip to content

Nemotron 3.5 Transcribe: audio input, the 65,536-token window, an hour of audio, MTP drafts - #1632

Open
BobClawblaw wants to merge 10 commits into
ashhart:mainfrom
BobClawblaw:nemotron-transcribe-audio
Open

BobClawblaw wants to merge 10 commits into
ashhart:mainfrom
BobClawblaw:nemotron-transcribe-audio

Conversation

@BobClawblaw

Copy link
Copy Markdown
Contributor

What this changes

Closes #1549. The server takes audio for Nemotron 3.5 Transcribe: OpenAI input_audio and vLLM audio_url data-URL
parts with 16 kHz mono WAV in user messages, encoded at each request's prompt pass, a clip's rows keyed in the prompt
cache. The model gets its trained 65,536-token window (config.json's 262,144 is the backbone's), up to an hour of audio
a request (160 MiB chat bodies only when the engine takes audio), and MTP drafts with the clip's rows in the head.
Recipe: docs/recipes/nemotron-3.5-transcribe.md. Stacked on #1631.

Receipt

  • Environment: one GB10 (sm_121), the checkpoint above, --context 65536, greedy, thinking off.
  • LibriSpeech test-clean read end to end:
Audio WER MTP drafts --no-drafts
11 min 1.13% 40.4 s, 76.1 tok/s 73.7 s, 34.1 tok/s
30 min 1.27% 104.2 s, 74.8 tok/s 190.8 s, 33.4 tok/s
60 min 1.18% 228.9 s, 70.0 tok/s 411.2 s, 32.4 tok/s
  • Exactness: drafted replies byte-identical to --no-drafts on all three; --prompt-cache-gib 0 gives the same replies
    as the default on resumed clips, seeded sampling, speaker tags, translation, language id, audio Q&A, thinking, two
    turns; four long clips at once equal their solo runs; a repeated clip's first token 0.381 → 0.067 s.
  • Full contract on the stack's top: SUMMARY 452 kernels: 452 pass gates 1-4, 0 fail, 6 known findings; 325 controls: 325 red as planted, 0 missed; 321 limit problems (the stack on main d33dcfc; none of the limit problems is in this stack's launches). The stack then rebased onto 3f0a715 without conflicts; the three sets, zig build test and the Transcribe clips were re-run there.
  • Not served: CTC word timestamps, non-WAV formats, the DFlash2 drafter, the FP8/NVFP4 variants (listed in the recipe).
  • Harness quality suite not run.

Overlap

atc overlap lists #1445 and #1446 as conflicting, in the shared registration lists (registry.zig, cuda_kernels.zig, kernels.zig, kernel-contract.md, tests/cuda/main.zig); whichever lands second rebases.

@BobClawblaw

Copy link
Copy Markdown
Contributor Author

Rebased onto #1631's d5d067e, which fixes the seven cuda_load_gpu recovery crashes (the hand-built load-recovery engines now null bf16x). No other change: the tree differs from 06b023c only by those two lines. test-bolt-load-host 40/40 and test-cuda-host pass on Linux.

@BobClawblaw

Copy link
Copy Markdown
Contributor Author

Rebased onto d377fcc (with #1630 and #1631 under it). Two changes for lean, both pure moves:

  • core/engine_api.zig had grown to 606 lines on main plus this PR, so Stop and CallGate moved unchanged to core/engine_gates.zig, re-exported under the same names; no caller changes.
  • server/openai.zig's one-use audio import is inlined, which keeps the file at 600 lines.

Checked on the pushed head: fmt, lean (0 new) and zig build test; the kernel contract, golden, security, fuzz and dev-tools on the same commits two rebases earlier (19ecc44d1).

On a GB10 (first rebase, d887be514 against the pre-rebase head 3ae00f5):

  • tf-cuda-test bf16-experts passes.
  • The full CUDA kernel contract: 511 kernels pass gates 1-4, 342 controls red as planted, nothing new. Its exit code is 1, from live limit problems in other families' kernels; none are in this stack's kernels.
  • Six reference clips (8 to 379 tokens, up to 130 s of audio), served greedy: every reply identical to the pre-rebase build's, and drafted replies identical to --no-drafts ones (the 130 s clip 8.02 s drafted against 13.53 s without drafts).

On an RTX 5090 (dd7cc1a06, with #1769's brace fix on top, which main needs to build CUDA at all): test-cuda-host passes, and the full CUDA kernel contract gives 520 kernels passing gates 1-4, 0 failures, the same 6 known findings, and nemo_audio's and the bf16 experts' controls red as planted. One control elsewhere was missed: nvfp4_expert_waves<2, 2, 4> with its items dropped past the first wave stays green at the two-wave shape on sm_120. That control and its kernel are main's NVFP4 experts, which this stack doesn't touch, and the GB10 run catches it; I'll raise it separately. The stack as of the 20705d6 rebase (5647dbdf2) builds there too, with both moved controls in the controls fatbin; the rebase onto d377fcc since changes only a cache persistence test.

…m) from its bf16 weights, audio rows spliced after the embeds

The checkpoint's llm.* tensors load as published: NeMo's layer names, fp32 A_log/D/dt_bias, the stacked [E, in, out]
experts on the bf16 grouped format with the shared expert as experts E and E + 1, TE's empty _extra_state skipped.
The audio encoder and CTC aligner tensors are left for the audio path. A prompt pass's audio rows replace the
<|audio|> positions' embeddings, as image rows do.
… ASR encoder, streaming Sortformer, fusion), audio-check

NeMo's vLLM SALM path as ParallelExpertEncoder's online inference runs it: the log-mel frontend on the host, the ASR
TransformerEncoder over context-extended 500-frame windows, the Sortformer over the same windows with its speaker
cache and FIFO, thresholded speakers through the sinusoid kernel, and the projection to the language model's width.
nemo_audio.cu adds q/k LayerNorm with partial RoPE, attention over a window's valid keys and the Sortformer head's
glue; the rest runs on the vision towers' kernels. audio-check writes every stage under the reference's names.
…r FIFO and pooling) run under test-cuda-host
The Bolt load-recovery tests build an Engine by hand and null each optional kernel set; bf16x was left
undefined, so deinit unloaded a garbage module (seven tests crashed on Linux and Windows CI).
…o_url WAV parts), encoded at each request's prompt pass, rows keyed by clip in the prompt cache
… a request (160 MiB chat bodies when the engine takes audio), MTP drafts with the clip's rows in the head
… audio input), its index row and the API's audio parts
@BobClawblaw
BobClawblaw force-pushed the nemotron-transcribe-audio branch from a18905c to 540e914 Compare October 31, 2026 21:25
@BobClawblaw

Copy link
Copy Markdown
Contributor Author

Rebased onto fbbc20d. Main's YaRN work added contextCeiling to openWith in native/cuda.zig where this PR reads Transcribe's trained_context; the window now comes from contextCeiling when a family has it (Qwen's YaRN), else trained_context (Transcribe's 65,536), else config.json, so neither path changes.

Checked on the pushed head: fmt, lean (0 new) and zig build test on the Mac; a CUDA build and test-cuda-host on an RTX 5090 (sm_120). On the same commits one rebase earlier (on 389ca13; main's commits since change tool grammar, GLM's vision tower and the contract controls' brace): the kernel contract, golden, security, fuzz and dev-tools on the Mac, and on a GB10 the served build reports context: 65536 by default, refuses --context 70000 ("exceeds this model's 65536-token window"), and the six reference clips give replies identical to the earlier head's (d887be514).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nemotron 3.5 Transcribe 30B-A4B (speech in, BF16) on native CUDA

1 participant