A high-throughput and memory-efficient inference and serving engine for LLMs
Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git
Synced Nov 15, 14:45 UTC
[torch.compile][TPU] Make @support_torch_compile work for XLA backend (#15782)
Signed-off-by: Siyuan Liu <lsiyuan@google.com> Signed-off-by: mgoin <mgoin64@gmail.com> Co-authored-by: mgoin <mgoin64@gmail.com>
Siyuan Liu committed
Apr 7, 2025 at 23:23 UTC
87918e40c4bdc7ff8204501bb307a783d6354347
2 files changed
+47
-76
vllm/v1/worker/tpu_model_runner.py
+38
-73
@@ -15,6 +15,7 @@ import torch_xla.runtime as xr
15
import vllm.envs as envs
16
from vllm.attention.backends.abstract import AttentionType
17
from vllm.attention.layer import Attention
18
+from vllm.compilation.wrapper import TorchCompileWrapperWithCustomDispatcher
19
from vllm.config import VllmConfig
20
from vllm.forward_context import set_forward_context
21
from vllm.logger import init_logger
@@ -691,11 +692,10 @@ class TPUModelRunner:
692
hidden_states = self.model(
693
input_ids=input_ids,
694
positions=self.position_ids,
694
- kv_caches=self.kv_caches,
695
inputs_embeds=inputs_embeds,
696
)
697
- selected_token_ids = self.model.sample_from_hidden(
698
- hidden_states, tpu_sampling_metadata)
697
+ selected_token_ids = self.sample_from_hidden(hidden_states,
698
+ tpu_sampling_metadata)
699
# Remove padding on cpu and keep dynamic op outside of xla graph.
700
selected_token_ids = selected_token_ids.cpu()[:num_reqs]
701
@@ -795,17 +795,15 @@ class TPUModelRunner:
795
"get_tensor_model_parallel_rank",
796
return_value=xm_tp_rank):
797
model = get_model(vllm_config=self.vllm_config)
798
- model = model.eval()
798
+ # Sync all pending XLA execution during model initialization and weight
799
+ # loading.
800
xm.mark_step()
801
xm.wait_device_ops()
801
- model = ModelWrapperV1(model)
802
- self.model = torch.compile(model,
803
- backend="openxla",
804
- fullgraph=True,
805
- dynamic=False)
802
+ self.model = model
803
+ self.sampler = TPUSampler()
804
805
@torch.no_grad()
808
- def _dummy_run(self, kv_caches, num_tokens: int) -> None:
806
+ def _dummy_run(self, num_tokens: int) -> None:
807
if self.is_multimodal_model:
808
input_ids = None
809
inputs_embeds = torch.zeros((num_tokens, self.hidden_size),
@@ -856,7 +854,6 @@ class TPUModelRunner:
854
with set_forward_context(attn_metadata, self.vllm_config, 0):
855
out = self.model(input_ids=input_ids,
856
positions=position_ids,
859
- kv_caches=kv_caches,
857
inputs_embeds=inputs_embeds)
858
self._hidden_states_dtype = out.dtype
859
@@ -868,7 +865,7 @@ class TPUModelRunner:
865
start = time.perf_counter()
866
for num_tokens in self.num_tokens_paddings:
867
logger.info(" -- num_tokens: %d", num_tokens)
871
- self._dummy_run(self.kv_caches, num_tokens)
868
+ self._dummy_run(num_tokens)
869
xm.mark_step()
870
xm.wait_device_ops()
871
end = time.perf_counter()
@@ -899,8 +896,7 @@ class TPUModelRunner:
896
from_input_batch(self.input_batch, indices)
897
logger.info(" -- num_tokens: %d, num_seqs: %d", num_tokens,
898
num_reqs_to_sample)
902
- out = self.model.sample_from_hidden(dummy_hidden,
903
- sampling_meta)
899
+ out = self.sample_from_hidden(dummy_hidden, sampling_meta)
900
out = out.cpu()
901
# Requests can't be more than tokens. But do compile for the
902
# next bigger value in case num_tokens uses bucketed padding.
@@ -954,45 +950,17 @@ class TPUModelRunner:
950
self.vllm_config.compilation_config.static_forward_context,
951
self.kv_caches)
952
957
-
958
-class ModelWrapperV1(nn.Module):
959
-
960
- def __init__(self, model: nn.Module):
961
- super().__init__()
962
- self.model = model
963
- self.sampler = TPUSampler()
964
-
965
- def sample(
966
- self, logits: torch.Tensor,
967
- sampling_metadata: TPUSupportedSamplingMetadata) -> SamplerOutput:
968
- sampler_out = self.sampler(logits, sampling_metadata)
969
- return sampler_out
970
-
971
- def forward(
972
- self,
973
- input_ids: torch.Tensor,
974
- positions: torch.Tensor,
975
- kv_caches: list[torch.Tensor],
976
- inputs_embeds: Optional[torch.Tensor] = None,
977
- ) -> torch.Tensor:
978
- """Executes the forward pass of the model.
979
-
980
- Args:
981
- input_ids: The input token IDs of shape [num_tokens].
982
- positions: The input position IDs of shape [num_tokens].
983
- kv_caches: The key and value caches. They can be None during the
984
- memory profiling at initialization.
985
- inputs_embeds: The input embeddings of shape [num_tokens,
986
- hidden_size]. It is used for multimodal models.
987
- """
988
-
989
- hidden_states = self.model(
990
- input_ids=input_ids,
991
- positions=positions,
992
- inputs_embeds=inputs_embeds,
993
- )
994
-
995
- return hidden_states
953
+ def reset_dynamo_cache(self):
954
+ if self.is_multimodal_model:
955
+ assert hasattr(self.model, "language_model")
956
+ compiled_model = self.model.language_model.model
957
+ else:
958
+ compiled_model = self.model.model
959
+ if isinstance(compiled_model, TorchCompileWrapperWithCustomDispatcher):
960
+ logger.info("Clear dynamo cache and cached dynamo bytecode.")
961
+ torch._dynamo.eval_frame.remove_from_cache(
962
+ compiled_model.original_code_object)
963
+ compiled_model.compiled_codes.clear()
964
965
def sample_from_hidden(
966
self,
@@ -1000,33 +968,30 @@ class ModelWrapperV1(nn.Module):
968
sampling_metadata: TPUSupportedSamplingMetadata,
969
) -> torch.Tensor:
970
"""
1003
- Sample with xla-friendly function. This function is to be traced
1004
- separately from `forward` for lighter compilation overhead.
1005
- """
971
+ Sample with xla-friendly function. This function is to be traced
972
+ separately for lighter compilation overhead.
973
+ """
974
# Tensor `sample_hidden_states` is of fixed pre-compiled size.
975
sample_hidden_states = \
976
hidden_states[sampling_metadata.indices_do_sample]
1009
- logits = self.compute_logits(sample_hidden_states)
977
+ # SamplingMetadata here for pruning output in LogitsProcessor, disabled.
978
+ logits = self.model.compute_logits(sample_hidden_states, None)
979
+
980
+ def sample(
981
+ logits: torch.Tensor,
982
+ sampling_metadata: TPUSupportedSamplingMetadata
983
+ ) -> SamplerOutput:
984
+ sampler_out = self.sampler(logits, sampling_metadata)
985
+ return sampler_out
986
+
987
# Optimized greedy sampling branch, tracing both paths in a single pass
988
# NOTE all_greedy is a scalar, this is just an optimized if/else.
1012
- out_tokens = torch.where(sampling_metadata.all_greedy,
1013
- torch.argmax(logits, dim=-1, keepdim=True),
1014
- self.sample(logits, sampling_metadata)\
1015
- .sampled_token_ids)
989
+ out_tokens = torch.where(
990
+ sampling_metadata.all_greedy,
991
+ torch.argmax(logits, dim=-1, keepdim=True),
992
+ sample(logits, sampling_metadata).sampled_token_ids)
993
return out_tokens
994
1018
- def compute_logits(self,
1019
- hidden_states: torch.Tensor) -> Optional[torch.Tensor]:
1020
- # SamplingMetadata here for pruning output in LogitsProcessor, disabled
1021
- logits = self.model.compute_logits(hidden_states, None)
1022
- return logits
1023
-
1024
- def get_multimodal_embeddings(self, *args, **kwargs):
1025
- return self.model.get_multimodal_embeddings(*args, **kwargs)
1026
-
1027
- def get_input_embeddings(self, *args, **kwargs):
1028
- return self.model.get_input_embeddings(*args, **kwargs)
1029
-
995
996
def _get_padded_number(n: int, multiple: int) -> int:
997
return ((n + multiple - 1) // multiple) * multiple
vllm/v1/worker/tpu_worker.py
+9
-3
@@ -157,13 +157,19 @@ class TPUWorker:
157
runner_kv_caches)
158
159
self.model_runner._dummy_run(
160
- runner_kv_caches,
161
- num_tokens=self.scheduler_config.max_num_batched_tokens,
162
- )
160
+ self.scheduler_config.max_num_batched_tokens)
161
162
# Synchronize before measuring the memory usage.
163
xm.wait_device_ops()
164
165
+ # During the profiling run, the model runs without KV cache. After
166
+ # the profiling run, the model always runs with KV cache. Here we clear
167
+ # the dynamo cache and cached bytecode to ensure the model always has
168
+ # one compiled bytecode. Having one FX graph/cached bytecode per
169
+ # compiled model is required for `support_torch_compile` decorator to
170
+ # skip dynamo guard.
171
+ self.model_runner.reset_dynamo_cache()
172
+
173
# Get the maximum amount of memory used by the model weights and
174
# intermediate activations.
175
m = xm.get_memory_info(self.device)