main
py 526 lines 17.9 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 """Inference-only Jamba model."""
4
5 from collections.abc import Iterable
6 from itertools import islice
7
8 import torch
9 from torch import nn
10 from transformers import JambaConfig
11
12 from vllm.compilation.decorators import support_torch_compile
13 from vllm.config import CacheConfig, ModelConfig, VllmConfig
14 from vllm.distributed import get_tensor_model_parallel_world_size
15 from vllm.distributed.parallel_state import get_pp_group
16 from vllm.model_executor.layers.attention import Attention
17 from vllm.model_executor.layers.fused_moe import (
18 FusedMoEFactory,
19 GateLinear,
20 )
21 from vllm.model_executor.layers.layernorm import RMSNorm
22 from vllm.model_executor.layers.linear import (
23 QKVParallelLinear,
24 RowParallelLinear,
25 )
26 from vllm.model_executor.layers.logits_processor import LogitsProcessor
27 from vllm.model_executor.layers.mamba.mamba_mixer import MambaMixer
28 from vllm.model_executor.layers.mamba.mamba_utils import (
29 MambaStateCopyFunc,
30 MambaStateCopyFuncCalculator,
31 MambaStateDtypeCalculator,
32 MambaStateShapeCalculator,
33 )
34 from vllm.model_executor.layers.pooler import DispatchPooler
35 from vllm.model_executor.layers.quantization import QuantizationConfig
36 from vllm.model_executor.layers.vocab_parallel_embedding import (
37 ParallelLMHead,
38 VocabParallelEmbedding,
39 )
40 from vllm.model_executor.models.llama import LlamaMLP as JambaMLP
41 from vllm.sequence import IntermediateTensors
42
43 from .interfaces import (
44 HasInnerState,
45 IsHybrid,
46 SupportsLoRA,
47 SupportsMambaPrefixCaching,
48 SupportsPP,
49 )
50 from .utils import (
51 AutoWeightsLoader,
52 WeightsMapper,
53 make_empty_intermediate_tensors_factory,
54 make_layers,
55 maybe_prefix,
56 )
57
58
59 class JambaMoE(nn.Module):
60 def __init__(
61 self,
62 config: JambaConfig,
63 num_experts: int | None = None,
64 top_k: int | None = None,
65 params_dtype: torch.dtype | None = None,
66 tp_size: int | None = None,
67 quant_config: QuantizationConfig | None = None,
68 prefix: str = "",
69 ):
70 super().__init__()
71 self.num_total_experts = num_experts or config.num_experts
72 self.top_k = top_k or config.num_experts_per_tok
73 self.hidden_size = config.hidden_size
74 self.intermediate_size = config.intermediate_size
75
76 if self.num_total_experts > 1:
77 self.router = GateLinear(
78 self.hidden_size,
79 self.num_total_experts,
80 params_dtype=params_dtype,
81 prefix=f"{prefix}.router",
82 )
83
84 self.experts = FusedMoEFactory(
85 self.num_total_experts,
86 self.top_k,
87 self.hidden_size,
88 self.intermediate_size,
89 tp_size=tp_size,
90 params_dtype=params_dtype,
91 renormalize=False,
92 use_grouped_topk=False,
93 quant_config=quant_config,
94 prefix=f"{prefix}.experts",
95 )
96
97 def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
98 orig_shape = hidden_states.shape
99 hidden_states = hidden_states.view(-1, self.hidden_size)
100 # router_logits: (batch * sequence_length, n_experts)
101 if self.num_total_experts > 1:
102 router_logits, _ = self.router(hidden_states)
103 else:
104 router_logits = torch.ones(
105 (hidden_states.shape[0], 1),
106 device=hidden_states.device,
107 dtype=hidden_states.dtype,
108 )
109 hidden_states = self.experts(hidden_states, router_logits)
110 return hidden_states.view(orig_shape)
111
112
113 class JambaMambaDecoderLayer(nn.Module):
114 def __init__(
115 self,
116 config: JambaConfig,
117 layer_idx: int,
118 model_config: ModelConfig | None = None,
119 cache_config: CacheConfig | None = None,
120 quant_config: QuantizationConfig | None = None,
121 is_lora_enabled: bool = False,
122 prefix: str = "",
123 **kwargs,
124 ) -> None:
125 super().__init__()
126 self.config = config
127 self.is_lora_enabled = is_lora_enabled
128 self.mamba = MambaMixer(
129 hidden_size=config.hidden_size,
130 ssm_state_size=config.mamba_d_state,
131 conv_kernel_size=config.mamba_d_conv,
132 intermediate_size=config.mamba_expand * config.hidden_size,
133 time_step_rank=config.mamba_dt_rank,
134 use_conv_bias=config.mamba_conv_bias,
135 use_bias=config.mamba_proj_bias,
136 use_rms_norm=True,
137 rms_norm_eps=config.rms_norm_eps,
138 activation=config.hidden_act,
139 is_lora_enabled=self.is_lora_enabled,
140 model_config=model_config,
141 cache_config=cache_config,
142 prefix=f"{prefix}.mixer",
143 )
144
145 num_experts = config.layers_num_experts[layer_idx]
146 if num_experts > 1:
147 self.feed_forward = JambaMoE(
148 config,
149 quant_config=quant_config,
150 prefix=f"{prefix}.feed_forward",
151 )
152 else:
153 self.feed_forward = JambaMLP(
154 config.hidden_size,
155 config.intermediate_size,
156 config.hidden_act,
157 quant_config=quant_config,
158 prefix=f"{prefix}.feed_forward",
159 )
160 self.input_layernorm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
161 self.pre_ff_layernorm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
162
163 def forward(
164 self,
165 hidden_states: torch.Tensor,
166 residual: torch.Tensor | None,
167 **kwargs,
168 ):
169 if residual is None:
170 residual = hidden_states
171 hidden_states = self.input_layernorm(hidden_states)
172 else:
173 hidden_states, residual = self.input_layernorm(hidden_states, residual)
174
175 output = torch.empty_like(hidden_states)
176 self.mamba(hidden_states, output)
177 # Fully Connected
178 hidden_states, residual = self.pre_ff_layernorm(output, residual)
179 hidden_states = self.feed_forward(hidden_states)
180 return hidden_states, residual
181
182
183 class JambaAttentionDecoderLayer(nn.Module):
184 def __init__(
185 self,
186 config: JambaConfig,
187 layer_idx: int,
188 model_config: ModelConfig | None = None,
189 cache_config: CacheConfig | None = None,
190 quant_config: QuantizationConfig | None = None,
191 prefix: str = "",
192 **kwargs,
193 ) -> None:
194 super().__init__()
195 self.hidden_size = config.hidden_size
196 tp_size = get_tensor_model_parallel_world_size()
197 self.total_num_heads = config.num_attention_heads
198 assert self.total_num_heads % tp_size == 0
199 self.num_heads = self.total_num_heads // tp_size
200 self.total_num_kv_heads = config.num_key_value_heads
201 if self.total_num_kv_heads >= tp_size:
202 # Number of KV heads is greater than TP size, so we partition
203 # the KV heads across multiple tensor parallel GPUs.
204 assert self.total_num_kv_heads % tp_size == 0
205 else:
206 # Number of KV heads is less than TP size, so we replicate
207 # the KV heads across multiple tensor parallel GPUs.
208 assert tp_size % self.total_num_kv_heads == 0
209 self.num_kv_heads = max(1, self.total_num_kv_heads // tp_size)
210 self.head_dim = config.hidden_size // self.total_num_heads
211 self.q_size = self.num_heads * self.head_dim
212 self.kv_size = self.num_kv_heads * self.head_dim
213 self.scaling = self.head_dim**-0.5
214
215 self.qkv_proj = QKVParallelLinear(
216 config.hidden_size,
217 self.head_dim,
218 self.total_num_heads,
219 self.total_num_kv_heads,
220 bias=False,
221 quant_config=quant_config,
222 prefix=f"{prefix}.qkv_proj",
223 )
224 self.o_proj = RowParallelLinear(
225 self.total_num_heads * self.head_dim,
226 config.hidden_size,
227 bias=False,
228 quant_config=quant_config,
229 prefix=f"{prefix}.o_proj",
230 )
231
232 self.attn = Attention(
233 self.num_heads,
234 self.head_dim,
235 self.scaling,
236 num_kv_heads=self.num_kv_heads,
237 cache_config=cache_config,
238 prefix=f"{prefix}.attn",
239 )
240
241 num_experts = config.layers_num_experts[layer_idx]
242 if num_experts > 1:
243 self.feed_forward = JambaMoE(
244 config,
245 quant_config=quant_config,
246 prefix=f"{prefix}.feed_forward",
247 )
248 else:
249 self.feed_forward = JambaMLP(
250 config.hidden_size,
251 config.intermediate_size,
252 config.hidden_act,
253 quant_config=quant_config,
254 prefix=f"{prefix}.feed_forward",
255 )
256 self.input_layernorm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
257 self.pre_ff_layernorm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
258
259 def self_attention(
260 self,
261 positions: torch.Tensor,
262 hidden_states: torch.Tensor,
263 **kwargs,
264 ) -> torch.Tensor:
265 qkv, _ = self.qkv_proj(hidden_states)
266 q, k, v = qkv.split([self.q_size, self.kv_size, self.kv_size], dim=-1)
267 attn_output = self.attn(q, k, v)
268 output, _ = self.o_proj(attn_output)
269 return output
270
271 def forward(
272 self,
273 positions: torch.Tensor,
274 hidden_states: torch.Tensor,
275 residual: torch.Tensor | None,
276 **kwargs,
277 ):
278 if residual is None:
279 residual = hidden_states
280 hidden_states = self.input_layernorm(hidden_states)
281 else:
282 hidden_states, residual = self.input_layernorm(hidden_states, residual)
283
284 hidden_states = self.self_attention(
285 positions=positions,
286 hidden_states=hidden_states,
287 )
288 # Fully Connected
289 hidden_states, residual = self.pre_ff_layernorm(hidden_states, residual)
290 hidden_states = self.feed_forward(hidden_states)
291 return hidden_states, residual
292
293
294 ALL_DECODER_LAYER_TYPES = {
295 "attention": JambaAttentionDecoderLayer,
296 "mamba": JambaMambaDecoderLayer,
297 }
298
299
300 @support_torch_compile
301 class JambaModel(nn.Module):
302 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
303 super().__init__()
304
305 config = vllm_config.model_config.hf_config
306 model_config = vllm_config.model_config
307 cache_config = vllm_config.cache_config
308 quant_config = vllm_config.quant_config
309
310 self.config = config
311
312 self.vocab_size = config.vocab_size
313
314 self.embed_tokens = VocabParallelEmbedding(
315 self.vocab_size,
316 config.hidden_size,
317 )
318
319 extra_kwargs = {"is_lora_enabled": bool(vllm_config.lora_config)}
320
321 def get_layer(prefix: str):
322 layer_idx = int(prefix.rsplit(".", 1)[1])
323 layer_class = ALL_DECODER_LAYER_TYPES[config.layers_block_type[layer_idx]]
324 return layer_class(
325 config,
326 layer_idx,
327 model_config,
328 cache_config,
329 quant_config=quant_config,
330 prefix=prefix,
331 **extra_kwargs,
332 )
333
334 self.start_layer, self.end_layer, self.layers = make_layers(
335 config.num_hidden_layers, get_layer, prefix=f"{prefix}.layers"
336 )
337 self.make_empty_intermediate_tensors = make_empty_intermediate_tensors_factory(
338 ["hidden_states", "residual"], config.hidden_size
339 )
340
341 self.final_layernorm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
342
343 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
344 return self.embed_tokens(input_ids)
345
346 def forward(
347 self,
348 input_ids: torch.Tensor | None,
349 positions: torch.Tensor,
350 intermediate_tensors: IntermediateTensors | None = None,
351 inputs_embeds: torch.Tensor | None = None,
352 ) -> torch.Tensor:
353 if get_pp_group().is_first_rank:
354 if inputs_embeds is not None:
355 hidden_states = inputs_embeds
356 else:
357 hidden_states = self.embed_input_ids(input_ids)
358 residual = None
359 else:
360 assert intermediate_tensors is not None
361 hidden_states = intermediate_tensors["hidden_states"]
362 residual = intermediate_tensors["residual"]
363
364 for layer in islice(self.layers, self.start_layer, self.end_layer):
365 hidden_states, residual = layer(
366 positions=positions, hidden_states=hidden_states, residual=residual
367 )
368
369 if not get_pp_group().is_last_rank:
370 return IntermediateTensors(
371 {"hidden_states": hidden_states, "residual": residual}
372 )
373 hidden_states, _ = self.final_layernorm(hidden_states, residual)
374 return hidden_states
375
376
377 class JambaForCausalLM(
378 nn.Module,
379 HasInnerState,
380 SupportsLoRA,
381 SupportsPP,
382 IsHybrid,
383 SupportsMambaPrefixCaching,
384 ):
385 hf_to_vllm_mapper = WeightsMapper(
386 orig_to_new_substr={".self_attn.": ".", ".A_log": ".A"},
387 orig_to_new_stacked={
388 ".q_proj": (".qkv_proj", "q"),
389 ".k_proj": (".qkv_proj", "k"),
390 ".v_proj": (".qkv_proj", "v"),
391 # .experts.gate_up_proj must be handled by MoERunner.load_weights for EP
392 ".feed_forward.gate_proj": (".feed_forward.gate_up_proj", 0),
393 ".feed_forward.up_proj": (".feed_forward.gate_up_proj", 1),
394 },
395 )
396 packed_modules_mapping = {
397 "qkv_proj": [
398 "q_proj",
399 "k_proj",
400 "v_proj",
401 ],
402 "gate_up_proj": ["gate_proj", "up_proj"],
403 "in_proj": ["in_proj"],
404 }
405
406 # LoRA specific attributes
407 embedding_modules = {
408 "embed_tokens": "input_embeddings",
409 "lm_head": "output_embeddings",
410 }
411
412 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
413 config = vllm_config.model_config.hf_config
414
415 scheduler_config = vllm_config.scheduler_config
416
417 super().__init__()
418 self.config = config
419 self.vllm_config = vllm_config
420 self.model_config = vllm_config.model_config
421 self.scheduler_config = scheduler_config
422 self.model = JambaModel(
423 vllm_config=vllm_config, prefix=maybe_prefix(prefix, "model")
424 )
425
426 self.lm_head = ParallelLMHead(
427 config.vocab_size,
428 config.hidden_size,
429 prefix=maybe_prefix(prefix, "lm_head"),
430 )
431
432 self.logits_processor = LogitsProcessor(config.vocab_size)
433
434 self.make_empty_intermediate_tensors = (
435 self.model.make_empty_intermediate_tensors
436 )
437
438 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
439 return self.model.embed_input_ids(input_ids)
440
441 def forward(
442 self,
443 input_ids: torch.Tensor | None,
444 positions: torch.Tensor,
445 intermediate_tensors: IntermediateTensors | None = None,
446 inputs_embeds: torch.Tensor | None = None,
447 **kwargs,
448 ):
449 hidden_states = self.model(
450 input_ids, positions, intermediate_tensors, inputs_embeds
451 )
452 return hidden_states
453
454 def copy_inputs_before_cuda_graphs(self, input_buffers, **kwargs):
455 return self.mamba_cache.copy_inputs_before_cuda_graphs(input_buffers, **kwargs)
456
457 def get_seqlen_agnostic_capture_inputs(self, batch_size: int):
458 return self.mamba_cache.get_seqlen_agnostic_capture_inputs(batch_size)
459
460 @classmethod
461 def get_mamba_state_dtype_from_config(
462 cls,
463 vllm_config: "VllmConfig",
464 ) -> tuple[torch.dtype, torch.dtype]:
465 return MambaStateDtypeCalculator.mamba1_state_dtype(
466 vllm_config.model_config.dtype,
467 vllm_config.cache_config.mamba_cache_dtype,
468 vllm_config.cache_config.mamba_ssm_cache_dtype,
469 )
470
471 @classmethod
472 def get_mamba_state_shape_from_config(
473 cls,
474 vllm_config: "VllmConfig",
475 ) -> tuple[tuple[int, int], tuple[int, int]]:
476 parallel_config = vllm_config.parallel_config
477 hf_config = vllm_config.model_config.hf_config
478 hidden_size = hf_config.hidden_size
479
480 return MambaStateShapeCalculator.mamba1_state_shape(
481 tp_world_size=parallel_config.tensor_parallel_size,
482 intermediate_size=hf_config.mamba_expand * hidden_size,
483 state_size=hf_config.mamba_d_state,
484 conv_kernel=hf_config.mamba_d_conv,
485 )
486
487 @classmethod
488 def get_mamba_state_copy_func(cls) -> tuple[MambaStateCopyFunc, MambaStateCopyFunc]:
489 return MambaStateCopyFuncCalculator.mamba1_state_copy_func()
490
491 def compute_logits(
492 self,
493 hidden_states: torch.Tensor,
494 ) -> torch.Tensor | None:
495 logits = self.logits_processor(self.lm_head, hidden_states)
496 return logits
497
498 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
499 loader = AutoWeightsLoader(self)
500 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
501
502
503 class JambaForSequenceClassification(JambaForCausalLM):
504 is_pooling_model = True
505
506 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
507 super().__init__(vllm_config=vllm_config, prefix=prefix)
508
509 config = vllm_config.model_config.hf_config
510 num_labels: int = config.num_labels
511 score_bias: bool = getattr(config, "score_bias", False)
512
513 # TODO: The original reward weights have float32 accuracy data, we
514 # would like to load them in fp32 to get that extra precision.
515 # Currently weight_loader passes the weight which is already in bf16
516 self.score = nn.Linear(
517 config.hidden_size,
518 num_labels,
519 bias=score_bias,
520 dtype=vllm_config.model_config.head_dtype,
521 )
522
523 pooler_config = vllm_config.model_config.pooler_config
524 assert pooler_config is not None
525
526 self.pooler = DispatchPooler.for_seq_cls(pooler_config, classifier=self.score)