2121from cppmega_mlx .nn ._tilelang ._msl_transform import MSLDispatchUnsupported
2222from cppmega_mlx .nn ._tilelang .m2rnn import (
2323 _validate_inputs ,
24+ m2rnn_bwd_metal ,
2425)
2526
2627
@@ -3198,17 +3199,33 @@ def m2rnn_mapped_packed_post_path_c_status(
31983199 if not fwd_status .available :
31993200 return fwd_status
32003201 if require_backward :
3202+ scan_fwd_status = _kernel_lowering_status (
3203+ f"mapped packed M2RNN Path C { carrier_dtype } K={ k_dim } fwd for bwd cache" ,
3204+ _mapped_packed_fwd_kernel_for ,
3205+ batch ,
3206+ seq ,
3207+ total_heads ,
3208+ q_heads ,
3209+ k_heads ,
3210+ v_heads ,
3211+ w_heads ,
3212+ f_heads ,
3213+ k_dim ,
3214+ v_dim ,
3215+ carrier_dtype ,
3216+ )
3217+ if not scan_fwd_status .available :
3218+ return scan_fwd_status
32013219 post_bwd_status = _kernel_lowering_status (
3202- f"mapped packed M2RNN inline post Path C { carrier_dtype } bwd" ,
3203- _post_residual_gate_bwd_from_recurrence_kernel_for ,
3220+ f"mapped packed M2RNN inline post Path C { carrier_dtype } split bwd" ,
3221+ _post_residual_gate_bwd_kernel_for ,
32043222 batch ,
32053223 seq ,
32063224 total_heads ,
32073225 q_heads ,
32083226 k_heads ,
32093227 v_heads ,
32103228 g_heads ,
3211- f_heads ,
32123229 k_dim ,
32133230 v_dim ,
32143231 conv_dim ,
@@ -3520,6 +3537,97 @@ def _expand_mapped_heads_for_reference(
35203537 return mx .repeat (x , repeats = total_heads // heads , axis = axis )
35213538
35223539
3540+ def _reduce_expanded_head_gradient (
3541+ grad : mx .array ,
3542+ * ,
3543+ axis : int ,
3544+ heads : int ,
3545+ total_heads : int ,
3546+ ) -> mx .array :
3547+ if heads == total_heads :
3548+ return grad
3549+ group = total_heads // heads
3550+ axis = axis if axis >= 0 else grad .ndim + axis
3551+ shape = list (grad .shape )
3552+ shape [axis ] = heads
3553+ shape .insert (axis + 1 , group )
3554+ return mx .sum (grad .reshape (tuple (shape )), axis = axis + 1 )
3555+
3556+
3557+ def _m2rnn_mapped_packed_bwd_path_b_reduced (
3558+ dy : mx .array ,
3559+ conv_input : mx .array ,
3560+ W : mx .array ,
3561+ xf : mx .array ,
3562+ tanh_cache : mx .array ,
3563+ h0 : mx .array ,
3564+ * ,
3565+ q_heads : int ,
3566+ k_heads : int ,
3567+ v_heads : int ,
3568+ ) -> tuple [mx .array , mx .array , mx .array , mx .array ]:
3569+ batch , seq , conv_dim = conv_input .shape
3570+ total_heads = int (h0 .shape [1 ])
3571+ k_dim = int (h0 .shape [2 ])
3572+ v_dim = int (h0 .shape [3 ])
3573+ if conv_dim != _mapped_conv_dim (q_heads , k_heads , v_heads , k_dim , v_dim ):
3574+ raise ValueError ("conv_input width does not match mapped M2RNN head layout" )
3575+
3576+ q_stop = q_heads * k_dim
3577+ k_stop = q_stop + k_heads * k_dim
3578+ q = conv_input [:, :, :q_stop ].reshape (batch , seq , q_heads , k_dim )
3579+ k = conv_input [:, :, q_stop :k_stop ].reshape (batch , seq , k_heads , k_dim )
3580+ v = conv_input [:, :, k_stop :].reshape (batch , seq , v_heads , v_dim )
3581+
3582+ q_full = _expand_mapped_heads_for_reference (q , axis = - 2 , total_heads = total_heads )
3583+ k_full = _expand_mapped_heads_for_reference (k , axis = - 2 , total_heads = total_heads )
3584+ v_full = _expand_mapped_heads_for_reference (v , axis = - 2 , total_heads = total_heads )
3585+ W_full = _expand_mapped_heads_for_reference (W , axis = 0 , total_heads = total_heads )
3586+ xf_full = _expand_mapped_heads_for_reference (xf , axis = - 1 , total_heads = total_heads )
3587+
3588+ dq_full , dk_full , dv_full , dW_full , dxf_full , dh0 = m2rnn_bwd_metal (
3589+ dy ,
3590+ q_full ,
3591+ k_full ,
3592+ v_full ,
3593+ W_full ,
3594+ xf_full ,
3595+ tanh_cache ,
3596+ h0 ,
3597+ )
3598+ dq = _reduce_expanded_head_gradient (
3599+ dq_full ,
3600+ axis = - 2 ,
3601+ heads = q_heads ,
3602+ total_heads = total_heads ,
3603+ ).reshape (batch , seq , q_heads * k_dim )
3604+ dk = _reduce_expanded_head_gradient (
3605+ dk_full ,
3606+ axis = - 2 ,
3607+ heads = k_heads ,
3608+ total_heads = total_heads ,
3609+ ).reshape (batch , seq , k_heads * k_dim )
3610+ dv = _reduce_expanded_head_gradient (
3611+ dv_full ,
3612+ axis = - 2 ,
3613+ heads = v_heads ,
3614+ total_heads = total_heads ,
3615+ ).reshape (batch , seq , v_heads * v_dim )
3616+ dW = _reduce_expanded_head_gradient (
3617+ dW_full ,
3618+ axis = 0 ,
3619+ heads = int (W .shape [0 ]),
3620+ total_heads = total_heads ,
3621+ )
3622+ dxf = _reduce_expanded_head_gradient (
3623+ dxf_full ,
3624+ axis = - 1 ,
3625+ heads = int (xf .shape [- 1 ]),
3626+ total_heads = total_heads ,
3627+ )
3628+ return mx .concatenate ([dq , dk , dv ], axis = - 1 ), dW , dxf , dh0
3629+
3630+
35233631def _m2rnn_mapped_packed_reference_bwd (
35243632 dy : mx .array ,
35253633 conv_input : mx .array ,
@@ -4941,7 +5049,7 @@ def _apply_vjp(
49415049 v_heads = v_heads ,
49425050 )
49435051 _y , _h_last , tanh_cache = full
4944- grads = m2rnn_mapped_packed_bwd_path_c (
5052+ grads = _m2rnn_mapped_packed_bwd_path_b_reduced (
49455053 dy ,
49465054 conv_input ,
49475055 W ,
@@ -5043,19 +5151,16 @@ def _apply_vjp(
50435151 del output
50445152 conv_input , W , xf , h0 , D , projected = primals
50455153 dpost = cotangent [0 ]
5046- full = _m2rnn_mapped_packed_post_fwd_path_c_full (
5154+ recurrent_full = _m2rnn_mapped_packed_fwd_path_c_full (
50475155 conv_input ,
50485156 W ,
50495157 xf ,
50505158 h0 ,
5051- D ,
5052- projected ,
50535159 q_heads = q_heads ,
50545160 k_heads = k_heads ,
50555161 v_heads = v_heads ,
5056- g_heads = g_heads ,
50575162 )
5058- if full is None :
5163+ if recurrent_full is None :
50595164 _raise_mapped_packed_post_path_c_unavailable (
50605165 conv_input ,
50615166 W ,
@@ -5068,16 +5173,14 @@ def _apply_vjp(
50685173 v_heads = v_heads ,
50695174 g_heads = g_heads ,
50705175 )
5071- _post , _h_last , tanh_cache = full
5176+ y_recurrent , _h_last , tanh_cache = recurrent_full
50725177 dpost_for_kernel = (
50735178 dpost if dpost .dtype == conv_input .dtype else dpost .astype (conv_input .dtype )
50745179 )
5075- post_grads = _m2rnn_inline_post_bwd_path_c_kernel (
5180+ post_grads = _m2rnn_post_residual_gate_bwd_path_c_kernel (
50765181 dpost_for_kernel ,
5182+ y_recurrent ,
50775183 conv_input ,
5078- xf ,
5079- h0 ,
5080- tanh_cache ,
50815184 D ,
50825185 projected ,
50835186 q_heads = q_heads ,
@@ -5101,7 +5204,7 @@ def _apply_vjp(
51015204 )
51025205 return _match_primal_gradient_dtypes (grads , primals )
51035206 dy_recurrent , dconv_post , dD , dprojected = post_grads
5104- dconv_recurrent , dW , dxf , dh0 = m2rnn_mapped_packed_bwd_path_c (
5207+ dconv_recurrent , dW , dxf , dh0 = _m2rnn_mapped_packed_bwd_path_b_reduced (
51055208 dy_recurrent ,
51065209 conv_input ,
51075210 W ,
0 commit comments