@@ -1283,12 +1283,19 @@ def forward(
12831283 if prequant_activation_payload is not None :
12841284 x_fp8_pre , x_scales_pre = prequant_activation_payload
12851285 w1_fused_payload = _get_fp8_weight_attr (w1 , "fp8" )
1286- z , y1 = _fused_blockscaled_gated_forward (
1287- x , w1 , expert_frequency_offset , x_gather_idx ,
1288- w1_fp8_pre = w1_fused_payload ,
1289- x_fp8_pre = x_fp8_pre , x_scales_pre = x_scales_pre ,
1290- store_z = not cfg .recompute_z ,
1291- fuse_y1_quant = fuse_y1 ,
1286+ fuse_y1 = _use_fuse_y1_quant ()
1287+ z , y1 , y1_fp8_fused , y1_scales_fused = (
1288+ _fused_blockscaled_gated_forward (
1289+ x ,
1290+ w1 ,
1291+ expert_frequency_offset ,
1292+ x_gather_idx ,
1293+ w1_fp8_pre = w1_fused_payload ,
1294+ x_fp8_pre = x_fp8_pre ,
1295+ x_scales_pre = x_scales_pre ,
1296+ store_z = not cfg .recompute_z ,
1297+ fuse_y1_quant = fuse_y1 ,
1298+ )
12921299 )
12931300 if cfg .recompute_z :
12941301 # Forward skips preact storage; z is materialized just-in-time
@@ -2053,9 +2060,22 @@ def forward(
20532060
20542061 # w2 decoupling: in FP8+aligned+fused_gated mode, backward doesn't
20552062 # read bf16 w2 data (uses fp8 dgated cache + metadata). This enables
2056- # stash_bf16_to_cpu() to resize_(0) the bf16 param storage.
2057- _w2_decouple = z_is_fp8 and cfg .fused_gated
2063+ # clear_param_storage("moe_expert") to release bf16 expert weight storage
2064+ # without requiring recompute_z/save_z_fp8.
2065+ _w2_decouple = (
2066+ cfg .enabled
2067+ and use_quack_gemm
2068+ and cfg .alignment_assumed
2069+ and cfg .fused_gated
2070+ )
20582071 ctx ._w2_decoupled = _w2_decouple
2072+ if _w2_decouple :
2073+ ctx ._w2_dgated_fp8 , ctx ._w2_dgated_scales = _get_fp8_weight_attr (
2074+ w2 , "transposed_fp8"
2075+ )
2076+ ctx ._w2_shape = w2 .shape # (H, I, E)
2077+ ctx ._w2_dtype = w2 .dtype
2078+ ctx ._w2_device = w2 .device
20592079
20602080 if z_is_fp8 :
20612081 recompute_args = _PREQUANTIZED_SCALES .pop ("z_fp8_recompute" , None )
@@ -2099,10 +2119,6 @@ def forward(
20992119 else :
21002120 z_fp8 , z_raw_scales = quantize_activation_blockscaled_fast (z )
21012121 if _w2_decouple :
2102- ctx ._w2_dgated_fp8 , ctx ._w2_dgated_scales = _get_fp8_weight_attr (w2 , "transposed_fp8" )
2103- ctx ._w2_shape = w2 .shape # (H, I, E)
2104- ctx ._w2_dtype = w2 .dtype
2105- ctx ._w2_device = w2 .device
21062122 ctx .save_for_backward (
21072123 z_fp8 ,
21082124 z_raw_scales ,
@@ -2129,17 +2145,30 @@ def forward(
21292145 s_reverse_scatter_idx ,
21302146 )
21312147 else :
2132- ctx .save_for_backward (
2133- z ,
2134- w2 ,
2135- b2 ,
2136- topk_scores ,
2137- topk_scores_expert_order ,
2138- expert_frequency_offset ,
2139- x_gather_idx ,
2140- s_scatter_idx ,
2141- s_reverse_scatter_idx ,
2142- )
2148+ if _w2_decouple :
2149+ ctx .save_for_backward (
2150+ z ,
2151+ # w2 omitted — backward uses ctx._w2_dgated_fp8 + metadata
2152+ b2 ,
2153+ topk_scores ,
2154+ topk_scores_expert_order ,
2155+ expert_frequency_offset ,
2156+ x_gather_idx ,
2157+ s_scatter_idx ,
2158+ s_reverse_scatter_idx ,
2159+ )
2160+ else :
2161+ ctx .save_for_backward (
2162+ z ,
2163+ w2 ,
2164+ b2 ,
2165+ topk_scores ,
2166+ topk_scores_expert_order ,
2167+ expert_frequency_offset ,
2168+ x_gather_idx ,
2169+ s_scatter_idx ,
2170+ s_reverse_scatter_idx ,
2171+ )
21432172
21442173 # Keep w2 FP8 cache — backward hits cache (~38µs savings) at ~37MB memory cost.
21452174 # The cache auto-invalidates via w._version when optimizer updates weights.
@@ -2201,20 +2230,35 @@ def backward(ctx, dout: torch.Tensor):
22012230 # Defer dequantize: FP8 path uses fused kernel, others lazy-dequant
22022231 z = None
22032232 else :
2204- (
2205- z ,
2206- w2 ,
2207- b2 ,
2208- topk_scores ,
2209- topk_scores_expert_order ,
2210- expert_frequency_offset ,
2211- x_gather_idx ,
2212- s_scatter_idx ,
2213- s_reverse_scatter_idx ,
2214- ) = ctx .saved_tensor ()
2215- w2_shape = w2 .shape
2216- w2_dtype = w2 .dtype
2217- w2_device = w2 .device
2233+ if ctx ._w2_decoupled :
2234+ (
2235+ z ,
2236+ b2 ,
2237+ topk_scores ,
2238+ topk_scores_expert_order ,
2239+ expert_frequency_offset ,
2240+ x_gather_idx ,
2241+ s_scatter_idx ,
2242+ s_reverse_scatter_idx ,
2243+ ) = ctx .saved_tensor ()
2244+ w2_shape = ctx ._w2_shape
2245+ w2_dtype = ctx ._w2_dtype
2246+ w2_device = ctx ._w2_device
2247+ else :
2248+ (
2249+ z ,
2250+ w2 ,
2251+ b2 ,
2252+ topk_scores ,
2253+ topk_scores_expert_order ,
2254+ expert_frequency_offset ,
2255+ x_gather_idx ,
2256+ s_scatter_idx ,
2257+ s_reverse_scatter_idx ,
2258+ ) = ctx .saved_tensor ()
2259+ w2_shape = w2 .shape
2260+ w2_dtype = w2 .dtype
2261+ w2_device = w2 .device
22182262 z_fp8 = z_raw_scales_u8 = None
22192263 if getattr (ctx , "_needs_z_recompute_bf16" , False ):
22202264 # Replace the zero-storage bf16 placeholder with a freshly recomputed
0 commit comments