Mike0021 commited on
Commit
a0336b6
·
verified ·
1 Parent(s): dd8b2a6

exp7: fastvideo-kernel 0.3.4 CUDA VSA w/ triton fallback

Browse files
Files changed (2) hide show
  1. requirements.txt +4 -0
  2. vsa_h3.py +59 -8
requirements.txt CHANGED
@@ -5,6 +5,10 @@ diffusers==0.40.0
5
  # is what compiles the vendored VSA block-sparse kernels. torchvision is not needed anywhere in this Space.
6
  transformers
7
  accelerate
 
 
 
 
8
  # PyAV muxes the generated soundtrack onto the frames (`diffusers.utils.encode_video`).
9
  av
10
  pillow
 
5
  # is what compiles the vendored VSA block-sparse kernels. torchvision is not needed anywhere in this Space.
6
  transformers
7
  accelerate
8
+ # FastVideo's published CUDA kernels: the block-sparse VSA forward, sm_100a source with sm_120a cubins in the
9
+ # same fatbin (this pool's GPU). Only needs torch>=2.5, so the platform torch is untouched. If the op refuses
10
+ # to run, `vsa_h3` falls back to the vendored Triton kernels below.
11
+ fastvideo-kernel==0.3.4
12
  # PyAV muxes the generated soundtrack onto the frames (`diffusers.utils.encode_video`).
13
  av
14
  pillow
vsa_h3.py CHANGED
@@ -33,6 +33,7 @@ from __future__ import annotations
33
 
34
  import functools
35
  import math
 
36
  from dataclasses import dataclass
37
 
38
  import torch
@@ -279,6 +280,36 @@ def _block_mask(scores: torch.Tensor, geometry: VSAGeometry) -> torch.Tensor:
279
  return mask
280
 
281
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
282
  def sparse_attention(
283
  query: torch.Tensor,
284
  key: torch.Tensor,
@@ -298,14 +329,34 @@ def sparse_attention(
298
 
299
  mask = _block_mask(scores, geometry)
300
  q2k_index, q2k_num = map_to_index(mask)
301
- out_tiled, _ = triton_block_sparse_attn_forward(
302
- query_tiled,
303
- key_tiled,
304
- value_tiled,
305
- q2k_index,
306
- q2k_num,
307
- geometry.variable_block_sizes,
308
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
309
  out = out_tiled.index_select(2, geometry.untile_index)
310
 
311
  if gate_compress is not None:
 
33
 
34
  import functools
35
  import math
36
+ import os
37
  from dataclasses import dataclass
38
 
39
  import torch
 
280
  return mask
281
 
282
 
283
+ # The sparse-attention kernel, resolved once per process. FastVideo's published CUDA wheel carries the
284
+ # block-sparse forward as sm_100a source with sm_120a cubins in the same fatbin — this pool's GPU is sm_120 —
285
+ # but its `is_supported` gate hard-checks capability == (10, 0) and would never select it here. We call the
286
+ # public `block_sparse_attn_sm100a` entry directly (need_lse=False, the production inference path) and treat
287
+ # the dense-equivalence `/selftest` as the numerical gate. Any import or launch failure falls back to the
288
+ # vendored Triton kernels; `H3_VSA_CUDA=0` forces Triton up front.
289
+ _CUDA_SPARSE: dict = {"resolved": False, "op": None}
290
+
291
+
292
+ def _resolve_cuda_sparse_op():
293
+ if _CUDA_SPARSE["resolved"]:
294
+ return _CUDA_SPARSE["op"]
295
+ _CUDA_SPARSE["resolved"] = True
296
+ if os.environ.get("H3_VSA_CUDA", "1") != "1":
297
+ return None
298
+ try:
299
+ from fastvideo_kernel import block_sparse_attn_sm100a as sm100a
300
+
301
+ op = sm100a.block_sparse_attn_sm100a
302
+ probe = sm100a._FWD_BY_BLOCK # noqa: F841 - import-time check that the extension loaded
303
+ if not sm100a._HAS_VSA_SM100A:
304
+ raise ImportError("fastvideo_kernel compiled without the sm100a VSA forward")
305
+ _CUDA_SPARSE["op"] = op
306
+ print("[vsa] CUDA sparse-attention kernel: fastvideo_kernel (sm100a fatbin on sm120)", flush=True)
307
+ except Exception as error: # noqa: BLE001 - any failure means Triton
308
+ print(f"[vsa] fastvideo_kernel unavailable ({type(error).__name__}: {error}); using vendored Triton", flush=True)
309
+ _CUDA_SPARSE["op"] = None
310
+ return _CUDA_SPARSE["op"]
311
+
312
+
313
  def sparse_attention(
314
  query: torch.Tensor,
315
  key: torch.Tensor,
 
329
 
330
  mask = _block_mask(scores, geometry)
331
  q2k_index, q2k_num = map_to_index(mask)
332
+ # The CUDA path only handles an even tile count (one CTA owns an adjacent pair of query blocks); anything
333
+ # else — or any launch failure — falls back to the vendored Triton kernels for the rest of the process.
334
+ out_tiled = None
335
+ cuda_op = _resolve_cuda_sparse_op()
336
+ if cuda_op is not None and geometry.n_tiles % 2 == 0:
337
+ try:
338
+ out_tiled, _ = cuda_op(
339
+ query_tiled,
340
+ key_tiled,
341
+ value_tiled,
342
+ q2k_index,
343
+ q2k_num,
344
+ geometry.variable_block_sizes,
345
+ need_lse=False,
346
+ )
347
+ except Exception as error: # noqa: BLE001 - a refused launch must not kill the request
348
+ print(f"[vsa] CUDA kernel failed ({type(error).__name__}: {error}); falling back to Triton", flush=True)
349
+ _CUDA_SPARSE["op"] = None
350
+ out_tiled = None
351
+ if out_tiled is None:
352
+ out_tiled, _ = triton_block_sparse_attn_forward(
353
+ query_tiled,
354
+ key_tiled,
355
+ value_tiled,
356
+ q2k_index,
357
+ q2k_num,
358
+ geometry.variable_block_sizes,
359
+ )
360
  out = out_tiled.index_select(2, geometry.untile_index)
361
 
362
  if gate_compress is not None: