[diffusion] perf: build qwen's masked varlen metadata host-side (#33954)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -39,6 +39,7 @@ from sglang.multimodal_gen.runtime.layers.attention import (
|
|||||||
DynamicVarlenMaskMeta,
|
DynamicVarlenMaskMeta,
|
||||||
USPAttention,
|
USPAttention,
|
||||||
build_varlen_mask_meta,
|
build_varlen_mask_meta,
|
||||||
|
build_varlen_mask_meta_from_ranges,
|
||||||
)
|
)
|
||||||
from sglang.multimodal_gen.runtime.layers.elementwise import MulAdd
|
from sglang.multimodal_gen.runtime.layers.elementwise import MulAdd
|
||||||
from sglang.multimodal_gen.runtime.layers.fused_scale_shift_gate import (
|
from sglang.multimodal_gen.runtime.layers.fused_scale_shift_gate import (
|
||||||
@@ -1565,6 +1566,26 @@ class QwenImageTransformer2DModel(CachableDiT, LayerwiseOffloadableModuleMixin):
|
|||||||
# once, so build varlen metadata replay-locally from the current
|
# once, so build varlen metadata replay-locally from the current
|
||||||
# static mask instead of closing over stale cu_seqlens/indices.
|
# static mask instead of closing over stale cu_seqlens/indices.
|
||||||
block_attention_kwargs["attn_mask_meta"] = DynamicVarlenMaskMeta()
|
block_attention_kwargs["attn_mask_meta"] = DynamicVarlenMaskMeta()
|
||||||
|
elif (
|
||||||
|
txt_seq_lens is not None
|
||||||
|
and len(txt_seq_lens) == batch_size
|
||||||
|
and all(0 <= n <= encoder_hidden_states.shape[1] for n in txt_seq_lens)
|
||||||
|
):
|
||||||
|
# txt_seq_lens already carries each row's valid text prefix
|
||||||
|
# (the mask is built from it), so the varlen metadata can be
|
||||||
|
# assembled host-side; the mask-based builder costs a GPU
|
||||||
|
# nonzero plus a device sync on every denoising step.
|
||||||
|
txt_len = encoder_hidden_states.shape[1]
|
||||||
|
block_attention_kwargs["attn_mask_meta"] = (
|
||||||
|
build_varlen_mask_meta_from_ranges(
|
||||||
|
[
|
||||||
|
[(0, int(n)), (txt_len, txt_len + image_seq_len)]
|
||||||
|
for n in txt_seq_lens
|
||||||
|
],
|
||||||
|
max_seqlen=txt_len + image_seq_len,
|
||||||
|
device=hidden_states.device,
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
# Precompute varlen metadata once per request so every block
|
# Precompute varlen metadata once per request so every block
|
||||||
# reuses the same cu_seqlens / indices instead of rebuilding.
|
# reuses the same cu_seqlens / indices instead of rebuilding.
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
"""Host-built varlen metadata must match the mask-based (nonzero) builder."""
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
import torch
|
||||||
|
|
||||||
|
from sglang.multimodal_gen.runtime.layers.attention.layer import (
|
||||||
|
build_varlen_mask_meta,
|
||||||
|
build_varlen_mask_meta_from_ranges,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestHostVarlenMetaEquivalence(unittest.TestCase):
|
||||||
|
def test_prefix_text_plus_full_image_matches_nonzero_builder(self):
|
||||||
|
txt_len, img_len = 7, 5
|
||||||
|
txt_seq_lens = [3, 7, 0]
|
||||||
|
bs = len(txt_seq_lens)
|
||||||
|
mask = torch.zeros(bs, txt_len + img_len, dtype=torch.bool)
|
||||||
|
for row, n in enumerate(txt_seq_lens):
|
||||||
|
mask[row, :n] = True
|
||||||
|
mask[row, txt_len:] = True
|
||||||
|
|
||||||
|
ref = build_varlen_mask_meta(mask)
|
||||||
|
host = build_varlen_mask_meta_from_ranges(
|
||||||
|
[[(0, n), (txt_len, txt_len + img_len)] for n in txt_seq_lens],
|
||||||
|
max_seqlen=txt_len + img_len,
|
||||||
|
device=mask.device,
|
||||||
|
)
|
||||||
|
|
||||||
|
for key in ("cu_seqlens", "indices", "inv_indices"):
|
||||||
|
torch.testing.assert_close(host[key], ref[key], rtol=0, atol=0)
|
||||||
|
self.assertEqual(host["max_seqlen"], ref["max_seqlen"])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user