Skip to content

Commit 3a88375

Browse files
committed
fix(path-c): carrier-dtype gradient banks for fp8
Route parameter/activation gradients to the model's bf16/fp16 carrier (Path B keeps grads in the bf16 parameter dtype, so bf16 grad banks are parity-consistent; the previous unconditional float32 for every *_grad doubled the gradient arenas). fp8/int classification now applies to forward value buffers only (a gradient of an fp8/int buffer is a real-valued carrier grad). Recurrent-state grads (h0_grad/ state_in_grad), q/kv scales, and LSE stay float32. fp8 Path-C-vs-B parity 9/9 PASS.
1 parent 6b9cad8 commit 3a88375

1 file changed

Lines changed: 32 additions & 11 deletions

File tree

cppmega_mlx/runtime/path_c_fusion_schedules.py

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12753,32 +12753,53 @@ def _buffer_dtype(
1275312753
*,
1275412754
shape_env: PathCModelShapeEnv | None = None,
1275512755
) -> str:
12756-
if str(buffer_name).endswith("_grad"):
12757-
return "float32"
1275812756
canonical = _canonical_buffer_name(buffer_name)
12759-
if canonical in {"q_fp8", "kv_fp8"}:
12760-
return "uint8"
12761-
if canonical == "target_ids":
12762-
return "int32"
12763-
if buffer_name == "indices" or buffer_name.endswith("_indices"):
12764-
return "int32"
12765-
if buffer_name.endswith("_has_sinks"):
12766-
return "int32"
12757+
is_grad = str(buffer_name).endswith("_grad")
12758+
# fp8/int classification applies to forward VALUE buffers only; the gradient of
12759+
# an fp8/int buffer is a real-valued gradient (carrier dtype), never uint8/int32.
12760+
if not is_grad:
12761+
if canonical in {"q_fp8", "kv_fp8"}:
12762+
return "uint8"
12763+
if canonical == "target_ids":
12764+
return "int32"
12765+
if buffer_name == "indices" or buffer_name.endswith("_indices"):
12766+
return "int32"
12767+
if buffer_name.endswith("_has_sinks"):
12768+
return "int32"
12769+
# FP32-mandatory: fp8 dequant scales, LSE reductions, and recurrent scan/state
12770+
# accumulation INCLUDING their initial-state/state-input gradients (h0/state_in)
12771+
# — downcasting corrupts the fp8 matmul, softmax normalization, or recurrent
12772+
# backward stability. (In-kernel reverse-scan accumulators live in threadgroup
12773+
# scratch and are already float32 via accum_dtype, independent of this map.)
1276712774
if canonical in {
1276812775
"mamba3_angle_state",
1276912776
"mamba3_angle_checkpoint",
1277012777
"mamba3_angle_grad_state",
1277112778
"mamba3_conv_state",
1277212779
"mamba3_h_checkpoint",
12780+
"mamba3_h0_grad",
1277312781
"m2rnn_h_state",
1277412782
"m2rnn_h_checkpoint",
12783+
"m2rnn_h0_grad",
12784+
"state_in_grad",
1277512785
"q_scale",
1277612786
"kv_scale",
1277712787
"lse",
1277812788
} or buffer_name.endswith(
12779-
("_scale", "_sm_scale", "_lse")
12789+
(
12790+
"_scale",
12791+
"_sm_scale",
12792+
"_lse",
12793+
"_h0_grad",
12794+
"_state_in_grad",
12795+
)
1278012796
):
1278112797
return "float32"
12798+
# Parameter/activation VALUE buffers AND their gradients carry the model's
12799+
# bf16/fp16 carrier dtype. Path B keeps gradients in the bf16 parameter dtype,
12800+
# so bf16 grad banks are parity-consistent (the previous unconditional float32
12801+
# for every *_grad doubled the gradient arenas). For a float32 model the carrier
12802+
# resolves to float32, so behaviour is unchanged (no regression).
1278212803
return (
1278312804
str(shape_env.model_value_dtype)
1278412805
if shape_env is not None and str(shape_env.model_value_dtype)

0 commit comments

Comments
 (0)