@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 4de7146351
Fork 0

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, 01:00 UTC

[V0 deprecation] Remove V0 HPU backend (#21131)

Signed-off-by: Woosuk Kwon <woosuk.kwon@berkeley.edu>

Woosuk Kwon committed Jul 17, 2025 at 16:37 UTC 4de7146351d67be0010b7007ba4da48462962153
27 files changed +10 -3926
docker/Dockerfile.hpu deleted
-21
@@ -1,21 +0,0 @@
1 -FROM vault.habana.ai/gaudi-docker/1.20.1/ubuntu22.04/habanalabs/pytorch-installer-2.6.0:latest
2 -
3 -COPY ./ /workspace/vllm
4 -
5 -WORKDIR /workspace/vllm
6 -
7 -RUN pip install -v -r requirements/hpu.txt
8 -
9 -ENV no_proxy=localhost,127.0.0.1
10 -ENV PT_HPU_ENABLE_LAZY_COLLECTIVES=true
11 -
12 -RUN VLLM_TARGET_DEVICE=hpu python3 setup.py install
13 -
14 -# install development dependencies (for testing)
15 -RUN python3 -m pip install -e tests/vllm_test_utils
16 -
17 -WORKDIR /workspace/
18 -
19 -RUN ln -s /workspace/vllm/tests && ln -s /workspace/vllm/examples && ln -s /workspace/vllm/benchmarks
20 -
21 -ENTRYPOINT ["python3", "-m", "vllm.entrypoints.openai.api_server"]
requirements/hpu.txt deleted
-12
@@ -1,12 +0,0 @@
1 -# Common dependencies
2 --r common.txt
3 -
4 -# Dependencies for HPU code
5 -ray
6 -triton==3.1.0
7 -pandas
8 -numpy==1.26.4
9 -tabulate
10 -setuptools>=77.0.3,<80.0.0
11 -setuptools-scm>=8
12 -vllm-hpu-extension @ git+https://github.com/HabanaAI/vllm-hpu-extension.git@f1f6624
setup.py
+2 -34
@@ -410,29 +410,6 @@ class repackage_wheel(build_ext):
410 package_data[package_name].append(file_name)
411
412
413 -def _is_hpu() -> bool:
414 - # if VLLM_TARGET_DEVICE env var was set explicitly, skip HPU autodetection
415 - if os.getenv("VLLM_TARGET_DEVICE", None) == VLLM_TARGET_DEVICE:
416 - return VLLM_TARGET_DEVICE == "hpu"
417 -
418 - # if VLLM_TARGET_DEVICE was not set explicitly, check if hl-smi succeeds,
419 - # and if it doesn't, check if habanalabs driver is loaded
420 - is_hpu_available = False
421 - try:
422 - out = subprocess.run(["hl-smi"], capture_output=True, check=True)
423 - is_hpu_available = out.returncode == 0
424 - except (FileNotFoundError, PermissionError, subprocess.CalledProcessError):
425 - if sys.platform.startswith("linux"):
426 - try:
427 - output = subprocess.check_output(
428 - 'lsmod | grep habanalabs | wc -l', shell=True)
429 - is_hpu_available = int(output) > 0
430 - except (ValueError, FileNotFoundError, PermissionError,
431 - subprocess.CalledProcessError):
432 - pass
433 - return is_hpu_available
434 -
435 -
413 def _no_device() -> bool:
414 return VLLM_TARGET_DEVICE == "empty"
415
@@ -440,7 +417,7 @@ def _no_device() -> bool:
417 def _is_cuda() -> bool:
418 has_cuda = torch.version.cuda is not None
419 return (VLLM_TARGET_DEVICE == "cuda" and has_cuda
443 - and not (_is_neuron() or _is_tpu() or _is_hpu()))
420 + and not (_is_neuron() or _is_tpu()))
421
422
423 def _is_hip() -> bool:
@@ -573,12 +550,6 @@ def get_vllm_version() -> str:
550 if neuron_version != MAIN_CUDA_VERSION:
551 neuron_version_str = neuron_version.replace(".", "")[:3]
552 version += f"{sep}neuron{neuron_version_str}"
576 - elif _is_hpu():
577 - # Get the Intel Gaudi Software Suite version
578 - gaudi_sw_version = str(get_gaudi_sw_version())
579 - if gaudi_sw_version != MAIN_CUDA_VERSION:
580 - gaudi_sw_version = gaudi_sw_version.replace(".", "")[:3]
581 - version += f"{sep}gaudi{gaudi_sw_version}"
553 elif _is_tpu():
554 version += f"{sep}tpu"
555 elif _is_cpu():
@@ -625,8 +596,6 @@ def get_requirements() -> list[str]:
596 requirements = _read_requirements("rocm.txt")
597 elif _is_neuron():
598 requirements = _read_requirements("neuron.txt")
628 - elif _is_hpu():
629 - requirements = _read_requirements("hpu.txt")
599 elif _is_tpu():
600 requirements = _read_requirements("tpu.txt")
601 elif _is_cpu():
@@ -635,8 +604,7 @@ def get_requirements() -> list[str]:
604 requirements = _read_requirements("xpu.txt")
605 else:
606 raise ValueError(
638 - "Unsupported platform, please use CUDA, ROCm, Neuron, HPU, "
639 - "or CPU.")
607 + "Unsupported platform, please use CUDA, ROCm, Neuron, or CPU.")
608 return requirements
609
610
vllm/_custom_ops.py
+1 -2
@@ -13,8 +13,7 @@ from vllm.scalar_type import ScalarType
13
14 logger = init_logger(__name__)
15
16 -if not current_platform.is_tpu() and not current_platform.is_hpu()\
17 - and not current_platform.is_xpu():
16 +if not current_platform.is_tpu() and not current_platform.is_xpu():
17 try:
18 import vllm._C
19 except ImportError as e:
vllm/attention/backends/hpu_attn.py deleted
-319
@@ -1,319 +0,0 @@
1 -# SPDX-License-Identifier: Apache-2.0
2 -# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 -
4 -###############################################################################
5 -# Copyright (C) 2024 Habana Labs, Ltd. an Intel Company
6 -###############################################################################
7 -
8 -from dataclasses import dataclass
9 -from typing import Any, Dict, List, Optional, Tuple, Type
10 -
11 -import torch
12 -import vllm_hpu_extension.kernels as kernels
13 -import vllm_hpu_extension.ops as ops
14 -from vllm_hpu_extension.flags import enabled_flags
15 -from vllm_hpu_extension.utils import Matmul, Softmax, VLLMKVCache
16 -
17 -from vllm.attention.backends.abstract import (AttentionBackend, AttentionImpl,
18 - AttentionLayer,
19 - AttentionMetadata, AttentionType,
20 - is_quantized_kv_cache)
21 -from vllm.attention.backends.utils import CommonAttentionState
22 -from vllm.attention.ops.hpu_paged_attn import (HPUPagedAttention,
23 - HPUPagedAttentionMetadata)
24 -from vllm.logger import init_logger
25 -
26 -logger = init_logger(__name__)
27 -
28 -
29 -class HPUAttentionBackend(AttentionBackend):
30 -
31 - @staticmethod
32 - def get_name() -> str:
33 - return "HPU_ATTN"
34 -
35 - @staticmethod
36 - def get_impl_cls() -> Type["HPUAttentionImpl"]:
37 - return HPUAttentionImpl
38 -
39 - @staticmethod
40 - def get_metadata_cls() -> Type["AttentionMetadata"]:
41 - return HPUAttentionMetadata
42 -
43 - @staticmethod
44 - def get_state_cls() -> Type["CommonAttentionState"]:
45 - return CommonAttentionState
46 -
47 - @staticmethod
48 - def get_kv_cache_shape(
49 - num_blocks: int,
50 - block_size: int,
51 - num_kv_heads: int,
52 - head_size: int,
53 - ) -> Tuple[int, ...]:
54 - return HPUPagedAttention.get_kv_cache_shape(num_blocks, block_size,
55 - num_kv_heads, head_size)
56 -
57 - @staticmethod
58 - def swap_blocks(
59 - src_kv_cache: torch.Tensor,
60 - dst_kv_cache: torch.Tensor,
61 - src_to_dsts: torch.Tensor,
62 - ) -> None:
63 - HPUPagedAttention.swap_blocks(src_kv_cache, dst_kv_cache, src_to_dsts)
64 -
65 - @staticmethod
66 - def copy_blocks(
67 - kv_caches: List[torch.Tensor],
68 - src_to_dsts: torch.Tensor,
69 - ) -> None:
70 - HPUPagedAttention.copy_blocks(kv_caches, src_to_dsts)
71 -
72 -
73 -@dataclass
74 -class HPUAttentionMetadata(HPUPagedAttentionMetadata, AttentionMetadata):
75 - """Metadata for HPUAttentionbackend."""
76 - # Currently, input sequences can only contain all prompts
77 - # or all decoding. True if all sequences are prompts.
78 - is_prompt: bool
79 - attn_bias: Optional[torch.Tensor]
80 - seq_lens_tensor: Optional[torch.Tensor]
81 - context_lens_tensor: Optional[torch.Tensor]
82 -
83 -
84 -class HPUAttentionImpl(AttentionImpl, torch.nn.Module):
85 - """
86 - If the input tensors contain prompt tokens, the layout is as follows:
87 - |<--------------- num_prefill_tokens ----------------->|
88 - |<--prefill_0-->|<--prefill_1-->|...|<--prefill_N-1--->|
89 -
90 - Otherwise, the layout is as follows:
91 - |<----------------- num_decode_tokens ------------------>|
92 - |<--decode_0-->|..........|<--decode_M-1-->|<--padding-->|
93 -
94 - Generation tokens can contain padding when cuda-graph is used.
95 - Currently, prompt tokens don't contain any padding.
96 -
97 - The prompts might have different lengths, while the generation tokens
98 - always have length 1.
99 - """
100 -
101 - def __init__(
102 - self,
103 - num_heads: int,
104 - head_size: int,
105 - scale: float,
106 - num_kv_heads: int,
107 - alibi_slopes: Optional[List[float]],
108 - sliding_window: Optional[int],
109 - kv_cache_dtype: str,
110 - blocksparse_params: Optional[Dict[str, Any]] = None,
111 - max_seq_len: int = 4096,
112 - attn_type: str = AttentionType.DECODER,
113 - kv_sharing_target_layer_name: Optional[str] = None,
114 - use_irope: bool = False,
115 - ) -> None:
116 - super(AttentionImpl, self).__init__()
117 - if kv_sharing_target_layer_name is not None:
118 - raise NotImplementedError("KV sharing is not supported in V0 "
119 - "HPU_ATTN backend.")
120 - if use_irope:
121 - logger.warning_once(
122 - "Using irope in HPU is not supported yet, it will fall back "
123 - "to global attention for long context.")
124 - self.kv_cache_dtype = kv_cache_dtype
125 - self.num_heads = num_heads
126 - self.head_size = head_size
127 - self.scale = float(scale)
128 - self.matmul_qk = Matmul()
129 - self.softmax = Softmax()
130 - self.matmul_av = Matmul()
131 - self.batch2block_matmul = Matmul()
132 - self.block2batch_matmul = Matmul()
133 - self.k_cache = VLLMKVCache()
134 - self.v_cache = VLLMKVCache()
135 - self.fused_scaled_dot_product_attention = kernels.fsdpa()
136 -
137 - self.prefill_impl = 'naive'
138 - if "flex_attention" in enabled_flags():
139 - self.prefill_impl = 'flex'
140 - if "fsdpa" in enabled_flags():
141 - assert alibi_slopes is None, \
142 - 'Prefill with FusedSDPA not supported with alibi slopes!'
143 - self.prefill_impl = 'fsdpa'
144 -
145 - self.num_kv_heads = num_heads if num_kv_heads is None else num_kv_heads
146 - self.sliding_window = sliding_window
147 - self.alibi_slopes = alibi_slopes
148 - if alibi_slopes is not None:
149 - alibi_slopes_tensor = torch.tensor(alibi_slopes,
150 - dtype=torch.bfloat16)
151 - self.alibi_slopes = alibi_slopes_tensor
152 - self.num_queries_per_kv = self.num_heads // self.num_kv_heads
153 -
154 - if self.prefill_impl == 'fsdpa':
155 - assert alibi_slopes is None, \
156 - 'Prefill with FusedSDPA not supported with alibi slopes!'
157 -
158 - supported_head_sizes = HPUPagedAttention.get_supported_head_sizes()
159 - if head_size not in supported_head_sizes:
160 - raise ValueError(
161 - f"Head size {head_size} is not supported by PagedAttention. "
162 - f"Supported head sizes are: {supported_head_sizes}.")
163 -
164 - self.attn_type = attn_type
165 - if self.attn_type != AttentionType.DECODER:
166 - raise NotImplementedError("Encoder self-attention and "
167 - "encoder/decoder cross-attention "
168 - "are not implemented for "
169 - "HPUAttentionImpl")
170 -
171 - if is_quantized_kv_cache(self.kv_cache_dtype):
172 - raise NotImplementedError(
173 - "HPUAttention with FP8 KV cache not yet supported")
174 -
175 - def forward(
176 - self,
177 - layer: AttentionLayer,
178 - query: torch.Tensor,
179 - key: torch.Tensor,
180 - value: torch.Tensor,
181 - kv_cache: torch.Tensor,
182 - attn_metadata: HPUAttentionMetadata,
183 - output: Optional[torch.Tensor] = None,
184 - output_scale: Optional[torch.Tensor] = None,
185 - ) -> torch.Tensor:
186 - """Forward pass with xFormers and PagedAttention.
187 -
188 - Args:
189 - query: shape = [num_tokens, num_heads * head_size]
190 - key: shape = [num_tokens, num_kv_heads * head_size]
191 - value: shape = [num_tokens, num_kv_heads * head_size]
192 - kv_cache = [2, num_blocks, block_size * num_kv_heads * head_size]
193 - attn_metadata: Metadata for attention.
194 - Returns:
195 - shape = [num_tokens, num_heads * head_size]
196 - """
197 - if output_scale is not None:
198 - raise NotImplementedError(
199 - "fused output quantization is not yet supported"
200 - " for HPUAttentionImpl")
201 -
202 - batch_size, seq_len, hidden_size = query.shape
203 - _, seq_len_kv, _ = key.shape
204 -
205 - key = key.view(-1, self.num_kv_heads, self.head_size)
206 - value = value.view(-1, self.num_kv_heads, self.head_size)
207 - block_indices = attn_metadata.block_indices
208 - block_offsets = attn_metadata.block_offsets
209 - key_cache = None
210 - value_cache = None
211 - if attn_metadata.is_prompt and self.attn_type \
212 - is not AttentionType.ENCODER_ONLY:
213 - key = key.unflatten(0, (block_indices.size(0), -1))
214 - value = value.unflatten(0, (block_indices.size(0), -1))
215 - if kv_cache is not None and isinstance(kv_cache, tuple):
216 - key_cache, value_cache = HPUPagedAttention.split_kv_cache(
217 - kv_cache, self.num_kv_heads, self.head_size)
218 -
219 - # Reshape the input keys and values and store them in the cache.
220 - # If kv_cache is not provided, the new key and value tensors are
221 - # not cached. This happens during the initial memory profiling run.
222 - key_cache = self.k_cache(key, key_cache, block_indices,
223 - block_offsets)
224 - value_cache = self.v_cache(value, value_cache, block_indices,
225 - block_offsets)
226 -
227 - if attn_metadata.is_prompt:
228 - # Prompt run.
229 - query_shape = (batch_size, seq_len, self.num_heads, self.head_size)
230 - kv_shape = (batch_size, seq_len_kv, self.num_kv_heads,
231 - self.head_size)
232 -
233 - attn_bias = attn_metadata.attn_bias
234 - if attn_bias is not None and self.alibi_slopes is not None:
235 - position_bias = _make_alibi_bias(self.alibi_slopes,
236 - self.num_kv_heads,
237 - attn_bias.dtype,
238 - attn_bias.shape[-1])
239 - attn_bias = attn_bias.tile((1, self.num_kv_heads, 1, 1))
240 - attn_bias.add_(position_bias)
241 -
242 - block_list = attn_metadata.block_list if attn_metadata \
243 - and attn_metadata.block_list is not None else None
244 -
245 - out = ops.prompt_attention(
246 - impl=self.prefill_impl,
247 - query=query.view(query_shape),
248 - key=key.view(kv_shape),
249 - value=value.view(kv_shape),
250 - is_causal=True,
251 - attn_bias=attn_bias,
252 - valid_seq_lengths=attn_metadata.seq_lens_tensor,
253 - **self.common_attention_args(block_list, key_cache,
254 - value_cache))
255 - output = out.reshape(batch_size, seq_len, hidden_size)
256 - else:
257 - # Decoding run.
258 - output = HPUPagedAttention.forward_decode(
259 - query=query,
260 - block_mapping=attn_metadata.block_mapping,
261 - block_bias=attn_metadata.attn_bias,
262 - block_groups=attn_metadata.block_groups,
263 - **self.common_attention_args(attn_metadata.block_list,
264 - key_cache, value_cache))
265 - # Reshape the output tensor.
266 - return output.view(batch_size, seq_len, hidden_size)
267 -
268 - def common_attention_args(self,
269 - block_list=None,
270 - key_cache=None,
271 - value_cache=None):
272 - fsdpa_op = self.fused_scaled_dot_product_attention.apply \
273 - if self.fused_scaled_dot_product_attention is not None else None
274 - return {
275 - 'scale': self.scale,
276 - 'matmul_qk_op': self.matmul_qk,
277 - 'matmul_av_op': self.matmul_av,
278 - 'batch2block_matmul_op': self.batch2block_matmul,
279 - 'block2batch_matmul_op': self.block2batch_matmul,
280 - 'fsdpa_op': fsdpa_op,
281 - 'keys_fetch_func': self.k_cache.fetch_from_cache,
282 - 'values_fetch_func': self.v_cache.fetch_from_cache,
283 - 'softmax_op': self.softmax,
284 - 'block_list': block_list,
285 - 'key_cache': key_cache,
286 - 'value_cache': value_cache,
287 - }
288 -
289 -
290 -def _make_alibi_bias(
291 - alibi_slopes: torch.Tensor,
292 - num_kv_heads: int,
293 - dtype: torch.dtype,
294 - seq_len: int,
295 -) -> torch.Tensor:
296 - bias = torch.arange(seq_len, dtype=dtype)
297 - # NOTE(zhuohan): HF uses
298 - # `bias = bias[None, :].repeat(seq_len, 1)`
299 - # here. We find that both biases give the same results, but
300 - # the bias below more accurately follows the original ALiBi
301 - # paper.
302 - # Calculate a matrix where each element represents ith element- jth
303 - # element.
304 - bias = bias[None, :] - bias[:, None]
305 -
306 - padded_len = (seq_len + 7) // 8 * 8
307 - num_heads = alibi_slopes.shape[0]
308 - bias = torch.empty(
309 - 1, # batch size
310 - num_heads,
311 - seq_len,
312 - padded_len,
313 - device=alibi_slopes.device,
314 - dtype=dtype,
315 - )[:, :, :, :seq_len].copy_(bias)
316 - bias.mul_(alibi_slopes[:, None, None])
317 - if num_heads != num_kv_heads:
318 - bias = bias.unflatten(1, (num_kv_heads, num_heads // num_kv_heads))
319 - return bias
vllm/attention/ops/hpu_paged_attn.py deleted
-88
@@ -1,88 +0,0 @@
1 -# SPDX-License-Identifier: Apache-2.0
2 -# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 -
4 -###############################################################################
5 -# Copyright (C) 2024 Habana Labs, Ltd. an Intel Company
6 -###############################################################################
7 -
8 -from dataclasses import dataclass
9 -from typing import List, Optional, Tuple
10 -
11 -import torch
12 -from vllm_hpu_extension import cache_ops, ops
13 -
14 -# Should be the same as PARTITION_SIZE in `paged_attention_v2_launcher`.
15 -_PARTITION_SIZE = 512
16 -
17 -
18 -@dataclass
19 -class HPUPagedAttentionMetadata:
20 - """Metadata for PagedAttention."""
21 - block_list: Optional[torch.Tensor]
22 - block_mapping: Optional[torch.Tensor]
23 - block_usage: Optional[torch.Tensor]
24 - block_indices: Optional[torch.Tensor]
25 - block_offsets: Optional[torch.Tensor]
26 - block_groups: Optional[torch.Tensor]
27 -
28 -
29 -class HPUPagedAttention:
30 -
31 - @staticmethod
32 - def get_supported_head_sizes() -> List[int]:
33 - return [64, 80, 96, 112, 128, 256]
34 -
35 - @staticmethod
36 - def get_kv_cache_shape(
37 - num_blocks: int,
38 - block_size: int,
39 - num_kv_heads: int,
40 - head_size: int,
41 - ) -> Tuple[int, ...]:
42 - return (num_blocks, block_size, num_kv_heads, head_size)
43 -
44 - @staticmethod
45 - def split_kv_cache(
46 - kv_cache: torch.Tensor,
47 - num_kv_heads: int,
48 - head_size: int,
49 - ) -> Tuple[torch.Tensor, torch.Tensor]:
50 - key_cache = kv_cache[0]
51 - value_cache = kv_cache[1]
52 - return key_cache, value_cache
53 -
54 - @staticmethod
55 - def write_to_paged_cache(key: torch.Tensor, value: torch.Tensor,
56 - key_cache: torch.Tensor,
57 - value_cache: torch.Tensor,
58 - slot_mapping: torch.Tensor, kv_cache_dtype: str,
59 - is_prompt: bool) -> None:
60 - cache_ops.reshape_and_cache(key, value, key_cache, value_cache,
61 - slot_mapping, kv_cache_dtype, is_prompt)
62 -
63 - @staticmethod
64 - def forward_decode(**kwargs) -> torch.Tensor:
65 - return ops.flat_pa(**kwargs)
66 -
67 - @staticmethod
68 - def swap_blocks(
69 - src_kv_cache: Tuple[torch.Tensor, torch.Tensor],
70 - dst_kv_cache: Tuple[torch.Tensor, torch.Tensor],
71 - src_to_dsts: torch.Tensor,
72 - ) -> None:
73 - src_key_cache = src_kv_cache[0]
74 - dst_key_cache = dst_kv_cache[0]
75 - cache_ops.swap_blocks(src_key_cache, dst_key_cache, src_to_dsts)
76 -
77 - src_value_cache = src_kv_cache[1]
78 - dst_value_cache = dst_kv_cache[1]
79 - cache_ops.swap_blocks(src_value_cache, dst_value_cache, src_to_dsts)
80 -
81 - @staticmethod
82 - def copy_blocks(
83 - kv_caches: List[Tuple[torch.Tensor, torch.Tensor]],
84 - src_to_dsts: torch.Tensor,
85 - ) -> None:
86 - key_caches = [kv_cache[0] for kv_cache in kv_caches]
87 - value_caches = [kv_cache[1] for kv_cache in kv_caches]
88 - cache_ops.copy_blocks(key_caches, value_caches, src_to_dsts)
vllm/config.py
+1 -1
@@ -2452,7 +2452,7 @@ class SchedulerConfig:
2452 return self.num_scheduler_steps > 1
2453
2454
2455 -Device = Literal["auto", "cuda", "neuron", "cpu", "tpu", "xpu", "hpu"]
2455 +Device = Literal["auto", "cuda", "neuron", "cpu", "tpu", "xpu"]
2456
2457
2458 @config
vllm/core/block/cpu_gpu_block_allocator.py
+1 -3
@@ -7,7 +7,6 @@ from vllm.core.block.interfaces import (Block, BlockAllocator, BlockId,
7 DeviceAwareBlockAllocator)
8 from vllm.core.block.naive_block import NaiveBlock, NaiveBlockAllocator
9 from vllm.core.block.prefix_caching_block import PrefixCachingBlockAllocator
10 -from vllm.platforms import current_platform
10 from vllm.utils import Device
11
12
@@ -56,8 +55,7 @@ class CpuGpuBlockAllocator(DeviceAwareBlockAllocator):
55 - The block IDs are assigned contiguously, with GPU block IDs coming
56 before CPU block IDs.
57 """
59 - # For HPU, block id 0 is used only for padding
60 - reserved_blocks = 1 if current_platform.is_hpu() else 0
58 + reserved_blocks = 0
59 block_ids = list(
60 range(reserved_blocks, num_gpu_blocks + num_cpu_blocks))
61 num_gpu_blocks -= reserved_blocks
vllm/distributed/device_communicators/hpu_communicator.py deleted
-46
@@ -1,46 +0,0 @@
1 -# SPDX-License-Identifier: Apache-2.0
2 -# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 -
4 -import torch
5 -import torch.distributed as dist
6 -
7 -from vllm.platforms import current_platform
8 -
9 -from .base_device_communicator import DeviceCommunicatorBase
10 -
11 -if current_platform.is_hpu():
12 - import habana_frameworks.torch as htorch # noqa: F401
13 -
14 -
15 -class HpuCommunicator(DeviceCommunicatorBase):
16 -
17 - def all_reduce(self, input_: torch.Tensor) -> torch.Tensor:
18 - # FIXME(kzawora): this is a workaround for a bug in Habana PT bridge
19 - # occurring when PT_HPU_ENABLE_LAZY_COLLECTIVES=true env var is used
20 - # (which is required for tensor parallel HPUGraph inference)
21 - htorch.core.mark_step()
22 - dist.all_reduce(input_, group=self.device_group)
23 - return input_
24 -
25 - def all_gather(self, input_: torch.Tensor, dim: int = -1) -> torch.Tensor:
26 - world_size = self.world_size
27 - if dim < 0:
28 - # Convert negative dim to positive.
29 - dim += input_.dim()
30 - input_size = input_.size()
31 - # Allocate output tensor.
32 - output_tensor = torch.empty((world_size, ) + input_size,
33 - dtype=input_.dtype,
34 - device=input_.device)
35 - # All-gather.
36 - htorch.core.mark_step()
37 - dist.all_gather_into_tensor(output_tensor,
38 - input_,
39 - group=self.device_group)
40 - # Reshape
41 - output_tensor = output_tensor.movedim(0, dim)
42 - output_tensor = output_tensor.reshape(input_size[:dim] +
43 - (world_size *
44 - input_size[dim], ) +
45 - input_size[dim + 1:])
46 - return output_tensor
vllm/engine/arg_utils.py
+2 -3
@@ -1365,9 +1365,8 @@ class EngineArgs:
1365 supported = False
1366 if current_platform.is_rocm() or (
1367 current_platform.is_cuda()
1368 - and current_platform.is_device_capability(100)) or (
1369 - current_platform.device_name
1370 - == "hpu"): # handle hpu also for OOT platform
1368 + and current_platform.is_device_capability(100)
1369 + ): # handle hpu also for OOT platform
1370 supported = True
1371 elif fp8_attention and will_use_fa:
1372 from vllm.attention.utils.fa_utils import (
vllm/envs.py
-15
@@ -106,8 +106,6 @@ if TYPE_CHECKING:
106 VLLM_RAY_PER_WORKER_GPUS: float = 1.0
107 VLLM_RAY_BUNDLE_INDICES: str = ""
108 VLLM_CUDART_SO_PATH: Optional[str] = None
109 - VLLM_USE_HPU_CONTIGUOUS_CACHE_FETCH: bool = True
110 - VLLM_HPU_USE_DELAYED_SAMPLING: bool = False
109 VLLM_DP_RANK: int = 0
110 VLLM_DP_RANK_LOCAL: int = -1
111 VLLM_DP_SIZE: int = 1
@@ -780,19 +778,6 @@ environment_variables: dict[str, Callable[[], Any]] = {
778 "VLLM_CUDART_SO_PATH":
779 lambda: os.getenv("VLLM_CUDART_SO_PATH", None),
780
783 - # Contiguous cache fetching to avoid using costly gather operation on
784 - # Gaudi3. This is only applicable to HPU contiguous cache. If set to true,
785 - # contiguous cache fetch will be used.
786 - "VLLM_USE_HPU_CONTIGUOUS_CACHE_FETCH":
787 - lambda: os.environ.get("VLLM_CONTIGUOUS_PA", "true").lower() in
788 - ("1", "true"),
789 -
790 - # Use delayed sampling for HPU to reduce host cpu overhead
791 - # between each step.
792 - "VLLM_HPU_USE_DELAYED_SAMPLING":
793 - lambda: os.environ.get("VLLM_DELAYED_SAMPLING", "false").lower() in
794 - ("1", "true"),
795 -
781 # Rank of the process in the data parallel setting
782 "VLLM_DP_RANK":
783 lambda: int(os.getenv("VLLM_DP_RANK", "0")),
vllm/lora/layers.py
-4
@@ -1164,10 +1164,6 @@ class LogitsProcessorWithLoRA(BaseLayerWithLoRA):
1164 posinf=pos_inf,
1165 neginf=neg_inf))
1166
1167 - # HPU needs special handling to prune out dummy samples.
1168 - if current_platform.is_hpu():
1169 - lora_logits = lora_logits[:logits.shape[0], :]
1170 -
1167 logits[:,
1168 self.base_layer.org_vocab_size:self.base_layer.org_vocab_size +
1169 lora_logits.shape[1]] = lora_logits
vllm/lora/punica_wrapper/punica_hpu.py deleted
-145
@@ -1,145 +0,0 @@
1 -# SPDX-License-Identifier: Apache-2.0
2 -# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 -
4 -from typing import TYPE_CHECKING, Optional, Union, final
5 -
6 -import torch
7 -from vllm_hpu_extension.ops import (dispatch_bgmv_embedding,
8 - dispatch_bgmv_linear)
9 -
10 -from .punica_base import PunicaWrapperBase
11 -from .utils import convert_mapping
12 -
13 -if TYPE_CHECKING:
14 - # avoid circuit import
15 - from vllm.lora.layers import LoRAMapping
16 - from vllm.lora.models import LongContextLoRAContext
17 -
18 -
19 -@final
20 -class PunicaWrapperHPU(PunicaWrapperBase):
21 -
22 - def __init__(self, max_num_batched_tokens: int, max_batches: int,
23 - device: Union[torch.device, str], **kwargs):
24 - # Increasing max_num_batched_tokens by 3x to handle increase in
25 - # tensor size due to padding.
26 - PunicaWrapperBase.__init__(self, 3 * max_num_batched_tokens,
27 - max_batches, device)
28 -
29 - def _update_base_metadata(
30 - self,
31 - mapping: "LoRAMapping",
32 - lora_index_to_id: list[Optional[int]],
33 - max_loras: int,
34 - vocab_size: int,
35 - extra_vocab_size: int,
36 - long_lora_context: Optional["LongContextLoRAContext"] = None,
37 - ):
38 - (
39 - base_indices,
40 - sampler_indices,
41 - sampler_indices_padded,
42 - embeddings_indices,
43 - long_lora_offsets_tensor,
44 - indices_len,
45 - ) = convert_mapping(mapping, lora_index_to_id, max_loras, vocab_size,
46 - extra_vocab_size, self.device, None)
47 - # Updating each element in `long_lora_offsets` with `lora_offset` slows
48 - # down perf in HPU due to a series of `strided_insert` ops during lazy
49 - # graph accumulation. Hence HPU appends `lora_offset` to a list and
50 - # converts it to a tensor only after it is ready.
51 - if long_lora_context:
52 - index_mapping_indices: list[int] = list(
53 - mapping.index_mapping).copy()
54 - long_lora_offsets: list[int] = []
55 - for i in range(len(index_mapping_indices)):
56 - lora_offset: int = long_lora_context.offsets_by_lora_id.get(
57 - index_mapping_indices[i], 0)
58 - long_lora_offsets.append(lora_offset)
59 - long_lora_offsets_tensor = torch.tensor(long_lora_offsets,
60 - device=self.device,
61 - dtype=torch.long)
62 - indices_len[-1] = long_lora_offsets_tensor.shape[-1]
63 -
64 - self._token_lora_indices[:base_indices.shape[0]].copy_(base_indices)
65 - self._sampler_indices[:sampler_indices.shape[0]].copy_(sampler_indices)
66 - self._sampler_indices_padded[:sampler_indices_padded.shape[0]].copy_(
67 - sampler_indices_padded)
68 - self._embeddings_indices[:embeddings_indices.
69 - shape[0], :embeddings_indices.shape[1]].copy_(
70 - embeddings_indices)
71 - if long_lora_offsets_tensor is not None:
72 - self._long_lora_indices[:long_lora_offsets_tensor.shape[0]].copy_(
73 - long_lora_offsets_tensor)
74 - else:
75 - self._long_lora_indices.zero_()
76 - self.indices_len[:] = indices_len
77 -
78 - def add_lora_embedding(self,
79 - y: torch.Tensor,
80 - x: torch.Tensor,
81 - lora_b_stacked: torch.Tensor,
82 - add_inputs: bool = True,
83 - **kwargs) -> None:
84 - dispatch_bgmv_embedding(y, x, lora_b_stacked, 0)
85 -
86 - def add_lora_linear(self,
87 - y: torch.Tensor,
88 - x: torch.Tensor,
89 - lora_a_stacked: tuple[torch.Tensor, ...],
90 - lora_b_stacked: tuple[torch.Tensor, ...],
91 - lora_bias_stacked: Optional[tuple[torch.Tensor, ...]],
92 - scale: float,
93 - output_slices: tuple[int, ...],
94 - *,
95 - buffer: Optional[tuple[torch.Tensor, ...]] = None,
96 - **kwargs) -> None:
97 - y_org = y
98 - x = x.view(-1, x.shape[-1])
99 - y = y.view(-1, y.shape[-1])
100 - offset_left = 0
101 -
102 - for slice_idx in range(len(output_slices)):
103 - dispatch_bgmv_linear(
104 - y[:, offset_left:offset_left + output_slices[slice_idx]], x,
105 - lora_a_stacked[slice_idx], lora_b_stacked[slice_idx], 0, scale)
106 - offset_left += output_slices[slice_idx]
107 - y = y.view_as(y_org)
108 -
109 - def add_lora_logits(self,
110 - y: torch.Tensor,
111 - x: torch.Tensor,
112 - lora_a_stacked: torch.Tensor,
113 - lora_b_stacked: torch.Tensor,
114 - scale,
115 - *,
116 - buffer: Optional[torch.Tensor] = None,
117 - **kwargs) -> None:
118 - y_org = y
119 - y = y.view(-1, y.shape[-1])
120 - x = x.view(-1, x.shape[-1])
121 - dispatch_bgmv_linear(y, x, lora_a_stacked, lora_b_stacked, 0, scale)
122 - y = y.view_as(y_org)
123 -
124 - def add_shrink(
125 - self,
126 - y: Union[tuple[torch.Tensor, ...], torch.Tensor],
127 - x: torch.Tensor,
128 - lora_a_stacked: tuple[torch.Tensor, ...],
129 - scale: float,
130 - **kwargs,
131 - ) -> None:
132 - raise NotImplementedError
133 -
134 - def add_expand(
135 - self,
136 - y: torch.Tensor,
137 - x: Union[tuple[torch.Tensor, ...], torch.Tensor],
138 - lora_b_stacked: tuple[torch.Tensor, ...],
139 - lora_bias_stacked: Optional[tuple[torch.Tensor, ...]],
140 - output_slices: tuple[int, ...],
141 - offset_start: int = 0,
142 - add_inputs=True,
143 - **kwargs,
144 - ) -> None:
145 - raise NotImplementedError
vllm/model_executor/custom_op.py
-7
@@ -73,11 +73,6 @@ class CustomOp(nn.Module):
73 # NOTE(woosuk): This is a placeholder for future extensions.
74 return self.forward_native(*args, **kwargs)
75
76 - def forward_hpu(self, *args, **kwargs):
77 - # By default, we assume that Gaudi ops are compatible with the
78 - # PyTorch-native implementation.
79 - return self.forward_native(*args, **kwargs)
80 -
76 def forward_neuron(self, *args, **kwargs):
77 # By default, we assume that Neuron ops are compatible with the
78 # PyTorch-native implementation.
@@ -106,8 +101,6 @@ class CustomOp(nn.Module):
101 return self.forward_hip
102 elif current_platform.is_cpu():
103 return self.forward_cpu
109 - elif current_platform.is_hpu():
110 - return self.forward_hpu
104 elif current_platform.is_tpu():
105 return self.forward_tpu
106 elif current_platform.is_xpu():
vllm/model_executor/layers/fused_moe/layer.py
-36
@@ -475,39 +475,6 @@ class UnquantizedFusedMoEMethod(FusedMoEMethodBase, CustomOp):
475 activation,
476 )
477
478 - def forward_hpu(
479 - self,
480 - layer: torch.nn.Module,
481 - x: torch.Tensor,
482 - use_grouped_topk: bool,
483 - top_k: int,
484 - router_logits: torch.Tensor,
485 - renormalize: bool,
486 - topk_group: Optional[int] = None,
487 - num_expert_group: Optional[int] = None,
488 - global_num_experts: int = -1,
489 - expert_map: Optional[torch.Tensor] = None,
490 - custom_routing_function: Optional[Callable] = None,
491 - scoring_func: str = "softmax",
492 - e_score_correction_bias: Optional[torch.Tensor] = None,
493 - apply_router_weight_on_input: bool = False,
494 - activation: str = "silu",
495 - ) -> torch.Tensor:
496 - assert not use_grouped_topk
497 - assert num_expert_group is None
498 - assert topk_group is None
499 - assert custom_routing_function is None
500 - assert layer is not None
501 - assert apply_router_weight_on_input is False
502 - if scoring_func != "softmax":
503 - raise NotImplementedError(
504 - "Only softmax scoring function is supported for HPU.")
505 - if e_score_correction_bias is not None:
506 - raise NotImplementedError(
507 - "Expert score correction bias is not supported for HPU.")
508 - return layer.hpu_fused_moe(x, layer.w13_weight, layer.w2_weight,
509 - router_logits, top_k)
510 -
478 def forward_tpu(
479 self,
480 layer: torch.nn.Module,
@@ -716,9 +683,6 @@ class FusedMoE(torch.nn.Module):
683 if self.scoring_func != "softmax" and not self.use_grouped_topk:
684 raise ValueError("Only softmax scoring function is supported for "
685 "non-grouped topk.")
719 - if current_platform.is_hpu():
720 - from vllm_hpu_extension.ops import DynamicFusedMOE
721 - self.hpu_fused_moe = DynamicFusedMOE(self.global_num_experts)
686
687 if vllm_config.model_config is not None:
688 model_dtype = vllm_config.model_config.dtype
vllm/model_executor/layers/layernorm.py
-20
@@ -170,26 +170,6 @@ class RMSNorm(CustomOp):
170 else:
171 return norm_func(x, self.weight.data, self.variance_epsilon)
172
173 - def forward_hpu(
174 - self,
175 - x: torch.Tensor,
176 - residual: Optional[torch.Tensor] = None,
177 - ) -> Union[torch.Tensor, tuple[torch.Tensor, torch.Tensor]]:
178 - from vllm_hpu_extension.kernels import rms_norm
179 - HPUFusedRMSNorm = rms_norm()
180 - if HPUFusedRMSNorm is None:
181 - return self.forward_native(x, residual)
182 - if residual is not None:
183 - orig_shape = x.shape
184 - residual += x.view(residual.shape)
185 - # Note: HPUFusedRMSNorm requires 3D tensors as inputs
186 - x = HPUFusedRMSNorm.apply(residual, self.weight,
187 - self.variance_epsilon)
188 - return x.view(orig_shape), residual
189 -
190 - x = HPUFusedRMSNorm.apply(x, self.weight, self.variance_epsilon)
191 - return x
192 -
173 def forward_xpu(
174 self,
175 x: torch.Tensor,
vllm/model_executor/layers/rotary_embedding.py
-58
@@ -229,64 +229,6 @@ class RotaryEmbedding(CustomOp):
229 self.cos_sin_cache, self.is_neox_style)
230 return query, key
231
232 - def forward_hpu(
233 - self,
234 - positions: torch.Tensor,
235 - query: torch.Tensor,
236 - key: Optional[torch.Tensor] = None,
237 - offsets: Optional[torch.Tensor] = None,
238 - ) -> tuple[torch.Tensor, Optional[torch.Tensor]]:
239 - from habana_frameworks.torch.hpex.kernels import (
240 - RotaryPosEmbeddingMode, apply_rotary_pos_emb)
241 - if offsets is not None:
242 - offsets = offsets.view(positions.shape[0], -1)
243 - positions = positions + offsets
244 - positions = positions.flatten()
245 - num_tokens = positions.shape[0]
246 - cos_sin = self.cos_sin_cache.index_select(0, positions).view(
247 - num_tokens, 1, -1)
248 - cos, sin = cos_sin.chunk(2, dim=-1)
249 - # HPU RoPE kernel requires hidden dimension for cos and sin to be equal
250 - # to query hidden dimension, so the original tensors need to be
251 - # expanded
252 - # GPT-NeoX kernel requires position_ids = None, offset, mode = BLOCKWISE
253 - # and expansion of cos/sin tensors via concatenation
254 - # GPT-J kernel requires position_ids = None, offset = 0, mode = PAIRWISE
255 - # and expansion of cos/sin tensors via repeat_interleave
256 - rope_mode: RotaryPosEmbeddingMode
257 - if self.is_neox_style:
258 - rope_mode = RotaryPosEmbeddingMode.BLOCKWISE
259 - cos = torch.cat((cos, cos), dim=-1)
260 - sin = torch.cat((sin, sin), dim=-1)
261 - else:
262 - rope_mode = RotaryPosEmbeddingMode.PAIRWISE
263 - sin = torch.repeat_interleave(sin,
264 - 2,
265 - dim=-1,
266 - output_size=cos_sin.shape[-1])
267 - cos = torch.repeat_interleave(cos,
268 - 2,
269 - dim=-1,
270 - output_size=cos_sin.shape[-1])
271 -
272 - query_shape = query.shape
273 - query = query.view(num_tokens, -1, self.head_size)
274 - query_rot = query[..., :self.rotary_dim]
275 - query_pass = query[..., self.rotary_dim:]
276 - query_rot = apply_rotary_pos_emb(query_rot, cos, sin, None, 0,
277 - rope_mode)
278 - query = torch.cat((query_rot, query_pass), dim=-1).reshape(query_shape)
279 -
280 - if key is not None:
281 - key_shape = key.shape
282 - key = key.view(num_tokens, -1, self.head_size)
283 - key_rot = key[..., :self.rotary_dim]
284 - key_pass = key[..., self.rotary_dim:]
285 - key_rot = apply_rotary_pos_emb(key_rot, cos, sin, None, 0,
286 - rope_mode)
287 - key = torch.cat((key_rot, key_pass), dim=-1).reshape(key_shape)
288 - return query, key
289 -
232 def forward_neuron(
233 self,
234 positions: torch.Tensor,
vllm/model_executor/layers/vocab_parallel_embedding.py
+2 -14
@@ -388,20 +388,8 @@ class VocabParallelEmbedding(torch.nn.Module):
388
389 # Copy the data. Select chunk corresponding to current shard.
390 loaded_weight = loaded_weight.narrow(output_dim, start_idx, shard_size)
391 -
392 - if current_platform.is_hpu():
393 - # FIXME(kzawora): Weight copy with slicing bugs out on Gaudi here,
394 - # so we're using a workaround. Remove this when fixed in
395 - # HPU PT bridge.
396 - padded_weight = torch.cat([
397 - loaded_weight,
398 - torch.zeros(param.shape[0] - loaded_weight.shape[0],
399 - *loaded_weight.shape[1:])
400 - ])
401 - param.data.copy_(padded_weight)
402 - else:
403 - param[:loaded_weight.shape[0]].data.copy_(loaded_weight)
404 - param[loaded_weight.shape[0]:].data.fill_(0)
391 + param[:loaded_weight.shape[0]].data.copy_(loaded_weight)
392 + param[loaded_weight.shape[0]:].data.fill_(0)
393
394 def forward(self, input_):
395 if self.tp_size > 1:
vllm/model_executor/model_loader/bitsandbytes_loader.py
+1 -10
@@ -199,10 +199,6 @@ class BitsAndBytesModelLoader(BaseModelLoader):
199
200 if self.pre_quant:
201 if self.load_8bit:
202 - if current_platform.is_hpu():
203 - raise ValueError(
204 - "currently hpu supports 4bit quantization only")
205 -
202 return self._quantized_8bit_generator(
203 hf_weights_files, use_safetensors,
204 quant_state_dict), quant_state_dict
@@ -306,10 +302,6 @@ class BitsAndBytesModelLoader(BaseModelLoader):
302 in temp_state_dict):
303 quant_state = _parse_quant_state(mapped_weight_name,
304 temp_state_dict)
309 - if current_platform.is_hpu():
310 - assert quant_state.quant_type == "nf4", (
311 - "currently hpu supports nf4 quant_type only")
312 -
305 quant_state_dict[mapped_weight_name] = quant_state
306 yield org_weight_name, weight_tensor
307 else:
@@ -380,8 +372,7 @@ class BitsAndBytesModelLoader(BaseModelLoader):
372 ...]
373
374 # bitsandbytes requires data in GPU
383 - if (weight_sub_tensor.is_cuda
384 - or weight_sub_tensor.device.type == "hpu"):
375 + if weight_sub_tensor.is_cuda:
376 loaded_weight = weight_sub_tensor
377 else:
378 loaded_weight = weight_sub_tensor.to(
vllm/model_executor/model_loader/default_loader.py
-10
@@ -218,16 +218,6 @@ class DefaultModelLoader(BaseModelLoader):
218
219 weights_iterator = _xla_weights_iterator(weights_iterator)
220
221 - elif current_platform.is_hpu():
222 - import habana_frameworks.torch.core as htcore
223 -
224 - def _hpu_weights_iterator(iterator: Generator):
225 - for weights in iterator:
226 - yield weights
227 - htcore.mark_step()
228 -
229 - weights_iterator = _hpu_weights_iterator(weights_iterator)
230 -
221 if self.counter_before_loading_weights == 0.0:
222 self.counter_before_loading_weights = time.perf_counter()
223 # Apply the prefix.
vllm/platforms/__init__.py
-18
@@ -116,23 +116,6 @@ def rocm_platform_plugin() -> Optional[str]:
116 return "vllm.platforms.rocm.RocmPlatform" if is_rocm else None
117
118
119 -def hpu_platform_plugin() -> Optional[str]:
120 - is_hpu = False
121 - logger.debug("Checking if HPU platform is available.")
122 - try:
123 - from importlib import util
124 - is_hpu = util.find_spec('habana_frameworks') is not None
125 - if is_hpu:
126 - logger.debug("Confirmed HPU platform is available.")
127 - else:
128 - logger.debug("HPU platform is not available because "
129 - "habana_frameworks is not found.")
130 - except Exception as e:
131 - logger.debug("HPU platform is not available because: %s", str(e))
132 -
133 - return "vllm.platforms.hpu.HpuPlatform" if is_hpu else None
134 -
135 -
119 def xpu_platform_plugin() -> Optional[str]:
120 is_xpu = False
121 logger.debug("Checking if XPU platform is available.")
@@ -208,7 +191,6 @@ builtin_platform_plugins = {
191 'tpu': tpu_platform_plugin,
192 'cuda': cuda_platform_plugin,
193 'rocm': rocm_platform_plugin,
211 - 'hpu': hpu_platform_plugin,
194 'xpu': xpu_platform_plugin,
195 'cpu': cpu_platform_plugin,
196 'neuron': neuron_platform_plugin,
vllm/platforms/hpu.py deleted
-114
@@ -1,114 +0,0 @@
1 -# SPDX-License-Identifier: Apache-2.0
2 -# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 -
4 -import os
5 -from typing import TYPE_CHECKING, Optional
6 -
7 -import torch
8 -
9 -from vllm import envs
10 -from vllm.logger import init_logger
11 -from vllm.utils import DEFAULT_MAX_NUM_BATCHED_TOKENS
12 -
13 -from .interface import Platform, PlatformEnum, _Backend
14 -
15 -if TYPE_CHECKING:
16 - from vllm.config import VllmConfig
17 -else:
18 - VllmConfig = None
19 -
20 -logger = init_logger(__name__)
21 -
22 -
23 -class HpuPlatform(Platform):
24 - _enum = PlatformEnum.HPU
25 - device_name: str = "hpu"
26 - device_type: str = "hpu"
27 - dispatch_key: str = "HPU"
28 - ray_device_key: str = "HPU"
29 - dist_backend: str = "hccl"
30 - device_control_env_var: str = "HABANA_VISIBLE_MODULES"
31 -
32 - @classmethod
33 - def get_attn_backend_cls(cls, selected_backend: _Backend, head_size: int,
34 - dtype: torch.dtype, kv_cache_dtype: Optional[str],
35 - block_size: int, use_v1: bool,
36 - use_mla: bool) -> str:
37 - logger.info("Using HPUAttention backend.")
38 - return "vllm.attention.backends.hpu_attn.HPUAttentionBackend"
39 -
40 - @classmethod
41 - def is_async_output_supported(cls, enforce_eager: Optional[bool]) -> bool:
42 - return True
43 -
44 - @classmethod
45 - def inference_mode(cls):
46 - return torch.no_grad()
47 -
48 - @classmethod
49 - def set_device(cls, device: torch.device) -> None:
50 - """
51 - Set the device for the current platform.
52 - """
53 - torch.hpu.set_device(device)
54 -
55 - @classmethod
56 - def check_and_update_config(cls, vllm_config: VllmConfig) -> None:
57 -
58 - scheduler_config = vllm_config.scheduler_config
59 - parallel_config = vllm_config.parallel_config
60 - if scheduler_config.is_multi_step:
61 - parallel_config.worker_cls = \
62 - "vllm.worker.multi_step_hpu_worker.MultiStepHPUWorker"
63 -
64 - if vllm_config.speculative_config is not None:
65 - raise NotImplementedError(
66 - "Speculative decoding is not implemented for HPU")
67 -
68 - if parallel_config.worker_cls == "auto":
69 - parallel_config.worker_cls = "vllm.worker.hpu_worker.HPUWorker"
70 -
71 - # NOTE(kzawora): default block size for Gaudi should be 128
72 - # smaller sizes still work, but very inefficiently
73 - cache_config = vllm_config.cache_config
74 - if cache_config and cache_config.block_size is None:
75 - cache_config.block_size = 128
76 - if (parallel_config.distributed_executor_backend == 'mp'
77 - and envs.VLLM_WORKER_MULTIPROC_METHOD == 'fork'):
78 - if os.environ.get("VLLM_WORKER_MULTIPROC_METHOD",
79 - None) is not None:
80 - logger.warning("On HPU, VLLM_WORKER_MULTIPROC_METHOD=fork "
81 - "might cause application hangs on exit. Using "
82 - "VLLM_WORKER_MULTIPROC_METHOD=fork anyway, "
83 - "as it was explicitly requested.")
84 - else:
85 - logger.warning(
86 - "On HPU, VLLM_WORKER_MULTIPROC_METHOD=fork "
87 - "might cause application hangs on exit. Setting "
88 - "VLLM_WORKER_MULTIPROC_METHOD to 'spawn'. "
89 - "To override that behavior, please set "
90 - "VLLM_WORKER_MULTIPROC_METHOD=fork explicitly.")
91 - os.environ["VLLM_WORKER_MULTIPROC_METHOD"] = "spawn"
92 -
93 - if vllm_config.model_config and vllm_config.model_config.use_mla:
94 - logger.info(
95 - "MLA is enabled on a non-GPU platform; forcing chunked "
96 - "prefill and prefix caching to be disabled.")
97 - vllm_config.scheduler_config.enable_chunked_prefill = False
98 - vllm_config.scheduler_config.chunked_prefill_enabled = False
99 - vllm_config.scheduler_config.max_num_batched_tokens = max(
100 - vllm_config.scheduler_config.max_model_len,
101 - DEFAULT_MAX_NUM_BATCHED_TOKENS)
102 -
103 - @classmethod
104 - def is_pin_memory_available(cls):
105 - logger.warning("Pin memory is not supported on HPU.")
106 - return False
107 -
108 - @classmethod
109 - def get_punica_wrapper(cls) -> str:
110 - return "vllm.lora.punica_wrapper.punica_hpu.PunicaWrapperHPU"
111 -
112 - @classmethod
113 - def get_device_communicator_cls(cls) -> str:
114 - return "vllm.distributed.device_communicators.hpu_communicator.HpuCommunicator" # noqa
vllm/platforms/interface.py
-5
@@ -54,7 +54,6 @@ class _Backend(enum.Enum):
54 FLASHMLA_VLLM_V1 = enum.auto()
55 FLASHMLA = enum.auto() # Supported by V1
56 CUTLASS_MLA_VLLM_V1 = enum.auto()
57 - HPU_ATTN = enum.auto()
57 PALLAS = enum.auto()
58 PALLAS_VLLM_V1 = enum.auto()
59 IPEX = enum.auto()
@@ -69,7 +68,6 @@ class PlatformEnum(enum.Enum):
68 CUDA = enum.auto()
69 ROCM = enum.auto()
70 TPU = enum.auto()
72 - HPU = enum.auto()
71 XPU = enum.auto()
72 CPU = enum.auto()
73 NEURON = enum.auto()
@@ -154,9 +152,6 @@ class Platform:
152 def is_tpu(self) -> bool:
153 return self._enum == PlatformEnum.TPU
154
157 - def is_hpu(self) -> bool:
158 - return self._enum == PlatformEnum.HPU
159 -
155 def is_xpu(self) -> bool:
156 return self._enum == PlatformEnum.XPU
157
vllm/plugins/__init__.py
-13
@@ -2,7 +2,6 @@
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 import logging
5 -import os
5 from typing import Any, Callable
6
7 import torch
@@ -75,18 +74,6 @@ def load_general_plugins():
74 if current_platform.is_xpu():
75 # see https://github.com/pytorch/pytorch/blob/43c5f59/torch/_dynamo/config.py#L158
76 torch._dynamo.config.disable = True
78 - elif current_platform.is_hpu():
79 - # NOTE(kzawora): PT HPU lazy backend (PT_HPU_LAZY_MODE = 1)
80 - # does not support torch.compile
81 - # Eager backend (PT_HPU_LAZY_MODE = 0) must be selected for
82 - # torch.compile support
83 - is_lazy = os.environ.get('PT_HPU_LAZY_MODE', '1') == '1'
84 - if is_lazy:
85 - torch._dynamo.config.disable = True
86 - # NOTE(kzawora) multi-HPU inference with HPUGraphs (lazy-only)
87 - # requires enabling lazy collectives
88 - # see https://docs.habana.ai/en/latest/PyTorch/Inference_on_PyTorch/Inference_Using_HPU_Graphs.html # noqa: E501
89 - os.environ['PT_HPU_ENABLE_LAZY_COLLECTIVES'] = 'true'
77
78 plugins = load_plugins_by_group(group=DEFAULT_PLUGINS_GROUP)
79 # general plugins, we only need to execute the loaded functions
vllm/worker/hpu_model_runner.py deleted
-2320
@@ -1,2320 +0,0 @@
1 -# SPDX-License-Identifier: Apache-2.0
2 -# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 -
4 -###############################################################################
5 -# Copyright (C) 2024 Habana Labs, Ltd. an Intel Company
6 -###############################################################################
7 -
8 -import collections
9 -import contextlib
10 -import dataclasses
11 -import functools
12 -import gc
13 -import itertools
14 -import math
15 -import os
16 -import time
17 -from array import array
18 -from enum import Enum, IntEnum
19 -from typing import (TYPE_CHECKING, Any, Callable, Dict, List, NamedTuple,
20 - Optional, Set, Tuple, Type, TypeVar, Union)
21 -
22 -import habana_frameworks.torch as htorch
23 -import habana_frameworks.torch.internal.bridge_config as bc
24 -import torch
25 -import torch.nn as nn
26 -import vllm_hpu_extension.environment as environment
27 -from vllm_hpu_extension.bucketing.common import get_bucketing_context
28 -from vllm_hpu_extension.ops import LoraMask as LoraMask
29 -from vllm_hpu_extension.profiler import (HabanaHighLevelProfiler,
30 - HabanaMemoryProfiler, format_bytes)
31 -
32 -import vllm.envs as envs
33 -from vllm.attention import AttentionMetadata, get_attn_backend
34 -from vllm.config import DeviceConfig, VllmConfig
35 -from vllm.distributed import broadcast_tensor_dict
36 -from vllm.distributed.parallel_state import get_world_group
37 -from vllm.forward_context import set_forward_context
38 -from vllm.logger import init_logger
39 -from vllm.lora.layers import LoRAMapping
40 -from vllm.lora.request import LoRARequest
41 -from vllm.lora.worker_manager import LRUCacheWorkerLoRAManager
42 -from vllm.model_executor import SamplingMetadata
43 -from vllm.model_executor.layers.layernorm import RMSNorm
44 -from vllm.model_executor.layers.sampler import SamplerOutput, get_sampler
45 -from vllm.model_executor.layers.vocab_parallel_embedding import (
46 - VocabParallelEmbedding)
47 -from vllm.model_executor.model_loader import get_model
48 -from vllm.model_executor.sampling_metadata import SequenceGroupToSample
49 -from vllm.multimodal import BatchedTensorInputs, MultiModalKwargs
50 -from vllm.sampling_params import SamplingParams
51 -from vllm.sequence import (CompletionSequenceGroupOutput, IntermediateTensors,
52 - Logprob, SequenceData, SequenceGroupMetadata,
53 - SequenceOutput)
54 -from vllm.utils import (bind_kv_cache, is_pin_memory_available,
55 - make_tensor_with_pad)
56 -from vllm.worker.model_runner_base import (
57 - ModelRunnerBase, ModelRunnerInputBase,
58 - _add_attn_metadata_broadcastable_dict,
59 - _add_sampling_metadata_broadcastable_dict,
60 - _init_attn_metadata_from_tensor_dict,
61 - _init_sampling_metadata_from_tensor_dict)
62 -
63 -if TYPE_CHECKING:
64 - from vllm.attention.backends.abstract import AttentionBackend
65 -
66 -logger = init_logger(__name__)
67 -
68 -_TYPE_CACHE = {}
69 -# These values are assumed to be zero in several places.
70 -# Use caution when updating them!
71 -_PAD_SLOT_ID = 0
72 -_PAD_BLOCK_ID = 0
73 -
74 -LORA_WARMUP_RANK = 8
75 -
76 -DUMMY_TOKEN_ID = -1
77 -
78 -
79 -class PhaseType(Enum):
80 - PREFILL = 'prefill'
81 - PREFIX_PREFILL = 'prefix_prefill'
82 - DECODE = 'decode'
83 -
84 -
85 -def subtuple(obj: object,
86 - typename: str,
87 - to_copy: List[str],
88 - to_override: Optional[Dict[str, object]] = None):
89 - if obj is None:
90 - return None
91 - if to_override is None:
92 - to_override = {}
93 - fields = set(to_copy) | set(to_override.keys())
94 - if type(obj) is dict:
95 - values = {key: obj[key] for key in fields if key in obj}
96 - else:
97 - values = {f: to_override.get(f, getattr(obj, f)) for f in fields}
98 - if typename not in _TYPE_CACHE:
99 - _TYPE_CACHE[typename] = collections.namedtuple(typename,
100 - ' '.join(fields))
101 - return _TYPE_CACHE[typename](**values)
102 -
103 -
104 -def round_up(value: int, k: int):
105 - return (value + k - 1) // k * k
106 -
107 -
108 -def align_workers(value, op):
109 - group = get_world_group().cpu_group
110 - world_size = torch.distributed.get_world_size()
111 - if world_size <= 1:
112 - return value
113 - value_t = torch.tensor(value, device='cpu')
114 - torch.distributed.all_reduce(value_t, op=op, group=group)
115 - return value_t.item()
116 -
117 -
118 -def setup_profiler():
119 - schedule = torch.profiler.schedule(wait=0, warmup=2, active=1, repeat=1)
120 - DEVICE = 'hpu'
121 - activities = [torch.profiler.ProfilerActivity.CPU]
122 - activities.extend([torch.profiler.ProfilerActivity.HPU] if DEVICE ==
123 - 'hpu' else [])
124 - #from habana_frameworks.torch.activity_profiler import DebugActivity
125 - #debug_activities=[DebugActivity.BRIDGE_FUNCTION_CALLS]
126 -
127 - profiler = torch.profiler.profile(
128 - schedule=schedule,
129 - activities=activities,
130 - #debug_activities=debug_activities,
131 - on_trace_ready=torch.profiler.tensorboard_trace_handler('.',
132 - use_gzip=True),
133 - record_shapes=False,
134 - with_stack=True)
135 - return profiler
136 -
137 -
138 -def pad_list(input, k, v):
139 - input_len = len(input)
140 - target_len = round_up(input_len, k)
141 - padding = target_len - input_len
142 - return input + [v] * padding
143 -
144 -
145 -def gather_list(input, indices, v):
146 - return [input[i] if i is not None else v for i in indices]
147 -
148 -
149 -def flatten(in_list):
150 - return list(itertools.chain(*in_list))
151 -
152 -
153 -def precompute_indices_and_offsets(block_size, slot_mapping, is_prompt):
154 - slot_mapping = slot_mapping.flatten()
155 - indices = torch.div(slot_mapping, block_size, rounding_mode="floor")
156 - if is_prompt:
157 - indices = indices.unflatten(0, (-1, block_size))[:, 0]
158 - offsets = None
159 - else:
160 - offsets = torch.fmod(slot_mapping, block_size)
161 - return indices, offsets
162 -
163 -
164 -def modify_decoder_layer(module: torch.nn.Module, suffix="DecoderLayer"):
165 - if module.__class__.__name__.endswith(suffix):
166 -
167 - def forward_hook(module, args, output):
168 - htorch.core.mark_step()
169 - return output
170 -
171 - module.register_forward_hook(forward_hook)
172 -
173 - for child_name, child_module in module.named_children():
174 - modify_decoder_layer(child_module)
175 -
176 -
177 -class HpuModelAdapter:
178 -
179 - def __init__(self, model, vllm_config):
180 - self.model = model
181 - self.sampler = get_sampler()
182 - self.prefill_use_fusedsdpa = os.getenv('VLLM_PROMPT_USE_FUSEDSDPA',
183 - '0').lower() in ['1', 'true']
184 - self.vllm_config = vllm_config
185 - self.block_size = vllm_config.cache_config.block_size
186 - self.dtype = vllm_config.model_config.dtype
187 - enforce_eager = vllm_config.model_config.enforce_eager
188 -
189 - if not htorch.utils.internal.is_lazy() and not enforce_eager:
190 - if os.getenv('VLLM_REGIONAL_COMPILATION',
191 - 'true').lower() == 'true':
192 - self.regional_compilation_layers_list = [
193 - RMSNorm, VocabParallelEmbedding
194 - ]
195 - self._regional_compilation(self.model)
196 - else:
197 - self.model = torch.compile(self.model,
198 - backend='hpu_backend',
199 - dynamic=False)
200 -
201 - def _regional_compilation(self,
202 - module,
203 - parent_module=None,
204 - module_name=None):
205 - if isinstance(module, torch.nn.ModuleList):
206 - for children_name, children_module in module.named_children():
207 - self._compile_region(module, children_name, children_module)
208 - elif any(
209 - isinstance(module, layer)
210 - for layer in self.regional_compilation_layers_list):
211 - self._compile_region(parent_module, module_name, module)
212 - else:
213 - for children_name, children_module in module.named_children():
214 - self._regional_compilation(children_module, module,
215 - children_name)
216 -
217 - def _compile_region(self, model, name, module):
218 - module = torch.compile(module, backend='hpu_backend', dynamic=False)
219 - setattr(model, name, module)
220 -
221 - def _set_attn_bias(self, attn_metadata, batch_size, seq_len, device,
222 - dtype):
223 - if (attn_metadata is None
224 - or (self.prefill_use_fusedsdpa \
225 - and attn_metadata.block_list is None)
226 - or not attn_metadata.is_prompt):
227 - return attn_metadata
228 -
229 - prefill_metadata = attn_metadata
230 -
231 - seq_lens_t = prefill_metadata.seq_lens_tensor
232 - context_lens_t = prefill_metadata.context_lens_tensor
233 - query_lens_t = seq_lens_t - context_lens_t
234 -
235 - block_list = attn_metadata.block_list
236 - max_context_len = (block_list.size(-1) //
237 - batch_size if block_list is not None else 0)
238 - max_context_len = max_context_len * self.block_size
239 - past_mask = torch.arange(0,
240 - max_context_len,
241 - dtype=torch.int32,
242 - device=device)
243 - past_mask = (past_mask.view(1, -1).expand(batch_size, -1).ge(
244 - context_lens_t.view(-1, 1)).view(batch_size, 1, -1).expand(
245 - batch_size, seq_len, -1).view(batch_size, 1, seq_len, -1))
246 -
247 - len_mask = (torch.arange(0, seq_len, device=device,
248 - dtype=torch.int32).view(1, seq_len).ge(
249 - query_lens_t.unsqueeze(-1)).view(
250 - batch_size, 1, 1, seq_len))
251 - causal_mask = torch.triu(torch.ones((batch_size, 1, seq_len, seq_len),
252 - device=device,
253 - dtype=torch.bool),
254 - diagonal=1)
255 - mask = causal_mask.logical_or(len_mask)
256 - mask = torch.concat((past_mask, mask), dim=-1)
257 - attn_bias = (torch.zeros_like(mask, dtype=dtype).masked_fill_(
258 - mask, -math.inf))
259 - attn_metadata = prefill_metadata._replace(attn_bias=attn_bias)
260 - return attn_metadata
261 -
262 - def _set_block_mapping(self, metadata, batch_size, device, dtype):
263 - mask = torch.arange(0,
264 - self.block_size,
265 - device=device,
266 - dtype=torch.int32).unsqueeze(0)
267 - mask = mask >= metadata.block_usage.unsqueeze(-1)
268 - attn_bias = (torch.zeros_like(mask, dtype=dtype).masked_fill_(
269 - mask, -math.inf))
270 - if os.environ.get('VLLM_USE_FAKE_HPU',
271 - '0') == '0' and htorch.utils.internal.is_lazy():
272 - block_mapping = torch.nn.functional.one_hot(metadata.block_groups,
273 - num_classes=batch_size)
274 - else:
275 - # Unfortunately one_hot on CPU/torch.compile mode/eager mode
276 - # doesn't handle out of bounds classes so we need to convert
277 - # all negative values to 0 (block_mapping) or bs (block_groups)
278 - block_groups = metadata.block_groups.to(torch.long)
279 - block_mapping = torch.nn.functional.relu(block_groups)
280 - block_mapping = torch.nn.functional.one_hot(block_mapping,
281 - num_classes=batch_size)
282 - oob_values = block_groups.lt(0)
283 - block_mapping.masked_fill_(oob_values.unsqueeze(-1), 0)
284 - block_groups.masked_fill_(oob_values, batch_size)
285 - metadata = metadata._replace(block_groups=block_groups)
286 - block_mapping = block_mapping.to(dtype)
287 - metadata = metadata._replace(block_mapping=block_mapping,
288 - attn_bias=attn_bias)
289 - return metadata
290 -
291 - def _update_metadata(self, attn_metadata, batch_size, seq_len, device,
292 - dtype):
293 - if attn_metadata.is_prompt:
294 - meta = attn_metadata
295 - attn_metadata = self._set_attn_bias(meta, batch_size, seq_len,
296 - device, dtype)
297 - else:
298 - meta = attn_metadata
299 - attn_metadata = self._set_block_mapping(meta, batch_size, device,
300 - dtype)
301 - return attn_metadata
302 -
303 - def forward(self, *args, **kwargs):
304 - kwargs = kwargs.copy()
305 - selected_token_indices = kwargs.pop('selected_token_indices')
306 - if 'warmup_mode' in kwargs:
307 - kwargs.pop('warmup_mode')
308 - virtual_engine = 0
309 - if 'virtual_engine' in kwargs:
310 - virtual_engine = kwargs.pop('virtual_engine')
311 - input_ids = kwargs['input_ids']
312 - attn_metadata = self._update_metadata(kwargs.pop('attn_metadata'),
313 - input_ids.size(0),
314 - input_ids.size(1),
315 - input_ids.device, self.dtype)
316 - LoraMask.setLoraMask(kwargs.pop('lora_mask'))
317 - with set_forward_context(attn_metadata, self.vllm_config,
318 - virtual_engine):
319 - hidden_states = self.model(*args, **kwargs)
320 - hidden_states = hidden_states.view(-1, hidden_states.shape[-1])
321 - hidden_states = hidden_states.index_select(0,
322 - selected_token_indices)
323 - return hidden_states
324 -
325 - def compute_logits(self, *args, **kwargs):
326 - return self.model.compute_logits(*args, **kwargs)
327 -
328 - def sample(self, *args, **kwargs):
329 - return self.sampler(*args, **kwargs)
330 -
331 -
332 -class PreparePromptMetadata(NamedTuple):
333 - input_tokens: torch.Tensor
334 - input_positions: List[List[int]]
335 - attn_metadata: Optional[AttentionMetadata]
336 - seq_lens: List[int]
337 - query_lens: List[int]
338 - lora_index_mapping: List[List[int]]
339 - lora_prompt_mapping: List[List[int]]
340 - lora_requests: Set[LoRARequest]
341 - multi_modal_kwargs: Optional[Dict[str, BatchedTensorInputs]]
342 - slot_mapping: List[List[int]]
343 - lora_ids: List[int]
344 -
345 - @classmethod
346 - def empty(cls):
347 - return PreparePromptMetadata(input_tokens=[],
348 - input_positions=[],
349 - attn_metadata=None,
350 - seq_lens=[],
351 - query_lens=[],
352 - lora_index_mapping=[],
353 - lora_prompt_mapping=[],
354 - lora_requests=set(),
355 - multi_modal_kwargs=None,
356 - slot_mapping=[],
357 - lora_ids=[])
358 -
359 -
360 -class PrepareDecodeMetadata(NamedTuple):
361 - input_tokens: torch.Tensor
362 - input_positions: List[List[int]]
363 - attn_metadata: Optional[AttentionMetadata]
364 - lora_index_mapping: List[List[int]]
365 - lora_prompt_mapping: List[List[int]]
366 - lora_requests: Set[LoRARequest]
367 - slot_mapping: List[List[int]]
368 - lora_ids: List[int]
369 -
370 - @classmethod
371 - def empty(cls):
372 - return PrepareDecodeMetadata(input_tokens=[],
373 - input_positions=[],
374 - attn_metadata=None,
375 - lora_index_mapping=[],
376 - lora_prompt_mapping=[],
377 - lora_requests=set(),
378 - slot_mapping=[],
379 - lora_ids=[])
380 -
381 -
382 -# How batches are constructed.
383 -class BatchType(IntEnum):
384 - # Every batch is prefill.
385 - PREFILL = 0
386 - # Every batch is decode.
387 - DECODE = 1
388 - # Batch is a mixture of prefill and decode.
389 - MIXED = 2
390 -
391 -
392 -TModelInputForHPU = TypeVar('TModelInputForHPU', bound="ModelInputForHPU")
393 -
394 -
395 -@dataclasses.dataclass(frozen=True)
396 -class ModelInputForHPU(ModelRunnerInputBase):
397 - """
398 - This base class contains metadata needed for the base model forward pass
399 - but not metadata for possible additional steps, e.g., sampling. Model
400 - runners that run additional steps should subclass this method to add
401 - additional fields.
402 - """
403 - input_tokens: Optional[torch.Tensor] = None
404 - input_positions: Optional[torch.Tensor] = None
405 - seq_lens: Optional[List[int]] = None
406 - query_lens: Optional[List[int]] = None
407 - lora_mapping: Optional["LoRAMapping"] = None
408 - lora_requests: Optional[Set[LoRARequest]] = None
409 - attn_metadata: Optional["AttentionMetadata"] = None
410 - multi_modal_kwargs: Optional[Dict[str, torch.Tensor]] = None
411 - real_batch_size: Optional[int] = None
412 - batch_size_padded: Optional[int] = None
413 - virtual_engine: int = 0
414 - lora_ids: Optional[List[int]] = None
415 - async_callback: Optional[Callable] = None
416 - is_first_multi_step: bool = True
417 - is_last_step: bool = True
418 -
419 - def as_broadcastable_tensor_dict(self) -> Dict[str, Any]:
420 - tensor_dict = {
421 - "input_tokens": self.input_tokens,
422 - "input_positions": self.input_positions,
423 - "lora_requests": self.lora_requests,
424 - "lora_mapping": self.lora_mapping,
425 - "multi_modal_kwargs": self.multi_modal_kwargs,
426 - "real_batch_size": self.real_batch_size,
427 - "batch_size_padded": self.batch_size_padded,
428 - "virtual_engine": self.virtual_engine,
429 - "lora_ids": self.lora_ids,
430 - "is_first_multi_step": self.is_first_multi_step,
431 - "is_last_step": self.is_last_step,
432 - }
433 - _add_attn_metadata_broadcastable_dict(tensor_dict, self.attn_metadata)
434 - return tensor_dict
435 -
436 - @classmethod
437 - def from_broadcasted_tensor_dict(
438 - cls: Type[TModelInputForHPU],
439 - tensor_dict: Dict[str, Any],
440 - attn_backend: Optional["AttentionBackend"] = None,
441 - ) -> TModelInputForHPU:
442 - if attn_backend is not None:
443 - tensor_dict = _init_attn_metadata_from_tensor_dict(
444 - attn_backend, tensor_dict)
445 - return cls(**tensor_dict)
446 -
447 -
448 -@dataclasses.dataclass(frozen=True)
449 -class ModelInputForHPUWithSamplingMetadata(ModelInputForHPU):
450 - """
451 - Used by the ModelRunner.
452 - """
453 - sampling_metadata: Optional["SamplingMetadata"] = None
454 - # Used for speculative decoding. We do not broadcast it because it is only
455 - # used by the driver worker.
456 - is_prompt: Optional[bool] = None
457 -
458 - def as_broadcastable_tensor_dict(self) -> Dict[str, Any]:
459 - tensor_dict = {
460 - "input_tokens": self.input_tokens,
461 - "input_positions": self.input_positions,
462 - "lora_requests": self.lora_requests,
463 - "lora_mapping": self.lora_mapping,
464 - "multi_modal_kwargs": self.multi_modal_kwargs,
465 - "lora_ids": self.lora_ids,
466 - }
467 - _add_attn_metadata_broadcastable_dict(tensor_dict, self.attn_metadata)
468 - _add_sampling_metadata_broadcastable_dict(tensor_dict,
469 - self.sampling_metadata)
470 - return tensor_dict
471 -
472 - @classmethod
473 - def from_broadcasted_tensor_dict(
474 - cls,
475 - tensor_dict: Dict[str, Any],
476 - attn_backend: Optional["AttentionBackend"] = None,
477 - ) -> "ModelInputForHPUWithSamplingMetadata":
478 - tensor_dict = _init_sampling_metadata_from_tensor_dict(tensor_dict)
479 - # FIXME(kzawora): this fails for whatever reason - why?
480 - if attn_backend is not None:
481 - tensor_dict = _init_attn_metadata_from_tensor_dict(
482 - attn_backend, tensor_dict)
483 - return cls(**tensor_dict)
484 -
485 -
486 -class HPUModelRunnerBase(ModelRunnerBase[TModelInputForHPU]):
487 - """
488 - Helper class for shared methods between GPU model runners.
489 - """
490 - _model_input_cls: Type[TModelInputForHPU]
491 -
492 - def __init__(
493 - self,
494 - vllm_config: VllmConfig,
495 - is_driver_worker: bool = False,
496 - return_hidden_states: bool = False,
497 - ):
498 - ModelRunnerBase.__init__(self, vllm_config=vllm_config)
499 - environment.set_model_config(self.model_config)
500 - self.is_driver_worker = is_driver_worker
501 - self.return_hidden_states = return_hidden_states
502 -
503 - self.sliding_window = (self.model_config.get_sliding_window()
504 - if self.model_config is not None else None)
505 - self.device_config = (self.device_config if self.device_config
506 - is not None else DeviceConfig())
507 - self.device = self.device_config.device
508 - self.enforce_eager = self.model_config.enforce_eager
509 - self.max_num_seqs = self.scheduler_config.max_num_seqs
510 - # NOTE(kzawora): Change that to scheduler_config.max_num_prefill_seqs
511 - # once padding-aware scheduling gets merged
512 - self.max_num_prefill_seqs = 64
513 - self.max_model_len = self.scheduler_config.max_model_len
514 - self.max_num_batched_tokens = \
515 - self.scheduler_config.max_num_batched_tokens
516 - self.block_size = self.cache_config.block_size
517 -
518 - self.pin_memory = is_pin_memory_available()
519 - self.kv_cache_dtype = self.cache_config.cache_dtype
520 -
521 - self.attn_backend = get_attn_backend(
522 - self.model_config.get_head_size(),
523 - self.model_config.dtype,
524 - self.kv_cache_dtype,
525 - self.block_size,
526 - self.model_config.is_attention_free,
527 - )
528 -
529 - # Lazy initialization
530 - self.lora_manager: LRUCacheWorkerLoRAManager = None
531 - self.model: torch.nn.Module = None
532 - self.inc_initialized_successfully = False
533 -
534 - # Profiler stats
535 - self.profiler = HabanaHighLevelProfiler()
536 - self.profiler_counter_helper = HabanaProfilerCounterHelper()
537 - self.seen_configs: set = set()
538 - self._mem_margin: Optional[int] = None
539 - HPUBucketingContext = get_bucketing_context()
540 - self.bucketing_ctx = HPUBucketingContext(self.max_num_seqs,
541 - self.max_num_prefill_seqs,
542 - self.block_size,
543 - self.max_num_batched_tokens,
544 - False, self.max_model_len)
545 - self.graphed_buckets: Set[Any] = set()
546 - self._set_gc_threshold()
547 - if self.vllm_config.cache_config.enable_prefix_caching:
548 - os.environ.setdefault("VLLM_CONTIGUOUS_PA", "False")
549 - assert os.environ.get(
550 - "VLLM_CONTIGUOUS_PA",
551 - "").lower() != "true", "Contiguous PA doesn't support APC"
552 - self.use_contiguous_pa = envs.VLLM_USE_HPU_CONTIGUOUS_CACHE_FETCH
553 -
554 - # For multi-step scheduling
555 - self.cached_step_outputs: List[torch.Tensor] = []
556 - # For delayed sampling
557 - self.cached_step_inputs: List[
558 - ModelInputForHPUWithSamplingMetadata] = []
559 -
560 - def _set_gc_threshold(self) -> None:
561 - # Read https://docs.python.org/3/library/gc.html#gc.set_threshold
562 - # for comprehensive description of gc generations.
563 - # We can either use VLLM_GC_THR_GEN[0-2] (this has higher priority)
564 - # to set particular generation threshold or use simpler
565 - # VLLM_GC_THR_MULTIPLIER to multiply default values.
566 - default_gc_thrs = list(gc.get_threshold())
567 - requested_gc_thrs = [0] * len(default_gc_thrs)
568 - for i in range(len(default_gc_thrs)):
569 - requested_gc_thrs[i] = int(
570 - os.environ.get(f'VLLM_GC_THR_GEN{i}', default_gc_thrs[i]))
571 - if requested_gc_thrs == default_gc_thrs:
572 - gc_thr_multiplier = int(os.environ.get('VLLM_GC_THR_MULTIPLIER',
573 - 2))
574 - requested_gc_thrs = [
575 - t * gc_thr_multiplier for t in default_gc_thrs
576 - ]
577 - gc.set_threshold(*requested_gc_thrs)
578 -
579 - self.skip_warmup = os.environ.get('VLLM_SKIP_WARMUP',
580 - 'false').lower() == 'true'
581 -
582 - def load_model(self) -> None:
583 - import habana_frameworks.torch.core as htcore
584 - if self.model_config.quantization == 'inc' or \
585 - self.model_config.quantization == 'fp8':
586 - htcore.hpu_set_env()
587 - with HabanaMemoryProfiler() as m:
588 - with HabanaMemoryProfiler() as m_getmodel:
589 - self.model = get_model(vllm_config=self.vllm_config)
590 - msg = ("Pre-loading model weights on "
591 - f"{next(self.model.parameters()).device} "
592 - f"took {m_getmodel.get_summary_string()}")
593 - logger.info(msg)
594 -
595 - if self.lora_config:
596 - assert hasattr(self.model, "embedding_modules"
597 - ), "Model does not have embedding_modules"
598 - assert hasattr(
599 - self.model, "embedding_padding_modules"
600 - ), "Model does not have embedding_padding_modules"
601 - assert not self.lora_config.bias_enabled, \
602 - "Bias support in LoRA is not enabled in HPU yet."
603 - assert not self.lora_config.fully_sharded_loras, \
604 - "Fully sharded LoRAs is not enabled in HPU yet."
605 -
606 - # Use get_text_config() in case of multimodal models
607 - text_config = self.model_config.hf_config.get_text_config()
608 -
609 - self.lora_manager = LRUCacheWorkerLoRAManager(
610 - self.scheduler_config.max_num_seqs,
611 - self.scheduler_config.max_num_batched_tokens,
612 - self.vocab_size,
613 - self.lora_config,
614 - self.device,
615 - self.model.embedding_modules,
616 - self.model.embedding_padding_modules,
617 - max_position_embeddings=text_config.
618 - max_position_embeddings,
619 - )
620 - self.model = self.lora_manager.create_lora_manager(self.model)
621 -
622 - if self.model_config.quantization == 'inc':
623 - logger.info("Preparing model with INC..")
624 - with HabanaMemoryProfiler() as m_inc:
625 - from neural_compressor.torch.quantization import (
626 - FP8Config, convert, prepare)
627 - config = FP8Config.from_json_file(
628 - os.getenv("QUANT_CONFIG", ""))
629 - if config.measure:
630 - self.model = prepare(self.model, config)
631 - elif config.quantize:
632 - self.model = convert(self.model, config)
633 - htcore.hpu_initialize(self.model,
634 - mark_only_scales_as_const=True)
635 - self.inc_initialized_successfully = True
636 - logger.info("Preparing model with INC took %s",
637 - m_inc.get_summary_string())
638 - else:
639 - self.model = self.model.to("hpu")
640 - htcore.mark_step()
641 - modify_decoder_layer(self.model)
642 - torch.hpu.synchronize()
643 -
644 - with HabanaMemoryProfiler() as m_wrap:
645 - self.model = _maybe_wrap_in_hpu_graph(
646 - self.model, vllm_config=self.vllm_config)
647 - msg = f"Wrapping in HPU Graph took {m_wrap.get_summary_string()}"
648 - logger.info(msg)
649 -
650 - self.model_memory_usage = m.consumed_device_memory
651 - msg = f"Loading model weights took in total {m.get_summary_string()}"
652 - logger.info(msg)
653 -
654 - def _add_dummy_seq(self, seq_group_metadata_list, is_prompt):
655 - real_batch_size = len(seq_group_metadata_list)
656 - batch_size_padded = self.bucketing_ctx.get_padded_batch_size(
657 - real_batch_size, is_prompt)
658 - batch_size_padding = batch_size_padded - real_batch_size
659 -
660 - seq_group_metadata_list = seq_group_metadata_list.copy()
661 -
662 - if batch_size_padding > 0:
663 - dummy_seq_group_metadata = self.create_dummy_seq_group_metadata(
664 - 0, 0, is_prompt)
665 - seq_group_metadata_list.extend(dummy_seq_group_metadata
666 - for _ in range(batch_size_padding))
667 - return seq_group_metadata_list, real_batch_size, batch_size_padded
668 -
669 - def _maybe_wrap_in_hpu_graph(self, *args, **kwargs):
670 - return htorch.hpu.wrap_in_hpu_graph(
671 - HpuModelAdapter(*args, **kwargs), disable_tensor_cache=True
672 - ) if htorch.utils.internal.is_lazy() else HpuModelAdapter(
673 - *args, **kwargs)
674 -
675 - def get_model(self) -> nn.Module:
676 - return self.model
677 -
678 - def _use_graphs(self, batch_size, seq_len, is_prompt):
679 - if self.enforce_eager:
680 - return False
681 - if self.skip_warmup:
682 - return True
683 - return (batch_size, seq_len, is_prompt) in self.graphed_buckets
684 -
685 - def _is_valid_bucket(self, bucket):
686 - return bucket[0] * bucket[1] <= self.max_num_batched_tokens
687 -
688 - def _prepare_prompt(
689 - self,
690 - seq_group_metadata_list: List[SequenceGroupMetadata],
691 - ) -> PreparePromptMetadata:
692 - input_tokens: List[List[int]] = []
693 - input_positions: List[List[int]] = []
694 - slot_mapping: List[List[int]] = []
695 - lora_index_mapping: List[List[int]] = []
696 - lora_prompt_mapping: List[List[int]] = []
697 - lora_requests: Set[LoRARequest] = set()
698 -
699 - seq_lens: List[int] = []
700 - context_lens: List[int] = []
701 - query_lens: List[int] = []
702 - prefix_block_tables: List[List[int]] = []
703 - multi_modal_kwargs_list: List[MultiModalKwargs] = []
704 -
705 - if len(seq_group_metadata_list) == 0:
706 - return PreparePromptMetadata.empty()
707 -
708 - for seq_group_metadata in seq_group_metadata_list:
709 - assert seq_group_metadata.is_prompt
710 - seq_ids = list(seq_group_metadata.seq_data.keys())
711 - assert len(seq_ids) == 1
712 - seq_id = seq_ids[0]
713 -
714 - computed_block_nums = seq_group_metadata.computed_block_nums
715 - if (self.scheduler_config is not None
716 - and self.scheduler_config.chunked_prefill_enabled
717 - and not (computed_block_nums is None
718 - or computed_block_nums == [])):
719 - raise RuntimeError(
720 - "chunked prefill cannot be used with prefix caching "
721 - "now.")
722 -
723 - token_chunk_size = seq_group_metadata.token_chunk_size
724 - seq_data = seq_group_metadata.seq_data[seq_id]
725 - context_len = seq_data.get_num_computed_tokens()
726 - # We should use get_len here because in case of preemption
727 - # it contains output tokens.
728 - seq_len = min(seq_data.get_len(), context_len + token_chunk_size)
729 - prompt_tokens = seq_data.get_token_ids()[context_len:seq_len]
730 - seq_lens.append(seq_len)
731 -
732 - # NOTE: This only works for oooooooxxx style attention.
733 - if computed_block_nums is not None and len(
734 - computed_block_nums) > 0 and self.sliding_window is None:
735 - # Prefix is not supported with sliding_window
736 - context_len = len(computed_block_nums) * self.block_size
737 - if context_len == seq_len \
738 - and self.vllm_config.cache_config.enable_prefix_caching:
739 - # Fully cached prompt - compute only last token
740 - context_len = context_len - 1
741 - prompt_tokens = prompt_tokens[context_len:]
742 - prefix_block_tables.append(computed_block_nums)
743 - elif self.scheduler_config.chunked_prefill_enabled:
744 - if seq_group_metadata.block_tables is not None:
745 - # Prefill has chunked before.
746 - block_table = seq_group_metadata.block_tables[seq_id]
747 - prefix_block_tables.append(block_table)
748 - else:
749 - # The first prefill.
750 - prefix_block_tables.append([])
751 - else:
752 - prefix_block_tables.append([])
753 - # Right now, prefill start is always 0. However, this
754 - # assumption can be changed once chunked prefill is introduced.
755 - assert context_len == 0
756 -
757 - # actual prompt lens
758 - context_lens.append(context_len)
759 - query_lens.append(seq_len - context_len)
760 - input_tokens.append(prompt_tokens)
761 - # NOTE(woosuk): Here we assume that the first token in the prompt
762 - # is always the first token in the sequence.
763 - input_positions.append(list(range(context_len, seq_len)))
764 -
765 - mm_kwargs = seq_group_metadata.multi_modal_data
766 - if mm_kwargs:
767 - multi_modal_kwargs_list.append(mm_kwargs)
768 -
769 - if seq_group_metadata.block_tables is None:
770 - # During memory profiling, the block tables are not initialized
771 - # yet. In this case, we just use a dummy slot mapping.
772 - slot_mapping.append([_PAD_SLOT_ID] * seq_len)
773 - continue
774 -
775 - # Compute the slot mapping.
776 - slot_mapping.append([])
777 - block_table = seq_group_metadata.block_tables[seq_id]
778 -
779 - # Mask the [0, start_idx) tokens of the prompt with _PAD_SLOT_ID,
780 - # where start_idx is max(0, seq_len - sliding_window).
781 - # For example, if the prompt len is 10, sliding window is 8, and
782 - # block size is 4, the first two tokens are masked and the slot
783 - # mapping will be [-1, -1, 2, 3, 4, 5, 6, 7, 0, 1].
784 - start_idx = 0
785 - if self.sliding_window is not None:
786 - assert context_len == 0, (
787 - "Prefix caching is currently not supported with "
788 - "sliding window attention")
789 - start_idx = max(0, seq_len - self.sliding_window)
790 - for i in range(context_len, seq_len):
791 - if i < start_idx:
792 - slot_mapping[-1].append(_PAD_SLOT_ID)
793 - continue
794 -
795 - block_number = block_table[i // self.block_size]
796 - block_offset = i % self.block_size
797 - slot = block_number * self.block_size + block_offset
798 - slot_mapping[-1].append(slot)
799 -
800 - max_query_len = max(query_lens)
801 - sum_query_len = sum(query_lens)
802 - real_num_seqs = len(query_lens)
803 - assert max_query_len > 0
804 -
805 - max_prompt_len = max(
806 - self.bucketing_ctx.get_padded_prompt_seq_len(max_query_len),
807 - self.block_size)
808 -
809 - lora_ids: List[int] = []
810 - for seq_group_metadata, context_len in zip(seq_group_metadata_list,
811 - context_lens):
812 - lora_id = seq_group_metadata.lora_int_id
813 - lora_ids.append(lora_id)
814 -
815 - if lora_id > 0:
816 - lora_requests.add(seq_group_metadata.lora_request)
817 -
818 - lora_index_mapping += [lora_id] * max_prompt_len
819 - lora_prompt_mapping.extend(
820 - [lora_id] *
821 - (max_prompt_len
822 - if seq_group_metadata.sampling_params.prompt_logprobs else 1))
823 -
824 - if any(context_lens):
825 - assert not self.scheduler_config.chunked_prefill_enabled
826 - # prefix caching
827 -
828 - max_num_block = max(len(bt) for bt in prefix_block_tables)
829 - prefix_block_list = list(
830 - itertools.chain.from_iterable(
831 - bt if len(bt) == max_num_block else bt +
832 - ([_PAD_BLOCK_ID] * (max_num_block - len(bt)))
833 - for bt in prefix_block_tables))
834 -
835 - pad_len = len(prefix_block_list)
836 - prefix_block_list = pad_list(prefix_block_list, pad_len,
837 - _PAD_BLOCK_ID)
838 -
839 - prefix_block_list_tensor = torch.tensor(prefix_block_list,
840 - dtype=torch.long,
841 - device=self.device)
842 - else:
843 - prefix_block_list_tensor = None
844 -
845 - input_tokens = make_tensor_with_pad(input_tokens,
846 - max_len=max_prompt_len,
847 - pad=0,
848 - dtype=torch.long,
849 - device=self.device)
850 -
851 - input_positions = make_tensor_with_pad(input_positions,
852 - max_len=max_prompt_len,
853 - pad=0,
854 - dtype=torch.long,
855 - device=self.device)
856 -
857 - slot_mapping = make_tensor_with_pad(slot_mapping,
858 - max_len=max_prompt_len,
859 - pad=_PAD_SLOT_ID,
860 - dtype=torch.long,
861 - device=self.device)
862 -
863 - seq_lens_tensor = torch.tensor(seq_lens,
864 - dtype=torch.long,
865 - device=self.device)
866 -
867 - context_lens_tensor = torch.tensor(context_lens,
868 - dtype=torch.long,
869 - device=self.device)
870 -
871 - block_indices, block_offsets = precompute_indices_and_offsets(
872 - self.block_size, slot_mapping, True)
873 - attn_metadata = self.attn_backend.make_metadata(
874 - is_prompt=True,
875 - block_list=prefix_block_list_tensor,
876 - block_mapping=None,
877 - block_usage=None,
878 - block_indices=block_indices,
879 - block_offsets=block_offsets,
880 - block_groups=None,
881 - attn_bias=None,
882 - seq_lens_tensor=seq_lens_tensor,
883 - context_lens_tensor=context_lens_tensor,
884 - num_prefills=real_num_seqs,
885 - num_prefill_tokens=sum_query_len,
886 - num_decode_tokens=0,
887 - slot_mapping=slot_mapping,
888 - multi_modal_placeholder_index_maps=
889 - None, # FIXME(kzawora): multi-modality will not work here
890 - enable_kv_scales_calculation=False,
891 - )
892 - multi_modal_kwargs = MultiModalKwargs.batch(multi_modal_kwargs_list)
893 -
894 - return PreparePromptMetadata(input_tokens=input_tokens,
895 - input_positions=input_positions,
896 - attn_metadata=attn_metadata,
897 - seq_lens=seq_lens,
898 - query_lens=query_lens,
899 - lora_index_mapping=lora_index_mapping,
900 - lora_prompt_mapping=lora_prompt_mapping,
901 - lora_requests=lora_requests,
902 - multi_modal_kwargs=multi_modal_kwargs,
903 - slot_mapping=slot_mapping,
904 - lora_ids=lora_ids)
905 -
906 - def _prepare_decode(
907 - self,
908 - seq_group_metadata_list: List[SequenceGroupMetadata],
909 - output=None,
910 - ) -> PrepareDecodeMetadata:
911 - input_tokens: List[List[int]] = []
912 - input_positions: List[List[int]] = []
913 - slot_mapping: List[List[int]] = []
914 - seq_lens: List[int] = []
915 - block_tables: List[List[int]] = []
916 - lora_index_mapping: List[List[int]] = []
917 - lora_prompt_mapping: List[List[int]] = []
918 - lora_requests: Set[LoRARequest] = set()
919 -
920 - if len(seq_group_metadata_list) == 0:
921 - return PrepareDecodeMetadata.empty()
922 - lora_ids: List[int] = []
923 -
924 - dummy_slots = itertools.cycle(
925 - range(_PAD_SLOT_ID, _PAD_SLOT_ID + self.block_size))
926 -
927 - for seq_group_metadata in seq_group_metadata_list:
928 - assert not seq_group_metadata.is_prompt
929 - assert seq_group_metadata.token_chunk_size == 1
930 -
931 - seq_ids = list(seq_group_metadata.seq_data.keys())
932 - lora_id = seq_group_metadata.lora_int_id
933 - lora_ids.append(lora_id)
934 -
935 - if lora_id > 0:
936 - lora_requests.add(seq_group_metadata.lora_request)
937 -
938 - for seq_id in seq_ids:
939 - seq_data = seq_group_metadata.seq_data[seq_id]
940 - if output is None:
941 - generation_token = seq_data.get_last_token_id()
942 - input_tokens.append([generation_token])
943 -
944 - seq_len = seq_data.get_len()
945 - position = seq_len - 1
946 - input_positions.append([position])
947 -
948 - seq_len = seq_len if self.sliding_window is None else min(
949 - seq_len, self.sliding_window)
950 - seq_lens.append(seq_len)
951 -
952 - block_table = seq_group_metadata.block_tables[seq_id]
953 - num_fully_occupied_blocks = position // self.block_size
954 - block_table = block_table[:num_fully_occupied_blocks + 1]
955 -
956 - if len(block_table) == 0:
957 - block_number = _PAD_BLOCK_ID
958 - else:
959 - block_number = block_table[position // self.block_size]
960 - if block_number == _PAD_BLOCK_ID:
961 - slot = next(dummy_slots)
962 - else:
963 - block_offset = position % self.block_size
964 - slot = block_number * self.block_size + block_offset
965 - slot_mapping.append([slot])
966 - lora_index_mapping.append(lora_id)
967 - lora_prompt_mapping.append(lora_id)
968 -
969 - if self.sliding_window is not None:
970 - sliding_window_blocks = (self.sliding_window //
971 - self.block_size)
972 - block_table = block_table[-sliding_window_blocks:]
973 - block_tables.append(block_table)
974 -
975 - if output is None:
976 - input_tokens = torch.tensor(input_tokens,
977 - dtype=torch.long,
978 - device=self.device)
979 - else:
980 - real_batch_size = len(seq_group_metadata_list)
981 - input_tokens = output[:real_batch_size]
982 -
983 - input_positions = torch.tensor(input_positions,
984 - dtype=torch.long,
985 - device=self.device)
986 -
987 - num_decode_tokens = sum(seq_lens)
988 -
989 - last_block_usage = [
990 - slot[0] % self.block_size + 1 for slot in slot_mapping
991 - ]
992 - block_groups = [[i] * len(bt) for i, bt in enumerate(block_tables)]
993 - block_usage = [[self.block_size] * (len(bt) - 1) + [lbu]
994 - for bt, lbu in zip(block_tables, last_block_usage)
995 - if bt]
996 -
997 - block_list = flatten(block_tables)
998 - block_groups = flatten(block_groups)
999 - block_usage = flatten(block_usage)
1000 -
1001 - assert len(block_list) == len(block_groups)
1002 - assert len(block_list) == len(block_usage)
1003 -
1004 - padding_fn = None
1005 - if self.use_contiguous_pa:
1006 - block_bucket_size = max(max(block_list) + 1, len(block_list))
1007 - block_bucket_size = self.bucketing_ctx.get_padded_decode_num_blocks(
1008 - block_bucket_size)
1009 - indices: List[Any]
1010 - indices = [None] * block_bucket_size
1011 - for i, bid in enumerate(block_list):
1012 - indices[bid] = i
1013 - padding_fn = lambda tensor, pad_value: gather_list(
1014 - tensor, indices, pad_value)
1015 - else:
1016 - block_bucket_size = \
1017 - self.bucketing_ctx.get_padded_decode_num_blocks(
1018 - len(block_list))
1019 - padding_fn = lambda tensor, pad_value: pad_list(
1020 - tensor, block_bucket_size, pad_value)
1021 -
1022 - block_list = padding_fn(block_list, _PAD_BLOCK_ID)
1023 - block_groups = padding_fn(block_groups, -1)
1024 - block_usage = padding_fn(block_usage, 1)
1025 -
1026 - block_list = torch.tensor(block_list,
1027 - dtype=torch.int,
1028 - device=self.device)
1029 - block_groups = torch.tensor(block_groups,
1030 - dtype=torch.int,
1031 - device=self.device)
1032 - block_usage = torch.tensor(block_usage,
1033 - dtype=self.model_config.dtype,
1034 - device=self.device)
1035 - slot_mapping = torch.tensor(slot_mapping,
1036 - dtype=torch.long,
1037 - device=self.device)
1038 -
1039 - block_indices, block_offsets = precompute_indices_and_offsets(
1040 - self.block_size, slot_mapping, False)
1041 -
1042 - attn_metadata = self.attn_backend.make_metadata(
1043 - is_prompt=False,
1044 - block_list=block_list,
1045 - block_mapping=None,
1046 - block_usage=block_usage,
1047 - block_indices=block_indices,
1048 - block_offsets=block_offsets,
1049 - block_groups=block_groups,
1050 - attn_bias=None,
1051 - seq_lens_tensor=None,
1052 - context_lens_tensor=None,
1053 - num_prefills=0,
1054 - num_prefill_tokens=0,
1055 - num_decode_tokens=num_decode_tokens,
1056 - slot_mapping=slot_mapping,
1057 - multi_modal_placeholder_index_maps=None,
1058 - enable_kv_scales_calculation=False,
1059 - )
1060 - return PrepareDecodeMetadata(input_tokens=input_tokens,
1061 - input_positions=input_positions,
1062 - attn_metadata=attn_metadata,
1063 - lora_index_mapping=lora_index_mapping,
1064 - lora_prompt_mapping=lora_prompt_mapping,
1065 - lora_requests=lora_requests,
1066 - slot_mapping=slot_mapping,
1067 - lora_ids=lora_ids)
1068 -
1069 - def prepare_input_tensors(
1070 - self,
1071 - seq_group_metadata_list: List[SequenceGroupMetadata],
1072 - ) -> Tuple[TModelInputForHPU, SamplingMetadata]:
1073 - if len(seq_group_metadata_list) == 0:
1074 - return self._model_input_cls(), None
1075 -
1076 - input_tokens = None
1077 - input_positions = None
1078 - lora_mapping = None
1079 - lora_requests = None
1080 - multi_modal_kwargs = None
1081 - batch_type = None
1082 - seq_lens = None
1083 - query_lens = None
1084 - real_batch_size = None
1085 - batch_size_padded = None
1086 -
1087 - self.event_start = self.profiler.get_timestamp_us()
1088 - is_prompt = seq_group_metadata_list[0].is_prompt
1089 - base_event_name = 'prompt' if is_prompt else 'decode'
1090 - self.profiler.start('internal', base_event_name)
1091 -
1092 - seq_group_metadata_list, real_batch_size, batch_size_padded = (
1093 - self._add_dummy_seq(seq_group_metadata_list, is_prompt))
1094 -
1095 - prefill_reqs = []
1096 - decode_reqs = []
1097 - for seq_group_meta in seq_group_metadata_list:
1098 - if seq_group_meta.is_prompt:
1099 - prefill_reqs.append(seq_group_meta)
1100 - else:
1101 - decode_reqs.append(seq_group_meta)
1102 -
1103 - # Prepare input tensors.
1104 - (
1105 - input_tokens,
1106 - input_positions,
1107 - prefill_attn_metadata,
1108 - seq_lens,
1109 - query_lens,
1110 - lora_index_mapping,
1111 - lora_prompt_mapping,
1112 - lora_requests,
1113 - multi_modal_kwargs,
1114 - slot_mapping,
1115 - lora_ids,
1116 - ) = self._prepare_prompt(prefill_reqs)
1117 - (
1118 - decode_input_tokens,
1119 - decode_input_positions,
1120 - decode_attn_metadata,
1121 - decode_lora_index_mapping,
1122 - decode_lora_prompt_mapping,
1123 - decode_lora_requests,
1124 - decode_slot_mapping,
1125 - decode_lora_ids,
1126 - ) = self._prepare_decode(decode_reqs)
1127 - sampling_metadata = SamplingMetadata.prepare(seq_group_metadata_list,
1128 - seq_lens, query_lens,
1129 - self.device,
1130 - self.pin_memory)
1131 -
1132 - if not self.scheduler_config.chunked_prefill_enabled:
1133 - assert (len(prefill_reqs) and len(decode_reqs)) == 0
1134 -
1135 - num_prefills = len(seq_lens)
1136 - num_prefill_tokens = len(input_tokens)
1137 - num_decode_tokens = len(decode_input_tokens)
1138 -
1139 - # NOTE(kzawora): Here we diverge from GPU code - we don't
1140 - # support mixed batches, so we either use decode or prefill
1141 - # inputs, without coalescing.
1142 - assert (num_prefills == 0 and num_decode_tokens > 0) or (
1143 - num_prefills > 0
1144 - and num_decode_tokens == 0), "HPU does not support mixed batches!"
1145 - if num_decode_tokens > 0:
1146 - input_tokens = decode_input_tokens
1147 - input_positions = decode_input_positions
1148 - slot_mapping = decode_slot_mapping
1149 - lora_index_mapping = decode_lora_index_mapping
1150 - lora_prompt_mapping = decode_lora_prompt_mapping
1151 - lora_requests = decode_lora_requests
1152 - lora_ids = decode_lora_ids
1153 -
1154 - # FIXME: We need to adjust selected_token_indices to accommodate
1155 - # for padding
1156 - max_len = input_tokens.size(1)
1157 - paddings = [max_len - q for q in query_lens]
1158 - paddings = [0] + paddings[:-1]
1159 - paddings = list(itertools.accumulate(paddings))
1160 - paddings_prompt_logprobs = []
1161 - for i, seq_group_metadata in enumerate(seq_group_metadata_list):
1162 - if seq_group_metadata.sampling_params.prompt_logprobs is not None \
1163 - and seq_group_metadata.is_prompt:
1164 - paddings_prompt_logprobs += ([paddings[i]] * seq_lens[i])
1165 - paddings = torch.tensor(
1166 - paddings_prompt_logprobs if paddings_prompt_logprobs else paddings,
1167 - dtype=sampling_metadata.selected_token_indices.dtype,
1168 - device=sampling_metadata.selected_token_indices.device)
1169 - sampling_metadata.selected_token_indices.add_(paddings)
1170 -
1171 - if self.lora_config:
1172 - lora_mapping = LoRAMapping(
1173 - **dict(index_mapping=lora_index_mapping,
1174 - prompt_mapping=lora_prompt_mapping,
1175 - is_prefill=(num_prefills > 0)))
1176 - else:
1177 - lora_mapping = None
1178 -
1179 - if (prefill_attn_metadata is not None
1180 - and decode_attn_metadata is not None):
1181 - batch_type = BatchType.MIXED
1182 - raise NotImplementedError("Mixed batch is not supported on HPU")
1183 - elif prefill_attn_metadata is not None:
1184 - batch_type = BatchType.PREFILL
1185 - else:
1186 - batch_type = BatchType.DECODE
1187 -
1188 - metadata_dict = {
1189 - "input_tokens": input_tokens,
1190 - "input_positions": input_positions,
1191 - "selected_token_indices": sampling_metadata.selected_token_indices,
1192 - "lora_requests": lora_requests,
1193 - "lora_mapping": lora_mapping,
1194 - "multi_modal_kwargs": multi_modal_kwargs,
1195 - "num_prefill_tokens": num_prefill_tokens,
1196 - "num_decode_tokens": num_decode_tokens,
1197 - "slot_mapping": slot_mapping,
1198 - "num_prefills": num_prefills,
1199 - "batch_type": batch_type,
1200 - "seq_lens": seq_lens,
1201 - "query_lens": query_lens
1202 - }
1203 - if prefill_attn_metadata is not None:
1204 - metadata_dict.update(prefill_attn_metadata.asdict_zerocopy())
1205 - else:
1206 - assert decode_attn_metadata is not None
1207 - metadata_dict.update(decode_attn_metadata.asdict_zerocopy())
1208 -
1209 - attn_metadata = prefill_attn_metadata if \
1210 - prefill_attn_metadata is not None else decode_attn_metadata
1211 -
1212 - return self._model_input_cls(input_tokens=input_tokens,
1213 - seq_lens=seq_lens,
1214 - query_lens=query_lens,
1215 - input_positions=input_positions,
1216 - attn_metadata=attn_metadata,
1217 - lora_requests=lora_requests,
1218 - lora_mapping=lora_mapping,
1219 - multi_modal_kwargs=multi_modal_kwargs,
1220 - real_batch_size=real_batch_size,
1221 - batch_size_padded=batch_size_padded,
1222 - lora_ids=lora_ids), \
1223 - sampling_metadata
1224 -
1225 - def _seq_len(self, attn_metadata):
1226 - if attn_metadata.num_prefills != 0:
1227 - return attn_metadata.slot_mapping.size(1)
1228 - else:
1229 - return attn_metadata.block_list.numel()
1230 -
1231 - def trim_attn_metadata(self, metadata: AttentionMetadata) -> object:
1232 - # NOTE(kzawora): To anyone working on this in the future:
1233 - # Trimming metadata is required when using HPUGraphs.
1234 - # Attention metadata is going to be hashed by PT bridge, and
1235 - # appropriate HPUGraphs will be matched based on all inputs' hash.
1236 -
1237 - # Before you put more keys in here, make sure you know their
1238 - # value type and make sure you know how it's going to be hashed.
1239 - # You can find that information in input_hash function
1240 - # in habana_frameworks/torch/hpu/graphs.py. You can also hash
1241 - # it manually with torch.hpu.graphs.input_hash(attention_metadata)
1242 -
1243 - # If you use primitive types here - they will get hashed based
1244 - # on their value. You *will* get lots of excessive graph captures
1245 - # (and an OOM eventually) if you decide to put something like
1246 - # seq_len int here.
1247 - # If you absolutely need a scalar, put it in a tensor. Tensors
1248 - # get hashed using their metadata, not their values:
1249 - # input_hash(torch.tensor(123)) == input_hash(torch.tensor(321))
1250 - # input_hash(123) != input_hash(321)
1251 - # input_hash("abc") != input_hash("cba")
1252 - attention_metadata = subtuple(metadata, 'TrimmedAttentionMetadata', [
1253 - 'attn_bias',
1254 - 'seq_lens_tensor',
1255 - 'context_lens_tensor',
1256 - 'block_list',
1257 - 'block_mapping',
1258 - 'block_usage',
1259 - 'slot_mapping',
1260 - 'is_prompt',
1261 - 'block_indices',
1262 - 'block_offsets',
1263 - 'block_groups',
1264 - ])
1265 - return attention_metadata
1266 -
1267 - def create_dummy_seq_group_metadata(self,
1268 - group_id,
1269 - seq_len,
1270 - is_prompt,
1271 - lora_request=None):
1272 - sampling_params = SamplingParams(temperature=0)
1273 - num_blocks = math.ceil(seq_len / self.block_size)
1274 - seq_len = max(seq_len, 1)
1275 - if is_prompt:
1276 - input_len = seq_len
1277 - output_len = 0
1278 - block_tables = None
1279 - else:
1280 - input_len = seq_len - 1
1281 - output_len = 1
1282 - block_tables = {group_id: [_PAD_BLOCK_ID] * num_blocks}
1283 - prompt_token_ids = [0] * input_len
1284 - output_token_ids = [1] * output_len
1285 - prompt_token_ids_array = array('l', prompt_token_ids) # noqa: F821
1286 - seq_data = SequenceData(prompt_token_ids_array)
1287 - seq_data.output_token_ids = output_token_ids
1288 - return SequenceGroupMetadata(request_id=str(group_id),
1289 - is_prompt=(output_len == 0),
1290 - seq_data={group_id: seq_data},
1291 - sampling_params=sampling_params,
1292 - block_tables=block_tables,
1293 - lora_request=lora_request)
1294 -
1295 - def profile_run(self) -> None:
1296 - num_layers = self.model_config.get_num_layers(self.parallel_config)
1297 - kv_caches = [None] * num_layers
1298 - bind_kv_cache(
1299 - self.vllm_config.compilation_config.static_forward_context,
1300 - [kv_caches])
1301 - _, max_seq_len = self.bucketing_ctx.get_max_prompt_shape()
1302 - max_batch_size = min(self.max_num_seqs,
1303 - self.max_num_batched_tokens // max_seq_len)
1304 - self.warmup_scenario(max_batch_size, max_seq_len, True, kv_caches,
1305 - False, True)
1306 - return
1307 -
1308 - def warmup_scenario(self,
1309 - batch_size,
1310 - seq_len,
1311 - is_prompt,
1312 - kv_caches,
1313 - is_pt_profiler_run=False,
1314 - is_lora_profile_run=False) -> None:
1315 - use_graphs = self._use_graphs(batch_size, seq_len, is_prompt)
1316 - scenario_name = ("warmup_"
1317 - f"{'prompt' if is_prompt else 'decode'}_"
1318 - f"bs{batch_size}_"
1319 - f"seq{seq_len}_"
1320 - f"graphs{'T' if use_graphs else 'F'}")
1321 - # This represents the maximum number of different requests
1322 - # that will have unique loras, an therefore the max amount of memory
1323 - # consumption create dummy lora request copies from the lora request
1324 - # passed in, which contains a lora from the lora warmup path.
1325 - dummy_lora_requests: List[LoRARequest] = []
1326 - dummy_lora_requests_per_seq: List[LoRARequest] = []
1327 - if self.lora_config and is_lora_profile_run:
1328 - assert self.lora_manager is not None
1329 - with self.lora_manager.dummy_lora_cache():
1330 - for idx in range(self.lora_config.max_loras):
1331 - lora_id = idx + 1
1332 - dummy_lora_request = LoRARequest(
1333 - lora_name=f"warmup_{lora_id}",
1334 - lora_int_id=lora_id,
1335 - lora_local_path="/not/a/real/path",
1336 - )
1337 - self.lora_manager.add_dummy_lora(dummy_lora_request,
1338 - rank=LORA_WARMUP_RANK)
1339 - dummy_lora_requests.append(dummy_lora_request)
1340 - dummy_lora_requests_per_seq = [
1341 - dummy_lora_requests[idx % len(dummy_lora_requests)]
1342 - for idx in range(batch_size)
1343 - ]
1344 - self.profiler.start('internal', scenario_name)
1345 - times = 3 if use_graphs or is_pt_profiler_run else 1
1346 - if is_prompt:
1347 - seqs = [
1348 - self.create_dummy_seq_group_metadata(
1349 - i,
1350 - seq_len,
1351 - is_prompt,
1352 - lora_request=dummy_lora_requests_per_seq[i]
1353 - if dummy_lora_requests_per_seq else None)
1354 - for i in range(batch_size)
1355 - ]
1356 - else:
1357 - # FIXME: seq_len is actually number of blocks
1358 - blocks = [seq_len // batch_size for _ in range(batch_size)]
1359 - blocks[0] += seq_len % batch_size
1360 - seqs = [
1361 - self.create_dummy_seq_group_metadata(
1362 - i,
1363 - b * self.block_size - 1,
1364 - is_prompt,
1365 - lora_request=dummy_lora_requests_per_seq[i]
1366 - if dummy_lora_requests_per_seq else None)
1367 - for i, b in enumerate(blocks)
1368 - ]
1369 - torch.hpu.synchronize()
1370 - profiler = None
1371 - if is_pt_profiler_run and self.is_driver_worker:
1372 - profiler = setup_profiler()
1373 - profiler.start()
1374 - for _ in range(times):
1375 - inputs = self.prepare_model_input(seqs)
1376 - is_single_step = \
1377 - self.vllm_config.scheduler_config.num_scheduler_steps == 1
1378 - if is_prompt or is_single_step:
1379 - self.execute_model(inputs, None, warmup_mode=True)
1380 - else: # decode with multi-step
1381 - inputs = dataclasses.replace(inputs,
1382 - is_first_multi_step=True,
1383 - is_last_step=False)
1384 - self.execute_model(inputs,
1385 - None,
1386 - warmup_mode=True,
1387 - num_steps=2,
1388 - seqs=seqs)
1389 - inputs = dataclasses.replace(inputs,
1390 - is_first_multi_step=False,
1391 - is_last_step=True)
1392 - self.execute_model(inputs,
1393 - None,
1394 - warmup_mode=True,
1395 - num_steps=2,
1396 - seqs=seqs)
1397 - torch.hpu.synchronize()
1398 - if profiler:
1399 - profiler.step()
1400 - if profiler:
1401 - profiler.stop()
1402 - self.profiler.end()
1403 - gc.collect()
1404 -
1405 - def remove_all_loras(self):
1406 - if not self.lora_manager:
1407 - raise RuntimeError("LoRA is not enabled.")
1408 - self.lora_manager.remove_all_adapters()
1409 -
1410 - def set_active_loras(self, lora_requests: Set[LoRARequest],
1411 - lora_mapping: LoRAMapping) -> None:
1412 - if not self.lora_manager:
1413 - raise RuntimeError("LoRA is not enabled.")
1414 - self.lora_manager.set_active_adapters(lora_requests, lora_mapping)
1415 -
1416 - def add_lora(self, lora_request: LoRARequest) -> bool:
1417 - if not self.lora_manager:
1418 - raise RuntimeError("LoRA is not enabled.")
1419 - return self.lora_manager.add_adapter(lora_request)
1420 -
1421 - def remove_lora(self, lora_id: int) -> bool:
1422 - if not self.lora_manager:
1423 - raise RuntimeError("LoRA is not enabled.")
1424 - return self.lora_manager.remove_adapter(lora_id)
1425 -
1426 - def pin_lora(self, lora_id: int) -> bool:
1427 - if not self.lora_manager:
1428 - raise RuntimeError("LoRA is not enabled.")
1429 - return self.lora_manager.pin_adapter(lora_id)
1430 -
1431 - def list_loras(self) -> Set[int]:
1432 - if not self.lora_manager:
1433 - raise RuntimeError("LoRA is not enabled.")
1434 - return self.lora_manager.list_adapters()
1435 -
1436 - def log_warmup(self, phase, i, max_i, batch_size, seq_len):
1437 - free_mem = format_bytes(
1438 - HabanaMemoryProfiler.current_free_device_memory())
1439 - dim = "num_blocks"
1440 - if phase == "Prompt":
1441 - dim = "seq_len"
1442 - msg = (f"[Warmup][{phase}][{i+1}/{max_i}] "
1443 - f"batch_size:{batch_size} "
1444 - f"{dim}:{seq_len} "
1445 - f"free_mem:{free_mem}")
1446 - logger.info(msg)
1447 -
1448 - def warmup_all_buckets(self, buckets, is_prompt, kv_caches):
1449 - for i, (batch_size, seq_len) in enumerate(reversed(buckets)):
1450 - self.log_warmup('Prompt' if is_prompt else 'Decode', i,
1451 - len(buckets), batch_size, seq_len)
1452 - self.warmup_scenario(batch_size, seq_len, is_prompt, kv_caches)
1453 -
1454 - def warmup_graphs(self,
1455 - strategy,
1456 - buckets,
1457 - is_prompt,
1458 - kv_caches,
1459 - available_mem,
1460 - starting_mem=0,
1461 - total_batch_seq=0.001):
1462 - total_mem = starting_mem
1463 - idx = 0
1464 - phase = f'Graph/{"Prompt" if is_prompt else "Decode"}'
1465 - num_candidates = len(buckets)
1466 - ordering : Union[Callable[[Any], Tuple[Any, Any]], \
1467 - Callable[[Any], Tuple[Any, Any, Any]]]
1468 - if strategy == 'min_tokens':
1469 - ordering = lambda b: (b[0] * b[1], b[1], b[0])
1470 - elif strategy == 'max_bs':
1471 - ordering = lambda b: (-b[0], b[1])
1472 - else:
1473 - raise NotImplementedError(
1474 - f'Unsupported graph allocation strategy: {strategy}')
1475 - buckets = list(sorted(buckets, key=ordering))
1476 - captured_all = True
1477 - for idx, (batch_size, seq_len) in enumerate(buckets):
1478 - # Graph memory usage is proportional to seq dimension in a batch
1479 - batch_seq = batch_size * seq_len if is_prompt else batch_size
1480 - mem_estimate = batch_seq / total_batch_seq * total_mem
1481 - if mem_estimate >= available_mem:
1482 - captured_all = False
1483 - continue
1484 - graphed_bucket = (batch_size, seq_len, is_prompt)
1485 - if graphed_bucket in self.graphed_buckets:
1486 - continue
1487 - self.graphed_buckets.add(graphed_bucket)
1488 - self.log_warmup(phase, idx, num_candidates, batch_size, seq_len)
1489 - with HabanaMemoryProfiler() as mem_prof:
1490 - self.warmup_scenario(batch_size, seq_len, is_prompt, kv_caches)
1491 - used_mem = align_workers(mem_prof.consumed_device_memory,
1492 - torch.distributed.ReduceOp.MAX)
1493 - available_mem -= used_mem
1494 - total_mem += used_mem
1495 - total_batch_seq += batch_seq
1496 -
1497 - return total_mem, total_batch_seq, captured_all
1498 -
1499 - def log_graph_warmup_summary(self, buckets, is_prompt, total_mem):
1500 - num_candidates = len(buckets)
1501 - phase = f'Graph/{"Prompt" if is_prompt else "Decode"}'
1502 - graphed = list(c[:2] for c in self.graphed_buckets
1503 - if c[2] == is_prompt)
1504 - if num_candidates == 0:
1505 - num_candidates = 1
1506 - msg = (f'{phase} captured:{len(graphed)} '
1507 - f'({100 * len(graphed) / num_candidates:.1f}%) '
1508 - f'used_mem:{format_bytes(total_mem)} '
1509 - f'buckets:{sorted(list(graphed))}')
1510 - logger.info(msg)
1511 -
1512 - @torch.inference_mode()
1513 - def warmup_model(self, kv_caches: List[torch.Tensor]) -> None:
1514 - max_blocks = kv_caches[0][0].size(0)
1515 - self.bucketing_ctx.generate_decode_buckets(max_blocks)
1516 - if profile := os.environ.get('VLLM_PT_PROFILE', None):
1517 - phase, bs, seq_len, graph = profile.split('_')
1518 - is_prompt = phase == 'prompt'
1519 - graphs = graph == 't'
1520 - if graphs:
1521 - self.graphed_buckets.add((int(bs), int(seq_len), is_prompt))
1522 - self.warmup_scenario(int(bs), int(seq_len), is_prompt, kv_caches,
1523 - True)
1524 - raise AssertionError("Finished profiling")
1525 - if not htorch.utils.internal.is_lazy() and not self.enforce_eager:
1526 - cache_size_limit = 1 + 3 * (
1527 - len(self.bucketing_ctx.prompt_buckets) +
1528 - len(self.bucketing_ctx.decode_buckets))
1529 - torch._dynamo.config.cache_size_limit = max(
1530 - cache_size_limit, torch._dynamo.config.cache_size_limit)
1531 - # Multiply by 8 to follow the original default ratio between
1532 - # the cache_size_limit and accumulated_cache_size_limit
1533 - torch._dynamo.config.accumulated_cache_size_limit = max(
1534 - cache_size_limit * 8,
1535 - torch._dynamo.config.accumulated_cache_size_limit)
1536 - if self.skip_warmup:
1537 - logger.info("Skipping warmup...")
1538 - return
1539 - self.profiler.start('internal', 'warmup')
1540 - start_mem = HabanaMemoryProfiler.current_device_memory_usage()
1541 - start_time = time.perf_counter()
1542 -
1543 - compile_only_mode_context = functools.partial(bc.env_setting,
1544 - "PT_COMPILE_ONLY_MODE",
1545 - True)
1546 - can_use_compile_only_mode = True
1547 - try:
1548 - with compile_only_mode_context():
1549 - pass
1550 - logger.debug("Using PT_COMPILE_ONLY_MODE.")
1551 - except KeyError:
1552 - can_use_compile_only_mode = False
1553 - logger.warning('Cannot use PT_COMPILE_ONLY_MODE. '
1554 - 'Warmup time will be negatively impacted. '
1555 - 'Please update Gaudi Software Suite.')
1556 - with compile_only_mode_context(
1557 - ) if can_use_compile_only_mode else contextlib.nullcontext():
1558 - self.warmup_all_buckets(self.bucketing_ctx.prompt_buckets, True,
1559 - kv_caches)
1560 - self.warmup_all_buckets(self.bucketing_ctx.decode_buckets, False,
1561 - kv_caches)
1562 -
1563 - if not self.enforce_eager and htorch.utils.internal.is_lazy():
1564 - assert self.mem_margin is not None, \
1565 - ("HabanaWorker.determine_num_available_blocks needs "
1566 - "to be called before warming up the model.")
1567 - free_mem = HabanaMemoryProfiler.current_free_device_memory()
1568 - graph_free_mem = free_mem - self.mem_margin
1569 - graph_free_mem = align_workers(graph_free_mem,
1570 - torch.distributed.ReduceOp.MIN)
1571 - prompt_graph_mem_ratio = float(
1572 - os.environ.get('VLLM_GRAPH_PROMPT_RATIO', '0.3'))
1573 - prompt_available_memory = (prompt_graph_mem_ratio *
1574 - graph_free_mem)
1575 - decode_available_memory = (graph_free_mem -
1576 - prompt_available_memory)
1577 - msg = (
1578 - f"Using {format_bytes(graph_free_mem)}"
1579 - f"/{format_bytes(free_mem)} "
1580 - "of free device memory for HPUGraphs, "
1581 - f"{format_bytes(prompt_available_memory)} for prompt and "
1582 - f"{format_bytes(decode_available_memory)} for decode "
1583 - f"(VLLM_GRAPH_PROMPT_RATIO={prompt_graph_mem_ratio})")
1584 - logger.info(msg)
1585 - prompt_strategy = os.environ.get('VLLM_GRAPH_PROMPT_STRATEGY',
1586 - 'min_tokens')
1587 - decode_strategy = os.environ.get('VLLM_GRAPH_DECODE_STRATEGY',
1588 - 'max_bs')
1589 - mem_post_prompt, prompt_batch_seq, prompt_captured_all = \
1590 - self.warmup_graphs(
1591 - prompt_strategy, self.bucketing_ctx.prompt_buckets,
1592 - True, kv_caches, prompt_available_memory)
1593 - mem_post_decode, decode_batch_seq, decode_captured_all = \
1594 - self.warmup_graphs(
1595 - decode_strategy, self.bucketing_ctx.decode_buckets,
1596 - False, kv_caches, decode_available_memory)
1597 -
1598 - # Not all prompt buckets were captured, but all decode buckets
1599 - # were captured and we have some free graph-allocated space
1600 - # left. Let's try to use it for capturing more prompt buckets.
1601 - if (mem_post_decode + mem_post_prompt < graph_free_mem
1602 - and not prompt_captured_all and decode_captured_all):
1603 - mem_post_prompt, _, prompt_captured_all = (
1604 - self.warmup_graphs(
1605 - prompt_strategy, self.bucketing_ctx.prompt_buckets,
1606 - True, kv_caches,
1607 - graph_free_mem - mem_post_prompt - mem_post_decode,
1608 - mem_post_prompt, prompt_batch_seq))
1609 -
1610 - # Not all decode buckets were captured, but all prompt buckets
1611 - # were captured and we have some free graph-allocated space
1612 - # left. Let's try to use it for capturing more decode buckets.
1613 - if mem_post_decode + mem_post_prompt < graph_free_mem \
1614 - and not decode_captured_all \
1615 - and prompt_captured_all:
1616 - mem_post_decode, _, _ = self.warmup_graphs(
1617 - decode_strategy, self.bucketing_ctx.decode_buckets,
1618 - False, kv_caches,
1619 - graph_free_mem - mem_post_prompt - mem_post_decode,
1620 - mem_post_decode, decode_batch_seq)
1621 -
1622 - self.log_graph_warmup_summary(
1623 - self.bucketing_ctx.prompt_buckets, True, mem_post_prompt)
1624 - self.log_graph_warmup_summary(
1625 - self.bucketing_ctx.decode_buckets, False, mem_post_decode)
1626 -
1627 - end_time = time.perf_counter()
1628 - end_mem = HabanaMemoryProfiler.current_device_memory_usage()
1629 - elapsed_time = end_time - start_time
1630 - msg = (
1631 - f"Warmup finished in {elapsed_time:.0f} secs, "
1632 - f"allocated {format_bytes(end_mem - start_mem)} of device memory")
1633 - logger.info(msg)
1634 - self.profiler.end()
1635 -
1636 - @property
1637 - def vocab_size(self) -> int:
1638 - return self.model_config.get_vocab_size()
1639 -
1640 - @property
1641 - def mem_margin(self) -> Optional[int]:
1642 - return self._mem_margin
1643 -
1644 - @mem_margin.setter
1645 - def mem_margin(self, value):
1646 - self._mem_margin = value
1647 -
1648 -
1649 -def _maybe_wrap_in_hpu_graph(*args, **kwargs):
1650 - return htorch.hpu.wrap_in_hpu_graph(
1651 - HpuModelAdapter(*args, **kwargs), disable_tensor_cache=True
1652 - ) if htorch.utils.internal.is_lazy() else HpuModelAdapter(*args, **kwargs)
1653 -
1654 -
1655 -class HabanaProfilerCounterHelper:
1656 -
1657 - def __init__(self):
1658 - self.niter = 0
1659 - self.average_real_throughput = None
1660 - self.logged_once = False
1661 - self.real_seq_lens = []
1662 - self.prompt_seq_lens = []
1663 -
1664 - def capture_seq_group_metadata_stats(self, seq_group_metadata_list):
1665 - self.real_seq_lens = [
1666 - len(seq_data.prompt_token_ids) + len(seq_data.output_token_ids)
1667 - for seq_group_metadata in seq_group_metadata_list
1668 - for seq_data in seq_group_metadata.seq_data.values()
1669 - ]
1670 - self.prompt_seq_lens = [
1671 - len(seq_data.prompt_token_ids)
1672 - for seq_group_metadata in seq_group_metadata_list
1673 - for seq_data in seq_group_metadata.seq_data.values()
1674 - ]
1675 -
1676 - def get_counter_dict(self, cache_config, duration, seq_len,
1677 - batch_size_padded, real_batch_size, is_prompt):
1678 - throughput = batch_size_padded / (duration / 1e6)
1679 - throughput_effective = real_batch_size / (duration / 1e6)
1680 -
1681 - real_max_seq_len = max(self.real_seq_lens)
1682 - real_num_tokens = sum(self.real_seq_lens)
1683 - padded_num_tokens = batch_size_padded * seq_len
1684 - batch_token_utilization = real_num_tokens / padded_num_tokens
1685 - if self.average_real_throughput is None:
1686 - self.average_real_throughput = throughput_effective
1687 - else: # https://www.heikohoffmann.de/htmlthesis/node134.html
1688 - self.average_real_throughput = self.average_real_throughput + 1 / (
1689 - self.niter + 1) * (throughput_effective -
1690 - self.average_real_throughput)
1691 - phase = "prompt" if is_prompt else "decode"
1692 - counters = {
1693 - f'{phase}_bucket_batch_size': batch_size_padded,
1694 - f'{phase}_batch_size': real_batch_size,
1695 - f'{phase}_bucket_seq_len': seq_len,
1696 - f'{phase}_seq_len': real_max_seq_len,
1697 - f'{phase}_bucket_gen_throughput': throughput,
1698 - f'{phase}_real_gen_throughput': throughput_effective,
1699 - f'{phase}_batch_token_utilization': batch_token_utilization,
1700 - 'average_real_throughput': self.average_real_throughput,
1701 - 'engine_iteration': self.niter,
1702 - }
1703 - self.niter += 1
1704 - if is_prompt:
1705 - prompt_bucket_in_throughput = (seq_len * batch_size_padded) / (
1706 - duration / 1e6)
1707 - prompt_real_in_throughput = sum(
1708 - self.prompt_seq_lens) / (duration / 1e6)
1709 - counters[
1710 - f'{phase}_bucket_in_throughput'] = prompt_bucket_in_throughput
1711 - counters[f'{phase}_real_in_throughput'] = prompt_real_in_throughput
1712 -
1713 - # KV cache might not be created yet (e.g. for profiling run)
1714 - if cache_config.num_gpu_blocks is not None and \
1715 - cache_config.num_gpu_blocks != 0:
1716 - cache_num_blocks_used = [
1717 - math.ceil(sl / cache_config.block_size)
1718 - for sl in self.real_seq_lens
1719 - ]
1720 - cache_total_num_blocks_used = sum(cache_num_blocks_used)
1721 - num_cache_blocks = cache_config.num_gpu_blocks
1722 - cache_total_num_free_blocks = \
1723 - num_cache_blocks - cache_total_num_blocks_used
1724 - cache_computed_utilization = \
1725 - cache_total_num_blocks_used / num_cache_blocks
1726 - max_blocks_per_seq = math.ceil(seq_len / cache_config.block_size)
1727 - batch_block_utilization = cache_total_num_blocks_used / (
1728 - batch_size_padded * max_blocks_per_seq)
1729 - counters['cache_num_blocks_used'] = cache_total_num_blocks_used
1730 - counters['cache_num_free_blocks'] = cache_total_num_free_blocks
1731 - counters['cache_computed_utilization'] = cache_computed_utilization
1732 - counters[
1733 - f'{phase}_batch_block_utilization'] = batch_block_utilization
1734 - if not self.logged_once:
1735 - counters['const_cache_num_blocks'] = cache_config.num_gpu_blocks
1736 - counters[
1737 - 'const_gpu_memory_utilization'] = \
1738 - cache_config.gpu_memory_utilization
1739 - counters['const_block_size'] = cache_config.block_size
1740 - self.logged_once = True
1741 - return counters
1742 -
1743 -
1744 -def unwrap_model(model):
1745 - if isinstance(model, torch._dynamo.eval_frame.OptimizedModule):
1746 - return unwrap_model(model._orig_mod)
1747 - else:
1748 - model = list(vars(model)['_modules'].values())[0]
1749 - modules = list(vars(model)['_modules'].values())
1750 - return modules
1751 -
1752 -
1753 -class HPUModelRunner(HPUModelRunnerBase[ModelInputForHPUWithSamplingMetadata]):
1754 - """
1755 - GPU model runner with sampling step.
1756 - """
1757 - _model_input_cls: Type[ModelInputForHPUWithSamplingMetadata] = (
1758 - ModelInputForHPUWithSamplingMetadata)
1759 -
1760 - def make_model_input_from_broadcasted_tensor_dict(
1761 - self,
1762 - tensor_dict: Dict[str, Any],
1763 - ) -> ModelInputForHPUWithSamplingMetadata:
1764 - return (
1765 - ModelInputForHPUWithSamplingMetadata.from_broadcasted_tensor_dict(
1766 - tensor_dict,
1767 - attn_backend=self.attn_backend,
1768 - ))
1769 -
1770 - @torch.inference_mode()
1771 - def prepare_model_input(
1772 - self,
1773 - seq_group_metadata_list: List[SequenceGroupMetadata],
1774 - virtual_engine: int = 0,
1775 - finished_requests_ids: Optional[List[str]] = None
1776 - ) -> ModelInputForHPUWithSamplingMetadata:
1777 - """Prepare the model input based on a given sequence group, including
1778 - metadata for the sampling step.
1779 - The API assumes seq_group_metadata_list is sorted by prefill -> decode.
1780 - The result tensors and data structure also batches input in prefill
1781 - -> decode order. For example,
1782 - - input_tokens[:num_prefill_tokens] contains prefill tokens.
1783 - - input_tokens[num_prefill_tokens:] contains decode tokens.
1784 - If cuda graph is required, this API automatically pads inputs.
1785 - """
1786 - with self.profiler.record_event('internal', 'prepare_input_tensors'):
1787 - assert seq_group_metadata_list is not None
1788 - if self.profiler.enabled:
1789 - self.profiler_counter_helper.capture_seq_group_metadata_stats(
1790 - seq_group_metadata_list=seq_group_metadata_list)
1791 - model_input, sampling_metadata = self.prepare_input_tensors(
1792 - seq_group_metadata_list)
1793 - assert model_input.attn_metadata is not None
1794 - is_prompt = model_input.attn_metadata.is_prompt
1795 -
1796 - return dataclasses.replace(model_input,
1797 - sampling_metadata=sampling_metadata,
1798 - is_prompt=is_prompt,
1799 - virtual_engine=virtual_engine)
1800 -
1801 - def finish_measurements(self):
1802 - from neural_compressor.torch.quantization import finalize_calibration
1803 - finalize_calibration(self.model.model)
1804 -
1805 - def _num_blocks(self, attn_metadata):
1806 - if attn_metadata.block_list is None:
1807 - return 0
1808 - return attn_metadata.block_list.numel()
1809 -
1810 - def _phase(self, attn_metadata):
1811 - phase_type: PhaseType
1812 - is_prompt = attn_metadata.is_prompt
1813 - is_prefix_prefill = is_prompt and attn_metadata.block_list is not None
1814 - if is_prompt and is_prefix_prefill:
1815 - phase_type = PhaseType.PREFIX_PREFILL
1816 - elif is_prompt and not is_prefix_prefill:
1817 - phase_type = PhaseType.PREFILL
1818 - elif not is_prompt:
1819 - phase_type = PhaseType.DECODE
1820 - else:
1821 - raise ValueError("Unrecognized pass type, likely due to malformed "
1822 - "attention metadata")
1823 - return phase_type
1824 -
1825 - def _check_config(self, batch_size, seq_len, attn_metadata, warmup_mode):
1826 - is_prefix_caching = self.vllm_config.cache_config.enable_prefix_caching
1827 - cfg: Optional[tuple] = None
1828 - assert cfg is None, "Configs changed between 2D and 3D"
1829 - if is_prefix_caching:
1830 - phase = self._phase(attn_metadata)
1831 - num_blocks = self._num_blocks(attn_metadata)
1832 - cfg = (batch_size, seq_len, num_blocks, phase)
1833 - else:
1834 - phase = 'prompt' if attn_metadata.is_prompt else 'decode'
1835 - cfg = (batch_size, seq_len, phase)
1836 - seen = cfg in self.seen_configs
1837 - self.seen_configs.add(cfg)
1838 - if not seen and not warmup_mode:
1839 - logger.warning("Configuration: %s was not warmed-up!",
1840 - (phase.value, batch_size, seq_len,
1841 - num_blocks) if is_prefix_caching else
1842 - (phase, batch_size, seq_len))
1843 -
1844 - def create_lora_mask(self, input_tokens: torch.Tensor, lora_ids: List[int],
1845 - is_prompt: bool):
1846 - '''
1847 - This is a helper function to create the mask for lora computations.
1848 - Lora Mask is needed to ensure we match the correct lora weights for the
1849 - for the request.
1850 - For Prompt phase we have
1851 - lora_mask with shape (batch_size * seq_len, max_loras * max_rank)
1852 - lora_logits_mask with shape (batch_size, max_loras * max_rank)
1853 - For Decode phase we have both
1854 - lora_mask and lora_logits_mask with shape
1855 - (batch_size, max_loras * max_rank)
1856 - '''
1857 - lora_mask: torch.Tensor = None
1858 - lora_logits_mask: torch.Tensor = None
1859 - lora_index = 0
1860 -
1861 - if self.lora_config:
1862 - if is_prompt:
1863 - lora_mask = torch.zeros(
1864 - input_tokens.shape[0] * input_tokens.shape[1],
1865 - (self.lora_config.max_loras) *\
1866 - self.lora_config.max_lora_rank,
1867 - dtype=self.lora_config.lora_dtype)
1868 - lora_logits_mask = torch.zeros(
1869 - input_tokens.shape[0], (self.lora_config.max_loras) *
1870 - self.lora_config.max_lora_rank,
1871 - dtype=self.lora_config.lora_dtype)
1872 -
1873 - ones = torch.ones(input_tokens.shape[1],
1874 - self.lora_config.max_lora_rank,
1875 - dtype=self.lora_config.lora_dtype)
1876 - logit_ones = torch.ones(1,
1877 - self.lora_config.max_lora_rank,
1878 - dtype=self.lora_config.lora_dtype)
1879 -
1880 - for i in range(len(lora_ids)):
1881 - if lora_ids[i] == 0:
1882 - continue
1883 - lora_index = self.lora_manager._adapter_manager.\
1884 - lora_index_to_id.index(lora_ids[i])
1885 - start_row = i * input_tokens.shape[1]
1886 - end_row = start_row + input_tokens.shape[1]
1887 - start_col = lora_index * self.lora_config.max_lora_rank
1888 - end_col = start_col + self.lora_config.max_lora_rank
1889 - lora_mask[start_row:end_row, start_col:end_col] = ones
1890 - lora_logits_mask[i, start_col:end_col] = logit_ones
1891 - lora_mask = lora_mask.to('hpu')
1892 - lora_logits_mask = lora_logits_mask.to('hpu')
1893 - else:
1894 - lora_mask = torch.zeros(input_tokens.shape[0],
1895 - (self.lora_config.max_loras) *
1896 - self.lora_config.max_lora_rank,
1897 - dtype=self.lora_config.lora_dtype)
1898 - ones = torch.ones(1,
1899 - self.lora_config.max_lora_rank,
1900 - dtype=self.lora_config.lora_dtype)
1901 - for i in range(len(lora_ids)):
1902 - if lora_ids[i] == 0:
1903 - continue
1904 - lora_index = self.lora_manager._adapter_manager.\
1905 - lora_index_to_id.index(lora_ids[i])
1906 - start_pos = lora_index * self.lora_config.max_lora_rank
1907 - end_pos = start_pos + self.lora_config.max_lora_rank
1908 - lora_mask[i, start_pos:end_pos] = ones
1909 - lora_mask = lora_mask.to('hpu')
1910 - lora_logits_mask = lora_mask
1911 -
1912 - return lora_mask, lora_logits_mask
1913 -
1914 - def _get_seq_ids(self, model_input):
1915 - return ([
1916 - sg.seq_ids[0] for sg in model_input.sampling_metadata.seq_groups
1917 - ])
1918 -
1919 - def _pad_to_max_num_seqs(self, tensor, value):
1920 - padding_needed = self.max_num_seqs - tensor.size(0)
1921 - if padding_needed:
1922 - padding = torch.full((padding_needed, *tensor.shape[1:]),
1923 - value,
1924 - device=tensor.device,
1925 - dtype=tensor.dtype)
1926 - tensor = torch.cat([tensor, padding])
1927 - return tensor
1928 -
1929 - @torch.inference_mode()
1930 - def execute_model(
1931 - self,
1932 - model_input: ModelInputForHPUWithSamplingMetadata,
1933 - kv_caches: List[torch.Tensor],
1934 - intermediate_tensors: Optional[IntermediateTensors] = None,
1935 - num_steps: int = 1,
1936 - warmup_mode=False,
1937 - seqs=None,
1938 - ) -> Optional[Union[List[SamplerOutput], IntermediateTensors]]:
1939 - VLLM_DELAYED_SAMPLING = envs.VLLM_HPU_USE_DELAYED_SAMPLING
1940 - use_delayed_sampling = VLLM_DELAYED_SAMPLING and not warmup_mode
1941 - assert not (use_delayed_sampling and num_steps != 1), \
1942 - 'Delayed sampling is not compatible with MSS!'
1943 - assert model_input.input_tokens is not None
1944 - if use_delayed_sampling and not model_input.is_prompt and \
1945 - self.is_driver_worker:
1946 - num_cached = len(self.cached_step_outputs)
1947 - assert num_cached > 0
1948 - cur_seq_ids = self._get_seq_ids(model_input)
1949 - cur_seq_id_pos = {
1950 - sid: idx
1951 - for idx, sid in enumerate(cur_seq_ids) if sid >= 0
1952 - }
1953 - htorch.core.mark_step()
1954 - for i in range(num_cached):
1955 - prev_seq_ids = self._get_seq_ids(self.cached_step_inputs[i])
1956 - target_indices = [
1957 - cur_seq_id_pos.get(psi, -1) for psi in prev_seq_ids
1958 - ]
1959 - padding = self.cached_step_outputs[i].size(0) - len(
1960 - target_indices)
1961 - target_indices.extend([-1] * padding)
1962 - target_indices = torch.tensor(
1963 - target_indices,
1964 - device=model_input.input_tokens.device,
1965 - dtype=model_input.input_tokens.dtype)
1966 - model_input.input_tokens.index_copy_(
1967 - 0, target_indices, self.cached_step_outputs[i])
1968 - htorch.core.mark_step()
1969 -
1970 - if not model_input.is_first_multi_step:
1971 - if not model_input.is_last_step:
1972 - # not first or last multi-step
1973 - return []
1974 - # last multi-step
1975 - output = self._decode_sampler_outputs(
1976 - model_input) if self.is_driver_worker else []
1977 - torch.hpu.synchronize()
1978 - if model_input.is_first_multi_step:
1979 - # first multi-step
1980 - if self.lora_config:
1981 - assert model_input.lora_requests is not None
1982 - assert model_input.lora_mapping is not None
1983 - self.set_active_loras(model_input.lora_requests,
1984 - model_input.lora_mapping)
1985 - # Rank!=0 workers has is_prompt==None
1986 - if use_delayed_sampling and not model_input.is_prompt and \
1987 - model_input.input_tokens.size(1) == 1:
1988 - if self.is_driver_worker:
1989 - model_kwargs_broadcast_data = {
1990 - "input_tokens": model_input.input_tokens
1991 - }
1992 - broadcast_tensor_dict(model_kwargs_broadcast_data, src=0)
1993 - input_tokens = model_input.input_tokens
1994 -
1995 - else:
1996 - model_kwargs_broadcast_data = broadcast_tensor_dict(src=0)
1997 - input_tokens = model_kwargs_broadcast_data["input_tokens"]
1998 - else:
1999 - input_tokens = model_input.input_tokens
2000 - input_positions = model_input.input_positions
2001 - attn_metadata = model_input.attn_metadata
2002 - sampling_metadata = model_input.sampling_metadata
2003 - real_batch_size = model_input.real_batch_size
2004 - batch_size_padded = model_input.batch_size_padded
2005 - assert input_tokens is not None
2006 - assert input_positions is not None
2007 - assert sampling_metadata is not None
2008 - assert attn_metadata is not None
2009 - is_prompt = attn_metadata.is_prompt
2010 - assert is_prompt is not None
2011 - batch_size = input_tokens.size(0)
2012 - seq_len = self._seq_len(attn_metadata)
2013 - use_graphs = self._use_graphs(batch_size, seq_len, is_prompt)
2014 - self._check_config(batch_size, seq_len, attn_metadata, warmup_mode)
2015 -
2016 - lora_mask: torch.Tensor = None
2017 - lora_logits_mask: torch.Tensor = None
2018 - if self.lora_config:
2019 - assert model_input.lora_ids is not None
2020 - lora_mask, lora_logits_mask = self.create_lora_mask(
2021 - input_tokens, model_input.lora_ids,
2022 - attn_metadata.is_prompt)
2023 -
2024 - execute_model_kwargs = {
2025 - "input_ids": input_tokens,
2026 - "positions": input_positions,
2027 - "attn_metadata": self.trim_attn_metadata(attn_metadata),
2028 - "intermediate_tensors": intermediate_tensors,
2029 - "lora_mask": lora_mask,
2030 - "virtual_engine": model_input.virtual_engine,
2031 - **(model_input.multi_modal_kwargs or {}),
2032 - }
2033 - if htorch.utils.internal.is_lazy():
2034 - execute_model_kwargs.update(
2035 - {"bypass_hpu_graphs": not use_graphs})
2036 -
2037 - htorch.core.mark_step()
2038 - if self.is_driver_worker:
2039 - model_event_name = ("model_"
2040 - f"{'prompt' if is_prompt else 'decode'}_"
2041 - f"bs{batch_size}_"
2042 - f"seq{seq_len}_"
2043 - f"graphs{'T' if use_graphs else 'F'}")
2044 - else:
2045 - model_event_name = 'model_executable'
2046 - if num_steps > 1 or use_delayed_sampling:
2047 - # in case of multi-step scheduling
2048 - # we only want to pythonize in the last step
2049 - sampling_metadata.skip_sampler_cpu_output = True
2050 - self.model.sampler.include_gpu_probs_tensor = True
2051 - cache_orig_output_tokens_len: List[Dict] = []
2052 -
2053 - def try_revert_dummy_output_tokens():
2054 - if len(cache_orig_output_tokens_len) > 0:
2055 - # Reuse the original output token ids length
2056 - for i, seq_group_metadata in enumerate(
2057 - seq_group_metadata_list):
2058 - for j, data in seq_group_metadata.seq_data.items():
2059 - orig_output_tokens_len = \
2060 - cache_orig_output_tokens_len[i][j]
2061 - data.output_token_ids = \
2062 - data.output_token_ids[:orig_output_tokens_len]
2063 -
2064 - for i in range(num_steps):
2065 - if i != 0 and not self.is_driver_worker:
2066 - broadcast_data = broadcast_tensor_dict(src=0)
2067 - if 'early_exit' in broadcast_data and broadcast_data[
2068 - 'early_exit']:
2069 - return [output] if num_steps == 1 else []
2070 - execute_model_kwargs.update({
2071 - "input_ids":
2072 - broadcast_data["input_ids"],
2073 - "positions":
2074 - broadcast_data["positions"],
2075 - "attn_metadata":
2076 - self.trim_attn_metadata(
2077 - broadcast_data["attn_metadata"])
2078 - })
2079 - with self.profiler.record_event('internal', model_event_name):
2080 - hidden_states = self.model.forward(
2081 - **execute_model_kwargs,
2082 - selected_token_indices=sampling_metadata.
2083 - selected_token_indices)
2084 -
2085 - if self.lora_config:
2086 - LoraMask.setLoraMask(
2087 - lora_logits_mask.index_select(
2088 - 0, sampling_metadata.selected_token_indices))
2089 -
2090 - # Compute the logits.
2091 - with self.profiler.record_event(
2092 - 'internal',
2093 - ('compute_logits_'
2094 - f'{"prompt" if is_prompt else "decode"}_bs'
2095 - f'{batch_size}_'
2096 - f'seq{seq_len}')):
2097 - if num_steps == 1:
2098 - sampling_metadata.selected_token_indices = None
2099 - logits = self.model.compute_logits(hidden_states,
2100 - sampling_metadata)
2101 - htorch.core.mark_step()
2102 - # Only perform sampling in the driver worker.
2103 - if not self.is_driver_worker:
2104 - continue
2105 -
2106 - if use_delayed_sampling:
2107 - fake_output = self._delayed_sampler_outputs(model_input)
2108 -
2109 - with self.profiler.record_event(
2110 - 'internal', ('sample_'
2111 - f'{"prompt" if is_prompt else "decode"}_'
2112 - f'bs{batch_size}_'
2113 - f'seq{seq_len}')):
2114 - output = self.model.sample(
2115 - logits=logits,
2116 - sampling_metadata=sampling_metadata,
2117 - )
2118 - if num_steps > 1:
2119 - output = output.sampled_token_ids
2120 - self.cached_step_outputs.append(output)
2121 - if use_delayed_sampling and self.is_driver_worker:
2122 - self._patch_prev_output()
2123 - output = self._pad_to_max_num_seqs(
2124 - output.sampled_token_ids, DUMMY_TOKEN_ID)
2125 - self.cached_step_outputs.append(output)
2126 - self.cached_step_inputs.append(model_input)
2127 - htorch.core.mark_step()
2128 - if model_input.async_callback is not None:
2129 - model_input.async_callback()
2130 - if i < num_steps - 1:
2131 - if i == 0:
2132 - if model_input.async_callback is not None:
2133 - ctx = model_input.async_callback.keywords[ # type: ignore
2134 - "ctx"]
2135 - seq_group_metadata_list = \
2136 - ctx.seq_group_metadata_list
2137 - elif seqs is not None:
2138 - seq_group_metadata_list = seqs
2139 - else:
2140 - raise RuntimeError(
2141 - "seq_group_metadata_list is uninitialized")
2142 - for i, seq_group_metadata in enumerate(
2143 - seq_group_metadata_list):
2144 - # Skip empty steps
2145 - seq_group_metadata.state.current_step += (
2146 - num_steps - 2)
2147 - # Cache the original output token ids
2148 - cache_orig_output_tokens_len.append({})
2149 - for j, data in seq_group_metadata.seq_data.items():
2150 - cache_orig_output_tokens_len[i][j] = \
2151 - len(data.output_token_ids)
2152 - for seq_group_metadata in seq_group_metadata_list:
2153 - for data in seq_group_metadata.seq_data.values():
2154 - max_output_len = sampling_metadata.seq_groups[
2155 - 0].sampling_params.max_tokens
2156 - if len(data.output_token_ids) < max_output_len - 1:
2157 - # add a place holder for prepare_decode
2158 - # arbitrary value, this could be any token
2159 - dummy_token = (540, )
2160 - data.output_token_ids += (dummy_token)
2161 - else:
2162 - broadcast_tensor_dict({'early_exit': True},
2163 - src=0)
2164 - if num_steps == 1:
2165 - return [output]
2166 - else:
2167 - try_revert_dummy_output_tokens()
2168 - return []
2169 -
2170 - result = self._prepare_decode(seq_group_metadata_list,
2171 - output=output)
2172 - execute_model_kwargs.update({
2173 - "input_ids":
2174 - result.input_tokens,
2175 - "positions":
2176 - result.input_positions,
2177 - "attn_metadata":
2178 - self.trim_attn_metadata(result.attn_metadata)
2179 - })
2180 - model_kwargs_broadcast_data = {
2181 - "input_ids": result.input_tokens,
2182 - "positions": result.input_positions,
2183 - "attn_metadata": vars(result.attn_metadata)
2184 - }
2185 - broadcast_tensor_dict(model_kwargs_broadcast_data, src=0)
2186 - else:
2187 - try_revert_dummy_output_tokens()
2188 -
2189 - if self.is_driver_worker and self.profiler.enabled:
2190 - # Stop recording 'execute_model' event
2191 - self.profiler.end()
2192 - event_end = self.profiler.get_timestamp_us()
2193 - counters = self.profiler_counter_helper.get_counter_dict(
2194 - cache_config=self.cache_config,
2195 - duration=event_end - self.event_start,
2196 - seq_len=seq_len,
2197 - batch_size_padded=batch_size_padded,
2198 - real_batch_size=real_batch_size,
2199 - is_prompt=is_prompt)
2200 - self.profiler.record_counter(self.event_start, counters)
2201 - if num_steps == 1:
2202 - if self.return_hidden_states:
2203 - # we only need to pass hidden states of most recent token
2204 - assert model_input.sampling_metadata is not None
2205 - if model_input.is_prompt:
2206 - output.prefill_hidden_states = hidden_states
2207 - output.hidden_states = hidden_states
2208 - if use_delayed_sampling:
2209 - if self.is_driver_worker:
2210 - return [fake_output]
2211 - else:
2212 - return []
2213 -
2214 - return [output] if self.is_driver_worker else []
2215 - else:
2216 - return []
2217 - return output if type(output) is list else [output]
2218 -
2219 - def _delayed_sampler_outputs(self, model_input):
2220 - next_token_ids = [[DUMMY_TOKEN_ID]] * len(
2221 - model_input.sampling_metadata.seq_groups)
2222 - sampler_output = self._make_decode_output(
2223 - next_token_ids, model_input.sampling_metadata.seq_groups)
2224 - return sampler_output
2225 -
2226 - def _decode_sampler_outputs(self, model_input):
2227 - use_async_out_proc = model_input.async_callback is not None
2228 - sampler_outputs = []
2229 - num_outputs = len(self.cached_step_outputs)
2230 - for i in range(num_outputs):
2231 - next_token_ids = self.cached_step_outputs.pop(0)
2232 - next_token_ids = next_token_ids.cpu().tolist()
2233 - sampler_output = self._make_decode_output(
2234 - next_token_ids, model_input.sampling_metadata.seq_groups)
2235 - sampler_outputs.append(sampler_output)
2236 -
2237 - if i < num_outputs - 1 and use_async_out_proc:
2238 - assert model_input.async_callback is not None
2239 - ctx = model_input.async_callback.keywords[ # type: ignore
2240 - "ctx"]
2241 - ctx.append_output(
2242 - outputs=[sampler_output],
2243 - seq_group_metadata_list=ctx.seq_group_metadata_list,
2244 - scheduler_outputs=ctx.scheduler_outputs,
2245 - is_async=False,
2246 - is_last_step=False,
2247 - is_first_step_output=False)
2248 - model_input.async_callback()
2249 -
2250 - if use_async_out_proc:
2251 - return [sampler_outputs[-1]]
2252 - else:
2253 - return sampler_outputs
2254 -
2255 - def _make_decode_output(
2256 - self,
2257 - next_token_ids: List[List[int]],
2258 - seq_groups: List[SequenceGroupToSample],
2259 - ) -> SamplerOutput:
2260 - zero_logprob = Logprob(0.0)
2261 - sampler_outputs = []
2262 - batch_idx = 0
2263 - for seq_group in seq_groups:
2264 - seq_ids = seq_group.seq_ids
2265 - seq_outputs = []
2266 - for seq_id in seq_ids:
2267 - next_token_id = next_token_ids[batch_idx][0]
2268 - seq_outputs.append(
2269 - SequenceOutput(seq_id, next_token_id,
2270 - {next_token_id: zero_logprob}))
2271 - batch_idx += 1
2272 - sampler_outputs.append(
2273 - CompletionSequenceGroupOutput(seq_outputs, None))
2274 - return SamplerOutput(sampler_outputs)
2275 -
2276 - def shutdown_inc(self):
2277 - can_finalize_inc = False
2278 - from contextlib import suppress
2279 - with suppress(AttributeError):
2280 - can_finalize_inc = (self.model_config.quantization == 'inc') and \
2281 - (self.model.model is not None) and \
2282 - self.inc_initialized_successfully and \
2283 - not getattr(self, "_is_inc_finalized", False)
2284 - if can_finalize_inc:
2285 - from neural_compressor.torch.quantization import (
2286 - finalize_calibration)
2287 - finalize_calibration(self.model.model)
2288 - self._is_inc_finalized = True
2289 -
2290 - def __del__(self):
2291 - self.shutdown_inc()
2292 -
2293 - def _patch_prev_output(self):
2294 - assert len(self.cached_step_inputs) == len(self.cached_step_outputs), \
2295 - f'''Inputs and outputs are out of sync!
2296 - {len(self.cached_step_inputs)} vs {len(self.cached_step_outputs)}'''
2297 - if len(self.cached_step_inputs) == 0:
2298 - return
2299 - model_input = self.cached_step_inputs.pop(0)
2300 - delayed_output = self.cached_step_outputs.pop(0).cpu().squeeze(
2301 - -1).tolist()
2302 - ctx = model_input.async_callback.keywords["ctx"] # type: ignore
2303 - # If there's no output to patch with, which is usually the case when
2304 - # we're starting a new request after all requests are completed.
2305 - if len(ctx.output_queue) == 0:
2306 - return
2307 - assert len(
2308 - ctx.output_queue) == 1, 'There should be exactly 1 output waiting!'
2309 - output_data = ctx.output_queue[0]
2310 - assert len(output_data.outputs) == 1
2311 - for fake_out, real_out in zip(output_data.outputs[0], delayed_output):
2312 - fake_out.samples[0].output_token = real_out
2313 - for sg, real_out in zip(output_data.seq_group_metadata_list,
2314 - delayed_output):
2315 - assert len(sg.seq_data) == 1
2316 - seq_data = list(sg.seq_data.values())[0]
2317 - # This is a hack. Assigning output_token_ids triggers
2318 - # a cache recomputation and we only need to update the last token
2319 - seq_data.output_token_ids_array[-1] = real_out
2320 - seq_data._cached_all_token_ids[-1] = real_out
vllm/worker/hpu_worker.py deleted
-485
@@ -1,485 +0,0 @@
1 -# SPDX-License-Identifier: Apache-2.0
2 -# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 -
4 -###############################################################################
5 -# Copyright (C) 2024 Habana Labs, Ltd. an Intel Company
6 -###############################################################################
7 -
8 -import contextlib
9 -import gc
10 -import os
11 -from typing import List, Optional, Set, Tuple, Type
12 -
13 -import habana_frameworks.torch as htorch # noqa:F401
14 -import torch
15 -import torch.distributed
16 -from vllm_hpu_extension.profiler import HabanaMemoryProfiler, format_bytes
17 -
18 -import vllm.envs as envs
19 -from vllm.config import ParallelConfig, VllmConfig
20 -from vllm.distributed import (ensure_model_parallel_initialized,
21 - init_distributed_environment)
22 -from vllm.logger import init_logger
23 -from vllm.lora.request import LoRARequest
24 -from vllm.model_executor import set_random_seed
25 -from vllm.model_executor.layers.sampler import SamplerOutput
26 -from vllm.platforms import current_platform
27 -from vllm.prompt_adapter.request import PromptAdapterRequest
28 -from vllm.sequence import ExecuteModelRequest
29 -from vllm.utils import bind_kv_cache
30 -from vllm.worker.cache_engine import CacheEngine
31 -from vllm.worker.hpu_model_runner import HPUModelRunner
32 -from vllm.worker.model_runner_base import ModelRunnerBase
33 -from vllm.worker.worker_base import (LocalOrDistributedWorkerBase, WorkerBase,
34 - WorkerInput)
35 -
36 -logger = init_logger(__name__)
37 -
38 -
39 -class HPUWorker(LocalOrDistributedWorkerBase):
40 - """A worker class that executes (a partition of) the model on a HPU.
41 -
42 - Each worker is associated with a single HPU. The worker is responsible for
43 - maintaining the KV cache and executing the model on the HPU. In case of
44 - distributed inference, each worker is assigned a partition of the model.
45 - """
46 -
47 - def __init__(
48 - self,
49 - vllm_config: VllmConfig,
50 - local_rank: int,
51 - rank: int,
52 - distributed_init_method: str,
53 - is_driver_worker: bool = False,
54 - model_runner_cls: Optional[Type[ModelRunnerBase]] = None,
55 - ) -> None:
56 - WorkerBase.__init__(self, vllm_config=vllm_config)
57 - self.parallel_config.rank = rank
58 - self.local_rank = local_rank
59 - self.rank = rank
60 - self.distributed_init_method = distributed_init_method
61 - self.is_driver_worker = is_driver_worker
62 - if self.is_driver_worker:
63 - assert self.rank == 0, "The driver worker must have rank 0."
64 -
65 - if self.model_config.trust_remote_code:
66 - # note: lazy import to avoid importing torch before initializing
67 - from vllm.utils import init_cached_hf_modules
68 - init_cached_hf_modules()
69 -
70 - self.model_runner: HPUModelRunner = HPUModelRunner(
71 - vllm_config=vllm_config, is_driver_worker=is_driver_worker)
72 - # Uninitialized cache engine. Will be initialized by
73 - # initialize_cache.
74 - self.cache_engine: List[HPUCacheEngine]
75 - # Initialize gpu_cache as pooling models don't initialize kv_caches
76 - self.hpu_cache: Optional[List[List[torch.Tensor]]] = None
77 - # Torch profiler. Enabled and configured through env vars:
78 - # VLLM_TORCH_PROFILER_DIR=/path/to/save/trace
79 - if envs.VLLM_TORCH_PROFILER_DIR:
80 - torch_profiler_trace_dir = envs.VLLM_TORCH_PROFILER_DIR
81 - logger.info("Profiling enabled. Traces will be saved to: %s",
82 - torch_profiler_trace_dir)
83 - self.profiler = torch.profiler.profile(
84 - activities=[
85 - torch.profiler.ProfilerActivity.CPU,
86 - torch.profiler.ProfilerActivity.HPU,
87 - ],
88 - with_stack=True,
89 - on_trace_ready=torch.profiler.tensorboard_trace_handler(
90 - torch_profiler_trace_dir, use_gzip=True))
91 - else:
92 - self.profiler = None
93 -
94 - def start_profile(self):
95 - if self.profiler is None:
96 - raise RuntimeError("Profiler is not enabled.")
97 - self.profiler.start()
98 -
99 - def stop_profile(self):
100 - if self.profiler is None:
101 - raise RuntimeError("Profiler is not enabled.")
102 - self.profiler.stop()
103 -
104 - def _set_env_vars(self):
105 - local_rank = self.local_rank
106 - if self.parallel_config.world_size == 1:
107 - local_rank = -1
108 - import os
109 - os.environ["LOCAL_RANK"] = str(local_rank)
110 - os.environ["ID"] = str(local_rank)
111 - os.environ["WORLD_SIZE"] = str(self.parallel_config.world_size)
112 - os.environ["RANK"] = str(self.rank)
113 -
114 - def init_device(self) -> None:
115 - if self.device_config.device.type == "hpu":
116 - self.device = torch.device("hpu")
117 - torch.hpu.set_device(self.device)
118 - else:
119 - raise RuntimeError(
120 - f"Not support device type: {self.device_config.device}")
121 - # Initialize the distributed environment.
122 - if self.model_config.quantization == 'inc':
123 - self._set_env_vars()
124 - init_worker_distributed_environment(self.parallel_config, self.rank,
125 - self.distributed_init_method,
126 - self.local_rank)
127 - # Set random seed.
128 - set_random_seed(self.model_config.seed)
129 -
130 - def load_model(self):
131 - self.model_runner.load_model()
132 -
133 - def execute_model(
134 - self,
135 - execute_model_req: Optional[ExecuteModelRequest] = None,
136 - ) -> Optional[List[SamplerOutput]]:
137 - # VLLM_HPU_LOG_STEP_GRAPH_COMPILATION - will log graph compilations per engine step, only when there was any - highly recommended to use alongside PT_HPU_METRICS_GC_DETAILS! # noqa:E501
138 - # VLLM_HPU_LOG_STEP_GRAPH_COMPILATION_ALL - will log graph compilations per engine step, always, even if there were none # noqa:E501
139 - # VLLM_HPU_LOG_STEP_CPU_FALLBACKS - will log cpu fallbacks per engine step, only when there was any # noqa:E501
140 - # VLLM_HPU_LOG_STEP_CPU_FALLBACKS_ALL - will log cpu fallbacks per engine step, always, even if there were none # noqa:E501
141 - log_graph_compilation_all = os.environ.get(
142 - 'VLLM_HPU_LOG_STEP_GRAPH_COMPILATION_ALL', '0') != '0'
143 - log_graph_compilation = os.environ.get(
144 - 'VLLM_HPU_LOG_STEP_GRAPH_COMPILATION',
145 - '0') != '0' or log_graph_compilation_all
146 - log_cpu_fallbacks_all = os.environ.get(
147 - 'VLLM_HPU_LOG_STEP_CPU_FALLBACKS_ALL', '0') != '0'
148 - log_cpu_fallbacks = os.environ.get('VLLM_HPU_LOG_STEP_CPU_FALLBACKS',
149 - '0') != '0' or log_cpu_fallbacks_all
150 - if (log_graph_compilation or log_cpu_fallbacks) and \
151 - execute_model_req is not None:
152 - from habana_frameworks.torch.hpu.metrics import metric_localcontext
153 - seq_group_metadata_list = execute_model_req.seq_group_metadata_list
154 - is_prompt = any([
155 - seq_group_metadata.is_prompt
156 - for seq_group_metadata in seq_group_metadata_list
157 - ])
158 - max_context_len = max([
159 - max([
160 - len(v.prompt_token_ids) + len(v.output_token_ids)
161 - for v in seq_group_metadata.seq_data.values()
162 - ]) for seq_group_metadata in seq_group_metadata_list
163 - ]) # whoa, that's some spicy stuff right here
164 - max_num_blocks = (
165 - (max_context_len - 1) // self.cache_config.block_size) + 1
166 - input_stats = (f'is_prompt: {is_prompt}, '
167 - f'num_seqs: {len(seq_group_metadata_list)}, '
168 - f'max_context_len: {max_context_len}, '
169 - f'max_num_blocks {max_num_blocks}')
170 - gc_ctx = metric_localcontext(
171 - "graph_compilation"
172 - ) if log_graph_compilation else contextlib.nullcontext()
173 - cpu_fallback_ctx = metric_localcontext(
174 - "cpu_fallback"
175 - ) if log_cpu_fallbacks else contextlib.nullcontext()
176 - with gc_ctx as gc_local_metric, \
177 - cpu_fallback_ctx as cpu_fallback_local_metric:
178 - output = LocalOrDistributedWorkerBase.execute_model(
179 - self, execute_model_req)
180 - if (log_graph_compilation and gc_local_metric.stats()[0][1]
181 - > 0) or log_graph_compilation_all:
182 - msg = ("VLLM_HPU_STEP_GRAPH_COMPILATION: "
183 - f"{gc_local_metric.stats()}, {input_stats}")
184 - logger.warning(msg)
185 - if (log_cpu_fallbacks and cpu_fallback_local_metric.stats()[0][1]
186 - > 0) or log_cpu_fallbacks_all:
187 - msg = ("VLLM_HPU_STEP_CPU_FALLBACK: "
188 - f"{cpu_fallback_local_metric.stats()}, {input_stats}")
189 - logger.warning(msg)
190 -
191 - return output
192 -
193 - output = LocalOrDistributedWorkerBase.execute_model(
194 - self, execute_model_req)
195 - return output
196 -
197 - @torch.inference_mode()
198 - def determine_num_available_blocks(self) -> Tuple[int, int]:
199 - """Profiles the peak memory usage of the model to determine how many
200 - KV blocks may be allocated without OOMs.
201 -
202 - The engine will first conduct a profiling of the existing memory usage.
203 - Then, it calculate the maximum possible number of GPU and CPU blocks
204 - that can be allocated with the remaining free memory.
205 -
206 - Tip:
207 - You may limit the usage of GPU memory
208 - by adjusting the `gpu_memory_utilization` parameter.
209 - """
210 - # Profile the memory usage of the model and get the maximum number of
211 - # cache blocks that can be allocated with the remaining free memory.
212 -
213 - # Execute a forward pass with dummy inputs to profile the memory usage
214 - # of the model.
215 - with HabanaMemoryProfiler() as m:
216 - self.model_runner.profile_run()
217 - torch.hpu.synchronize()
218 - msg = ("Model profiling run "
219 - f"took {m.get_summary_string()}")
220 - logger.info(msg)
221 - # At this point we should've allocated the maximum workspace for all
222 - # recipes we will use the extra memory for graphs/blocks
223 - free_hpu_memory = torch.hpu.mem_get_info()[0]
224 -
225 - cache_block_size = self.get_cache_block_size_bytes()
226 - graph_reserved_mem = (float(
227 - os.environ.get('VLLM_GRAPH_RESERVED_MEM', '0.1'))
228 - if not self.model_config.enforce_eager else 0)
229 - graph_headroom = 1 - graph_reserved_mem
230 - available_hpu_memory = free_hpu_memory * \
231 - self.cache_config.gpu_memory_utilization
232 - hpu_memory_margin = free_hpu_memory * (
233 - 1 - self.cache_config.gpu_memory_utilization)
234 - self.model_runner.mem_margin = hpu_memory_margin
235 - cache_size_bytes = available_hpu_memory * graph_headroom
236 - graph_headroom_bytes = available_hpu_memory * (1 - graph_headroom)
237 - msg = (
238 - f"Free device memory: {format_bytes(free_hpu_memory)}, "
239 - f"{format_bytes(available_hpu_memory)} usable "
240 - f"(gpu_memory_utilization={self.cache_config.gpu_memory_utilization}),"
241 - f" {format_bytes(graph_headroom_bytes)} reserved for HPUGraphs "
242 - f"(VLLM_GRAPH_RESERVED_MEM={graph_reserved_mem}), "
243 - f"{format_bytes(cache_size_bytes)} reserved for KV cache")
244 - logger.info(msg)
245 - num_hpu_blocks = int(cache_size_bytes // cache_block_size)
246 - num_cpu_blocks = int(self.cache_config.swap_space_bytes //
247 - cache_block_size)
248 - num_hpu_blocks = max(num_hpu_blocks, 0)
249 - num_cpu_blocks = max(num_cpu_blocks, 0)
250 - self.model_runner.bucketing_ctx.num_hpu_blocks = num_hpu_blocks
251 -
252 - if self.model_runner.lora_manager:
253 - self.model_runner.remove_all_loras()
254 -
255 - gc.collect()
256 - return num_hpu_blocks, num_cpu_blocks
257 -
258 - def initialize_cache(self, num_gpu_blocks: int,
259 - num_cpu_blocks: int) -> None:
260 - """Allocate GPU and CPU KV cache with the specified number of blocks.
261 -
262 - This also warms up the model, which may record CUDA graphs.
263 - """
264 - raise_if_cache_size_invalid(
265 - num_gpu_blocks, self.cache_config.block_size,
266 - self.model_config.max_model_len,
267 - self.parallel_config.pipeline_parallel_size)
268 -
269 - self.cache_config.num_gpu_blocks = num_gpu_blocks
270 - self.cache_config.num_cpu_blocks = num_cpu_blocks
271 -
272 - with HabanaMemoryProfiler() as m:
273 - self._init_cache_engine()
274 - torch.hpu.synchronize()
275 - msg = ("Initializing cache engine "
276 - f"took {m.get_summary_string()}")
277 - logger.info(msg)
278 - self._warm_up_model()
279 -
280 - def _init_cache_engine(self):
281 - assert self.cache_config.num_gpu_blocks is not None
282 - self.cache_engine = [
283 - HPUCacheEngine(self.cache_config, self.model_config,
284 - self.parallel_config, self.device_config)
285 - for _ in range(self.parallel_config.pipeline_parallel_size)
286 - ]
287 - self.hpu_cache = [
288 - self.cache_engine[ve].gpu_cache
289 - for ve in range(self.parallel_config.pipeline_parallel_size)
290 - ]
291 - bind_kv_cache(self.compilation_config.static_forward_context,
292 - self.hpu_cache)
293 -
294 - def _warm_up_model(self) -> None:
295 - # NOTE(kzawora): We should use virtual engine index here
296 - # for pipeline parallelism. Using 0 for now.
297 - assert self.hpu_cache is not None
298 - self.model_runner.warmup_model(self.hpu_cache[0])
299 - # Reset the seed to ensure that the random state is not affected by
300 - # the model initialization and profiling.
301 - set_random_seed(self.model_config.seed)
302 -
303 - def finish_measurements(self):
304 - self.model_runner.finish_measurements()
305 -
306 - @property
307 - def do_metadata_broadcast(self) -> bool:
308 - return self.parallel_config.tensor_parallel_size > 1
309 -
310 - @property
311 - def kv_cache(self) -> Optional[List[List[torch.Tensor]]]:
312 - return self.hpu_cache
313 -
314 - @torch.inference_mode()
315 - def prepare_worker_input(
316 - self, execute_model_req: ExecuteModelRequest) -> WorkerInput:
317 - virtual_engine = execute_model_req.virtual_engine
318 - num_seq_groups = len(execute_model_req.seq_group_metadata_list)
319 - # `blocks_to_swap_in` and `blocks_to_swap_out` are cpu tensors.
320 - # they contain parameters to launch cudamemcpyasync.
321 - blocks_to_swap_in = torch.tensor(execute_model_req.blocks_to_swap_in,
322 - device="cpu",
323 - dtype=torch.int64).view(-1, 2)
324 - blocks_to_swap_out = torch.tensor(execute_model_req.blocks_to_swap_out,
325 - device="cpu",
326 - dtype=torch.int64).view(-1, 2)
327 - # `blocks_to_copy` is a gpu tensor. The src and tgt of
328 - # blocks to copy are in the same device, and `blocks_to_copy`
329 - # can be used directly within cuda kernels.
330 - blocks_to_copy = torch.tensor(execute_model_req.blocks_to_copy,
331 - device=self.device,
332 - dtype=torch.int64).view(-1, 2)
333 -
334 - return WorkerInput(
335 - num_seq_groups=num_seq_groups,
336 - blocks_to_swap_in=blocks_to_swap_in,
337 - blocks_to_swap_out=blocks_to_swap_out,
338 - blocks_to_copy=blocks_to_copy,
339 - virtual_engine=virtual_engine,
340 - )
341 -
342 - @torch.inference_mode()
343 - def execute_worker(self, worker_input: WorkerInput) -> None:
344 - virtual_engine = worker_input.virtual_engine
345 - # Issue cache operations.
346 - if (worker_input.blocks_to_swap_in is not None
347 - and worker_input.blocks_to_swap_in.numel() > 0):
348 - self.cache_engine[virtual_engine].swap_in(
349 - worker_input.blocks_to_swap_in)
350 - if (worker_input.blocks_to_swap_out is not None
351 - and worker_input.blocks_to_swap_out.numel() > 0):
352 - self.cache_engine[virtual_engine].swap_out(
353 - worker_input.blocks_to_swap_out)
354 - if (worker_input.blocks_to_copy is not None
355 - and worker_input.blocks_to_copy.numel() > 0):
356 - self.cache_engine[virtual_engine].copy(worker_input.blocks_to_copy)
357 -
358 - def add_lora(self, lora_request: LoRARequest) -> bool:
359 - return self.model_runner.add_lora(lora_request)
360 -
361 - def remove_lora(self, lora_id: int) -> bool:
362 - return self.model_runner.remove_lora(lora_id)
363 -
364 - def pin_lora(self, lora_id: int) -> bool:
365 - return self.model_runner.pin_lora(lora_id)
366 -
367 - def list_loras(self) -> Set[int]:
368 - return self.model_runner.list_loras()
369 -
370 - def add_prompt_adapter(
371 - self, prompt_adapter_request: PromptAdapterRequest) -> bool:
372 - raise NotImplementedError(
373 - "Prompt Adapter is not implemented for HPU backend.")
374 -
375 - def remove_prompt_adapter(self, prompt_adapter_id: int) -> bool:
376 - raise NotImplementedError(
377 - "Prompt Adapter is not implemented for HPU backend.")
378 -
379 - def pin_prompt_adapter(self, prompt_adapter_id: int) -> bool:
380 - raise NotImplementedError(
381 - "Prompt Adapter is not implemented for HPU backend.")
382 -
383 - def list_prompt_adapters(self) -> Set[int]:
384 - raise NotImplementedError(
385 - "Prompt Adapter is not implemented for HPU backend.")
386 -
387 - def shutdown_inc(self):
388 - self.model_runner.shutdown_inc()
389 -
390 - @property
391 - def max_model_len(self) -> int:
392 - return self.model_config.max_model_len
393 -
394 - @property
395 - def vocab_size(self) -> int:
396 - return self.model_runner.vocab_size
397 -
398 - def get_cache_block_size_bytes(self) -> int:
399 - """Get the size of the KV cache block size in bytes.
400 - """
401 - return HPUCacheEngine.get_cache_block_size(self.cache_config,
402 - self.model_config,
403 - self.parallel_config)
404 -
405 -
406 -def init_worker_distributed_environment(
407 - parallel_config: ParallelConfig,
408 - rank: int,
409 - distributed_init_method: Optional[str] = None,
410 - local_rank: int = -1,
411 -) -> None:
412 - """Initialize the distributed environment."""
413 - init_distributed_environment(parallel_config.world_size,
414 - rank,
415 - distributed_init_method,
416 - local_rank,
417 - backend=current_platform.dist_backend)
418 -
419 - ensure_model_parallel_initialized(parallel_config.tensor_parallel_size,
420 - parallel_config.pipeline_parallel_size)
421 -
422 - if torch.distributed.is_initialized():
423 - torch_world_size = torch.distributed.get_world_size()
424 - if torch_world_size != parallel_config.world_size:
425 - raise RuntimeError(
426 - "torch.distributed is already initialized but the torch world "
427 - "size does not match parallel_config.world_size "
428 - f"({torch_world_size} vs. {parallel_config.world_size}).")
429 - elif not distributed_init_method:
430 - raise ValueError(
431 - "distributed_init_method must be set if torch.distributed "
432 - "is not already initialized")
433 - else:
434 - torch.distributed.init_process_group(
435 - backend="hccl",
436 - world_size=parallel_config.world_size,
437 - rank=rank,
438 - init_method=distributed_init_method,
439 - )
440 -
441 - # A small all_reduce for warmup & checking conformance.
442 - dummy_tensor_hpu = torch.ones(1).to('hpu')
443 - torch.distributed.all_reduce(dummy_tensor_hpu)
444 - assert dummy_tensor_hpu.item() == parallel_config.world_size
445 - ensure_model_parallel_initialized(parallel_config.tensor_parallel_size,
446 - parallel_config.pipeline_parallel_size)
447 -
448 -
449 -def raise_if_cache_size_invalid(num_gpu_blocks, block_size, max_model_len,
450 - pipeline_parallel_size) -> None:
451 - if num_gpu_blocks <= 0:
452 - raise ValueError("No available memory for the cache blocks. "
453 - "Try increasing `gpu_memory_utilization` when "
454 - "initializing the engine.")
455 - max_seq_len = block_size * (num_gpu_blocks // pipeline_parallel_size)
456 - if max_model_len > max_seq_len:
457 - raise ValueError(
458 - f"The model's max seq len ({max_model_len}) "
459 - "is larger than the maximum number of tokens that can be "
460 - f"stored in KV cache ({max_seq_len}). Try increasing "
461 - "`gpu_memory_utilization` or decreasing `max_model_len` when "
462 - "initializing the engine.")
463 -
464 -
465 -class HPUCacheEngine(CacheEngine):
466 -
467 - def _allocate_kv_cache(
468 - self,
469 - num_blocks: int,
470 - device: str,
471 - ) -> List[Tuple[torch.Tensor, torch.Tensor]]:
472 - """Allocates KV cache on the specified device."""
473 - kv_cache_shape = self.attn_backend.get_kv_cache_shape(
474 - num_blocks, self.block_size, self.num_kv_heads, self.head_size)
475 - kv_cache: List[Tuple[torch.Tensor, torch.Tensor]] = []
476 - for _ in range(self.num_attention_layers):
477 - key_cache = torch.zeros(kv_cache_shape,
478 - dtype=self.dtype,
479 - device=device)
480 - value_cache = torch.zeros(kv_cache_shape,
481 - dtype=self.dtype,
482 - device=device)
483 - kv_layer = (key_cache, value_cache)
484 - kv_cache.append(kv_layer)
485 - return kv_cache
vllm/worker/multi_step_hpu_worker.py deleted
-123
@@ -1,123 +0,0 @@
1 -# SPDX-License-Identifier: Apache-2.0
2 -# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 -
4 -###############################################################################
5 -# Copyright (C) 2025 Habana Labs, Ltd. an Intel Company
6 -###############################################################################
7 -
8 -import dataclasses
9 -from typing import Dict, Optional, Tuple
10 -
11 -import torch
12 -
13 -from vllm.distributed import broadcast_tensor_dict
14 -from vllm.sequence import ExecuteModelRequest
15 -from vllm.worker.hpu_model_runner import ModelInputForHPU
16 -from vllm.worker.hpu_worker import HPUWorker
17 -from vllm.worker.worker_base import WorkerInput
18 -
19 -
20 -class MultiStepHPUWorker(HPUWorker):
21 -
22 - def __init__(self, *args, **kwargs):
23 - super().__init__(*args, **kwargs)
24 - self.cached_model_input: Optional[ModelInputForHPU] = None
25 -
26 - def _get_driver_input_and_broadcast(
27 - self, execute_model_req: ExecuteModelRequest
28 - ) -> Tuple[ModelInputForHPU, WorkerInput, Dict[str, torch.Tensor]]:
29 - """
30 - Get the driver input and broadcast it to other workers.
31 - """
32 - assert self.is_driver_worker
33 - assert execute_model_req.virtual_engine == 0
34 -
35 - is_first_multi_step = execute_model_req.is_first_multi_step
36 - is_last_step = execute_model_req.is_last_step
37 -
38 - if is_first_multi_step:
39 - # on first step we prepare the worker input and model input normally
40 - worker_input: WorkerInput = self.prepare_worker_input(
41 - execute_model_req=execute_model_req)
42 - worker_input = dataclasses.replace(
43 - worker_input,
44 - num_steps=execute_model_req.num_lookahead_slots + 1)
45 - model_input: ModelInputForHPU = (
46 - self.model_runner.prepare_model_input(
47 - execute_model_req.seq_group_metadata_list,
48 - execute_model_req.virtual_engine,
49 - execute_model_req.finished_requests_ids))
50 -
51 - if execute_model_req.async_callback:
52 - model_input = dataclasses.replace(
53 - model_input,
54 - async_callback=execute_model_req.async_callback)
55 - else:
56 - # on subsequent steps we reuse the worker input and model input
57 - assert self.cached_model_input is not None
58 - model_input = self.cached_model_input
59 - worker_input = WorkerInput()
60 -
61 - model_input = dataclasses.replace(
62 - model_input,
63 - is_first_multi_step=is_first_multi_step,
64 - is_last_step=is_last_step)
65 -
66 - if self.do_metadata_broadcast:
67 - if is_first_multi_step:
68 - broadcast_data = worker_input.as_broadcastable_tensor_dict()
69 - broadcast_data.update(
70 - model_input.as_broadcastable_tensor_dict())
71 - broadcast_tensor_dict(broadcast_data, src=0)
72 - else:
73 - broadcast_data = {
74 - "is_first_multi_step": is_first_multi_step,
75 - "is_last_step": is_last_step,
76 - }
77 - broadcast_tensor_dict(broadcast_data, src=0)
78 -
79 - # Returning empty dict here to keep this compatible with
80 - # `LocalOrDistributedWorkerBase._get_driver_input_and_broadcast`
81 - return model_input, worker_input, {}
82 -
83 - def prepare_input(
84 - self,
85 - execute_model_req: Optional[ExecuteModelRequest] = None,
86 - ) -> Optional[Tuple[ModelInputForHPU, WorkerInput, Dict[str,
87 - torch.Tensor]]]:
88 - if self.is_driver_worker:
89 - if execute_model_req is None:
90 - if self.do_metadata_broadcast:
91 - # This signals that there's no more requests to process for
92 - # now. All workers are running infinite loop with
93 - # broadcast_tensor_dict, and it stops the loop when the
94 - # driver broadcasts an empty input. Send an empty input to
95 - # notify all other workers to stop their execution loop.
96 - broadcast_tensor_dict({}, src=0)
97 - return None
98 - model_input, worker_input, _ = self._get_driver_input_and_broadcast(
99 - execute_model_req)
100 - if model_input.is_first_multi_step:
101 - self.cached_model_input = model_input
102 - return model_input, worker_input, {}
103 - else:
104 - broadcast_data = broadcast_tensor_dict(src=0)
105 - if not broadcast_data:
106 - return None
107 -
108 - if len(broadcast_data) == 2:
109 - assert self.cached_model_input is not None
110 - self.cached_model_input = dataclasses.replace(
111 - self.cached_model_input,
112 - is_first_multi_step=broadcast_data["is_first_multi_step"],
113 - is_last_step=broadcast_data["is_last_step"])
114 - empty_worker_input = WorkerInput()
115 - return self.cached_model_input, empty_worker_input, {}
116 -
117 - worker_input = WorkerInput.from_broadcasted_tensor_dict(
118 - broadcast_data)
119 - model_input = (
120 - self.model_runner.
121 - make_model_input_from_broadcasted_tensor_dict(broadcast_data))
122 - self.cached_model_input = model_input
123 - return model_input, worker_input, {}