[NPU] Fix ViT graph key layout handling (#37758)
This commit is contained in:
@@ -63,7 +63,7 @@ class ViTNpuGraphRunner(ViTCudaGraphRunner):
|
|||||||
|
|
||||||
def _create_graph(
|
def _create_graph(
|
||||||
self,
|
self,
|
||||||
graph_key: int,
|
graph_key: Hashable,
|
||||||
):
|
):
|
||||||
|
|
||||||
graph = torch_npu.npu.NPUGraph()
|
graph = torch_npu.npu.NPUGraph()
|
||||||
@@ -132,9 +132,16 @@ class ViTNpuGraphRunner(ViTCudaGraphRunner):
|
|||||||
cu_seqlens: torch.Tensor,
|
cu_seqlens: torch.Tensor,
|
||||||
rotary_pos_emb_cos: Optional[torch.Tensor] = None,
|
rotary_pos_emb_cos: Optional[torch.Tensor] = None,
|
||||||
rotary_pos_emb_sin: Optional[torch.Tensor] = None,
|
rotary_pos_emb_sin: Optional[torch.Tensor] = None,
|
||||||
) -> int:
|
attention_layout_key: Optional[Hashable] = None,
|
||||||
|
) -> Hashable:
|
||||||
vit = self.vit
|
vit = self.vit
|
||||||
graph_key = self._get_graph_key(x_3d)
|
graph_key = self._get_graph_key(
|
||||||
|
x_3d,
|
||||||
|
cu_seqlens,
|
||||||
|
None,
|
||||||
|
attention_layout_key,
|
||||||
|
)
|
||||||
|
seq_len = x_3d.shape[0]
|
||||||
|
|
||||||
if graph_key in self.block_graphs:
|
if graph_key in self.block_graphs:
|
||||||
return graph_key
|
return graph_key
|
||||||
@@ -155,7 +162,7 @@ class ViTNpuGraphRunner(ViTCudaGraphRunner):
|
|||||||
self.block_output[graph_key] = x_3d
|
self.block_output[graph_key] = x_3d
|
||||||
self.block_input[graph_key] = x_3d
|
self.block_input[graph_key] = x_3d
|
||||||
self.block_ws[graph_key] = torch.empty(
|
self.block_ws[graph_key] = torch.empty(
|
||||||
graph_key,
|
seq_len,
|
||||||
num_heads,
|
num_heads,
|
||||||
attn_head_dim,
|
attn_head_dim,
|
||||||
device=self.device,
|
device=self.device,
|
||||||
@@ -178,7 +185,7 @@ class ViTNpuGraphRunner(ViTCudaGraphRunner):
|
|||||||
|
|
||||||
def replay(
|
def replay(
|
||||||
self,
|
self,
|
||||||
graph_key: int,
|
graph_key: Hashable,
|
||||||
x_3d: torch.Tensor,
|
x_3d: torch.Tensor,
|
||||||
rotary_pos_emb_cos: Optional[torch.Tensor] = None,
|
rotary_pos_emb_cos: Optional[torch.Tensor] = None,
|
||||||
rotary_pos_emb_sin: Optional[torch.Tensor] = None,
|
rotary_pos_emb_sin: Optional[torch.Tensor] = None,
|
||||||
@@ -210,16 +217,23 @@ class ViTNpuGraphRunner(ViTCudaGraphRunner):
|
|||||||
rotary_pos_emb_cos: Optional[torch.Tensor] = None,
|
rotary_pos_emb_cos: Optional[torch.Tensor] = None,
|
||||||
rotary_pos_emb_sin: Optional[torch.Tensor] = None,
|
rotary_pos_emb_sin: Optional[torch.Tensor] = None,
|
||||||
output_indices: Optional[torch.Tensor] = None,
|
output_indices: Optional[torch.Tensor] = None,
|
||||||
|
attention_layout_key: Optional[Hashable] = None,
|
||||||
) -> torch.Tensor:
|
) -> torch.Tensor:
|
||||||
# x: [seq_len, hidden] -> [S, B=1, H]
|
# x: [seq_len, hidden] -> [S, B=1, H]
|
||||||
x_3d = x.unsqueeze(1)
|
x_3d = x.unsqueeze(1)
|
||||||
graph_key = self._get_graph_key(x_3d)
|
graph_key = self._get_graph_key(
|
||||||
|
x_3d,
|
||||||
|
cu_seqlens,
|
||||||
|
None,
|
||||||
|
attention_layout_key,
|
||||||
|
)
|
||||||
if graph_key not in self.block_graphs:
|
if graph_key not in self.block_graphs:
|
||||||
self.create_graph(
|
self.create_graph(
|
||||||
x_3d=x_3d,
|
x_3d=x_3d,
|
||||||
cu_seqlens=cu_seqlens,
|
cu_seqlens=cu_seqlens,
|
||||||
rotary_pos_emb_cos=rotary_pos_emb_cos,
|
rotary_pos_emb_cos=rotary_pos_emb_cos,
|
||||||
rotary_pos_emb_sin=rotary_pos_emb_sin,
|
rotary_pos_emb_sin=rotary_pos_emb_sin,
|
||||||
|
attention_layout_key=attention_layout_key,
|
||||||
)
|
)
|
||||||
|
|
||||||
return self.replay(
|
return self.replay(
|
||||||
|
|||||||
@@ -1029,6 +1029,7 @@ class Qwen3VLMoeVisionModel(nn.Module, RotaryPosMixin):
|
|||||||
rotary_pos_emb_sin,
|
rotary_pos_emb_sin,
|
||||||
) = self._prepare_graph_inputs(x, grid_thw)
|
) = self._prepare_graph_inputs(x, grid_thw)
|
||||||
|
|
||||||
|
attention_layout_key = (tuple(cu_seqlens.tolist()), None)
|
||||||
cu_seqlens = cu_seqlens.to("cpu")
|
cu_seqlens = cu_seqlens.to("cpu")
|
||||||
return self.graph_runners.run(
|
return self.graph_runners.run(
|
||||||
x=x,
|
x=x,
|
||||||
@@ -1036,6 +1037,7 @@ class Qwen3VLMoeVisionModel(nn.Module, RotaryPosMixin):
|
|||||||
rotary_pos_emb_sin=rotary_pos_emb_sin,
|
rotary_pos_emb_sin=rotary_pos_emb_sin,
|
||||||
cu_seqlens=cu_seqlens,
|
cu_seqlens=cu_seqlens,
|
||||||
output_indices=None,
|
output_indices=None,
|
||||||
|
attention_layout_key=attention_layout_key,
|
||||||
)
|
)
|
||||||
|
|
||||||
def forward_with_cuda_graph(
|
def forward_with_cuda_graph(
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
import importlib
|
||||||
|
import sys
|
||||||
|
from types import SimpleNamespace
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import torch
|
||||||
|
|
||||||
|
from sglang.test.ci.ci_register import register_cpu_ci
|
||||||
|
|
||||||
|
register_cpu_ci(est_time=2, suite="base-a-test-cpu")
|
||||||
|
|
||||||
|
|
||||||
|
class _Block:
|
||||||
|
attn = SimpleNamespace(
|
||||||
|
qkv_backend_name="ascend_attn",
|
||||||
|
num_attention_heads_per_partition=2,
|
||||||
|
head_size=4,
|
||||||
|
)
|
||||||
|
|
||||||
|
def forward(self, x, output_ws=None):
|
||||||
|
return x
|
||||||
|
|
||||||
|
|
||||||
|
class _FakeGraph:
|
||||||
|
def replay(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def _load_npu_graph_runner():
|
||||||
|
# Load shared modules before stubbing torch_npu so platform detection stays on CPU.
|
||||||
|
importlib.import_module("sglang.srt.multimodal.vit_cuda_graph_runner")
|
||||||
|
torch_npu = SimpleNamespace()
|
||||||
|
with patch.dict(
|
||||||
|
sys.modules,
|
||||||
|
{
|
||||||
|
"torch_npu": torch_npu,
|
||||||
|
},
|
||||||
|
):
|
||||||
|
module = importlib.import_module(
|
||||||
|
"sglang.srt.hardware_backend.npu.graph_runner.vit_npu_graph_runner"
|
||||||
|
)
|
||||||
|
return module.ViTNpuGraphRunner
|
||||||
|
|
||||||
|
|
||||||
|
def test_npu_vit_graph_keys_include_attention_boundaries():
|
||||||
|
runner_cls = _load_npu_graph_runner()
|
||||||
|
vit = SimpleNamespace(
|
||||||
|
blocks=[_Block()],
|
||||||
|
merger=lambda x: x,
|
||||||
|
device=torch.device("cpu"),
|
||||||
|
dtype=torch.float32,
|
||||||
|
deepstack_visual_indexes=[],
|
||||||
|
deepstack_merger_list=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"torch.get_device_module",
|
||||||
|
return_value=SimpleNamespace(graph_pool_handle=lambda: object()),
|
||||||
|
):
|
||||||
|
runner = runner_cls(vit)
|
||||||
|
|
||||||
|
runner_cls._graph_memory_pool = None
|
||||||
|
runner._create_graph = lambda graph_key: runner.block_graphs.__setitem__(
|
||||||
|
graph_key, _FakeGraph()
|
||||||
|
)
|
||||||
|
|
||||||
|
x = torch.zeros(8, 8)
|
||||||
|
rotary = torch.zeros(8, 4)
|
||||||
|
first_layout = torch.tensor([0, 4, 8], dtype=torch.int32)
|
||||||
|
second_layout = torch.tensor([0, 2, 8], dtype=torch.int32)
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"sglang.srt.hardware_backend.npu.graph_runner."
|
||||||
|
"vit_npu_graph_runner.set_graph_pool_id"
|
||||||
|
):
|
||||||
|
runner.run(
|
||||||
|
x,
|
||||||
|
first_layout,
|
||||||
|
rotary_pos_emb_cos=rotary,
|
||||||
|
rotary_pos_emb_sin=rotary,
|
||||||
|
)
|
||||||
|
runner.run(
|
||||||
|
x,
|
||||||
|
second_layout,
|
||||||
|
rotary_pos_emb_cos=rotary,
|
||||||
|
rotary_pos_emb_sin=rotary,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(runner.block_graphs) == 2
|
||||||
|
assert {key[1][0] for key in runner.block_graphs} == {
|
||||||
|
(0, 4, 8),
|
||||||
|
(0, 2, 8),
|
||||||
|
}
|
||||||
|
assert all(
|
||||||
|
workspace.shape[0] == x.shape[0] for workspace in runner.block_ws.values()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(pytest.main([__file__, "-v"]))
|
||||||
Reference in New Issue
Block a user