Skip to content

Commit 2a4c9a1

Browse files
committed
refactor: integrate M2RNN Path C implementation, unify v4 architecture with Engram support, and document performance benchmarking results.
1 parent 4f0b5bc commit 2a4c9a1

28 files changed

Lines changed: 7957 additions & 1777 deletions

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,11 @@ bench/runs/*.json
4242
bench/runs/*
4343
docs/tilelang_ports/mamba3_path_b_vs_c_b1_t2048.diff
4444
docs/tilelang_ports/mamba3_path_c_lowered_b1_t2048.metal
45+
reports/profiling/*.diff
46+
reports/profiling/*.metal
47+
reports/profiling/xctrace_*.*/*
48+
reports/*/*/*.json
49+
.gitignore
50+
reports/profiling/xctrace_*.xml
51+
reports/profiling/xctrace_*.json
52+
reports/profiling/*.json

cppmega_mlx/nn/_tilelang/m2rnn_path_c.py

Lines changed: 118 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from cppmega_mlx.nn._tilelang._msl_transform import MSLDispatchUnsupported
2222
from 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+
35233631
def _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

Comments
 (0)