@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 1f69c4a892
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, 23:30 UTC

[Model] Support Mamba2 (Codestral Mamba) (#9292)

Signed-off-by: Tyler Michael Smith <tyler@neuralmagic.com> Co-authored-by: Yu Chin Fabian Lim <flim@sg.ibm.com>

Tyler Michael Smith committed Feb 17, 2025 at 07:17 UTC 1f69c4a892d35a362e9ffeaf74072aeecca2286b
9 files changed +376 -65
tests/models/decoder_only/language/test_mamba.py
+30 -13
@@ -4,6 +4,7 @@
4 Run `pytest tests/models/test_mamba.py`.
5 """
6 import pytest
7 +import torch
8 from transformers import AutoModelForCausalLM, AutoTokenizer
9
10 from vllm.engine.arg_utils import EngineArgs
@@ -11,7 +12,14 @@ from vllm.sampling_params import SamplingParams
12
13 from ...utils import check_outputs_equal
14
14 -MODELS = ["state-spaces/mamba-130m-hf", "tiiuae/falcon-mamba-tiny-dev"]
15 +MODELS = [
16 + "state-spaces/mamba-130m-hf",
17 + "tiiuae/falcon-mamba-tiny-dev",
18 + # TODO: Compare to a Mamba2 model. The HF transformers implementation of
19 + # Mamba2 is buggy for Codestral as it doesn't handle n_groups.
20 + # See https://github.com/huggingface/transformers/pull/35943
21 + # "mistralai/Mamba-Codestral-7B-v0.1",
22 +]
23
24
25 # Use lower-level interfaces to create this greedy generator, as mamba will
@@ -21,6 +29,10 @@ def generate_greedy(model_name, example_prompts, max_tokens):
29 tokenizer = AutoTokenizer.from_pretrained(model_name)
30 model = AutoModelForCausalLM.from_pretrained(model_name)
31
32 + # Set the device (GPU if available, else CPU)
33 + device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
34 + model.to(device)
35 +
36 # Generate texts from the prompts
37 outputs = []
38 for prompt in example_prompts:
@@ -29,7 +41,9 @@ def generate_greedy(model_name, example_prompts, max_tokens):
41 input_ids = inputs["input_ids"].to(model.device)
42
43 # Generate text using the model's generate method directly
32 - generated_ids = model.generate(input_ids, max_new_tokens=max_tokens)
44 + generated_ids = model.generate(input_ids,
45 + max_new_tokens=max_tokens,
46 + do_sample=False)
47 generated_text = tokenizer.decode(generated_ids[0],
48 skip_special_tokens=True)
49
@@ -50,7 +64,8 @@ def test_models(
64 ) -> None:
65 hf_outputs = generate_greedy(model, example_prompts, max_tokens)
66
53 - with vllm_runner(model, dtype=dtype) as vllm_model:
67 + # Set max_num_seqs to keep Codestral from going OOM at fp32
68 + with vllm_runner(model, dtype=dtype, max_num_seqs=16) as vllm_model:
69 vllm_outputs = vllm_model.generate_greedy(example_prompts, max_tokens)
70
71 # This test is for verifying whether the model's extra_repr
@@ -81,7 +96,7 @@ def test_batching(
96 ) -> None:
97 # To pass the small model tests, we need full precision.
98 for_loop_outputs = []
84 - with vllm_runner(model, dtype=dtype) as vllm_model:
99 + with vllm_runner(model, dtype=dtype, max_num_seqs=16) as vllm_model:
100 for prompt in example_prompts:
101 for_loop_outputs.append(
102 vllm_model.generate_greedy([prompt], max_tokens)[0])
@@ -165,20 +180,22 @@ def test_parallel_sampling(
180 max_tokens: int,
181 ) -> None:
182
168 - with vllm_runner(model, dtype=dtype) as vllm_model:
183 + # Numerical differences produce slightly different output for these
184 + if 'state-spaces' in model:
185 + example_prompts.pop(0)
186 + example_prompts.pop(0)
187 + example_prompts.pop(0)
188 +
189 + with vllm_runner(model, dtype=dtype, max_num_seqs=16) as vllm_model:
190 for_loop_outputs = []
191 for _ in range(10):
192 for_loop_outputs.append(
172 - # using example_prompts index 1 instead of 0 since with 0 the
173 - # logprobs get really close and the test doesn't pass
174 - vllm_model.generate_greedy([example_prompts[1]], max_tokens)
175 - [0])
193 + vllm_model.generate_greedy(example_prompts, max_tokens)[0])
194 sampling_params = SamplingParams(n=10,
195 temperature=0.001,
196 seed=0,
197 max_tokens=max_tokens)
180 - n_lt_1_outputs = vllm_model.generate([example_prompts[1]],
181 - sampling_params)
198 + n_lt_1_outputs = vllm_model.generate(example_prompts, sampling_params)
199 token_ids, texts = n_lt_1_outputs[0]
200 n_lt_1_outputs = [(token_id, text)
201 for token_id, text in zip(token_ids, texts)]
@@ -232,7 +249,7 @@ def test_models_preemption_recompute(
249 # Tests that outputs are identical with and w/o preemtions (recompute)
250 assert dtype == "float"
251
235 - with vllm_runner(model, dtype=dtype) as vllm_model:
252 + with vllm_runner(model, dtype=dtype, max_num_seqs=16) as vllm_model:
253 vllm_model.model.llm_engine.scheduler[
254 0].ENABLE_ARTIFICIAL_PREEMPT = True
255 preempt_vllm_outputs = vllm_model.generate_greedy(
@@ -283,7 +300,7 @@ def test_state_cleanup(
300 # This test is for verifying that the Mamba state is cleaned up between
301 # steps, If its not cleaned, an error would be expected.
302 try:
286 - with vllm_runner(model, dtype=dtype) as vllm_model:
303 + with vllm_runner(model, dtype=dtype, max_num_seqs=16) as vllm_model:
304 for _ in range(10):
305 vllm_model.generate_greedy([example_prompts[0]] * 100, 1)
306 except ValueError:
tests/models/registry.py
+2
@@ -145,6 +145,8 @@ _TEXT_GENERATION_EXAMPLE_MODELS = {
145 "LLaMAForCausalLM": _HfExamplesInfo("decapoda-research/llama-7b-hf",
146 is_available_online=False),
147 "MambaForCausalLM": _HfExamplesInfo("state-spaces/mamba-130m-hf"),
148 + "Mamba2ForCausalLM": _HfExamplesInfo("mistralai/Mamba-Codestral-7B-v0.1",
149 + is_available_online=False),
150 "FalconMambaForCausalLM": _HfExamplesInfo("tiiuae/falcon-mamba-7b-instruct"), # noqa: E501
151 "MiniCPMForCausalLM": _HfExamplesInfo("openbmb/MiniCPM-2B-sft-bf16",
152 trust_remote_code=True),
vllm/model_executor/layers/mamba/ops/ssd_chunk_scan.py
+6 -2
@@ -293,7 +293,8 @@ def _chunk_scan_fwd_kernel(
293 dA_cs_m_boundary = tl.load(
294 dA_cumsum_ptr +
295 (pid_m * BLOCK_SIZE_M + c_off - 1) * stride_dA_cs_csize,
296 - mask=(pid_m * BLOCK_SIZE_M + c_off - 1) > -1,
296 + mask=(((pid_m * BLOCK_SIZE_M + c_off - 1) > -1)
297 + and ((pid_m * BLOCK_SIZE_M + c_off) < chunk_size)),
298 other=0.0).to(tl.float32)
299
300 if HAS_SEQ_IDX:
@@ -463,7 +464,10 @@ def _seq_idx_to_chunk_indices_offsets(seq_idx, chunk_size: int):
464 p += (s % chunk_size > 0)
465
466 # get the dimensions
466 - _s, _e = s // chunk_size + p, e // chunk_size + p + 1
467 + # - the + 1 for _e is to shift the boundary by one chunk
468 + # - this shifting is not needed if chunk_size divides e
469 + _s, _e = s // chunk_size + p, e // chunk_size + p + (e % chunk_size
470 + > 0)
471
472 # adjust inidces and offsets
473 chunk_indices[_s:_e] -= p
vllm/model_executor/models/bamba.py
+2 -19
@@ -440,23 +440,6 @@ class BambaForCausalLM(nn.Module, HasInnerState, SupportsLoRA, SupportsPP,
440 self.make_empty_intermediate_tensors = (
441 self.model.make_empty_intermediate_tensors)
442
443 - # follow jamba
444 - if self.scheduler_config is not None and \
445 - not self.model_config.enforce_eager:
446 - # for compilation
447 - if self.scheduler_config.max_num_seqs > \
448 - vllm_config.compilation_config.max_capture_size:
449 - self.max_batch_size = \
450 - vllm_config.compilation_config.max_capture_size
451 - else:
452 - self.max_batch_size = vllm_config.pad_for_cudagraph(
453 - self.scheduler_config.max_num_seqs)
454 - elif self.scheduler_config is not None:
455 - # for eager just take the scheduler_config if avail
456 - self.max_batch_size = self.scheduler_config.max_num_seqs
457 - else:
458 - self.max_batch_size = 8192 + 2
459 -
443 def get_input_embeddings(self, input_ids: torch.Tensor) -> torch.Tensor:
444 return self.model.get_input_embeddings(input_ids)
445
@@ -474,8 +457,8 @@ class BambaForCausalLM(nn.Module, HasInnerState, SupportsLoRA, SupportsPP,
457 self.vllm_config.parallel_config, LayerBlockType.mamba)
458
459 self.mamba_cache = MambaCacheManager(
477 - self.lm_head.weight.dtype, num_mamba_layers,
478 - self.max_batch_size, *self._get_mamba_cache_shape())
460 + self.vllm_config, self.lm_head.weight.dtype, num_mamba_layers,
461 + *self._get_mamba_cache_shape())
462 mamba_cache_params = self.mamba_cache.current_run_tensors(**kwargs)
463 hidden_states = self.model(input_ids, positions, kv_caches,
464 attn_metadata, mamba_cache_params,
vllm/model_executor/models/jamba.py
+2 -13
@@ -426,17 +426,6 @@ class JambaForCausalLM(nn.Module, HasInnerState, SupportsLoRA, SupportsPP,
426
427 self.make_empty_intermediate_tensors = (
428 self.model.make_empty_intermediate_tensors)
429 - if self.scheduler_config is not None and \
430 - not self.model_config.enforce_eager:
431 - if self.scheduler_config.max_num_seqs > \
432 - vllm_config.compilation_config.max_capture_size:
433 - self.max_batch_size = \
434 - vllm_config.compilation_config.max_capture_size
435 - else:
436 - self.max_batch_size = vllm_config.pad_for_cudagraph(
437 - self.scheduler_config.max_num_seqs)
438 - else:
439 - self.max_batch_size = 8192 + 2
429
430 def get_input_embeddings(self, input_ids: torch.Tensor) -> torch.Tensor:
431 return self.model.get_input_embeddings(input_ids)
@@ -453,8 +442,8 @@ class JambaForCausalLM(nn.Module, HasInnerState, SupportsLoRA, SupportsPP,
442 num_mamba_layers = self.model_config.get_num_layers_by_block_type(
443 self.vllm_config.parallel_config, LayerBlockType.mamba)
444 self.mamba_cache = MambaCacheManager(
456 - self.lm_head.weight.dtype, num_mamba_layers,
457 - self.max_batch_size, *self._get_mamba_cache_shape())
445 + self.vllm_config, self.lm_head.weight.dtype, num_mamba_layers,
446 + *self._get_mamba_cache_shape())
447
448 mamba_cache_params = self.mamba_cache.current_run_tensors(**kwargs)
449
vllm/model_executor/models/mamba.py
+3 -15
@@ -166,14 +166,13 @@ class MambaForCausalLM(nn.Module, HasInnerState, IsAttentionFree, SupportsPP):
166 config = vllm_config.model_config.hf_config
167 cache_config = vllm_config.cache_config
168 lora_config = vllm_config.lora_config
169 - scheduler_config = vllm_config.scheduler_config
169 + self.scheduler_config = vllm_config.scheduler_config
170 assert not cache_config.enable_prefix_caching, \
171 "Mamba does not support prefix caching"
172
173 super().__init__()
174 self.config = config
175 self.vllm_config = vllm_config
176 - self.scheduler_config = scheduler_config
176 self.model_config = vllm_config.model_config
177 self.backbone = MambaModel(vllm_config=vllm_config,
178 prefix=maybe_prefix(prefix, "backbone"))
@@ -202,17 +201,6 @@ class MambaForCausalLM(nn.Module, HasInnerState, IsAttentionFree, SupportsPP):
201
202 self.make_empty_intermediate_tensors = (
203 self.backbone.make_empty_intermediate_tensors)
205 - if self.scheduler_config is not None and \
206 - not self.model_config.enforce_eager:
207 - if self.scheduler_config.max_num_seqs > \
208 - vllm_config.compilation_config.max_capture_size:
209 - self.max_batch_size = \
210 - vllm_config.compilation_config.max_capture_size
211 - else:
212 - self.max_batch_size = vllm_config.pad_for_cudagraph(
213 - self.scheduler_config.max_num_seqs)
214 - else:
215 - self.max_batch_size = 8192 + 2
204
205 def get_input_embeddings(self, input_ids: torch.Tensor) -> torch.Tensor:
206 return self.backbone.get_input_embeddings(input_ids)
@@ -229,8 +217,8 @@ class MambaForCausalLM(nn.Module, HasInnerState, IsAttentionFree, SupportsPP):
217 num_mamba_layers = self.model_config.get_num_layers_by_block_type(
218 self.vllm_config.parallel_config, LayerBlockType.mamba)
219 self.mamba_cache = MambaCacheManager(
232 - self.lm_head.weight.dtype, num_mamba_layers,
233 - self.max_batch_size, *self._get_mamba_cache_shape())
220 + self.vllm_config, self.lm_head.weight.dtype, num_mamba_layers,
221 + *self._get_mamba_cache_shape())
222
223 mamba_cache_params = self.mamba_cache.current_run_tensors(**kwargs)
224
vllm/model_executor/models/mamba2.py new
+320
@@ -0,0 +1,320 @@
1 +# SPDX-License-Identifier: Apache-2.0
2 +"""PyTorch MAMBA2 model."""
3 +from typing import Iterable, List, Optional, Set, Tuple
4 +
5 +import torch
6 +from torch import nn
7 +from transformers import MambaConfig
8 +
9 +from vllm.attention.backends.abstract import AttentionMetadata
10 +from vllm.config import VllmConfig
11 +from vllm.distributed import divide, get_tensor_model_parallel_world_size
12 +from vllm.distributed.parallel_state import get_pp_group
13 +from vllm.model_executor.layers.layernorm import RMSNorm
14 +from vllm.model_executor.layers.logits_processor import LogitsProcessor
15 +from vllm.model_executor.layers.mamba.mamba_mixer2 import (
16 + MambaMixer2, extra_groups_for_head_shards)
17 +from vllm.model_executor.layers.quantization.base_config import (
18 + QuantizationConfig)
19 +from vllm.model_executor.layers.sampler import SamplerOutput, get_sampler
20 +from vllm.model_executor.layers.vocab_parallel_embedding import (
21 + DEFAULT_VOCAB_PADDING_SIZE, ParallelLMHead, VocabParallelEmbedding)
22 +from vllm.model_executor.model_loader.weight_utils import default_weight_loader
23 +from vllm.model_executor.models.interfaces import (HasInnerState,
24 + IsAttentionFree)
25 +from vllm.model_executor.models.mamba_cache import (MambaCacheManager,
26 + MambaCacheParams)
27 +from vllm.model_executor.sampling_metadata import SamplingMetadata
28 +from vllm.sequence import IntermediateTensors
29 +from vllm.utils import LayerBlockType
30 +
31 +from .utils import (is_pp_missing_parameter,
32 + make_empty_intermediate_tensors_factory, make_layers,
33 + maybe_prefix)
34 +
35 +KVCache = Tuple[torch.Tensor, torch.Tensor]
36 +
37 +
38 +class Mamba2DecoderLayer(nn.Module):
39 +
40 + def __init__(self,
41 + config: MambaConfig,
42 + quant_config: Optional[QuantizationConfig] = None) -> None:
43 + super().__init__()
44 + self.config = config
45 + self.mixer = MambaMixer2(hidden_size=config.hidden_size,
46 + ssm_state_size=config.state_size,
47 + conv_kernel_size=config.conv_kernel,
48 + intermediate_size=getattr(
49 + config, "intermediate_size",
50 + config.expand * config.hidden_size),
51 + use_conv_bias=config.use_conv_bias,
52 + use_bias=config.use_bias,
53 + n_groups=config.n_groups,
54 + num_heads=config.num_heads,
55 + head_dim=config.head_dim,
56 + rms_norm_eps=config.layer_norm_epsilon,
57 + activation=config.hidden_act,
58 + chunk_size=config.chunk_size,
59 + quant_config=quant_config)
60 +
61 + self.norm = RMSNorm(config.hidden_size, eps=config.layer_norm_epsilon)
62 +
63 + def forward(
64 + self,
65 + hidden_states: torch.Tensor,
66 + attn_metadata: AttentionMetadata,
67 + residual: Optional[torch.Tensor],
68 + mamba_cache_params: MambaCacheParams,
69 + sequence_idx: Optional[torch.Tensor],
70 + **kwargs,
71 + ):
72 + if residual is None:
73 + residual = hidden_states
74 + hidden_states = self.norm(hidden_states)
75 + else:
76 + hidden_states, residual = self.norm(hidden_states, residual)
77 +
78 + hidden_states = self.mixer(hidden_states, attn_metadata,
79 + mamba_cache_params, sequence_idx)
80 + return hidden_states, residual
81 +
82 +
83 +class Mamba2Model(nn.Module):
84 +
85 + def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
86 + super().__init__()
87 +
88 + config = vllm_config.model_config.hf_config
89 + quant_config = vllm_config.quant_config
90 + lora_config = vllm_config.lora_config
91 + is_lora_enabled = bool(lora_config)
92 + assert not is_lora_enabled
93 +
94 + self.config = config
95 + lora_vocab = ((lora_config.lora_extra_vocab_size *
96 + (lora_config.max_loras or 1)) if lora_config else 0)
97 + self.vocab_size = config.vocab_size + lora_vocab
98 + self.org_vocab_size = config.vocab_size
99 +
100 + self.embeddings = VocabParallelEmbedding(
101 + self.vocab_size,
102 + config.hidden_size,
103 + org_num_embeddings=config.vocab_size,
104 + )
105 +
106 + self.start_layer, self.end_layer, self.layers = make_layers(
107 + config.num_hidden_layers,
108 + lambda prefix: Mamba2DecoderLayer(config,
109 + quant_config=quant_config),
110 + prefix=f"{prefix}.layers")
111 +
112 + self.norm_f = RMSNorm(config.hidden_size,
113 + eps=config.layer_norm_epsilon)
114 + self.make_empty_intermediate_tensors = (
115 + make_empty_intermediate_tensors_factory(
116 + ["hidden_states", "residual"], config.hidden_size))
117 +
118 + def get_input_embeddings(self, input_ids: torch.Tensor) -> torch.Tensor:
119 + return self.embeddings(input_ids)
120 +
121 + def forward(
122 + self,
123 + input_ids: torch.Tensor,
124 + positions: torch.Tensor,
125 + attn_metadata: AttentionMetadata,
126 + mamba_cache_params: MambaCacheParams,
127 + intermediate_tensors: Optional[IntermediateTensors] = None,
128 + inputs_embeds: Optional[torch.Tensor] = None,
129 + ) -> torch.Tensor:
130 + if get_pp_group().is_first_rank:
131 + if inputs_embeds is not None:
132 + hidden_states = inputs_embeds
133 + else:
134 + hidden_states = self.get_input_embeddings(input_ids)
135 + residual = None
136 + else:
137 + assert intermediate_tensors is not None
138 + hidden_states = intermediate_tensors["hidden_states"]
139 + residual = intermediate_tensors["residual"]
140 +
141 + # pass a sequence index tensor, that is required for
142 + # proper continuous batching computation including
143 + # chunked prefill
144 + seq_idx = None
145 + if attn_metadata.num_prefills > 0:
146 + seq_idx = torch.zeros_like(input_ids, dtype=torch.int32)
147 + for i, (srt, end) in enumerate(
148 + zip(
149 + attn_metadata.query_start_loc,
150 + attn_metadata.query_start_loc[1:],
151 + )):
152 + seq_idx[srt:end] = i
153 + seq_idx.unsqueeze_(0)
154 +
155 + for i in range(len(self.layers)):
156 + layer = self.layers[i]
157 +
158 + hidden_states, residual = layer(
159 + positions=positions,
160 + hidden_states=hidden_states,
161 + attn_metadata=attn_metadata,
162 + residual=residual,
163 + mamba_cache_params=mamba_cache_params.at_layer_idx(
164 + i - self.start_layer),
165 + sequence_idx=seq_idx)
166 +
167 + if not get_pp_group().is_last_rank:
168 + return IntermediateTensors({
169 + "hidden_states": hidden_states,
170 + "residual": residual
171 + })
172 +
173 + hidden_states, _ = self.norm_f(hidden_states, residual)
174 +
175 + return hidden_states
176 +
177 +
178 +class Mamba2ForCausalLM(nn.Module, HasInnerState, IsAttentionFree):
179 +
180 + def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
181 + config = vllm_config.model_config.hf_config
182 + cache_config = vllm_config.cache_config
183 + lora_config = vllm_config.lora_config
184 + scheduler_config = vllm_config.scheduler_config
185 + assert not cache_config.enable_prefix_caching, \
186 + "Mamba does not support prefix caching"
187 +
188 + super().__init__()
189 + self.config = config
190 + self.vllm_config = vllm_config
191 + self.scheduler_config = scheduler_config
192 + self.model_config = vllm_config.model_config
193 + self.backbone = Mamba2Model(vllm_config=vllm_config,
194 + prefix=maybe_prefix(prefix, "backbone"))
195 + self.unpadded_vocab_size = config.vocab_size
196 + if lora_config:
197 + self.unpadded_vocab_size += lora_config.lora_extra_vocab_size
198 +
199 + self.lm_head = ParallelLMHead(
200 + self.unpadded_vocab_size,
201 + config.hidden_size,
202 + org_num_embeddings=config.vocab_size,
203 + padding_size=DEFAULT_VOCAB_PADDING_SIZE
204 + # We need bigger padding if using lora for kernel
205 + # compatibility
206 + if not lora_config else lora_config.lora_vocab_padding_size,
207 + )
208 + if config.tie_word_embeddings:
209 + self.lm_head = self.lm_head.tie_weights(self.backbone.embeddings)
210 +
211 + # Used to track and store by the Mamba cache between steps.
212 + self.mamba_cache: Optional[MambaCacheManager] = None
213 +
214 + self.logits_processor = LogitsProcessor(self.unpadded_vocab_size,
215 + config.vocab_size)
216 + self.sampler = get_sampler()
217 +
218 + self.make_empty_intermediate_tensors = (
219 + self.backbone.make_empty_intermediate_tensors)
220 +
221 + def get_input_embeddings(self, input_ids: torch.Tensor) -> torch.Tensor:
222 + return self.backbone.get_input_embeddings(input_ids)
223 +
224 + def forward(self,
225 + input_ids: torch.Tensor,
226 + positions: torch.Tensor,
227 + kv_caches: List[KVCache],
228 + attn_metadata: AttentionMetadata,
229 + intermediate_tensors: Optional[IntermediateTensors] = None,
230 + inputs_embeds: Optional[torch.Tensor] = None,
231 + **kwargs):
232 + if self.mamba_cache is None:
233 + num_mamba_layers = self.model_config.get_num_layers_by_block_type(
234 + self.vllm_config.parallel_config, LayerBlockType.mamba)
235 + self.mamba_cache = MambaCacheManager(
236 + self.vllm_config, self.lm_head.weight.dtype, num_mamba_layers,
237 + *self._get_mamba_cache_shape())
238 +
239 + mamba_cache_params = self.mamba_cache.current_run_tensors(**kwargs)
240 +
241 + hidden_states = self.backbone(input_ids, positions, attn_metadata,
242 + mamba_cache_params, intermediate_tensors,
243 + inputs_embeds)
244 +
245 + return hidden_states
246 +
247 + def copy_inputs_before_cuda_graphs(self, input_buffers, **kwargs):
248 + return self.mamba_cache.copy_inputs_before_cuda_graphs(
249 + input_buffers, **kwargs)
250 +
251 + def get_seqlen_agnostic_capture_inputs(self, batch_size: int):
252 + return self.mamba_cache.get_seqlen_agnostic_capture_inputs(batch_size)
253 +
254 + def _get_mamba_cache_shape(
255 + self) -> Tuple[Tuple[int, int], Tuple[int, int]]:
256 + world_size = get_tensor_model_parallel_world_size()
257 +
258 + conv_state_shape, temporal_state_shape = None, None
259 +
260 + intermediate_size = getattr(
261 + self.config, "intermediate_size",
262 + self.config.expand * self.config.hidden_size)
263 +
264 + # if n_groups is not divisible by world_size, need to extend the shards
265 + # to ensure all groups needed by a head is sharded along with it
266 + n_groups = (
267 + self.config.n_groups +
268 + extra_groups_for_head_shards(self.config.n_groups, world_size))
269 +
270 + # - heads and n_groups are TP-ed
271 + conv_dim = (intermediate_size + 2 * n_groups * self.config.state_size)
272 + conv_state_shape = (
273 + divide(conv_dim, world_size),
274 + self.config.conv_kernel - 1,
275 + )
276 +
277 + # These are not TP-ed as they depend on A, dt_bias, D
278 + # - they are typically small
279 + # e.g., (h_heads, d_head, d_state) = (128, 64, 128)
280 + temporal_state_shape = (
281 + divide(self.config.num_heads, world_size),
282 + self.config.head_dim,
283 + self.config.state_size,
284 + )
285 + return conv_state_shape, temporal_state_shape
286 +
287 + def compute_logits(self, hidden_states: torch.Tensor,
288 + sampling_metadata: SamplingMetadata) -> torch.Tensor:
289 + logits = self.logits_processor(self.lm_head, hidden_states,
290 + sampling_metadata)
291 + return logits
292 +
293 + def sample(
294 + self,
295 + logits: Optional[torch.Tensor],
296 + sampling_metadata: SamplingMetadata,
297 + ) -> Optional[SamplerOutput]:
298 + next_tokens = self.sampler(logits, sampling_metadata)
299 + return next_tokens
300 +
301 + def load_weights(self, weights: Iterable[Tuple[str,
302 + torch.Tensor]]) -> Set[str]:
303 + params_dict = dict(self.named_parameters())
304 + loaded_params: Set[str] = set()
305 + for name, loaded_weight in weights:
306 + if "A_log" in name:
307 + name = name.replace("A_log", "A")
308 +
309 + # Skip loading extra bias for GPTQ models.
310 + if name.endswith(".bias") and name not in params_dict:
311 + continue
312 + if is_pp_missing_parameter(name, self):
313 + continue
314 +
315 + param = params_dict[name]
316 + weight_loader = getattr(param, "weight_loader",
317 + default_weight_loader)
318 + weight_loader(param, loaded_weight)
319 + loaded_params.add(name)
320 + return loaded_params
vllm/model_executor/models/mamba_cache.py
+10 -3
@@ -1,11 +1,12 @@
1 # SPDX-License-Identifier: Apache-2.0
2
3 from dataclasses import dataclass
4 -from typing import Dict, List
4 +from typing import Dict, List, Tuple
5
6 import torch
7
8 from vllm.attention.backends.utils import PAD_SLOT_ID
9 +from vllm.config import VllmConfig
10
11
12 @dataclass
@@ -22,8 +23,14 @@ class MambaCacheParams:
23
24 class MambaCacheManager:
25
25 - def __init__(self, dtype, num_mamba_layers, max_batch_size,
26 - conv_state_shape, temporal_state_shape):
26 + def __init__(self, vllm_config: VllmConfig, dtype: torch.dtype,
27 + num_mamba_layers: int, conv_state_shape: Tuple[int, int],
28 + temporal_state_shape: Tuple[int, int]):
29 +
30 + # Determine max batch size to set size of MambaCache
31 + max_batch_size = vllm_config.scheduler_config.max_num_seqs
32 + if not vllm_config.model_config.enforce_eager:
33 + max_batch_size = vllm_config.pad_for_cudagraph(max_batch_size)
34
35 conv_state = torch.empty(size=(num_mamba_layers, max_batch_size) +
36 conv_state_shape,
vllm/model_executor/models/registry.py
+1
@@ -71,6 +71,7 @@ _TEXT_GENERATION_MODELS = {
71 "LLaMAForCausalLM": ("llama", "LlamaForCausalLM"),
72 "MambaForCausalLM": ("mamba", "MambaForCausalLM"),
73 "FalconMambaForCausalLM": ("mamba", "MambaForCausalLM"),
74 + "Mamba2ForCausalLM": ("mamba2", "Mamba2ForCausalLM"),
75 "MiniCPMForCausalLM": ("minicpm", "MiniCPMForCausalLM"),
76 "MiniCPM3ForCausalLM": ("minicpm3", "MiniCPM3ForCausalLM"),
77 "MistralForCausalLM": ("llama", "LlamaForCausalLM"),