feat(xla): add Gemma3n audio execution - #922
Conversation
74a7d39 to
876bcc3
Compare
|
Rebased onto Rebase integration:
Post-rebase validation:
The unchanged MLX-to-IREE audio threshold blocker remains, and CUDA is unavailable on the current host. No new numeric pass is claimed. This PR remains draft/blocked and #878 remains blocked by #932. |
876bcc3 to
2b6d949
Compare
|
Foundation refresh complete at head 2b6d949:
The draft remains fail-closed and status:blocked. This refresh does not change the recorded first unresolved boundary: sscp_conv_1_convolution still requires a representable cuDNN/IREE engine or reduction-plan contract. |
Add fail-closed audio configuration and artifact identities for static frame buckets. Validate canonical mel masks, fixed placeholder spans, and owned prepared-prefill metadata before requests cross the IREE boundary.
Pin the converted Q4 checkpoint's 277 audio tensor names, dtypes, shapes, and deterministic order. Reject missing, unexpected, or incompatible tensors before enabling the audio capability.
Implement the complete Gemma3n Conformer audio path with exact cumulative normalization, local relative attention, masking, projection, row mapping, and shared dense-PLE rounding semantics. Split the production graph at the natural typed boundary: audio.encode owns audio tower/embedder weights and returns projected soft rows, hard audio embeddings, and lengths; audio.merge_ple owns only the shared language input-head weights. This avoids pinned IREE monolithic-module backend failures while keeping all model math in IREE. Validate the full mlxcel-xla library and compile the maximum 2997-frame/context-256 artifacts with pinned IREE for both local CPU and CUDA targets. Refs #878
Execute the split audio encode and merge graphs through IREE and wire them into CLI and continuous batching. Preserve pinned processor left-padding mel features while zeroing only the static bucket tail. Refs #878
Keep the rebased LLaVA vision runtime on the shared aligned auxiliary-weight storage API used by Gemma3n audio. Refs #878
MLX CUDA materializes the quantized product as BF16 before adding the BF16 affine bias, while the XLA loader previously fused both operations before a single rounding step. This changed roughly half of the pinned Gemma3n audio embedding and projection weights and explains the tower-independent hard-audio mismatch. Use sequential BF16 rounding in both Gemma3n language and audio weight loaders, rename the helper to reflect its semantics, and cover a real projection double-rounding counterexample. Validation: cargo test -p mlxcel-xla weights::tests --lib; cargo check -p mlxcel-xla --features diagnostics; cargo clippy -p mlxcel-xla --features diagnostics --lib --fix --allow-dirty --allow-staged; cargo fmt --all -- --check. Refs #878
Make the MLX checkpoint-dtype boundary explicit by rounding processor-produced F32 mel features to BF16 before the first SSCP convolution, independent of the graph-wide contraction precision. Add a synthetic regression whose pre-cast and post-convolution-only results differ, and expose the first SSCP output through the diagnostics-only MLX and IREE bundles for one bounded parity check. Validation: cargo fmt --all -- --check; git diff --check; focused Gemma3n MLX CPU test; focused Gemma3n audio emitter tests; mlxcel-xla diagnostics cargo check. Refs #878
Add a deterministic first-convolution MLX/IREE CPU probe that distinguishes backend reduction schedules within the production BF16 input and output boundary. Extend the real-checkpoint audio gate with max-pair values, BF16 bit patterns, ULP counts, and non-BF16 counts without relaxing its absolute or RMS failure thresholds. Validation: oracle unit tests 3/3, CPU local-task probe pass, rustfmt and diff check. Refs #878
The bounded audio-only oracle localized broad BF16 drift to the first SSCP output: max abs 1.0, RMS 0.02212289754, and 1,429,092 values beyond one BF16 ULP. The graph declared bf16-accum-f32 but the convolution builder gave BF16-demoted operands a BF16 result, allowing cancellation-sensitive low-precision accumulation before normalization. Add an SSCP-only convolution contract that keeps BF16 operands while producing an F32 StableHLO result, then applies the existing explicit BF16 output rounding. Padding, NHWC/HWIO layout, weights, and failure thresholds remain unchanged. Validation: focused Gemma3n audio emitter tests, builder tests, a minimal IREE local LLVM CPU compile, cargo check with diagnostics, cargo fmt, and cargo clippy. The pinned actual-checkpoint gate was not rerun. Refs #878
The F32 SSCP accumulator fix reduced the bounded audio-only conv0 drift from RMS 0.02212289754 and 1,429,092 values beyond one BF16 ULP to RMS 0.00005109118683 and four values beyond one ULP, but the unchanged absolute threshold still fails and later encoder stages remain broadly divergent. Expose the BF16 convolution materialization, cumulative norm, activation, conv1, input projection, and first Conformer feed-forward boundaries in both MLX and IREE diagnostics. Report each over-one-ULP index with values, absolute difference, BF16 bits, and distance while capping pathological logs at 32 entries. Validation: Gemma3n audio emitter tests, xla-diagnostics example check, three focused oracle comparison tests, cargo fmt, and cargo clippy. The bounded actual-checkpoint oracle was not rerun after this diagnostics-only change. Refs #878
The modified actual diagnostic is bit-exact through the first SSCP convolution and first diverges in cumulative normalization. StableHLO's generic reductions and reduce-window prefix sum select backend-dependent association trees, while the pinned MLX CUDA oracle uses four-value lane accumulators, XOR warp reductions, and hierarchical warp scans. Lower only the Gemma3n SSCP cumulative norm sums and scans with the MLX CUDA association order. Keep convolution, F32 arithmetic, epsilon, BF16 materialization, and gate thresholds unchanged, and add a focused local IREE compile regression for the schedule. Validation: focused Gemma3n audio emitter tests; mlxcel-xla check; xla-diagnostics example check and three tests; focused IREE local LLVM CPU compile; rustfmt and diff check. Strict clippy remains blocked by pre-existing unrelated warnings; regular package clippy reports no new warning. The actual-checkpoint gate was not rerun. Refs #878
The MLX CUDA reduction/scan schedule fix reduced the first SSCP norm drift from RMS 7.032964031e-5, max BF16 ULP 16, and six over-one-ULP values to RMS 2.938648021e-5, max BF16 ULP one, and no over-one-ULP values. The unchanged absolute gate still fails at a one-ULP pair, while the preceding convolution remains bit-exact. Expose the first norm's per-time sum, cumulative sum, mean, squared sum, cumulative squared sum, variance, epsilon-stabilized variance, and inverse standard deviation on both MLX and IREE diagnostic paths. These bounded tensors distinguish remaining reduction/scan drift from epsilon addition or rsqrt without adding another full-size activation capture. Validation: focused Gemma3n audio emitter tests; xla-diagnostics example check and three tests; focused IREE local LLVM CPU compile; package and diagnostic-example clippy; rustfmt and diff check. No actual-checkpoint run was performed. Refs #878
Keep Gemma3n audio artifacts explicitly legacy-unqualified and adapt the newer Qwen2-VL loader to the typed auxiliary weight storage introduced by this branch.\n\nRefs #878
2b6d949 to
0a5aa90
Compare
|
Rebased onto current Validation:
The PR intentionally remains draft/fail-closed. The existing production-oracle blocker is unchanged: the first SSCP convolution still has 6 BF16-ULP mismatches ( |
Current-head CUDA actual at
|
MLX_ENABLE_TF32 |
first divergent stage |
|---|---|
1 (MLX default) |
sscp_conv_0_norm_cumulative_sum max_abs 1.562500000e-2 rms 2.432233746e-3 index 373 |
0 (declared policy) |
sscp_conv_0_norm_cumulative_sum max_abs 1.562500000e-2 rms 2.432233746e-3 index 373 |
So the improvement relative to the recorded blocker is attributable to this head rather than
to the reference policy, and the remaining divergence is a property of the emitted graph.
Recording the A/B because the negative result is what makes the attribution safe.
Remaining, unchanged: cumulative normalization and shared prefix scan, local attention,
relative shift, pooling, projection lengths, projected audio embeddings and dense PLE, then
logits/KV/greedy ASR token exactness and the CLI/server, isolation, cancellation and slot
reuse gates.
Summary
Latest CUDA evidence
The actual MLX CUDA versus IREE CUDA diagnostic proves the following boundaries bit-exact:
sscp_conv_0_convolutionsscp_conv_0activation, which is the BF16 input consumed by conv1The first divergence remains
sscp_conv_1_convolution. The controlled result-type experiment is now complete:The BF16-result candidate is decisively worse. Result typing is therefore not the fix: the production F32 accumulation/result followed by BF16 rounding is the correct representation and remains unchanged.
Backend audit
MLX CUDA's vendored convolution path constructs a cuDNN Frontend graph with BF16 I/O and F32 compute for BF16 operands. It requests Heuristic Mode A execution plans, checks support, builds a candidate, and caches the resulting graph by dtype, shapes, stride, padding, dilation, groups, and buffer alignments. It excludes plans marked
DOWN_CONVERT_INPUTS; its TF32-specific tensor-core exclusion is only applied when the convolution I/O dtype itself is F32, not for this BF16-input convolution.The selected cuDNN engine is backend state, not StableHLO state. The current MLX wrapper does not record the selected plan name/engine configuration or numerical notes. The vendored cuDNN Frontend can expose a selected plan name and plan metadata, and cuDNN API logging can expose backend calls, but obtaining that identity requires instrumenting the MLX/cuDNN layer or running an exact-shape cuDNN probe. Either approach can identify the MLX plan; neither creates an equivalent StableHLO/IREE selector.
A compiler-only exact-shape probe of the production conv1 operation was lowered with the pinned IREE CUDA compiler through
executable-configurations. IREE emitted its ownlinalg.genericreduction with BF16-to-F32 extension, F32 multiply/add, and an IREE GPU reduction/workgroup tiling configuration. It did not emit a cuDNN execution plan. Repeating the same probe with StableHLOprecision_config = HIGHESTproduced the same IREE lowering configuration and arithmetic, soprecision_configis not a usable diagnostics candidate for selecting the MLX/cuDNN reduction tree.StableHLO convolution exposes semantic shape/layout/precision configuration, but no cuDNN engine global index, knob map, numerical-note filter, or exact reduction-tree attribute. Consequently, a tiny cuDNN-vs-StableHLO probe could reproduce and characterize the backend difference, but it cannot force IREE to execute the same cuDNN plan. The existing actual-checkpoint diagnostic already supplies the stronger comparison because it uses the exact conv1 input and weights.
The precise blocker is therefore backend-limited: matching the final six sparse BF16 residuals would require one of the following new backend capabilities, none of which is safe to guess in this PR:
No production change, tolerance relaxation, heavyweight model rerun, or speculative candidate was added.
Validation
cargo test -p mlxcel-xla emitter::gemma3n_audio_emit::tests::— 5 passed, 5 environment-dependent tests ignored3.11.0rc20260316CUDA compile of the released conv1-shape result-type pair passedexecutable-configurationsaudit: custom F32 reduction lowering confirmed;DEFAULTandHIGHESTselect the same configurationcargo check -p mlxcel-xla --features diagnostics --testscargo clippy -p mlxcel-xla --tests --no-deps— existing unrelated warnings remaincargo fmt --all -- --checkgit diff --checkRemaining blocker
This PR remains draft and
status:blockedbecause the unchanged MLX-to-IREE audio thresholds have not passed. The result-type hypothesis is closed; the remaining mismatch is an unrepresentable backend reduction/engine-identity difference.Closes #878
Parent epic: #566