Skip to content

Commit ec4a882

Browse files
Allow causal scheduler with mask_mod (#155)
* Allow causal scheduler with mask_mod Signed-off-by: Matthew Bonanni <mbonanni@redhat.com> * Pass leading dims for aux tensors Signed-off-by: Matthew Bonanni <mbonanni@redhat.com> * Fix Signed-off-by: Matthew Bonanni <mbonanni@redhat.com> --------- Signed-off-by: Matthew Bonanni <mbonanni@redhat.com>
1 parent ed4b734 commit ec4a882

5 files changed

Lines changed: 72 additions & 12 deletions

File tree

csrc/composable_kernel

Submodule composable_kernel updated 3717 files

flash_attn/cute/cute_dsl_utils.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,14 @@ def to_cute_tensor(t, assumed_align=16, leading_dim=-1, fully_dynamic=False, ena
103103
return tensor.mark_layout_dynamic(leading_dim=leading_dim)
104104

105105

106-
def to_cute_aux_tensor(t, enable_tvm_ffi=True):
106+
def to_cute_aux_tensor(t, leading_dim=None, enable_tvm_ffi=True):
107107
"""Convert torch tensor to cute tensor for TVM FFI, tailored to FlexAttention aux tensors.
108108
This allows the user to specify alignment and leading dimension for aux tensors used in
109109
custom score_mod callables.
110110
"""
111111
assumed_align: int = getattr(t, "__assumed_align__", None)
112-
leading_dim: int = getattr(t, "__leading_dim__", None)
112+
if leading_dim is None:
113+
leading_dim = getattr(t, "__leading_dim__", None)
113114
fully_dynamic: bool = leading_dim is None
114115

115116
return to_cute_tensor(
@@ -121,14 +122,28 @@ def to_cute_aux_tensor(t, enable_tvm_ffi=True):
121122
)
122123

123124

124-
def get_aux_tensor_metadata(aux_tensors):
125+
def get_aux_tensor_metadata(aux_tensors, aux_tensor_leading_dims=None):
126+
if aux_tensor_leading_dims is not None:
127+
assert len(aux_tensor_leading_dims) == len(aux_tensors)
128+
125129
return tuple(
126130
(
127131
getattr(t, "__assumed_align__", 0),
128-
getattr(t, "__leading_dim__", -1),
129-
hasattr(t, "__leading_dim__"),
132+
(
133+
leading_dim
134+
if leading_dim is not None
135+
else getattr(t, "__leading_dim__", -1)
136+
),
137+
leading_dim is not None or hasattr(t, "__leading_dim__"),
138+
)
139+
for t, leading_dim in zip(
140+
aux_tensors,
141+
(
142+
aux_tensor_leading_dims
143+
if aux_tensor_leading_dims is not None
144+
else [None] * len(aux_tensors)
145+
),
130146
)
131-
for t in aux_tensors
132147
)
133148

134149

flash_attn/cute/interface.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -345,8 +345,6 @@ def _resolve_causal_local_window(causal, window_size_left, window_size_right, ma
345345
346346
Returns (causal, local, window_size_left, window_size_right).
347347
"""
348-
if mask_mod is not None:
349-
return False, False, window_size_left, window_size_right
350348
if causal:
351349
window_size_right = 0
352350
if window_size_left is not None and window_size_right is not None and window_size_left + window_size_right < 0:
@@ -396,6 +394,7 @@ def _flash_attn_fwd(
396394
out: Optional[torch.Tensor] = None,
397395
lse: Optional[torch.Tensor] = None,
398396
aux_tensors: Optional[list[torch.Tensor]] = None,
397+
aux_tensor_leading_dims: Optional[list[int]] = None,
399398
aux_scalars: Optional[tuple] = None,
400399
q_descale: Optional[torch.Tensor] = None,
401400
k_descale: Optional[torch.Tensor] = None,
@@ -768,8 +767,11 @@ def _flash_attn_fwd(
768767
q_stage=q_stage,
769768
)
770769
if aux_tensors is not None:
771-
aux_tensor_metadata = get_aux_tensor_metadata(aux_tensors)
770+
aux_tensor_metadata = get_aux_tensor_metadata(
771+
aux_tensors, aux_tensor_leading_dims
772+
)
772773
else:
774+
assert aux_tensor_leading_dims is None
773775
aux_tensor_metadata = None
774776
aux_scalar_metadata = tuple(type(s) for s in aux_scalars) if aux_scalars is not None else None
775777

@@ -931,7 +933,15 @@ def _flash_attn_fwd(
931933
cute_aux_tensors = None
932934
aux_tensor_metadata = None
933935
if aux_tensors is not None:
934-
cute_aux_tensors = [to_cute_aux_tensor(buf) for buf in aux_tensors]
936+
aux_tensor_leading_dims = (
937+
aux_tensor_leading_dims
938+
if aux_tensor_leading_dims is not None
939+
else [None] * len(aux_tensors)
940+
)
941+
cute_aux_tensors = [
942+
to_cute_aux_tensor(buf, leading_dim)
943+
for buf, leading_dim in zip(aux_tensors, aux_tensor_leading_dims)
944+
]
935945

936946
qv_tensor = to_cute_tensor(qv)
937947
gather_kv_indices_tensor = to_cute_tensor(gather_kv_indices)

flash_attn/cute/mask.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,41 @@ def apply_mask_sm100(
731731
)
732732

733733
else: # Causal or local
734+
if const_expr(mask_mod is not None):
735+
assert vec_size % 32 == 0 or 32 % vec_size == 0, (
736+
"vec_size must divide 32 or be a multiple of 32"
737+
)
738+
if const_expr(vec_size == 1):
739+
self.apply_mask_mod_sm100_scalar(
740+
acc_S,
741+
tScS_t2r,
742+
m_block,
743+
n_block,
744+
mask_seqlen,
745+
mask_mod,
746+
batch_idx,
747+
head_idx,
748+
aux_data,
749+
fastdiv_mods,
750+
head_divmod,
751+
check_q_boundary,
752+
)
753+
else:
754+
self.apply_mask_mod_sm100_vector(
755+
acc_S,
756+
tScS_t2r,
757+
m_block,
758+
n_block,
759+
mask_seqlen,
760+
mask_mod,
761+
batch_idx,
762+
head_idx,
763+
vec_size,
764+
aux_data,
765+
fastdiv_mods,
766+
head_divmod,
767+
check_q_boundary,
768+
)
734769
causal_row_offset = self.seqlen_k - n_block * self.tile_n - self.seqlen_q
735770
row_idx = tScS_t2r[0][0] + m_block * self.tile_m
736771
if const_expr(self.qhead_per_kvhead_packgqa != 1):

third_party/aiter

Submodule aiter updated 385 files

0 commit comments

Comments
 (0)