main
py 1,002 lines 34.7 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 """PyTorch Zamba2 model implementation for vLLM.
4
5 This module implements the Zamba2 architecture from
6 https://arxiv.org/abs/2411.15242, which combines Mamba and Transformer
7 architectures in a hybrid model optimized for efficient sequence modeling. The
8 model alternates between state space model layers and attention-based layers.
9 """
10
11 from collections.abc import Iterable
12 from itertools import cycle
13 from typing import Any
14
15 import torch
16 from torch import nn
17 from transformers import Zamba2Config
18
19 from vllm.compilation.decorators import support_torch_compile
20 from vllm.config import CacheConfig, ModelConfig, VllmConfig
21 from vllm.distributed import get_tensor_model_parallel_world_size
22 from vllm.model_executor.layers.activation import GeluAndMul
23 from vllm.model_executor.layers.attention import Attention
24 from vllm.model_executor.layers.layernorm import RMSNorm
25 from vllm.model_executor.layers.linear import (
26 ColumnParallelLinear,
27 MergedColumnParallelLinear,
28 QKVParallelLinear,
29 ReplicatedLinear,
30 RowParallelLinear,
31 )
32 from vllm.model_executor.layers.logits_processor import LogitsProcessor
33 from vllm.model_executor.layers.mamba.mamba_mixer2 import MambaMixer2
34 from vllm.model_executor.layers.mamba.mamba_utils import (
35 MambaStateCopyFunc,
36 MambaStateCopyFuncCalculator,
37 MambaStateDtypeCalculator,
38 MambaStateShapeCalculator,
39 )
40 from vllm.model_executor.layers.quantization import QuantizationConfig
41 from vllm.model_executor.layers.rotary_embedding import get_rope
42 from vllm.model_executor.layers.vocab_parallel_embedding import (
43 ParallelLMHead,
44 VocabParallelEmbedding,
45 )
46 from vllm.sequence import IntermediateTensors
47
48 from .interfaces import HasInnerState, IsHybrid, SupportsMambaPrefixCaching
49 from .utils import AutoWeightsLoader, WeightsMapper, maybe_prefix
50
51
52 class Zamba2LoRA(nn.Module):
53 """LoRA layer for the Zamba2 model.
54
55 Implements a LoRA layer that is used in shared attention and gated MLP
56 blocks.
57 """
58
59 def __init__(
60 self,
61 input_dim: int,
62 rank: int,
63 output_dim: int | list[int],
64 quant_config: QuantizationConfig | None = None,
65 prefix: str = "",
66 ):
67 """Initialize the attention layer.
68
69 Args:
70 input_dim: input dimension
71 rank: LoRA rank
72 output_dim: output dimension
73 quant_config: Configuration for model quantization
74 prefix: Module prefix used for quantization config lookup
75
76 """
77 super().__init__()
78
79 self.A = ColumnParallelLinear(
80 input_dim,
81 rank,
82 bias=False,
83 quant_config=quant_config,
84 gather_output=True,
85 prefix=f"{prefix}.A",
86 )
87
88 if isinstance(output_dim, list):
89 self.B: ColumnParallelLinear = MergedColumnParallelLinear(
90 rank,
91 output_dim,
92 bias=False,
93 quant_config=quant_config,
94 prefix=f"{prefix}.B",
95 )
96 else:
97 self.B = ColumnParallelLinear(
98 rank,
99 output_dim,
100 bias=False,
101 quant_config=quant_config,
102 prefix=f"{prefix}.B",
103 )
104
105 def forward(
106 self,
107 hidden_states: torch.Tensor,
108 ):
109 lora_output, _ = self.A(hidden_states)
110 lora_output, _ = self.B(lora_output)
111 return lora_output
112
113
114 class Zamba2Attention(nn.Module):
115 """Multi-head attention mechanism for the Zamba2 model.
116
117 Implements attention with parallel computation, QKV projections, optional
118 adapters and rotary position embeddings. The attention is computed across
119 distributed blocks for efficient processing.
120 """
121
122 def __init__(
123 self,
124 config: Zamba2Config,
125 bare_block_idx: int,
126 num_hybrid_layers: int,
127 cache_config: CacheConfig | None = None,
128 quant_config: QuantizationConfig | None = None,
129 prefix: str = "",
130 ) -> None:
131 """Initialize the attention layer.
132
133 Args:
134 config: The Zamba2 model configuration
135 bare_block_idx: Index of the bare attention block
136 num_hybrid_layers: Total number of hybrid layers
137 cache_config: Configuration for key-value caching
138 quant_config: Configuration for model quantization
139 prefix: Optional prefix for parameter names
140
141 """
142 super().__init__()
143 tp_size = get_tensor_model_parallel_world_size()
144 self.config = config
145 self.num_hybrid_layers = num_hybrid_layers
146
147 self.attention_hidden_size = config.attention_hidden_size
148 self.total_num_attention_heads = config.num_attention_heads
149 assert self.total_num_attention_heads % tp_size == 0
150 self.num_attention_heads = config.num_attention_heads // tp_size
151 self.attention_head_dim = config.attention_head_dim
152 self.qkv_size = self.attention_hidden_size // tp_size
153 self.scale = (self.attention_head_dim / 2) ** -0.5
154
155 if (
156 self.attention_head_dim * self.total_num_attention_heads
157 ) != self.attention_hidden_size:
158 raise ValueError(
159 f"attention_hidden_size must be divisible by"
160 f" num_attention_heads"
161 f" (got `attention_hidden_size`: {self.attention_hidden_size}"
162 f" and `num_heads`: {self.num_attention_heads})."
163 )
164
165 self.qkv_proj = QKVParallelLinear(
166 self.attention_hidden_size,
167 self.attention_head_dim,
168 self.total_num_attention_heads,
169 bias=False,
170 quant_config=quant_config,
171 prefix=f"{prefix}.qkv_proj",
172 )
173 self.o_proj = RowParallelLinear(
174 self.attention_hidden_size,
175 config.hidden_size,
176 bias=False,
177 quant_config=quant_config,
178 prefix=f"{prefix}.o_proj",
179 )
180
181 # Even though in Zamba2 weights are shared between attention layers, KV
182 # cache is unique for every attention layer. Hence, we need to define
183 # separate Attention objects, because in recent vLLM KV cache tensors
184 # are tied to specific Attention objects.
185
186 # Initialize attention blocks with proper indexing
187 self.dpa_list = nn.ModuleList([])
188 j = (
189 bare_block_idx
190 * (self.num_hybrid_layers + config.num_mem_blocks - 1)
191 // config.num_mem_blocks
192 )
193 for block_idx in range(self.num_hybrid_layers):
194 if block_idx % config.num_mem_blocks == bare_block_idx:
195 dpa = Attention(
196 self.num_attention_heads,
197 self.attention_head_dim,
198 self.scale,
199 cache_config=cache_config,
200 prefix=f"{prefix}.attn.{j}",
201 )
202 j += 1
203 else:
204 dpa = nn.Identity()
205 self.dpa_list.append(dpa)
206
207 # Initialize adapter layers if enabled
208 if config.use_shared_attention_adapter:
209 self.linear_q_adapter_list = nn.ModuleList([])
210 self.linear_k_adapter_list = nn.ModuleList([])
211 self.linear_v_adapter_list = nn.ModuleList([])
212
213 for block_idx in range(self.num_hybrid_layers):
214 if block_idx % config.num_mem_blocks == bare_block_idx:
215 linear_q_adapter = Zamba2LoRA(
216 self.attention_hidden_size,
217 config.adapter_rank,
218 self.attention_hidden_size,
219 quant_config=quant_config,
220 prefix=f"{prefix}.linear_q_adapter",
221 )
222 linear_k_adapter = Zamba2LoRA(
223 self.attention_hidden_size,
224 config.adapter_rank,
225 self.attention_hidden_size,
226 quant_config=quant_config,
227 prefix=f"{prefix}.linear_k_adapter",
228 )
229 linear_v_adapter = Zamba2LoRA(
230 self.attention_hidden_size,
231 config.adapter_rank,
232 self.attention_hidden_size,
233 quant_config=quant_config,
234 prefix=f"{prefix}.linear_v_adapter",
235 )
236 else:
237 linear_q_adapter = nn.Identity()
238 linear_k_adapter = nn.Identity()
239 linear_v_adapter = nn.Identity()
240
241 self.linear_q_adapter_list.append(linear_q_adapter)
242 self.linear_k_adapter_list.append(linear_k_adapter)
243 self.linear_v_adapter_list.append(linear_v_adapter)
244
245 if config.use_mem_rope:
246 self.rotary_emb = get_rope(
247 head_size=self.attention_head_dim,
248 max_position=config.max_position_embeddings,
249 rope_parameters=config.rope_parameters,
250 is_neox_style=True,
251 )
252
253 def forward(
254 self,
255 hidden_states: torch.Tensor,
256 block_idx: int,
257 position_ids: torch.Tensor,
258 ) -> torch.Tensor:
259 """Forward pass through the attention layer.
260
261 Args:
262 hidden_states: Input tensor [batch_size, seq_len, hidden_size]
263 position_ids: Position IDs for positional embeddings
264 block_idx: Current shared transformer block index
265
266 Returns:
267 Output tensor [batch_size, seq_len, hidden_size]
268
269 """
270 qkv, _ = self.qkv_proj(hidden_states)
271 query_states, key_states, value_states = qkv.split([self.qkv_size] * 3, dim=-1)
272
273 if self.config.use_shared_attention_adapter:
274 # Apply adapter transformations to Q, K, V if enabled
275 q_adapter = self.linear_q_adapter_list[block_idx]
276 assert not isinstance(q_adapter, nn.Identity)
277 q_lora_output = q_adapter(hidden_states)
278 query_states = query_states + q_lora_output
279
280 k_adapter = self.linear_k_adapter_list[block_idx]
281 assert not isinstance(k_adapter, nn.Identity)
282 k_lora_output = k_adapter(hidden_states)
283 key_states = key_states + k_lora_output
284
285 v_adapter = self.linear_v_adapter_list[block_idx]
286 assert not isinstance(v_adapter, nn.Identity)
287 v_lora_output = v_adapter(hidden_states)
288 value_states = value_states + v_lora_output
289
290 if self.config.use_mem_rope:
291 query_states, key_states = self.rotary_emb(
292 position_ids, query_states, key_states
293 )
294
295 y = self.dpa_list[block_idx](query_states, key_states, value_states)
296 y, _ = self.o_proj(y)
297 return y
298
299
300 class Zamba2MLP(nn.Module):
301 """Feed-forward MLP layer for the Zamba2 model.
302
303 Implements a gated feed-forward network that projects inputs to a larger
304 intermediate size, applies GELU activation with gating, then projects back
305 to the original size. Includes optional adapter layers for model adaptation.
306 """
307
308 def __init__(
309 self,
310 config: Zamba2Config,
311 bare_block_idx: int,
312 num_hybrid_layers: int,
313 quant_config: QuantizationConfig | None = None,
314 prefix: str = "",
315 ) -> None:
316 """Initialize the MLP layer.
317
318 Args:
319 config: The Zamba2 model configuration
320 bare_block_idx: Index of the bare block in the model
321 num_hybrid_layers: Total number of hybrid layers
322 quant_config: Configuration for model quantization
323 prefix: Module prefix used for quantization config lookup
324
325 """
326 super().__init__()
327 self.config = config
328 self.tp_size = get_tensor_model_parallel_world_size()
329 self.num_hybrid_layers = num_hybrid_layers
330 self.hidden_size = config.hidden_size
331 self.intermediate_size = config.intermediate_size
332
333 # Main projection layers with gating
334 self.gate_up_proj = MergedColumnParallelLinear(
335 self.hidden_size,
336 2 * [self.intermediate_size], # 2x for gate and input projections
337 bias=self.config.add_bias_linear,
338 quant_config=quant_config,
339 prefix=f"{prefix}.gate_up_proj",
340 )
341
342 self.down_proj = RowParallelLinear(
343 self.intermediate_size,
344 self.hidden_size,
345 bias=self.config.add_bias_linear,
346 quant_config=quant_config,
347 prefix=f"{prefix}.down_proj",
348 )
349
350 # Only allow GELU activations
351 if config.hidden_act != "gelu":
352 raise ValueError(
353 f"Only GELU activation is supported "
354 f"(got `hidden_act`: {config.hidden_act})"
355 )
356 self.act_fn = GeluAndMul()
357
358 # Initialize adapter layers
359 self.gate_up_proj_adapter_list = nn.ModuleList([])
360 for block_idx in range(self.num_hybrid_layers):
361 if block_idx % config.num_mem_blocks == bare_block_idx:
362 gate_up_proj_adapter = Zamba2LoRA(
363 config.hidden_size,
364 config.adapter_rank,
365 2 * [self.intermediate_size],
366 quant_config,
367 prefix=f"{prefix}.gate_up_proj_adapter_list.{block_idx}",
368 )
369 else:
370 gate_up_proj_adapter = nn.Identity()
371 self.gate_up_proj_adapter_list.append(gate_up_proj_adapter)
372
373 def forward(self, hidden_states: torch.Tensor, block_idx: int) -> torch.Tensor:
374 """Forward pass through the MLP layer.
375
376 Args:
377 hidden_states: Input tensor [batch_size, seq_len, hidden_size]
378 block_idx: Current shared transformer block index
379
380 Returns:
381 Output tensor [batch_size, seq_len, hidden_size] after applying
382 gated feed-forward transformation
383
384 """
385 # Project input to intermediate size with gating
386 gate_up_states, _ = self.gate_up_proj(hidden_states)
387
388 # Apply adapter transformation if present
389 adapter = self.gate_up_proj_adapter_list[block_idx]
390 assert not isinstance(adapter, nn.Identity)
391 lora_output = adapter(hidden_states)
392 gate_up_states = gate_up_states + lora_output
393
394 # Apply GELU activation with gating
395 hidden_states = self.act_fn(gate_up_states)
396
397 # Project back to hidden size
398 output, _ = self.down_proj(hidden_states)
399 return output
400
401
402 class Zamba2AttentionDecoderLayer(nn.Module):
403 """Single decoder layer combining attention and feed-forward networks.
404
405 This layer implements a standard transformer block with:
406 - Input layer normalization
407 - Multi-head self-attention
408 - Pre-feed-forward layer normalization
409 - Feed-forward network (MLP)
410 """
411
412 def __init__(
413 self,
414 config: Zamba2Config,
415 bare_block_idx: int,
416 num_hybrid_layers: int,
417 cache_config: CacheConfig | None = None,
418 quant_config: QuantizationConfig | None = None,
419 prefix: str = "",
420 ) -> None:
421 """Initialize the decoder layer.
422
423 Args:
424 config: The Zamba2 model configuration
425 bare_block_idx: Index of the bare block
426 num_hybrid_layers: Total number of hybrid layers
427 cache_config: Configuration for key-value caching
428 quant_config: Configuration for model quantization
429 prefix: Optional prefix for parameter names
430
431 """
432 super().__init__()
433
434 # Initialize attention sublayer
435 self.self_attn = Zamba2Attention(
436 config,
437 bare_block_idx=bare_block_idx,
438 num_hybrid_layers=num_hybrid_layers,
439 cache_config=cache_config,
440 quant_config=quant_config,
441 prefix=prefix,
442 )
443
444 # Initialize feed-forward sublayer
445 self.feed_forward = Zamba2MLP(
446 config,
447 bare_block_idx=bare_block_idx,
448 num_hybrid_layers=num_hybrid_layers,
449 quant_config=quant_config,
450 prefix=f"{prefix}.feed_forward",
451 )
452
453 # Initialize layer normalizations
454 # Input normalization operates on concatenated states
455 self.input_layernorm = RMSNorm(2 * config.hidden_size, eps=config.rms_norm_eps)
456 # Pre-FF normalization operates on attention output
457 self.pre_ff_layernorm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
458
459 def forward(
460 self,
461 hidden_states: torch.Tensor,
462 original_hidden_states: torch.Tensor,
463 block_idx: int,
464 positions: torch.Tensor,
465 ) -> torch.Tensor:
466 """Forward pass through the decoder layer.
467
468 Args:
469 hidden_states: Input tensor from previous layer
470 original_hidden_states: Original input tensor for residual
471 connection
472 block_idx: Current shared transformer block index
473 positions: IDs for positional embeddings
474
475 Returns:
476 Transformed hidden states after attention and feed-forward
477
478 """
479 # The argument original_hidden_states is concatenated with hidden_states
480 # (which is the output of the previous (mamba) layer).
481 # The concatenated tensor is then used as input of the pre-attention
482 # RMSNorm (see fig. 2 in https://arxiv.org/pdf/2405.16712).
483 hidden_states = torch.concatenate(
484 [hidden_states, original_hidden_states], dim=-1
485 )
486
487 # Layer norm before attention
488 hidden_states = self.input_layernorm(hidden_states)
489
490 # Self attention
491 hidden_states = self.self_attn(
492 hidden_states,
493 position_ids=positions,
494 block_idx=block_idx,
495 )
496
497 # Layer norm before feed-forward
498 hidden_states = self.pre_ff_layernorm(hidden_states)
499
500 # Feed-forward network
501 hidden_states = self.feed_forward(hidden_states, block_idx=block_idx)
502
503 return hidden_states
504
505
506 class Zamba2MambaDecoderLayer(nn.Module):
507 """Single Mamba decoder layer with normalization.
508
509 This implements a Mamba block. It includes input normalization
510 and can process sequences using either chunked or full
511 computation depending on configuration.
512 """
513
514 def __init__(
515 self,
516 config: Zamba2Config,
517 model_config: ModelConfig | None = None,
518 cache_config: CacheConfig | None = None,
519 quant_config: QuantizationConfig | None = None,
520 prefix: str = "",
521 ) -> None:
522 """Initialize the Mamba decoder layer.
523
524 Args:
525 config: The Zamba2 model configuration
526 model_config: The model config, when available
527 cache_config: The KV cache config, when available
528 quant_config: Configuration for model quantization
529 prefix: Module prefix used for quantization config lookup
530
531 """
532 super().__init__()
533
534 # Initialize Mamba mixer with expanded intermediate size
535 intermediate_size = config.mamba_expand * config.hidden_size
536 self.mamba = MambaMixer2(
537 hidden_size=config.hidden_size,
538 ssm_state_size=config.mamba_d_state,
539 conv_kernel_size=config.mamba_d_conv,
540 intermediate_size=intermediate_size,
541 use_conv_bias=config.use_conv_bias,
542 use_bias=config.add_bias_linear,
543 n_groups=config.mamba_ngroups,
544 num_heads=config.n_mamba_heads,
545 head_dim=intermediate_size // config.n_mamba_heads,
546 rms_norm_eps=config.rms_norm_eps,
547 activation="silu",
548 model_config=model_config,
549 cache_config=cache_config,
550 quant_config=quant_config,
551 prefix=f"{prefix}.mixer",
552 )
553
554 # Input normalization
555 self.input_layernorm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
556
557 def forward(
558 self,
559 hidden_states: torch.Tensor,
560 transformer_hidden_states: torch.Tensor | None = None,
561 positions: torch.Tensor | None = None,
562 original_hidden_states: torch.Tensor | None = None,
563 ) -> torch.Tensor:
564 """Forward pass through the Mamba decoder layer.
565
566 Args:
567 hidden_states: Input tensor [batch_size, seq_len, hidden_size]
568 transformer_hidden_states: Optional output from transformer path
569 Added to input if provided (used in hybrid architecture)
570 positions: Optional position IDs (unused in Mamba)
571 original_hidden_states: Optional original inputs (unused in Mamba)
572
573 Returns:
574 Transformed hidden states with residual connection applied
575
576 """
577 # Store input for residual connection
578 residual = hidden_states
579
580 # `transformer_hidden_states` is the output from shared
581 # transformer + linear layer (see fig. 2 in
582 # https://arxiv.org/pdf/2405.16712).
583 # `transformer_hidden_states` is then added to the input to the mamba
584 # layer below (as described in eq. (6) of
585 # https://arxiv.org/pdf/2405.16712).
586 if transformer_hidden_states is not None:
587 hidden_states = hidden_states + transformer_hidden_states
588
589 # Apply input normalization
590 hidden_states = self.input_layernorm(hidden_states)
591
592 # Process through Mamba mixer
593 output = self.mamba(hidden_states)
594
595 # residual connection after mamba
596 hidden_states = residual + output
597
598 return hidden_states
599
600
601 class Zamba2HybridLayer(nn.Module):
602 """Hybrid layer combining Transformer and Mamba architectures.
603
604 This layer implements the hybrid architecture described in the Zamba paper,
605 where a shared transformer pathway processes input in parallel with a Mamba
606 pathway. The transformer output is projected and added to the Mamba input
607 for enhanced representation learning.
608 """
609
610 def __init__(
611 self,
612 shared_transformer: Zamba2AttentionDecoderLayer,
613 config: Zamba2Config,
614 block_idx: int,
615 model_config: ModelConfig | None = None,
616 cache_config: CacheConfig | None = None,
617 quant_config: QuantizationConfig | None = None,
618 prefix: str = "",
619 ) -> None:
620 """Initialize the hybrid layer.
621
622 Args:
623 shared_transformer: Transformer decoder layer for attention pathway
624 config: The Zamba2 model configuration
625 block_idx: Index of this hybrid block in the model
626 model_config: The model config, when available
627 cache_config: The KV cache config, when available
628 quant_config: Configuration for model quantization
629 prefix: Module prefix used for quantization config lookup
630
631 """
632 super().__init__()
633 self.block_idx = block_idx
634 self.shared_transformer = shared_transformer
635 self.linear = ReplicatedLinear(
636 config.hidden_size,
637 config.hidden_size,
638 bias=False,
639 quant_config=quant_config,
640 prefix=f"{prefix}.linear",
641 )
642 self.mamba_decoder = Zamba2MambaDecoderLayer(
643 config,
644 model_config=model_config,
645 cache_config=cache_config,
646 quant_config=quant_config,
647 prefix=prefix,
648 )
649
650 def forward(
651 self,
652 hidden_states: torch.Tensor,
653 original_hidden_states: torch.Tensor,
654 positions: torch.Tensor,
655 ) -> torch.Tensor:
656 """Forward pass through the hybrid layer.
657
658 Processes input through parallel transformer and Mamba paths:
659 1. Transformer path processes input with attention
660 2. Transformer output is projected to match hidden size
661 3. Projected output is added to Mamba path input
662 4. Final output combines both paths' representations
663
664 Args:
665 hidden_states: Input tensor [batch_size, seq_len, hidden_size]
666 original_hidden_states: Original input for transformer residual
667 connection
668 positions: Position IDs for positional embeddings
669
670 Returns:
671 Output tensor combining transformer and Mamba representations
672
673 """
674 # Process through transformer pathway
675 transformer_hidden_states = self.shared_transformer(
676 hidden_states,
677 original_hidden_states=original_hidden_states,
678 block_idx=self.block_idx,
679 positions=positions,
680 )
681
682 # Project transformer output
683 transformer_hidden_states, _ = self.linear(transformer_hidden_states)
684
685 # Process through Mamba pathway with transformer injection
686 layer_outputs = self.mamba_decoder(
687 hidden_states,
688 transformer_hidden_states=transformer_hidden_states,
689 )
690
691 return layer_outputs
692
693
694 @support_torch_compile
695 class Zamba2Model(nn.Module):
696 """Core Zamba2 model combining transformer and Mamba architectures.
697
698 The model processes input through a sequence of hybrid and Mamba-only
699 layers, using token embeddings and final layer normalization.
700 """
701
702 def __init__(self, *, vllm_config: VllmConfig, prefix: str = "") -> None:
703 """Initialize the Zamba2 model.
704
705 Args:
706 vllm_config: Configuration object containing model, cache,
707 quantization and LoRA settings
708 prefix: Optional prefix for parameter names in state dict
709
710 """
711 super().__init__()
712
713 config = vllm_config.model_config.hf_config
714 model_config = vllm_config.model_config
715 cache_config = vllm_config.cache_config
716 quant_config = vllm_config.quant_config
717 lora_config = vllm_config.lora_config
718 is_lora_enabled = bool(lora_config)
719 assert not is_lora_enabled
720
721 self.config = config
722
723 self.vocab_size = config.vocab_size
724
725 # Initialize token embeddings
726 self.embed_tokens = VocabParallelEmbedding(
727 self.vocab_size,
728 config.hidden_size,
729 )
730
731 # Map hybrid layer indices to block indices
732 layer2block_map = {
733 layer_idx: block_idx
734 for block_idx, layer_idx in enumerate(config.hybrid_layer_ids)
735 }
736
737 # Create cyclic iterator of transformer blocks
738 blocks = cycle(
739 [
740 Zamba2AttentionDecoderLayer(
741 config,
742 bare_block_idx=idx,
743 num_hybrid_layers=len(layer2block_map),
744 cache_config=cache_config,
745 quant_config=quant_config,
746 prefix=f"{prefix}",
747 )
748 for idx in range(config.num_mem_blocks)
749 ]
750 )
751
752 # Initialize layers according to block type configuration
753 layers = []
754 for layer_idx, layer_type in enumerate(config.layers_block_type):
755 # tdoublep: avoid layers getting same index
756 # somewhat hacky but correct (I think)
757 prefix = str(len(layer2block_map) + layer_idx)
758 if layer_type == "hybrid":
759 block = next(blocks)
760 block_idx = layer2block_map[layer_idx]
761 layers.append(
762 Zamba2HybridLayer(
763 block,
764 config,
765 block_idx,
766 model_config=model_config,
767 cache_config=cache_config,
768 quant_config=quant_config,
769 prefix=prefix,
770 )
771 )
772 else:
773 layers.append(
774 Zamba2MambaDecoderLayer(
775 config,
776 model_config=model_config,
777 cache_config=cache_config,
778 quant_config=quant_config,
779 prefix=prefix,
780 )
781 )
782 self.layers = nn.ModuleList(layers)
783
784 # Final layer normalization
785 self.final_layernorm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
786
787 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
788 """Convert input token IDs to embeddings.
789
790 Args:
791 input_ids: Tensor of input token IDs
792
793 Returns:
794 Embedded representation of the input tokens
795
796 """
797 return self.embed_tokens(input_ids)
798
799 def forward(
800 self,
801 input_ids: torch.Tensor | None,
802 positions: torch.Tensor,
803 inputs_embeds: torch.Tensor | None = None,
804 ) -> torch.Tensor | IntermediateTensors:
805 """Forward pass through the model.
806
807 Args:
808 input_ids: Input token IDs
809 positions: Position IDs for embeddings
810 inputs_embeds: Optional pre-computed input embeddings
811
812 Returns:
813 Either final hidden states or intermediate tensors for pipeline
814 parallelism
815
816 """
817 # Handle pipeline parallelism for first rank
818 if inputs_embeds is None:
819 inputs_embeds = self.embed_input_ids(input_ids)
820 hidden_states = inputs_embeds
821
822 # Process through layers
823 original_hidden_states = torch.clone(hidden_states)
824 for layer_idx, layer in enumerate(self.layers):
825 layer_outputs = layer(
826 hidden_states,
827 original_hidden_states=original_hidden_states,
828 positions=positions,
829 )
830 hidden_states = layer_outputs
831
832 hidden_states = self.final_layernorm(hidden_states)
833 return hidden_states
834
835
836 class Zamba2ForCausalLM(nn.Module, HasInnerState, IsHybrid, SupportsMambaPrefixCaching):
837 """Zamba2 model with causal language modeling head.
838
839 This class wraps the core Zamba2 model and adds:
840 - A language modeling head for next token prediction
841 - Mamba state caching functionality
842 - Support for model parallelism and quantization
843 - Sampling capabilities for text generation
844 """
845
846 # To ensure correct weight loading and mapping.
847 hf_to_vllm_mapper = WeightsMapper(
848 orig_to_new_substr={
849 "A_log": "A",
850 "0.weight": "A.weight",
851 "1.weight": "B.weight",
852 },
853 orig_to_new_stacked={
854 ".self_attn.q_proj": (".self_attn.qkv_proj", "q"),
855 ".self_attn.k_proj": (".self_attn.qkv_proj", "k"),
856 ".self_attn.v_proj": (".self_attn.qkv_proj", "v"),
857 },
858 )
859
860 @classmethod
861 def get_mamba_state_dtype_from_config(
862 cls,
863 vllm_config: "VllmConfig",
864 ) -> tuple[torch.dtype, torch.dtype]:
865 return MambaStateDtypeCalculator.mamba2_state_dtype(
866 vllm_config.model_config.dtype,
867 vllm_config.cache_config.mamba_cache_dtype,
868 vllm_config.cache_config.mamba_ssm_cache_dtype,
869 )
870
871 @classmethod
872 def get_mamba_state_shape_from_config(
873 cls,
874 vllm_config: "VllmConfig",
875 ) -> tuple[tuple[int, int], tuple[int, int, int]]:
876 """Calculate shapes for Mamba's convolutional and state caches.
877
878 Args:
879 vllm_config: vLLM config
880
881 Returns:
882 Tuple containing:
883 - conv_state_shape: Shape for convolutional state cache
884 - temporal_state_shape: Shape for state space model cache
885
886 """
887 parallel_config = vllm_config.parallel_config
888 hf_config = vllm_config.model_config.hf_config
889 intermediate_size = hf_config.mamba_expand * hf_config.hidden_size
890
891 return MambaStateShapeCalculator.mamba2_state_shape(
892 intermediate_size=intermediate_size,
893 tp_world_size=parallel_config.tensor_parallel_size,
894 n_groups=hf_config.mamba_ngroups,
895 num_heads=hf_config.n_mamba_heads,
896 head_dim=hf_config.mamba_headdim,
897 state_size=hf_config.mamba_d_state,
898 conv_kernel=hf_config.mamba_d_conv,
899 )
900
901 @classmethod
902 def get_mamba_state_copy_func(cls) -> tuple[MambaStateCopyFunc, MambaStateCopyFunc]:
903 return MambaStateCopyFuncCalculator.mamba2_state_copy_func()
904
905 def __init__(self, *, vllm_config: VllmConfig, prefix: str = "") -> None:
906 """Initialize the Zamba2 model for causal language modeling.
907
908 Args:
909 vllm_config: Configuration containing model, cache, quantization,
910 LoRA and scheduler settings
911 prefix: Optional prefix for parameter names
912
913 Raises:
914 AssertionError: If prefix caching is enabled
915 (not supported by Mamba)
916
917 """
918 config = vllm_config.model_config.hf_config
919
920 scheduler_config = vllm_config.scheduler_config
921
922 super().__init__()
923 self.config = config
924 self.vllm_config = vllm_config
925 self.scheduler_config = scheduler_config
926 self.model_config = vllm_config.model_config
927
928 # Initialize core model
929 self.model = Zamba2Model(
930 vllm_config=vllm_config, prefix=maybe_prefix(prefix, "model")
931 )
932
933 # Initialize language modeling head
934 self.lm_head = ParallelLMHead(
935 config.vocab_size,
936 config.hidden_size,
937 prefix=maybe_prefix(prefix, "lm_head"),
938 )
939 # Tie weights with input embeddings if using same dimensions
940 self.lm_head = self.lm_head.tie_weights(self.model.embed_tokens)
941
942 # Initialize logits processing and sampling
943 self.logits_processor = LogitsProcessor(config.vocab_size)
944
945 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
946 """Convert input token IDs to embeddings.
947
948 Args:
949 input_ids: Tensor of input token IDs
950 Returns:
951 Embedded representation of the input tokens
952
953 """
954 return self.model.embed_input_ids(input_ids)
955
956 def forward(
957 self,
958 input_ids: torch.Tensor | None,
959 positions: torch.Tensor,
960 inputs_embeds: torch.Tensor | None = None,
961 **kwargs: Any,
962 ) -> torch.Tensor:
963 """Forward pass through the model.
964
965 Args:
966 input_ids: Input token IDs
967 positions: Position IDs for embeddings
968 inputs_embeds: Optional pre-computed input embeddings
969 **kwargs: Additional arguments passed to cache manager
970
971 Returns:
972 Output hidden states
973
974 """
975 # Forward pass through model
976 hidden_states = self.model(
977 input_ids,
978 positions,
979 inputs_embeds,
980 )
981
982 return hidden_states
983
984 def compute_logits(
985 self,
986 hidden_states: torch.Tensor,
987 ) -> torch.Tensor | None:
988 """Compute logits for next token prediction.
989
990 Args:
991 hidden_states: Hidden states from model forward pass
992
993 Returns:
994 Logits for next token prediction
995
996 """
997 logits = self.logits_processor(self.lm_head, hidden_states)
998 return logits
999
1000 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
1001 loader = AutoWeightsLoader(self)
1002 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)