Skip to content

Commit ac1a0d3

Browse files
committed
adding missed file
1 parent 1d6af66 commit ac1a0d3

1 file changed

Lines changed: 58 additions & 14 deletions

File tree

src/maxdiffusion/models/attention_flax.py

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,7 @@ def _ulysses_ring_attention(
824824
attention_mask: jax.Array = None,
825825
use_base2_exp: bool = True,
826826
use_experimental_scheduler: bool = False,
827+
bidirectional: bool = False,
827828
) -> jax.Array:
828829
"""Hybrid Ulysses + Ring (USP) with the CUSTOM splash kernel on main's mesh.
829830
@@ -894,20 +895,39 @@ def wrap_ulysses_ring_attention(query, key, value):
894895
value, _, _ = _pad_data_for_flash(value, heads, bkv)
895896

896897
bsizes = custom_splash._BlockSizes(block_q=bq, block_kv=bkv, block_kv_compute=bkv_compute)
897-
# (2) Ring (full ppermute over the cross-chip ring axis) with the custom kernel.
898-
ring_kernel = tokamax_ring_attention_kernel.make_custom_ring_attention(
899-
block_sizes=bsizes,
900-
bkv_compute_in=bkv_compute_in,
901-
orig_q_seq_len=query_seq_len,
902-
orig_kv_seq_len=key_seq_len,
903-
use_base2_exp=use_base2_exp,
904-
use_experimental_scheduler=use_experimental_scheduler,
905-
vmem_limit_bytes=vmem_limit_bytes,
906-
ring_axis=ring_axis,
907-
ring_size=num_ring_shards,
908-
)
909-
vmapped_ring = jax.vmap(ring_kernel, in_axes=(0, 0, 0))
910-
attention_output = vmapped_ring(query, key, value)
898+
if num_ring_shards == 1:
899+
# (2a) R=1: the ring is trivial (no rotation) -> use the lighter dedicated
900+
# splash kernel (fuse_reciprocal, no fp32 online-softmax residual windows).
901+
# Same math as the 1-step ring, and it fits BQ=8448 where the ring kernel
902+
# OOMs (its 3x residual windows). make_splash_mha returns [H, D, S].
903+
splash_kernel = custom_splash.make_splash_mha(
904+
block_sizes=bsizes,
905+
bkv_compute_in=bkv_compute_in,
906+
orig_q_seq_len=query_seq_len,
907+
orig_kv_seq_len=key_seq_len,
908+
heads_per_tile=heads_per_tile,
909+
use_base2_exp=use_base2_exp,
910+
use_experimental_scheduler=use_experimental_scheduler,
911+
vmem_limit_bytes=vmem_limit_bytes,
912+
)
913+
attention_output = jnp.swapaxes(jax.vmap(splash_kernel, in_axes=(0, 0, 0))(query, key, value), 2, 3)
914+
else:
915+
# (2b) Ring (full ppermute over the cross-chip ring axis) with the custom kernel.
916+
# bidirectional=True -> wrap-free schedule (streams K/V both directions one hop
917+
# at a time), for a non-wrapping ring axis. Selected by attention=ulysses_ring_custom_bidir.
918+
ring_kernel = tokamax_ring_attention_kernel.make_custom_ring_attention(
919+
block_sizes=bsizes,
920+
bkv_compute_in=bkv_compute_in,
921+
orig_q_seq_len=query_seq_len,
922+
orig_kv_seq_len=key_seq_len,
923+
use_base2_exp=use_base2_exp,
924+
use_experimental_scheduler=use_experimental_scheduler,
925+
vmem_limit_bytes=vmem_limit_bytes,
926+
ring_axis=ring_axis,
927+
ring_size=num_ring_shards,
928+
bidirectional=bidirectional,
929+
)
930+
attention_output = jax.vmap(ring_kernel, in_axes=(0, 0, 0))(query, key, value)
911931
attention_output = attention_output[:, :, :query_seq_len, :kv_size].astype(query.dtype)
912932

913933
# (3) Ulysses all-to-all back: sequence -> heads, restoring the layout.
@@ -1087,6 +1107,30 @@ def ulysses_ring_custom_kernel(q, k, v, context):
10871107
)
10881108

10891109

1110+
@register_kernel("ulysses_ring_custom_bidir")
1111+
def ulysses_ring_custom_bidir_kernel(q, k, v, context):
1112+
"""Wrap-free (bidirectional) variant of ulysses_ring_custom: the ring streams
1113+
K/V both directions one hop at a time, avoiding the diameter-length wrap hop
1114+
on a non-wrapping ring axis. Same USP split as ulysses_ring_custom otherwise."""
1115+
return _ulysses_ring_attention(
1116+
q,
1117+
k * context["scale"],
1118+
v,
1119+
context["heads"],
1120+
context["mesh"],
1121+
context["axis_names_q"],
1122+
context["axis_names_kv"],
1123+
context["flash_block_sizes"],
1124+
context["dtype"],
1125+
mask_padding_tokens=context["mask_padding_tokens"],
1126+
residual_checkpoint_name=context["residual_checkpoint_name"],
1127+
attention_mask=context["attention_mask"],
1128+
use_base2_exp=context.get("use_base2_exp", True),
1129+
use_experimental_scheduler=context.get("use_experimental_scheduler", False),
1130+
bidirectional=True,
1131+
)
1132+
1133+
10901134
@register_kernel("ulysses")
10911135
def ulysses_kernel(q, k, v, context):
10921136
return _ulysses_attention(

0 commit comments

Comments
 (0)