main
py 278 lines 9.33 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 """PyTorch MAMBA2 model."""
4
5 from collections.abc import Iterable
6
7 import torch
8 from torch import nn
9 from transformers import MambaConfig
10
11 from vllm.compilation.decorators import support_torch_compile
12 from vllm.config import CacheConfig, ModelConfig, VllmConfig
13 from vllm.distributed.parallel_state import get_pp_group
14 from vllm.model_executor.layers.layernorm import RMSNorm
15 from vllm.model_executor.layers.logits_processor import LogitsProcessor
16 from vllm.model_executor.layers.mamba.mamba_mixer2 import MambaMixer2
17 from vllm.model_executor.layers.mamba.mamba_utils import (
18 MambaStateCopyFunc,
19 MambaStateCopyFuncCalculator,
20 MambaStateDtypeCalculator,
21 MambaStateShapeCalculator,
22 )
23 from vllm.model_executor.layers.quantization import QuantizationConfig
24 from vllm.model_executor.layers.vocab_parallel_embedding import (
25 ParallelLMHead,
26 VocabParallelEmbedding,
27 )
28 from vllm.model_executor.models.interfaces import (
29 HasInnerState,
30 IsAttentionFree,
31 SupportsMambaPrefixCaching,
32 )
33 from vllm.sequence import IntermediateTensors
34
35 from .utils import (
36 AutoWeightsLoader,
37 WeightsMapper,
38 make_empty_intermediate_tensors_factory,
39 make_layers,
40 maybe_prefix,
41 )
42
43 KVCache = tuple[torch.Tensor, torch.Tensor]
44
45
46 class Mamba2DecoderLayer(nn.Module):
47 def __init__(
48 self,
49 config: MambaConfig,
50 model_config: ModelConfig | None = None,
51 cache_config: CacheConfig | None = None,
52 quant_config: QuantizationConfig | None = None,
53 prefix: str = "",
54 ) -> None:
55 super().__init__()
56 self.config = config
57 self.mixer = MambaMixer2(
58 hidden_size=config.hidden_size,
59 ssm_state_size=config.state_size,
60 conv_kernel_size=config.conv_kernel,
61 intermediate_size=getattr(
62 config, "intermediate_size", config.expand * config.hidden_size
63 ),
64 use_conv_bias=config.use_conv_bias,
65 use_bias=config.use_bias,
66 n_groups=config.n_groups,
67 num_heads=config.num_heads,
68 head_dim=config.head_dim,
69 rms_norm_eps=config.layer_norm_epsilon,
70 activation=config.hidden_act,
71 model_config=model_config,
72 cache_config=cache_config,
73 quant_config=quant_config,
74 prefix=f"{prefix}.mixer",
75 )
76
77 self.norm = RMSNorm(config.hidden_size, eps=config.layer_norm_epsilon)
78
79 def forward(
80 self,
81 hidden_states: torch.Tensor,
82 residual: torch.Tensor | None,
83 **kwargs,
84 ):
85 if residual is None:
86 residual = hidden_states
87 hidden_states = self.norm(hidden_states)
88 else:
89 hidden_states, residual = self.norm(hidden_states, residual)
90
91 output = self.mixer(hidden_states)
92 return output, residual
93
94
95 @support_torch_compile
96 class Mamba2Model(nn.Module):
97 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
98 super().__init__()
99
100 config = vllm_config.model_config.hf_config
101 model_config = vllm_config.model_config
102 cache_config = vllm_config.cache_config
103 quant_config = vllm_config.quant_config
104 lora_config = vllm_config.lora_config
105 is_lora_enabled = bool(lora_config)
106 assert not is_lora_enabled
107
108 self.config = config
109
110 self.vocab_size = config.vocab_size
111
112 self.embeddings = VocabParallelEmbedding(
113 self.vocab_size,
114 config.hidden_size,
115 )
116
117 self.start_layer, self.end_layer, self.layers = make_layers(
118 config.num_hidden_layers,
119 lambda prefix: Mamba2DecoderLayer(
120 config,
121 model_config=model_config,
122 cache_config=cache_config,
123 quant_config=quant_config,
124 prefix=prefix,
125 ),
126 prefix=f"{prefix}.layers",
127 )
128
129 self.norm_f = RMSNorm(config.hidden_size, eps=config.layer_norm_epsilon)
130 self.make_empty_intermediate_tensors = make_empty_intermediate_tensors_factory(
131 ["hidden_states", "residual"], config.hidden_size
132 )
133
134 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
135 return self.embeddings(input_ids)
136
137 def forward(
138 self,
139 input_ids: torch.Tensor | None,
140 positions: torch.Tensor,
141 intermediate_tensors: IntermediateTensors | None = None,
142 inputs_embeds: torch.Tensor | None = None,
143 ) -> torch.Tensor:
144 if get_pp_group().is_first_rank:
145 if inputs_embeds is not None:
146 hidden_states = inputs_embeds
147 else:
148 hidden_states = self.embed_input_ids(input_ids)
149 residual = None
150 else:
151 assert intermediate_tensors is not None
152 hidden_states = intermediate_tensors["hidden_states"]
153 residual = intermediate_tensors["residual"]
154
155 for i, layer in enumerate(self.layers):
156 hidden_states, residual = layer(
157 positions=positions, hidden_states=hidden_states, residual=residual
158 )
159
160 if not get_pp_group().is_last_rank:
161 return IntermediateTensors(
162 {"hidden_states": hidden_states, "residual": residual}
163 )
164
165 hidden_states, _ = self.norm_f(hidden_states, residual)
166
167 return hidden_states
168
169
170 class Mamba2ForCausalLM(
171 nn.Module, HasInnerState, IsAttentionFree, SupportsMambaPrefixCaching
172 ):
173 hf_to_vllm_mapper = WeightsMapper(orig_to_new_substr={".A_log": ".A"})
174
175 @classmethod
176 def get_mamba_state_dtype_from_config(
177 cls,
178 vllm_config: "VllmConfig",
179 ) -> tuple[torch.dtype, torch.dtype]:
180 return MambaStateDtypeCalculator.mamba2_state_dtype(
181 vllm_config.model_config.dtype,
182 vllm_config.cache_config.mamba_cache_dtype,
183 vllm_config.cache_config.mamba_ssm_cache_dtype,
184 )
185
186 @classmethod
187 def get_mamba_state_shape_from_config(
188 cls,
189 vllm_config: "VllmConfig",
190 ) -> tuple[tuple[int, int], tuple[int, int, int]]:
191 """Calculate shapes for Mamba's convolutional and state caches.
192
193 Args:
194 vllm_config: vLLM config
195
196 Returns:
197 Tuple containing:
198 - conv_state_shape: Shape for convolutional state cache
199 - temporal_state_shape: Shape for state space model cache
200
201 """
202 parallel_config = vllm_config.parallel_config
203 hf_config = vllm_config.model_config.hf_config
204 intermediate_size = hf_config.expand * hf_config.hidden_size
205
206 return MambaStateShapeCalculator.mamba2_state_shape(
207 intermediate_size=intermediate_size,
208 tp_world_size=parallel_config.tensor_parallel_size,
209 n_groups=hf_config.n_groups,
210 num_heads=hf_config.num_heads,
211 head_dim=hf_config.head_dim,
212 state_size=hf_config.state_size,
213 conv_kernel=hf_config.conv_kernel,
214 num_spec=vllm_config.num_speculative_tokens,
215 )
216
217 @classmethod
218 def get_mamba_state_copy_func(cls) -> tuple[MambaStateCopyFunc, MambaStateCopyFunc]:
219 return MambaStateCopyFuncCalculator.mamba2_state_copy_func()
220
221 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
222 config = vllm_config.model_config.hf_config
223
224 scheduler_config = vllm_config.scheduler_config
225
226 super().__init__()
227 self.config = config
228 self.vllm_config = vllm_config
229 self.scheduler_config = scheduler_config
230 self.model_config = vllm_config.model_config
231 self.backbone = Mamba2Model(
232 vllm_config=vllm_config, prefix=maybe_prefix(prefix, "backbone")
233 )
234
235 self.lm_head = ParallelLMHead(
236 config.vocab_size,
237 config.hidden_size,
238 prefix=maybe_prefix(prefix, "lm_head"),
239 )
240 if config.tie_word_embeddings:
241 self.lm_head = self.lm_head.tie_weights(self.backbone.embeddings)
242
243 self.logits_processor = LogitsProcessor(config.vocab_size)
244
245 self.make_empty_intermediate_tensors = (
246 self.backbone.make_empty_intermediate_tensors
247 )
248
249 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
250 return self.backbone.embed_input_ids(input_ids)
251
252 def forward(
253 self,
254 input_ids: torch.Tensor | None,
255 positions: torch.Tensor,
256 intermediate_tensors: IntermediateTensors | None = None,
257 inputs_embeds: torch.Tensor | None = None,
258 **kwargs,
259 ):
260 hidden_states = self.backbone(
261 input_ids, positions, intermediate_tensors, inputs_embeds
262 )
263
264 return hidden_states
265
266 def copy_inputs_before_cuda_graphs(self, input_buffers, **kwargs):
267 return self.mamba_cache.copy_inputs_before_cuda_graphs(input_buffers, **kwargs)
268
269 def get_seqlen_agnostic_capture_inputs(self, batch_size: int):
270 return self.mamba_cache.get_seqlen_agnostic_capture_inputs(batch_size)
271
272 def compute_logits(self, hidden_states: torch.Tensor) -> torch.Tensor:
273 logits = self.logits_processor(self.lm_head, hidden_states)
274 return logits
275
276 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
277 loader = AutoWeightsLoader(self)
278 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)