main
py 128 lines 4.48 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 import functools
4
5 import torch
6
7 from vllm.config import CacheConfig
8 from vllm.config.vllm import VllmConfig
9 from vllm.model_executor.layers.attention import Attention
10 from vllm.model_executor.layers.quantization import QuantizationConfig
11 from vllm.v1.attention.backend import (
12 AttentionBackend,
13 AttentionCGSupport,
14 AttentionMetadataBuilder,
15 CommonAttentionMetadata,
16 subclass_attention_backend,
17 )
18 from vllm.v1.attention.backends.utils import (
19 make_local_attention_virtual_batches,
20 )
21 from vllm.v1.attention.selector import get_attn_backend
22 from vllm.v1.kv_cache_interface import (
23 ChunkedLocalAttentionSpec,
24 KVCacheSpec,
25 get_kv_quant_mode,
26 )
27
28
29 @functools.lru_cache
30 def create_chunked_local_attention_backend(
31 underlying_attn_backend: type[AttentionBackend],
32 attention_chunk_size: int,
33 ) -> type[AttentionBackend]:
34 prefix = f"ChunkedLocalAttention_{attention_chunk_size}_"
35
36 underlying_builder = underlying_attn_backend.get_builder_cls()
37 assert issubclass(underlying_builder, AttentionMetadataBuilder)
38
39 class ChunkedLocalAttentionBuilder(underlying_builder): # type: ignore
40 @classmethod
41 def get_cudagraph_support(
42 cls: type["AttentionMetadataBuilder"],
43 vllm_config: VllmConfig,
44 kv_cache_spec: KVCacheSpec,
45 ) -> AttentionCGSupport:
46 # Explicit override in case the underlying builder specialized this getter.
47 # @override omitted only because of mypy limitation due to type variable.
48 return AttentionCGSupport.NEVER
49
50 def build(
51 self,
52 common_prefix_len: int,
53 common_attn_metadata: CommonAttentionMetadata,
54 fast_build: bool = False,
55 ):
56 cm, make_virtual_batches_block_table = make_local_attention_virtual_batches(
57 attention_chunk_size,
58 common_attn_metadata,
59 self.kv_cache_spec.block_size,
60 )
61 metadata = super().build(common_prefix_len, cm, fast_build)
62 metadata.make_virtual_batches_block_table = make_virtual_batches_block_table
63 return metadata
64
65 def update_block_table(
66 self, metadata, blk_table: torch.Tensor, slot_mapping: torch.Tensor
67 ):
68 blk_table = metadata.make_virtual_batches_block_table(blk_table)
69 return super().update_block_table(metadata, blk_table, slot_mapping)
70
71 attn_backend = subclass_attention_backend(
72 name_prefix=prefix,
73 attention_backend_cls=underlying_attn_backend,
74 builder_cls=ChunkedLocalAttentionBuilder,
75 )
76
77 return attn_backend
78
79
80 class ChunkedLocalAttention(Attention):
81 def __init__(
82 self,
83 num_heads: int,
84 head_size: int,
85 scale: float,
86 attention_chunk_size: int,
87 num_kv_heads: int | None = None,
88 alibi_slopes: list[float] | None = None,
89 cache_config: CacheConfig | None = None,
90 quant_config: QuantizationConfig | None = None,
91 kv_sharing_target_layer_name: str | None = None,
92 prefix: str = "",
93 ):
94 self.attention_chunk_size = attention_chunk_size
95 dtype = torch.get_default_dtype()
96 if cache_config is not None:
97 kv_cache_dtype = cache_config.cache_dtype
98 else:
99 kv_cache_dtype = "auto"
100
101 underlying_attn_backend = get_attn_backend(head_size, dtype, kv_cache_dtype)
102 attn_backend = create_chunked_local_attention_backend(
103 underlying_attn_backend, attention_chunk_size
104 )
105
106 super().__init__(
107 num_heads=num_heads,
108 head_size=head_size,
109 scale=scale,
110 num_kv_heads=num_kv_heads,
111 alibi_slopes=alibi_slopes,
112 cache_config=cache_config,
113 quant_config=quant_config,
114 prefix=prefix,
115 kv_sharing_target_layer_name=kv_sharing_target_layer_name,
116 attn_backend=attn_backend,
117 )
118
119 def get_kv_cache_spec(self, vllm_config: VllmConfig) -> KVCacheSpec:
120 assert self.attention_chunk_size
121 return ChunkedLocalAttentionSpec(
122 block_size=vllm_config.cache_config.block_size,
123 num_kv_heads=self.num_kv_heads,
124 head_size=self.head_size,
125 dtype=self.kv_cache_torch_dtype,
126 kv_quant_mode=get_kv_quant_mode(self.kv_cache_dtype),
127 attention_chunk_size=self.attention_chunk_size,
128 )