main
py 806 lines 28.2 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 import copy
4 from collections.abc import Callable, Iterable
5
6 import torch
7 import torch.nn as nn
8 from transformers.configuration_utils import PreTrainedConfig
9
10 from vllm.compilation.decorators import support_torch_compile
11 from vllm.config import CacheConfig, VllmConfig
12 from vllm.distributed import (
13 get_pp_group,
14 get_tensor_model_parallel_rank,
15 get_tensor_model_parallel_world_size,
16 )
17 from vllm.forward_context import get_forward_context
18 from vllm.logger import init_logger
19 from vllm.model_executor.layers.fused_moe import (
20 FusedMoEFactory,
21 GateLinear,
22 fused_moe_make_expert_params_mapping,
23 )
24 from vllm.model_executor.layers.layernorm import RMSNorm
25 from vllm.model_executor.layers.linear import (
26 ColumnParallelLinear,
27 MergedColumnParallelLinear,
28 ReplicatedLinear,
29 RowParallelLinear,
30 )
31 from vllm.model_executor.layers.logits_processor import LogitsProcessor
32 from vllm.model_executor.layers.mamba.linear.bailing_linear_attn import (
33 BailingMoELinearAttention,
34 _build_rope_parameters,
35 )
36 from vllm.model_executor.layers.mamba.mamba_utils import (
37 MambaStateCopyFuncCalculator,
38 MambaStateDtypeCalculator,
39 MambaStateShapeCalculator,
40 )
41 from vllm.model_executor.layers.mla import MLAModules, MultiHeadLatentAttentionWrapper
42 from vllm.model_executor.layers.quantization.base_config import QuantizationConfig
43 from vllm.model_executor.layers.rotary_embedding import get_rope
44 from vllm.model_executor.layers.vocab_parallel_embedding import (
45 ParallelLMHead,
46 VocabParallelEmbedding,
47 )
48 from vllm.model_executor.model_loader.weight_utils import (
49 default_weight_loader,
50 maybe_remap_kv_scale_name,
51 )
52 from vllm.model_executor.models.bailing_moe import BailingMLP
53 from vllm.sequence import IntermediateTensors
54 from vllm.v1.attention.backend import AttentionMetadata
55
56 from .interfaces import HasInnerState, IsHybrid, SupportsPP
57 from .utils import (
58 AutoWeightsLoader,
59 PPMissingLayer,
60 is_pp_missing_parameter,
61 make_layers,
62 maybe_prefix,
63 )
64
65 logger = init_logger(__name__)
66
67
68 def is_linear_layer(layer_idx, layer_group_size):
69 if layer_idx is None:
70 return False
71 if layer_group_size > 0:
72 return (layer_idx + 1) % layer_group_size != 0
73 else:
74 return False
75
76
77 class BailingMoeV25MLAAttention(nn.Module):
78 """MLA Attention for BailingMoeV2.5 full attention layers."""
79
80 def __init__(
81 self,
82 config: PreTrainedConfig,
83 quant_config: QuantizationConfig | None = None,
84 layer_id: int = 0,
85 prefix: str = "attention",
86 cache_config: CacheConfig | None = None,
87 ) -> None:
88 super().__init__()
89 self.hidden_size = config.hidden_size
90 self.num_heads = config.num_attention_heads
91 self.layer_id = layer_id
92 self.prefix = prefix
93
94 # MLA dimensions
95 self.qk_nope_head_dim = getattr(config, "qk_nope_head_dim", 128)
96 self.qk_rope_head_dim = getattr(config, "qk_rope_head_dim", 64)
97 self.qk_head_dim = self.qk_nope_head_dim + self.qk_rope_head_dim
98 self.v_head_dim = getattr(config, "v_head_dim", 128)
99
100 # LoRA ranks
101 self.q_lora_rank = getattr(config, "q_lora_rank", None)
102 self.kv_lora_rank = getattr(config, "kv_lora_rank", 512)
103
104 tp_size = get_tensor_model_parallel_world_size()
105 assert self.num_heads % tp_size == 0
106 self.num_local_heads = self.num_heads // tp_size
107
108 self.scaling = self.qk_head_dim**-0.5
109
110 # KV projections
111 self.kv_a_layernorm = RMSNorm(
112 self.kv_lora_rank,
113 eps=config.rms_norm_eps,
114 )
115 self.kv_b_proj = ColumnParallelLinear(
116 self.kv_lora_rank,
117 self.num_heads * (self.qk_nope_head_dim + self.v_head_dim),
118 bias=False,
119 quant_config=quant_config,
120 prefix=f"{prefix}.kv_b_proj",
121 )
122
123 # Output projection
124 self.o_proj = RowParallelLinear(
125 self.num_heads * self.v_head_dim,
126 self.hidden_size,
127 bias=False,
128 quant_config=quant_config,
129 prefix=f"{prefix}.o_proj",
130 )
131
132 if self.q_lora_rank is not None:
133 # Use fused_qkv_a_proj when q_lora_rank is set
134 self.fused_qkv_a_proj: MergedColumnParallelLinear | None = (
135 MergedColumnParallelLinear(
136 self.hidden_size,
137 [self.q_lora_rank, self.kv_lora_rank + self.qk_rope_head_dim],
138 bias=False,
139 quant_config=quant_config,
140 prefix=f"{prefix}.fused_qkv_a_proj",
141 disable_tp=True,
142 )
143 )
144 self.q_a_layernorm: RMSNorm | None = RMSNorm(
145 self.q_lora_rank,
146 eps=config.rms_norm_eps,
147 )
148 self.q_b_proj: ColumnParallelLinear | None = ColumnParallelLinear(
149 self.q_lora_rank,
150 self.num_heads * self.qk_head_dim,
151 bias=False,
152 quant_config=quant_config,
153 prefix=f"{prefix}.q_b_proj",
154 )
155 self.q_proj = None
156 self.kv_a_proj_with_mqa = None
157 else:
158 # Direct projections when no q_lora_rank
159 self.q_proj = ColumnParallelLinear(
160 self.hidden_size,
161 self.num_heads * self.qk_head_dim,
162 bias=False,
163 quant_config=quant_config,
164 prefix=f"{prefix}.q_proj",
165 )
166 self.kv_a_proj_with_mqa = ReplicatedLinear(
167 self.hidden_size,
168 self.kv_lora_rank + self.qk_rope_head_dim,
169 bias=False,
170 quant_config=quant_config,
171 prefix=f"{prefix}.kv_a_proj_with_mqa",
172 )
173 self.fused_qkv_a_proj = None
174 self.q_a_layernorm = None
175 self.q_b_proj = None
176
177 rope_parameters = _build_rope_parameters(config) or {}
178 # MLA rotates the full qk_rope_head_dim,
179 # partial_rotary_factor is for the linear-attn head only.
180 rope_parameters = {
181 k: v for k, v in rope_parameters.items() if k != "partial_rotary_factor"
182 }
183 rope_parameters["rope_dim"] = self.qk_rope_head_dim
184 max_position = getattr(config, "max_position_embeddings", 8192)
185 self.rotary_emb = get_rope(
186 head_size=self.qk_rope_head_dim,
187 max_position=max_position,
188 is_neox_style=False,
189 rope_parameters=rope_parameters,
190 )
191
192 # Build MLAModules for MultiHeadLatentAttentionWrapper
193 mla_modules = MLAModules(
194 kv_a_layernorm=self.kv_a_layernorm,
195 kv_b_proj=self.kv_b_proj,
196 rotary_emb=self.rotary_emb,
197 o_proj=self.o_proj,
198 fused_qkv_a_proj=self.fused_qkv_a_proj,
199 kv_a_proj_with_mqa=self.kv_a_proj_with_mqa,
200 q_a_layernorm=self.q_a_layernorm,
201 q_b_proj=self.q_b_proj,
202 q_proj=self.q_proj,
203 indexer=None,
204 is_sparse=False,
205 topk_indices_buffer=None,
206 )
207
208 self.mla_attn = MultiHeadLatentAttentionWrapper(
209 self.hidden_size,
210 self.num_local_heads,
211 self.scaling,
212 self.qk_nope_head_dim,
213 self.qk_rope_head_dim,
214 self.v_head_dim,
215 self.q_lora_rank,
216 self.kv_lora_rank,
217 mla_modules,
218 cache_config,
219 quant_config,
220 prefix,
221 )
222
223 def forward(
224 self,
225 hidden_states: torch.Tensor,
226 positions: torch.Tensor,
227 ) -> torch.Tensor:
228 """Forward pass for MLA attention."""
229 return self.mla_attn(positions, hidden_states)
230
231
232 class BailingMoeV25(nn.Module):
233 """Bailing MoE v2.5 - standalone implementation for linear attention model."""
234
235 def __init__(
236 self,
237 config: PreTrainedConfig,
238 quant_config: QuantizationConfig | None = None,
239 layer_id: int = 0,
240 prefix: str = "",
241 ):
242 super().__init__()
243
244 self.layer_id = layer_id
245 self.tp_size = get_tensor_model_parallel_world_size()
246 self.tp_rank = get_tensor_model_parallel_rank()
247 self.num_experts = config.num_experts
248 self.top_k = config.num_experts_per_tok
249 norm_topk_prob = getattr(config, "norm_topk_prob", None)
250 # Ring-2.5 reference implementations normalize routing weights by default.
251 self.norm_expert_prob = True if norm_topk_prob is None else bool(norm_topk_prob)
252 self.hidden_size = config.hidden_size
253 self.quant_config = quant_config
254 self.num_shared_experts = config.num_shared_experts
255 self.score_function: str | None = getattr(config, "score_function", None)
256 self.n_group = getattr(config, "n_group", None)
257 self.topk_group = getattr(config, "topk_group", None)
258 self.use_grouped_topk = self.n_group is not None and self.topk_group is not None
259 self.routed_scaling_factor = getattr(config, "routed_scaling_factor", 1.0)
260
261 router_dtype = getattr(config, "router_dtype", None)
262 if router_dtype is None or router_dtype == "fp32":
263 self.router_dtype = torch.float32
264 else:
265 self.router_dtype = torch.bfloat16
266
267 # Gate for routing
268 self.gate = GateLinear(
269 self.hidden_size,
270 self.num_experts,
271 out_dtype=self.router_dtype,
272 params_dtype=self.router_dtype,
273 prefix=f"{prefix}.gate",
274 )
275 if getattr(config, "moe_router_enable_expert_bias", False):
276 self.gate.expert_bias = nn.Parameter(
277 torch.empty((self.num_experts,), dtype=torch.float32),
278 )
279 else:
280 self.gate.expert_bias = None
281 correction_bias = (
282 self.gate.expert_bias if self.gate.expert_bias is not None else None
283 )
284 if self.score_function is not None:
285 assert (self.score_function == "softmax" and correction_bias is None) or (
286 self.score_function == "sigmoid" and correction_bias is not None
287 ), (
288 "score_function and correction_bias should be "
289 "(softmax, None) or (sigmoid, not None)"
290 )
291 else:
292 self.score_function = "softmax"
293
294 # Shared experts (using BailingMLP)
295 if self.num_shared_experts > 0:
296 if hasattr(config, "moe_shared_expert_intermediate_size"):
297 intermediate_size = config.moe_shared_expert_intermediate_size
298 else:
299 intermediate_size = config.moe_intermediate_size
300 intermediate_size *= config.num_shared_experts
301 self.shared_experts: BailingMLP | None = BailingMLP(
302 intermediate_size=intermediate_size,
303 config=config,
304 quant_config=quant_config,
305 reduce_results=False,
306 prefix=f"{prefix}.shared_experts",
307 )
308 else:
309 self.shared_experts = None
310
311 # Routed experts using FusedMoEFactory
312 self.experts = FusedMoEFactory(
313 shared_experts=self.shared_experts,
314 num_experts=self.num_experts,
315 top_k=self.top_k,
316 hidden_size=self.hidden_size,
317 intermediate_size=config.moe_intermediate_size,
318 renormalize=self.norm_expert_prob,
319 quant_config=quant_config,
320 prefix=f"{prefix}.experts",
321 scoring_func=self.score_function,
322 e_score_correction_bias=correction_bias,
323 num_expert_group=self.n_group,
324 topk_group=self.topk_group,
325 use_grouped_topk=self.use_grouped_topk,
326 router_logits_dtype=self.router_dtype,
327 routed_scaling_factor=self.routed_scaling_factor,
328 apply_routed_scale_to_output=True,
329 )
330
331 def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
332 num_tokens, hidden_size = hidden_states.shape
333 # Ensure contiguous token-major layout before router/projections.
334 hidden_states = hidden_states.contiguous().view(-1, hidden_size)
335
336 # router_logits: (num_tokens, n_experts)
337 router_logits, _ = self.gate(hidden_states)
338 router_logits = router_logits.to(hidden_states.dtype)
339
340 final_hidden_states = self.experts(
341 hidden_states=hidden_states, router_logits=router_logits
342 )
343
344 return final_hidden_states.view(num_tokens, hidden_size)
345
346
347 class BailingMoeV25DecoderLayer(nn.Module):
348 """Decoder layer supporting both linear and full attention."""
349
350 def __init__(
351 self,
352 config: PreTrainedConfig,
353 vllm_config: VllmConfig,
354 prefix: str = "layer",
355 layer_id: int = 0,
356 ) -> None:
357 super().__init__()
358 self.layer_id = layer_id
359 self.hidden_size = config.hidden_size
360
361 # Determine attention type (0 = linear, 1 = full)
362 self.attention_type = getattr(config, "attention_type", 1)
363
364 if self.attention_type == 0: # Linear attention
365 self.self_attn = BailingMoELinearAttention(
366 config,
367 vllm_config,
368 prefix=f"{prefix}.self_attn",
369 )
370 else: # Full attention
371 self.self_attn = BailingMoeV25MLAAttention(
372 config,
373 quant_config=vllm_config.quant_config,
374 layer_id=layer_id,
375 prefix=f"{prefix}.self_attn",
376 cache_config=vllm_config.cache_config,
377 )
378
379 # MLP/MoE
380 is_moe_layer = config.num_experts > 1 and layer_id >= getattr(
381 config, "first_k_dense_replace", 0
382 )
383
384 if is_moe_layer:
385 self.mlp = BailingMoeV25(
386 config,
387 quant_config=vllm_config.quant_config,
388 layer_id=layer_id,
389 prefix=f"{prefix}.mlp",
390 )
391 else:
392 self.mlp = BailingMLP(
393 intermediate_size=config.intermediate_size,
394 config=config,
395 quant_config=vllm_config.quant_config,
396 reduce_results=True,
397 prefix=f"{prefix}.mlp",
398 )
399
400 # Layer norms
401 rms_norm_eps = float(getattr(config, "rms_norm_eps", 1e-5))
402 self.input_layernorm = RMSNorm(self.hidden_size, eps=rms_norm_eps)
403 self.post_attention_layernorm = RMSNorm(self.hidden_size, eps=rms_norm_eps)
404
405 def forward(
406 self,
407 hidden_states: torch.Tensor,
408 positions: torch.Tensor,
409 attn_metadata: AttentionMetadata | None = None,
410 residual: torch.Tensor | None = None,
411 ) -> tuple[torch.Tensor, torch.Tensor | None]:
412 # Input layernorm
413 if residual is None:
414 residual = hidden_states
415 hidden_states = self.input_layernorm(hidden_states)
416 else:
417 hidden_states, residual = self.input_layernorm(hidden_states, residual)
418
419 # Self attention
420 if self.attention_type == 0:
421 # Linear attention uses output tensor
422 self_attention_output = torch.zeros_like(hidden_states)
423 self.self_attn(
424 hidden_states=hidden_states,
425 output=self_attention_output,
426 positions=positions,
427 )
428 else:
429 # Full attention
430 self_attention_output = self.self_attn(hidden_states, positions)
431
432 hidden_states, residual = self.post_attention_layernorm(
433 self_attention_output, residual
434 )
435 hidden_states = self.mlp(hidden_states)
436 return hidden_states, residual
437
438
439 @support_torch_compile(
440 dynamic_arg_dims={
441 "input_ids": 0,
442 "positions": -1,
443 "intermediate_tensors": 0,
444 "inputs_embeds": 0,
445 }
446 )
447 class BailingMoeV25Model(nn.Module):
448 """Bailing MoE v2.5 Model with hybrid attention support."""
449
450 def __init__(
451 self,
452 *,
453 vllm_config: VllmConfig,
454 prefix: str = "",
455 ):
456 super().__init__()
457 config = vllm_config.model_config.hf_config
458 self.config = config
459 self.vocab_size = config.vocab_size
460 self.embed_dim = config.hidden_size
461
462 # Determine layer types based on layer_group_size
463 self.layer_group_size = getattr(config, "layer_group_size", 1)
464 self.num_layers = config.num_hidden_layers
465
466 # decoder_attention_types: 0 = linear, 1 = full
467 self.decoder_attention_types = [
468 0 if is_linear_layer(i, self.layer_group_size) else 1
469 for i in range(self.num_layers)
470 ]
471
472 # Embeddings
473 if get_pp_group().is_first_rank:
474 self.word_embeddings = VocabParallelEmbedding(
475 self.vocab_size,
476 self.embed_dim,
477 org_num_embeddings=self.vocab_size,
478 )
479 else:
480 from vllm.model_executor.models.utils import PPMissingLayer
481
482 self.word_embeddings = PPMissingLayer()
483
484 # Layers
485 def layer_fn(prefix):
486 layer_idx = int(prefix.split(".")[-1])
487 layer_config = copy.deepcopy(config)
488 layer_config.attention_type = self.decoder_attention_types[layer_idx]
489
490 return BailingMoeV25DecoderLayer(
491 config=layer_config,
492 vllm_config=vllm_config,
493 prefix=prefix,
494 layer_id=layer_idx,
495 )
496
497 self.start_layer, self.end_layer, self.layers = make_layers(
498 self.num_layers, layer_fn, prefix=f"{prefix}.layers"
499 )
500
501 # Final norm
502 norm_kwargs = {}
503 if hasattr(config, "rms_norm_eps"):
504 norm_kwargs["eps"] = config.rms_norm_eps
505 if get_pp_group().is_last_rank:
506 self.norm = RMSNorm(config.hidden_size, **norm_kwargs)
507 else:
508 from vllm.model_executor.models.utils import PPMissingLayer
509
510 self.norm = PPMissingLayer()
511
512 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
513 return self.word_embeddings(input_ids)
514
515 @property
516 def embed_tokens(self) -> nn.Module:
517 return self.word_embeddings
518
519 def forward(
520 self,
521 input_ids: torch.Tensor | None,
522 positions: torch.Tensor,
523 intermediate_tensors: IntermediateTensors | None = None,
524 inputs_embeds: torch.Tensor | None = None,
525 ) -> torch.Tensor:
526 forward_context = get_forward_context()
527 attn_metadata = forward_context.attn_metadata
528
529 if get_pp_group().is_first_rank:
530 if inputs_embeds is None:
531 hidden_states = self.word_embeddings(input_ids)
532 else:
533 hidden_states = inputs_embeds
534 residual = None
535 else:
536 assert intermediate_tensors is not None
537 hidden_states = intermediate_tensors["hidden_states"]
538 residual = intermediate_tensors["residual"]
539
540 for layer in self.layers[self.start_layer : self.end_layer]:
541 hidden_states, residual = layer(
542 hidden_states=hidden_states,
543 positions=positions,
544 attn_metadata=attn_metadata,
545 residual=residual,
546 )
547
548 if not get_pp_group().is_last_rank:
549 return IntermediateTensors(
550 {"hidden_states": hidden_states, "residual": residual}
551 )
552 else:
553 if residual is not None:
554 hidden_states, _ = self.norm(hidden_states, residual)
555 else:
556 hidden_states = self.norm(hidden_states)
557 return hidden_states
558
559 def get_expert_mapping(self) -> list[tuple[str, str, int, str]]:
560 """Get expert parameter mapping for MoE layers."""
561 return fused_moe_make_expert_params_mapping(
562 self,
563 ckpt_gate_proj_name="gate_proj",
564 ckpt_down_proj_name="down_proj",
565 ckpt_up_proj_name="up_proj",
566 num_experts=self.config.num_experts,
567 num_redundant_experts=0,
568 )
569
570 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
571 """Load checkpoint weights with simplified mapping."""
572 params_dict = dict(self.named_parameters(remove_duplicate=False))
573 loaded_params: set[str] = set()
574
575 # Stacked parameter mappings (fused projections)
576 stacked_mappings = [
577 (".fused_qkv_a_proj", ".q_a_proj", 0),
578 (".fused_qkv_a_proj", ".kv_a_proj_with_mqa", 1),
579 (".gate_up_proj", ".gate_proj", 0),
580 (".gate_up_proj", ".up_proj", 1),
581 ]
582
583 # Expert parameter mappings from FusedMoEFactory
584 expert_mappings = list(self.get_expert_mapping())
585
586 def load_param(name: str, tensor: torch.Tensor, shard_id=None) -> bool:
587 """Load a single parameter."""
588 if name not in params_dict or is_pp_missing_parameter(name, self):
589 return False
590 if name.endswith(".bias") and name not in params_dict:
591 return False
592
593 param = params_dict[name]
594 weight_loader: Callable[..., None] = getattr(
595 param, "weight_loader", default_weight_loader
596 )
597
598 if shard_id is None:
599 weight_loader(param, tensor)
600 elif isinstance(shard_id, int):
601 weight_loader(param, tensor, shard_id)
602 else:
603 # Expert param: (expert_id, shard_id)
604 weight_loader(
605 param, tensor, name, expert_id=shard_id[0], shard_id=shard_id[1]
606 )
607
608 loaded_params.add(name)
609 return True
610
611 def normalize_name(name: str) -> str | None:
612 """Normalize checkpoint name to model parameter name."""
613 # Skip special weights
614 if name.startswith("model.mtp"):
615 return None
616 # Remove 'model.' prefix if present
617 # (e.g., 'model.layers.0...' -> 'layers.0...')
618 name = name.removeprefix("model.")
619 # Map attention.dense based on layer type
620 if "attention.dense" in name:
621 layer_idx = (
622 int(name.split("layers.")[1].split(".")[0])
623 if "layers." in name
624 else 0
625 )
626 attn_name = (
627 "self_attn.dense"
628 if is_linear_layer(layer_idx, self.config.layer_group_size)
629 else "self_attn.o_proj"
630 )
631 name = name.replace("attention.dense", attn_name)
632
633 # Standard mappings
634 name = name.replace("attention.", "self_attn.")
635 name = name.replace(
636 "mlp.gate.e_score_correction_bias", "mlp.gate.expert_bias"
637 )
638
639 return maybe_remap_kv_scale_name(name, params_dict)
640
641 for orig_name, weight in weights:
642 norm_name = normalize_name(orig_name)
643 if norm_name is None:
644 continue
645
646 # Try stacked mappings
647 loaded = False
648 for param_suf, weight_suf, shard_id in stacked_mappings:
649 if weight_suf not in norm_name:
650 continue
651 mapped = norm_name.replace(weight_suf, param_suf).replace(
652 "attention.", "self_attn."
653 )
654 if load_param(mapped, weight, shard_id):
655 loaded = True
656 break
657 if loaded:
658 continue
659
660 # Handle expert weights
661 if "mlp.experts" in norm_name:
662 # Expert bias
663 if (
664 "mlp.experts.e_score_correction_bias" in norm_name
665 or "mlp.experts.expert_bias" in norm_name
666 ):
667 alt = norm_name.replace(
668 "mlp.experts.e_score_correction_bias", "mlp.gate.expert_bias"
669 ).replace("mlp.experts.expert_bias", "mlp.gate.expert_bias")
670 if load_param(alt, weight) or load_param(norm_name, weight):
671 continue
672
673 # Routed experts
674 for (
675 param_name,
676 weight_name,
677 expert_id,
678 expert_shard_id,
679 ) in expert_mappings:
680 if weight_name not in norm_name:
681 continue
682 mapped = norm_name.replace(weight_name, param_name)
683 if load_param(mapped, weight, (expert_id, expert_shard_id)):
684 break
685 continue
686
687 # General parameters
688 load_param(norm_name, weight)
689
690 return loaded_params
691
692
693 class BailingMoeV25ForCausalLM(nn.Module, HasInnerState, IsHybrid, SupportsPP):
694 """Bailing MoE v2.5 For CausalLM."""
695
696 packed_modules_mapping = {
697 "gate_up_proj": ["gate_proj", "up_proj"],
698 }
699
700 def __init__(
701 self,
702 *,
703 vllm_config: VllmConfig,
704 prefix: str = "",
705 ) -> None:
706 super().__init__()
707 config = vllm_config.model_config.hf_config
708 quant_config = vllm_config.quant_config
709
710 self.config = config
711 self.quant_config = quant_config
712
713 self.model = BailingMoeV25Model(
714 vllm_config=vllm_config,
715 prefix=maybe_prefix(prefix, "model"),
716 )
717
718 if get_pp_group().is_last_rank:
719 self.lm_head = ParallelLMHead(
720 config.vocab_size,
721 config.hidden_size,
722 quant_config=quant_config,
723 prefix=maybe_prefix(prefix, "lm_head"),
724 )
725 self.logits_processor = LogitsProcessor(config.vocab_size)
726 else:
727 self.lm_head = PPMissingLayer()
728
729 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
730 return self.model.embed_input_ids(input_ids)
731
732 def forward(
733 self,
734 input_ids: torch.Tensor | None,
735 positions: torch.Tensor,
736 intermediate_tensors: IntermediateTensors | None = None,
737 inputs_embeds: torch.Tensor | None = None,
738 ) -> torch.Tensor:
739 hidden_states = self.model(
740 input_ids=input_ids,
741 positions=positions,
742 intermediate_tensors=intermediate_tensors,
743 inputs_embeds=inputs_embeds,
744 )
745 return hidden_states
746
747 def compute_logits(
748 self,
749 hidden_states: torch.Tensor,
750 ) -> torch.Tensor:
751 return self.logits_processor(self.lm_head, hidden_states)
752
753 def make_empty_intermediate_tensors(
754 self, batch_size: int, dtype: torch.dtype, device: torch.device
755 ) -> IntermediateTensors:
756 return IntermediateTensors(
757 {
758 "hidden_states": torch.zeros(
759 (batch_size, self.config.hidden_size), dtype=dtype, device=device
760 ),
761 "residual": torch.zeros(
762 (batch_size, self.config.hidden_size), dtype=dtype, device=device
763 ),
764 }
765 )
766
767 @classmethod
768 def get_mamba_state_shape_from_config(
769 cls,
770 vllm_config: VllmConfig,
771 ) -> tuple[tuple[int, int, int]]:
772 """Calculate shape for linear attention cache."""
773 config = vllm_config.model_config.hf_config
774 tp_size = vllm_config.parallel_config.tensor_parallel_size
775
776 head_dim = getattr(
777 config, "head_dim", config.hidden_size // config.num_attention_heads
778 )
779
780 # Return base state shape from linear attention (no padding)
781 return MambaStateShapeCalculator.linear_attention_state_shape(
782 num_heads=config.num_attention_heads,
783 tp_size=tp_size,
784 head_dim=head_dim,
785 )
786
787 @classmethod
788 def get_mamba_state_dtype_from_config(
789 cls,
790 vllm_config: VllmConfig,
791 ) -> tuple[torch.dtype, ...]:
792 return MambaStateDtypeCalculator.linear_attention_state_dtype(
793 vllm_config.model_config.dtype,
794 vllm_config.cache_config.mamba_cache_dtype,
795 )
796
797 @classmethod
798 def get_mamba_state_copy_func(cls) -> tuple:
799 return MambaStateCopyFuncCalculator.linear_attention_state_copy_func()
800
801 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
802 loader = AutoWeightsLoader(self)
803 return loader.load_weights(weights)
804
805 def get_expert_mapping(self) -> list[tuple[str, str, int, str]]:
806 return self.model.get_expert_mapping()