Skip to content

Commit 54c63b3

Browse files
committed
[feat]: auto-route VSA backend to CuTe BSHD fastpath at tile volume 256
forward() now derives block_elements = math.prod(VSA_TILE_SIZE) and, when it is 256 and the CuTe entrypoint is importable, calls video_sparse_attn_bshd directly (inputs already arrive in [B,S,H,D], so the BHSD transpose round-trip is skipped). The default (4,4,4) tile keeps the existing 64-element TK/Triton path byte-for-byte. VSA_TILE_SIZE stays the single module-level constant it already was on main -- no env var, no per-pipeline plumbing, no metadata/config threading. Switching to the Blackwell fastpath is a one-line change to that constant; everything else (build/tile/construct_variable_block_sizes) reads it unchanged.
1 parent 14553b7 commit 54c63b3

1 file changed

Lines changed: 29 additions & 12 deletions

File tree

fastvideo/attention/backends/video_sparse_attn.py

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
from fastvideo_kernel import video_sparse_attn
1010
except ImportError:
1111
video_sparse_attn = None
12+
try:
13+
from fastvideo_kernel import video_sparse_attn_bshd
14+
except ImportError:
15+
video_sparse_attn_bshd = None
1216

1317
from typing import Any
1418

@@ -18,6 +22,9 @@
1822
from fastvideo.logger import init_logger
1923

2024
logger = init_logger(__name__)
25+
# VSA tile shape. The tile volume picks the kernel path automatically in
26+
# forward(): (4,4,4)=64 -> existing TK/Triton path (default, unchanged);
27+
# (4,8,8)=256 -> FA4 CuTe block-sparse attention fastpath (Blackwell).
2128
VSA_TILE_SIZE = (4, 4, 4)
2229

2330

@@ -276,24 +283,34 @@ def forward( # type: ignore[override]
276283
gate_compress: torch.Tensor,
277284
attn_metadata: VideoSparseAttentionMetadata,
278285
) -> torch.Tensor:
279-
query = query.transpose(1, 2).contiguous()
280-
key = key.transpose(1, 2).contiguous()
281-
value = value.transpose(1, 2).contiguous()
282-
gate_compress = gate_compress.transpose(1, 2).contiguous()
283-
284286
VSA_sparsity = attn_metadata.VSA_sparsity
287+
block_elements = math.prod(VSA_TILE_SIZE)
288+
cur_topk = math.ceil((1 - VSA_sparsity) * (attn_metadata.total_seq_length / block_elements))
285289

286-
cur_topk = math.ceil((1 - VSA_sparsity) * (attn_metadata.total_seq_length / math.prod(VSA_TILE_SIZE)))
287-
288-
if video_sparse_attn is None:
289-
raise NotImplementedError("video_sparse_attn is not installed")
290-
hidden_states = video_sparse_attn(query,
290+
# 256-element tiles auto-route to the FA4 CuTe BSHD fastpath, which
291+
# consumes [B, S, H, D] directly -- skip the transpose round-trip.
292+
if block_elements == 256 and video_sparse_attn_bshd is not None:
293+
return video_sparse_attn_bshd(query,
291294
key,
292295
value,
293296
attn_metadata.variable_block_sizes,
294297
attn_metadata.variable_block_sizes,
295298
cur_topk,
296299
block_size=VSA_TILE_SIZE,
297-
compress_attn_weight=gate_compress).transpose(1, 2)
300+
compress_attn_weight=gate_compress)
298301

299-
return hidden_states
302+
if video_sparse_attn is None:
303+
raise NotImplementedError("video_sparse_attn is not installed")
304+
# Default 64-element-tile path (unchanged): BHSD round-trip.
305+
query = query.transpose(1, 2).contiguous()
306+
key = key.transpose(1, 2).contiguous()
307+
value = value.transpose(1, 2).contiguous()
308+
gate_compress = gate_compress.transpose(1, 2).contiguous()
309+
return video_sparse_attn(query,
310+
key,
311+
value,
312+
attn_metadata.variable_block_sizes,
313+
attn_metadata.variable_block_sizes,
314+
cur_topk,
315+
block_size=VSA_TILE_SIZE,
316+
compress_attn_weight=gate_compress).transpose(1, 2)

0 commit comments

Comments
 (0)