Skip to content

Commit 6079294

Browse files
committed
address CodeRabbit comments
Signed-off-by: Olivia Stoner <245287810+o-stoner@users.noreply.github.com>
1 parent d9a2641 commit 6079294

9 files changed

Lines changed: 71 additions & 20 deletions

File tree

tensorrt_llm/_torch/visual_gen/attention_backend/cute_dsl.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
Expects NHD layout ([B, S, H, D]) and supports float16/bfloat16.
2121
"""
2222

23+
import contextvars
2324
import math
2425
from contextlib import contextmanager
2526
from dataclasses import dataclass
@@ -198,22 +199,22 @@ def build(
198199
)
199200

200201

201-
_vsa_forward_context: Optional[VSAMetadata] = None
202+
_vsa_forward_context_var: contextvars.ContextVar[Optional[VSAMetadata]] = contextvars.ContextVar(
203+
"_vsa_forward_context", default=None
204+
)
202205

203206

204207
@contextmanager
205208
def set_vsa_forward_context(metadata: VSAMetadata):
206-
global _vsa_forward_context
207-
prev = _vsa_forward_context
208-
_vsa_forward_context = metadata
209+
token = _vsa_forward_context_var.set(metadata)
209210
try:
210211
yield
211212
finally:
212-
_vsa_forward_context = prev
213+
_vsa_forward_context_var.reset(token)
213214

214215

215216
def get_vsa_forward_context() -> Optional[VSAMetadata]:
216-
return _vsa_forward_context
217+
return _vsa_forward_context_var.get(None)
217218

218219

219220
def _mean_pool_cubes(
@@ -525,7 +526,10 @@ def _forward_vsa(
525526
o_c = torch.einsum("bhnm,bmhd->bnhd", attn_probs_c, v_c)
526527

527528
use_cute = (
528-
_vsa_import_error is None and is_cute_supported(q) and (q.dtype == k.dtype == v.dtype)
529+
_vsa_import_error is None
530+
and is_cute_supported(q)
531+
and (q.dtype == k.dtype == v.dtype)
532+
and num_cubes <= VSA_KERNEL_MAX_CUBES
529533
)
530534
topk_indices = attn_probs_c.topk(cur_topk, dim=-1).indices.to(torch.int32)
531535

@@ -534,11 +538,6 @@ def _forward_vsa(
534538
)
535539

536540
if use_cute:
537-
assert num_cubes <= VSA_KERNEL_MAX_CUBES, (
538-
f"VSA CuTe kernel supports at most {VSA_KERNEL_MAX_CUBES} cubes "
539-
f"(SMEM-allocated variable_block_sizes buffer); got num_cubes={num_cubes}. "
540-
"Lower video resolution/length or fall back to dense SDPA."
541-
)
542541
q_hnd = q_t.transpose(1, 2).contiguous()
543542
k_hnd = k_t.transpose(1, 2).contiguous()
544543
v_hnd = v_t.transpose(1, 2).contiguous()

tensorrt_llm/_torch/visual_gen/cute_dsl_kernels/blackwell/video_sparse_attention/block_sparse_attn_dsl_fwd.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ class VideoSparseAttentionForwardGroup2QInterleaveKV:
6262
Q1 0 S1 O1
6363
"""
6464

65+
MAX_INDICES = 4 * 1024
66+
6567
def __init__(
6668
self,
6769
block_m: int,
@@ -413,7 +415,7 @@ def __call__(
413415
(2, self.mma_tiler_qk[0], self.scale_buffers), (0, 1, 2)
414416
)
415417

416-
self.max_indices = 4 * 1024
418+
self.max_indices = self.MAX_INDICES
417419

418420
@cute.struct
419421
class SharedStorage:

tensorrt_llm/_torch/visual_gen/cute_dsl_kernels/blackwell/video_sparse_attention/interface.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,15 @@ def block_sparse_attn_from_indices_cute(
112112
"cutlass-dsl is not importable."
113113
)
114114

115+
num_q_blk = variable_block_sizes.shape[0]
116+
if num_q_blk > VideoSparseAttentionForward.MAX_INDICES:
117+
raise ValueError(
118+
f"variable_block_sizes has {num_q_blk} entries but the CuTe kernel "
119+
f"supports at most {VideoSparseAttentionForward.MAX_INDICES} "
120+
"(SMEM-allocated sVariable_block_sizes buffer). Lower video "
121+
"resolution/length or fall back to dense SDPA."
122+
)
123+
115124
B, H, T, D = q.shape
116125
if sm_scale is None:
117126
sm_scale = 1.0 / math.sqrt(D)

tensorrt_llm/_torch/visual_gen/models/wan/pipeline_wan.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -488,8 +488,10 @@ def forward(
488488

489489
# Apply an explicit user flow_shift override; otherwise keep the checkpoint
490490
# scheduler default so output matches the reference HuggingFace pipeline.
491+
sched_cfg = self.scheduler.config
492+
shift_key = None
493+
orig_shift = None
491494
if flow_shift is not None:
492-
sched_cfg = self.scheduler.config
493495
shift_key = (
494496
"shift"
495497
if "shift" in sched_cfg
@@ -498,10 +500,15 @@ def forward(
498500
else None
499501
)
500502
if shift_key is not None and sched_cfg[shift_key] != flow_shift:
501-
logger.info(f"flow_shift: {sched_cfg[shift_key]} -> {flow_shift} (user)")
503+
orig_shift = sched_cfg[shift_key]
504+
logger.info(f"flow_shift: {orig_shift} -> {flow_shift} (user)")
502505
self.scheduler.register_to_config(**{shift_key: flow_shift})
503506

504-
self.scheduler.set_timesteps(num_inference_steps, device=self.device)
507+
try:
508+
self.scheduler.set_timesteps(num_inference_steps, device=self.device)
509+
finally:
510+
if orig_shift is not None:
511+
self.scheduler.register_to_config(**{shift_key: orig_shift})
505512

506513
# Wan2.2 A14B: Calculate boundary timestep for two-stage denoising
507514
boundary_timestep = None

tensorrt_llm/_torch/visual_gen/models/wan/pipeline_wan_i2v.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -540,8 +540,10 @@ def forward(
540540
)
541541

542542
# Apply an explicit user flow_shift override; otherwise keep the checkpoint scheduler default.
543+
sched_cfg = self.scheduler.config
544+
shift_key = None
545+
orig_shift = None
543546
if flow_shift is not None:
544-
sched_cfg = self.scheduler.config
545547
shift_key = (
546548
"shift"
547549
if "shift" in sched_cfg
@@ -550,10 +552,15 @@ def forward(
550552
else None
551553
)
552554
if shift_key is not None and sched_cfg[shift_key] != flow_shift:
553-
logger.info(f"flow_shift: {sched_cfg[shift_key]} -> {flow_shift} (user)")
555+
orig_shift = sched_cfg[shift_key]
556+
logger.info(f"flow_shift: {orig_shift} -> {flow_shift} (user)")
554557
self.scheduler.register_to_config(**{shift_key: flow_shift})
555558

556-
self.scheduler.set_timesteps(num_inference_steps, device=self.device)
559+
try:
560+
self.scheduler.set_timesteps(num_inference_steps, device=self.device)
561+
finally:
562+
if orig_shift is not None:
563+
self.scheduler.register_to_config(**{shift_key: orig_shift})
557564

558565
# Wan2.2: Calculate boundary timestep for two-stage denoising
559566
boundary_timestep = None

tensorrt_llm/_torch/visual_gen/models/wan/transformer_wan.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ def __init__(
368368
)
369369
if _is_vsa:
370370
q_dim = num_heads * head_dim
371+
gate_tp_mode = TensorParallelMode.COLUMN if tp_size > 1 else None
371372
self.to_gate_compress = Linear(
372373
hidden_size,
373374
q_dim,
@@ -377,6 +378,8 @@ def __init__(
377378
quant_config=quant_config,
378379
skip_create_weights_in_init=skip_create_weights,
379380
force_dynamic_quantization=force_dynamic_quant,
381+
tensor_parallel_mode=gate_tp_mode,
382+
reduce_output=False,
380383
)
381384
self.to_gate_fine = Linear(
382385
hidden_size,
@@ -387,6 +390,8 @@ def __init__(
387390
quant_config=quant_config,
388391
skip_create_weights_in_init=skip_create_weights,
389392
force_dynamic_quantization=force_dynamic_quant,
393+
tensor_parallel_mode=gate_tp_mode,
394+
reduce_output=False,
390395
)
391396

392397
# I2V: Additional K/V projections for image embeddings.

tensorrt_llm/_torch/visual_gen/modules/attention.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ def _attn_impl(
455455
seq_len_kv = k.shape[1] if k is not None else seq_len
456456

457457
def _reshape_gate(gate: torch.Tensor) -> torch.Tensor:
458-
gate = gate.view(batch_size, -1, self.num_attention_heads, self.head_dim)
458+
gate = gate.view(batch_size, -1, self.local_num_attention_heads, self.head_dim)
459459
if backend_layout == AttentionTensorLayout.HND:
460460
gate = gate.transpose(1, 2)
461461
return gate

tests/unittest/_torch/visual_gen/test_attention_integration.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,11 @@ def _build_vsa_setup(sparsity: float, batch_size: int, seed: int):
698698
integrated = Attention(hidden_size, num_heads, qkv_mode=QKVMode.FUSE_QKV, config=cfg_vsa).to(
699699
device
700700
)
701+
# Fail loudly if the VSA path silently fell back to dense (which would set
702+
# attn_backend to "VANILLA") instead of selecting the CUTEDSL/VSA backend.
703+
assert integrated.attn_backend == "CUTEDSL", (
704+
f"Expected CUTEDSL (VSA) backend, got {integrated.attn_backend!r}"
705+
)
701706
copy_weights_self_attention(naive, integrated)
702707
naive.eval()
703708
integrated.eval()

tests/unittest/_torch/visual_gen/test_attention_perf.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,16 @@ def benchmark_single(
515515
)
516516
hidden_states, freqs = self.create_test_data(batch_size, seq_len, hidden_size, head_dim)
517517

518+
# Fail fast if the requested backend silently resolved to something
519+
# else (e.g. CUTEDSL/VSA downgraded to VANILLA dense for an
520+
# unsupported config).
521+
resolved_backend = getattr(model, "attn_backend", backend)
522+
if vsa_sparsity is not None:
523+
assert resolved_backend == "CUTEDSL", (
524+
f"VSA run requested CUTEDSL but the attention module resolved to "
525+
f"{resolved_backend!r}; refusing to report VSA timings for a dense fallback."
526+
)
527+
518528
# VSA needs an active forward context + a zero gate_compress; other
519529
# backends use neither.
520530
vsa_metadata = None
@@ -572,6 +582,7 @@ def _forward():
572582
"p99_ms": torch.quantile(times_tensor, 0.99).item(),
573583
"times_ms": times,
574584
"uses_sage": _is_sage_attention_enabled(model),
585+
"resolved_backend": resolved_backend,
575586
}
576587

577588
# Calculate throughput (approximate TOPS)
@@ -587,6 +598,9 @@ def _forward():
587598

588599
return stats
589600

601+
except AssertionError:
602+
# Backend-resolution / fail-fast checks are genuine test failures.
603+
raise
590604
except Exception as e:
591605
if verbose:
592606
print(f" {backend}: ERROR - {e}")
@@ -1224,6 +1238,9 @@ def test_vsa_module_vs_vanilla_wan22_t2v_14b(self, sparsity: float):
12241238
backend="CUTEDSL", vsa_sparsity=sparsity, latent_shape=self._LATENT_SHAPE, **common
12251239
)
12261240
assert vanilla is not None and vsa is not None, "benchmark returned None (skipped/failed)"
1241+
assert vsa["resolved_backend"] == "CUTEDSL", (
1242+
f"VSA timings came from {vsa['resolved_backend']!r}, not the CUTEDSL/VSA path"
1243+
)
12271244
assert vanilla["avg_ms"] > 0 and vsa["avg_ms"] > 0
12281245

12291246
speedup = vanilla["avg_ms"] / vsa["avg_ms"]

0 commit comments

Comments
 (0)