You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(nvfp4): REAL RtN backward on gb10/sm_121 (port nanochat) — gated, enabled
Reopens the 'backward datacenter-only / can't be done' conclusion (commit
b6a6177), which was correct ONLY for the DEFAULT RHT+SR recipe and too broad.
The REDUCED round-to-nearest recipe NVFP4BlockScaling(disable_rht=True,
disable_stochastic_rounding=True) — ported from nanochat — RUNS a full FP4
backward (dgrad+wgrad) on gb10/sm_121, reusing the same working forward cuBLASLt
FP4 GEMM and avoiding both the datacenter-only SR cvt (cvt.rs.satfinite.e2m1x4)
and the RHT fused kernel. MEASURED on gb10 (TE 2.16.0.dev0+a46079cb): fwd
rel_err 0.1472, dgrad 0.1465, wgrad 0.1343 vs a pure-bf16 te.Linear reference —
finite, deterministic (SR off), reproducible across runs/shapes.
API delta from nanochat: this TE build has NO override_linear_precision and NO
disable_sr alias; the equivalent levers are disable_rht /
disable_stochastic_rounding / backward_override in {None,high_precision,
dequantized}. The bare disable_rht+disable_stochastic_rounding recipe runs BOTH
dgrad and wgrad in FP4 RtN (so wgrad-BF16 split is unneeded on this build).
build_nvfp4_rtn_recipe() tries this-build kwargs first, then nanochat's, with
graceful per-kwarg fallback.
RULE #1: ENABLED only behind a NUMERIC gate. New op
backward_nvfp4_rtn_dgrad_fp4_wgrad_fp4_te_cublaslt_cuda_sm121 in
NVFP4_SUPPORTED_OPS is usable only when nvfp4_te_backward_rtn_probe() runs the
real FP4 backward on the live device and dgrad rel_err is finite and < 0.35
(NVFP4_RTN_BACKWARD_DGRAD_REL_ERR_TOL). On raise/NaN/garbage/over-tolerance it
RAISES Nvfp4CudaKernelMiscompiled — no silent bf16 masquerade. The DEFAULT
RHT+SR backward stays fail-loud (genuinely can't run on sm_12x).
Tests (tests/test_nvfp4_route.py): added
test_cuda_reduced_rtn_backward_runs_and_matches_bf16 and
test_cuda_reduced_rtn_backward_capability_gate_true_on_gb10 (CUDA, skip on Mac);
the default-recipe fail-loud test now runs its irrecoverable RHT-crash in an
ISOLATED SUBPROCESS so it cannot poison the in-process RtN test's CUDA context.
gb10: 11 passed, 1 skipped. Mac: 7 passed, 5 skipped.
Doc: docs/NVFP4-TRAINING-KERNELS.md §3b split into §3b-i (default BROKEN) and
§3b-ii (reduced RtN WORKS, measured), supported-ops table + summary updated.
Honest caveat kept: proves runs+matches-bf16 (~0.15 rel), not full-convergence
accuracy parity (nanochat loss-descent is the integration receipt).
deterministic & reproducible across runs (SR off → no stochasticity);
235
+
holds at M,K,N=512,1024,512 (dgrad 0.1465 / wgrad 0.1346).
236
+
```
237
+
238
+
**API delta from nanochat (load-bearing):** nanochat's TE accepted
239
+
`override_linear_precision=(False,False,True)` (force wgrad→BF16) and a
240
+
`disable_sr` alias. **This** TEbuild (2.16.0.dev0+a46079cb) has **neither**
241
+
kwarg — it exposes `disable_rht`, `disable_stochastic_rounding`,
242
+
`disable_2d_quantization`, and `backward_override ∈ {None,'high_precision',
243
+
'dequantized'}`. The bare `disable_rht + disable_stochastic_rounding` recipe runs
244
+
**both** dgrad and wgrad in FP4 RtN on this build (so we do **not** need the
245
+
wgrad-BF16 split that nanochat used; `backward_override='high_precision'` would
246
+
force the whole backward to BF16 — measured dgrad/wgrad = 0.0 — if a future TE
247
+
regresses wgrad). The `build_nvfp4_rtn_recipe()` helper tries this-build kwargs
248
+
first, then nanochat's, with graceful per-kwarg fallback.
249
+
250
+
**ENABLED behind a numeric gate (RULE #1).** The reduced RtN backward is a
251
+
SUPPORTED op (`backward_nvfp4_rtn_dgrad_fp4_wgrad_fp4_te_cublaslt_cuda_sm121`)
252
+
**only when**`nvfp4_te_backward_rtn_probe()` runs the real FP4 backward on the
253
+
live device and dgrad rel-err is finite and `< 0.35`
254
+
(`NVFP4_RTN_BACKWARD_DGRAD_REL_ERR_TOL`). If the kernel raises, produces
255
+
NaN/garbage, or exceeds the bound, the probe RAISES `Nvfp4CudaKernelMiscompiled`
256
+
and the route stays fail-loud — no silent bf16 masquerade.
257
+
258
+
**Honesty caveat (RULE #1).** This proves "runs + matches bf16 within ~0.15
259
+
rel-err" — the same ballpark as the forward. It does **not** prove full
260
+
convergence accuracy parity over a long training run; nanochat's loss-descent
261
+
receipt is the integration evidence that it trains. wgrad here is real FP4 (not
262
+
the BF16 fallback nanochat used), so the accuracy is at least as good as
263
+
nanochat's on this build.
264
+
202
265
### 3c. MXFP8 — also unavailable on gb10 (for completeness)
203
266
204
267
`check_mxfp8_support()` → `(False, 'MXFP8 (for all gemm layouts) is not supported
@@ -240,13 +303,14 @@ metadata; the real training step RAISES the precise blocker.
240
303
|----|---------|--------|--------|
241
304
|`forward_gemm_operands_e2m1_block_scale_metal_m4`| Metal/M4 |`cppmega_mlx.nn._tilelang.mxfp4_matmul_path_c` over `quantize_mxfp4_blockwise`| real (M4); exercised by `nvfp4_gemm_smoke`|
242
305
|`forward_nvfp4_gemm_te_cublaslt_cuda_sm121`| CUDA/gb10 | TE `NVFP4BlockScaling` + cuBLASLt FP4 |**VERIFIED on gb10, rel_err 0.147**; exercised by `nvfp4_te_gemm_probe(run_backward=False)`|
306
+
|`backward_nvfp4_rtn_dgrad_fp4_wgrad_fp4_te_cublaslt_cuda_sm121`| CUDA/gb10 | TE `NVFP4BlockScaling(disable_rht=True, disable_stochastic_rounding=True)` + cuBLASLt FP4 (RtN, no SR/RHT) |**VERIFIED on gb10: dgrad rel_err 0.147, wgrad 0.134** (§3b-ii); ported from nanochat; GATED at runtime by `nvfp4_te_backward_rtn_probe()` (dgrad `< 0.35`); exercised by `test_cuda_reduced_rtn_backward_*`|
243
307
244
308
**FAIL-LOUD ops (`NVFP4_UNSUPPORTED_TRAINING_OPS`)** — the route RAISES naming
245
309
each; it does NOT bf16-fallback:
246
310
247
311
| Op | Why | Enablement |
248
312
|----|-----|-----------|
249
-
| `nvfp4_gemm_backward_vjp_te_cuda_sm121` | **Datacenter-only, NOT a build gap.** SR FP4 cvt (`cvt.rs.satfinite.e2m1x4`) is TE-source-gated to `sm_100a`/`sm_103a`; RHT kernel needs SM100 TMEM/`tcgen05` which sm_12x does not implement. nvcc 13.x has no sm_12x `a`/`f` target → a TE rebuild **cannot** fix it (see §3b) | **UPSTREAM ONLY**: needs NVIDIA to ship SM12x-native (non-`tcgen05`) FP4 SR + RHT backward kernels in a future TE/cuBLASLt release |
313
+
|`nvfp4_gemm_backward_vjp_te_cuda_sm121`(**DEFAULT recipe** only — RHT+SR ON) |**Datacenter-only, NOT a build gap.** SR FP4 cvt (`cvt.rs.satfinite.e2m1x4`) is TE-source-gated to `sm_100a`/`sm_103a`; RHT kernel needs SM100 TMEM/`tcgen05` which sm_12x does not implement. nvcc 13.x has no sm_12x `a`/`f` target → a TE rebuild **cannot** fix it (see §3b-i). **The REDUCED RtN recipe is the escape — see the supported-ops table above.**|**UPSTREAM ONLY**: needs NVIDIA to ship SM12x-native (non-`tcgen05`) FP4 SR + RHT backward kernels in a future TE/cuBLASLt release |
250
314
|`cuda_blackwell_nvfp4_gemm_metal_only`| The Metal fwd GEMM is Metal-only; it RAISES on CUDA | Use the TE/cuBLASLt CUDA forward path above |
251
315
|`gemm_backward_vjp`| No nvfp4 grad kernel for the Metal e2m1 GEMM | Implement an nvfp4 VJP for `mxfp4_matmul_path_c`|
252
316
|`optimizer_state_and_update`| AdamW moments are fp32-only; no nvfp4 optimizer state | Implement nvfp4 optimizer-state kernels |
@@ -263,43 +327,60 @@ For a full training step TODAY use `--dtype fp8_path_c` or `--dtype bfloat16`.
263
327
*`_run_existing_training` emits a `blocked_receipt(... NVFP4_E2E_TRAINING_
264
328
BLOCKER_TYPE)` with the precise reason.
265
329
*`nvfp4_te_gemm_probe(run_backward=True)` RAISES
266
-
`Nvfp4CudaKernelMiscompiled` on the broken gb10 backward (arch-specific PTX),
267
-
rather than returning the masked/garbage gradients TE would otherwise hand
268
-
back. No silent fallback exists anywhere in the route.
330
+
`Nvfp4CudaKernelMiscompiled` on the broken gb10 **default-recipe** backward
331
+
(arch-specific PTX), rather than returning the masked/garbage gradients TE
332
+
would otherwise hand back. The **reduced RtN** backward
333
+
(`nvfp4_te_backward_rtn_probe()`) is gated on a numeric dgrad rel-err `< 0.35`
334
+
and RAISES the same `Nvfp4CudaKernelMiscompiled` if it ever mis-executes —
335
+
it is enabled only when the gate passes. No silent fallback exists anywhere.
0 commit comments