main
py 721 lines 27.3 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 # coding=utf-8
5 # Copyright 2026 The HY team.
6 # Copyright 2023 The vLLM team.
7 # Copyright 2022 EleutherAI and the HuggingFace Inc. team. All rights reserved.
8 #
9 # This code is based on EleutherAI's GPT-NeoX library and the GPT-NeoX
10 # and OPT implementations in this library. It has been modified from its
11 # original forms to accommodate minor architectural differences compared
12 # to GPT-NeoX and OPT used by the Meta AI team that trained the model.
13 #
14 # Licensed under the Apache License, Version 2.0 (the "License");
15 # you may not use this file except in compliance with the License.
16 # You may obtain a copy of the License at
17 #
18 # http://www.apache.org/licenses/LICENSE-2.0
19 #
20 # Unless required by applicable law or agreed to in writing, software
21 # distributed under the License is distributed on an "AS IS" BASIS,
22 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 # See the License for the specific language governing permissions and
24 # limitations under the License.
25 """Inference-only HY model compatible with HuggingFace weights."""
26
27 import typing
28 from collections.abc import Callable, Iterable
29 from itertools import islice
30 from typing import Any
31
32 import torch
33 from torch import nn
34 from transformers import PreTrainedConfig
35
36 from vllm.compilation.decorators import support_torch_compile
37 from vllm.config import CacheConfig, VllmConfig, get_current_vllm_config
38 from vllm.distributed import (
39 get_ep_group,
40 get_pp_group,
41 get_tensor_model_parallel_world_size,
42 )
43 from vllm.logger import init_logger
44 from vllm.model_executor.layers.activation import SiluAndMul
45 from vllm.model_executor.layers.attention import Attention
46 from vllm.model_executor.layers.fused_moe import (
47 FusedMoEFactory,
48 GateLinear,
49 fused_moe_make_expert_params_mapping,
50 )
51 from vllm.model_executor.layers.hpc import HpcRopeNorm, QkNormPolicy
52 from vllm.model_executor.layers.layernorm import RMSNorm
53 from vllm.model_executor.layers.linear import (
54 MergedColumnParallelLinear,
55 QKVParallelLinear,
56 RowParallelLinear,
57 )
58 from vllm.model_executor.layers.logits_processor import LogitsProcessor
59 from vllm.model_executor.layers.quantization import QuantizationConfig
60 from vllm.model_executor.layers.rotary_embedding import get_rope
61 from vllm.model_executor.layers.vocab_parallel_embedding import (
62 ParallelLMHead,
63 VocabParallelEmbedding,
64 )
65 from vllm.model_executor.model_loader.weight_utils import (
66 default_weight_loader,
67 maybe_remap_kv_scale_name,
68 )
69 from vllm.sequence import IntermediateTensors
70 from vllm.transformers_utils.configs.hy_v3 import HYV3Config
71
72 from .interfaces import MixtureOfExperts, SupportsLoRA, SupportsPP
73 from .utils import (
74 AutoWeightsLoader,
75 PPMissingLayer,
76 get_spec_layer_idx_from_weight_name,
77 is_pp_missing_parameter,
78 make_empty_intermediate_tensors_factory,
79 make_layers,
80 maybe_prefix,
81 )
82
83 logger = init_logger(__name__)
84
85
86 class HYV3FeedForward(nn.Module):
87 def __init__(
88 self,
89 hidden_size: int,
90 intermediate_size: int,
91 hidden_act: str,
92 quant_config: QuantizationConfig | None = None,
93 reduce_results: bool = True,
94 expert_gate: torch.nn.Linear | None = None,
95 prefix: str = "",
96 ) -> None:
97 super().__init__()
98 self.gate_up_proj = MergedColumnParallelLinear(
99 hidden_size,
100 [intermediate_size] * 2,
101 bias=False,
102 quant_config=quant_config,
103 prefix=f"{prefix}.gate_up_proj",
104 )
105 self.down_proj = RowParallelLinear(
106 intermediate_size,
107 hidden_size,
108 bias=False,
109 quant_config=quant_config,
110 reduce_results=reduce_results,
111 prefix=f"{prefix}.down_proj",
112 )
113 if hidden_act != "silu":
114 raise ValueError(
115 f"Unsupported activation: {hidden_act}. Only silu is supported for now."
116 )
117 self.act_fn = SiluAndMul()
118
119 def forward(self, x):
120 gate_up, _ = self.gate_up_proj(x)
121 out = self.act_fn(gate_up)
122 out, _ = self.down_proj(out)
123 return out
124
125
126 class HYV3MoEFused(nn.Module):
127 def __init__(
128 self,
129 config: HYV3Config,
130 quant_config: QuantizationConfig | None = None,
131 prefix: str = "",
132 enable_eplb: bool = False,
133 ):
134 super().__init__()
135 self.tp_size = get_tensor_model_parallel_world_size()
136 self.ep_group = get_ep_group().device_group
137 self.ep_size = self.ep_group.size()
138 self.n_routed_experts = config.num_experts
139 if self.tp_size > config.num_experts:
140 raise ValueError(
141 f"Tensor parallel size {self.tp_size} is greater than "
142 f"the number of experts {config.num_experts}."
143 )
144 top_k = config.num_experts_per_tok
145 intermediate_size = config.expert_hidden_dim
146 router_scaling_factor = getattr(config, "router_scaling_factor", 1.0)
147 vllm_config = get_current_vllm_config()
148 eplb_config = vllm_config.parallel_config.eplb_config
149 self.enable_eplb = enable_eplb
150
151 self.n_logical_experts = self.n_routed_experts
152 self.n_redundant_experts = eplb_config.num_redundant_experts
153 self.n_physical_experts = self.n_logical_experts + self.n_redundant_experts
154 self.n_local_physical_experts = self.n_physical_experts // self.ep_size
155 self.gate = GateLinear(
156 config.hidden_size,
157 config.num_experts,
158 bias=False,
159 out_dtype=torch.float32,
160 params_dtype=torch.float32,
161 prefix=f"{prefix}.gate",
162 )
163
164 self.shared_mlp: HYV3FeedForward | None
165 if config.num_shared_experts > 0:
166 self.shared_mlp = HYV3FeedForward(
167 hidden_size=config.hidden_size,
168 intermediate_size=config.expert_hidden_dim * config.num_shared_experts,
169 hidden_act=config.hidden_act,
170 quant_config=quant_config,
171 prefix=f"{prefix}.shared_mlp",
172 reduce_results=False,
173 )
174 else:
175 self.shared_mlp = None
176
177 self.expert_bias = nn.Parameter(
178 torch.empty(config.num_experts, dtype=torch.float32)
179 )
180 scoring_func = "sigmoid"
181 e_score_correction_bias = self.expert_bias
182
183 self.experts = FusedMoEFactory(
184 num_experts=self.n_routed_experts,
185 top_k=top_k,
186 hidden_size=config.hidden_size,
187 intermediate_size=intermediate_size,
188 renormalize=config.route_norm,
189 quant_config=quant_config,
190 prefix=f"{prefix}.experts",
191 enable_eplb=self.enable_eplb,
192 num_redundant_experts=self.n_redundant_experts,
193 scoring_func=scoring_func,
194 use_grouped_topk=True,
195 num_expert_group=1,
196 topk_group=1,
197 routed_scaling_factor=router_scaling_factor,
198 e_score_correction_bias=e_score_correction_bias,
199 n_shared_experts=config.num_shared_experts,
200 shared_experts=self.shared_mlp,
201 )
202
203 def forward(
204 self,
205 hidden_states: torch.Tensor,
206 ) -> torch.Tensor:
207 orig_shape = hidden_states.shape
208 hidden_dim = hidden_states.shape[-1]
209 hidden_states = hidden_states.view(-1, hidden_dim)
210
211 # router_logits: (num_tokens, n_experts)
212 router_logits, _ = self.gate(hidden_states)
213
214 final_hidden_states = self.experts(
215 hidden_states=hidden_states, router_logits=router_logits
216 )
217 return final_hidden_states.view(orig_shape)
218
219
220 class HYV3Attention(nn.Module):
221 def __init__(
222 self,
223 config: PreTrainedConfig,
224 hidden_size: int,
225 num_heads: int,
226 num_kv_heads: int,
227 rope_parameters: dict[str, Any],
228 max_position_embeddings: int = 8192,
229 head_dim: int | None = None,
230 rms_norm_eps: float = 1e-5,
231 cache_config: CacheConfig | None = None,
232 quant_config: QuantizationConfig | None = None,
233 prefix: str = "",
234 dual_chunk_attention_config: dict[str, Any] | None = None,
235 ) -> None:
236 super().__init__()
237 self.dtype = torch.get_default_dtype()
238 self.hidden_size = hidden_size
239 tp_size = get_tensor_model_parallel_world_size()
240 self.total_num_heads = num_heads
241 assert self.total_num_heads % tp_size == 0
242 self.num_heads = self.total_num_heads // tp_size
243 self.total_num_kv_heads = num_kv_heads
244 if self.total_num_kv_heads >= tp_size:
245 # Number of KV heads is greater than TP size, so we partition
246 # the KV heads across multiple tensor parallel GPUs.
247 assert self.total_num_kv_heads % tp_size == 0
248 else:
249 # Number of KV heads is less than TP size, so we replicate
250 # the KV heads across multiple tensor parallel GPUs.
251 assert tp_size % self.total_num_kv_heads == 0
252 self.num_kv_heads = max(1, self.total_num_kv_heads // tp_size)
253
254 if hasattr(config, "head_dim") and config.head_dim:
255 self.head_dim = config.head_dim
256 else:
257 self.head_dim = head_dim or (hidden_size // self.total_num_heads)
258 self.q_size = self.num_heads * self.head_dim
259 self.kv_size = self.num_kv_heads * self.head_dim
260 self.scaling = self.head_dim**-0.5
261 self.use_qk_norm = getattr(config, "qk_norm", False)
262 self.max_position_embeddings = max_position_embeddings
263
264 self.qkv_proj = QKVParallelLinear(
265 hidden_size,
266 self.head_dim,
267 self.total_num_heads,
268 self.total_num_kv_heads,
269 quant_config=quant_config,
270 bias=False,
271 prefix=f"{prefix}.qkv_proj",
272 )
273 self.o_proj = RowParallelLinear(
274 self.total_num_heads * self.head_dim,
275 hidden_size,
276 bias=False,
277 quant_config=quant_config,
278 prefix=f"{prefix}.o_proj",
279 )
280 # When the HPC fused RoPE+QK-Norm path is enabled, the RoPE cos/sin
281 # cache must be float32 to match the HPC kernel's expectations.
282 kv_cache_dtype = cache_config.cache_dtype if cache_config else "auto"
283 rope_support = HpcRopeNorm.support(
284 self.num_heads, self.num_kv_heads, self.head_dim, kv_cache_dtype
285 )
286 self.rotary_emb = get_rope(
287 self.head_dim,
288 max_position=max_position_embeddings,
289 rope_parameters=rope_parameters,
290 is_neox_style=True,
291 dtype=torch.float32 if rope_support else torch.get_default_dtype(),
292 )
293 self.attn = Attention(
294 self.num_heads,
295 self.head_dim,
296 self.scaling,
297 num_kv_heads=self.num_kv_heads,
298 cache_config=cache_config,
299 quant_config=quant_config,
300 prefix=f"{prefix}.attn",
301 )
302 if self.use_qk_norm:
303 # The HPC fused kernel reads norm weights directly in float32;
304 # the fallback path keeps the model default dtype.
305 norm_dtype = torch.float32 if rope_support else None
306 self.q_norm = RMSNorm(self.head_dim, rms_norm_eps, dtype=norm_dtype)
307 self.k_norm = RMSNorm(self.head_dim, rms_norm_eps, dtype=norm_dtype)
308
309 # HPC fused RoPE + QK-Norm + KV-Cache-Write (+ optional FP8 Q quant).
310 # HunYuan V3 applies QK-Norm *before* RoPE, so NORM_THEN_ROPE.
311 self.hpc_rope_norm: HpcRopeNorm | None = None
312 if rope_support:
313 self.hpc_rope_norm = HpcRopeNorm(
314 num_heads=self.num_heads,
315 num_kv_heads=self.num_kv_heads,
316 head_dim=self.head_dim,
317 cos_sin_cache=self.rotary_emb.cos_sin_cache,
318 use_qk_norm=self.use_qk_norm,
319 fallback_qnorm=self.q_norm if self.use_qk_norm else None,
320 fallback_knorm=self.k_norm if self.use_qk_norm else None,
321 kv_cache_dtype=kv_cache_dtype,
322 layer_name=self.attn.layer_name,
323 qk_norm_policy=QkNormPolicy.NORM_THEN_ROPE,
324 )
325 # FP8 Q is produced by HpcRopeNorm, so the attention layer must not
326 # re-quantize the query.
327 if self.hpc_rope_norm.use_fp8 and hasattr(self.attn, "query_quant"):
328 self.attn.query_quant = None
329
330 def forward(
331 self,
332 positions: torch.Tensor,
333 hidden_states: torch.Tensor,
334 ) -> torch.Tensor:
335 qkv, _ = self.qkv_proj(hidden_states)
336 q, k, v = qkv.split([self.q_size, self.kv_size, self.kv_size], dim=-1)
337 output_shape = None
338 if self.hpc_rope_norm is not None:
339 # HPC handles QK-Norm + RoPE + KV-cache write (+ optional FP8 Q
340 # quant) internally and returns the processed query. K/V are
341 # written into the paged cache by the fused op.
342 q = self.hpc_rope_norm(qkv, self.attn.layer_name)
343 q = q.view(-1, self.num_heads * self.head_dim)
344 attn_output = self.attn(q, k, v, output_shape, self.dtype)
345 else:
346 if self.use_qk_norm:
347 q_by_head = q.view(
348 *q.shape[:-1], q.shape[-1] // self.head_dim, self.head_dim
349 )
350 q_by_head = self.q_norm(q_by_head)
351 q = q_by_head.view(q.shape)
352
353 k_by_head = k.view(
354 *k.shape[:-1], k.shape[-1] // self.head_dim, self.head_dim
355 )
356 k_by_head = self.k_norm(k_by_head)
357 k = k_by_head.view(k.shape)
358 q, k = self.rotary_emb(positions, q, k)
359 attn_output = self.attn(q, k, v, output_shape)
360 attn_output = attn_output.view(q.shape[0], -1)
361 output, _ = self.o_proj(attn_output)
362 return output
363
364
365 class HYV3DecoderLayer(nn.Module):
366 def __init__(
367 self,
368 config: PreTrainedConfig,
369 cache_config: CacheConfig | None = None,
370 quant_config: QuantizationConfig | None = None,
371 prefix: str = "",
372 ) -> None:
373 super().__init__()
374 self.hidden_size = config.hidden_size
375 layer_idx = int(prefix.split(".")[-1])
376 max_position_embeddings = getattr(config, "max_position_embeddings", 8192)
377 self.self_attn = HYV3Attention(
378 config=config,
379 hidden_size=self.hidden_size,
380 num_heads=config.num_attention_heads,
381 num_kv_heads=config.num_key_value_heads,
382 rope_parameters=config.rope_parameters,
383 max_position_embeddings=max_position_embeddings,
384 head_dim=config.head_dim,
385 rms_norm_eps=config.rms_norm_eps,
386 cache_config=cache_config,
387 quant_config=quant_config,
388 prefix=f"{prefix}.self_attn",
389 )
390 self.input_layernorm = RMSNorm(config.hidden_size, config.rms_norm_eps)
391 self.post_attention_layernorm = RMSNorm(config.hidden_size, config.rms_norm_eps)
392 if not hasattr(config, "first_k_dense_replace"):
393 raise ValueError("first_k_dense_replace not exist,please check config")
394 if layer_idx < config.first_k_dense_replace:
395 self.mlp = HYV3FeedForward(
396 hidden_size=config.hidden_size,
397 intermediate_size=config.intermediate_size,
398 hidden_act=config.hidden_act,
399 quant_config=quant_config,
400 prefix=f"{prefix}.mlp",
401 )
402 self.block_type = "feedforward"
403 else:
404 self.mlp = HYV3MoEFused(
405 config=config, quant_config=quant_config, prefix=f"{prefix}.mlp"
406 )
407 self.block_type = "moe"
408
409 def forward(
410 self,
411 positions: torch.Tensor,
412 hidden_states: torch.Tensor,
413 residual: torch.Tensor | None,
414 idx: int = -1,
415 ) -> torch.Tensor:
416 if residual is None:
417 residual = hidden_states
418 hidden_states = self.input_layernorm(hidden_states)
419 else:
420 hidden_states, residual = self.input_layernorm(hidden_states, residual)
421
422 hidden_states = self.self_attn(
423 positions=positions,
424 hidden_states=hidden_states,
425 )
426
427 hidden_states, residual = self.post_attention_layernorm(hidden_states, residual)
428
429 hidden_states = self.mlp(hidden_states)
430
431 return hidden_states, residual
432
433
434 @support_torch_compile
435 class HYV3Model(nn.Module, MixtureOfExperts):
436 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
437 super().__init__()
438
439 config = vllm_config.model_config.hf_config
440 cache_config = vllm_config.cache_config
441 quant_config = vllm_config.quant_config
442
443 parallel_config = vllm_config.parallel_config
444 eplb_config = parallel_config.eplb_config
445 self.num_redundant_experts = eplb_config.num_redundant_experts
446
447 self.vocab_size = config.vocab_size
448 self.config = config
449 self.quant_config = quant_config
450
451 self.embed_tokens = VocabParallelEmbedding(
452 config.vocab_size,
453 config.hidden_size,
454 )
455
456 self.start_layer, self.end_layer, self.layers = make_layers(
457 config.num_hidden_layers,
458 lambda prefix: HYV3DecoderLayer(
459 config=config,
460 cache_config=cache_config,
461 quant_config=quant_config,
462 prefix=prefix,
463 ),
464 prefix=f"{prefix}.layers",
465 )
466 self.norm = RMSNorm(config.hidden_size, config.rms_norm_eps)
467 self.make_empty_intermediate_tensors = make_empty_intermediate_tensors_factory(
468 ["hidden_states", "residual"], config.hidden_size
469 )
470
471 # Set MoE hyperparameters
472 self.num_expert_groups = 1
473 self.moe_layers = []
474 example_layer: HYV3MoEFused | None = None
475 for layer in self.layers:
476 if isinstance(layer, PPMissingLayer):
477 continue
478
479 assert isinstance(layer, HYV3DecoderLayer)
480 if layer.block_type == "moe":
481 assert isinstance(layer.mlp, HYV3MoEFused)
482 example_layer = layer.mlp
483 self.moe_layers.append(example_layer.experts)
484
485 if example_layer is None:
486 self.num_moe_layers = 0
487 raise RuntimeError("No MoE layer found in model.layers.")
488
489 self.num_moe_layers = len(self.moe_layers)
490 self.num_logical_experts = example_layer.n_logical_experts
491 self.num_physical_experts = example_layer.n_physical_experts
492 self.num_local_physical_experts = example_layer.n_local_physical_experts
493 self.num_routed_experts = example_layer.n_routed_experts
494 self.num_redundant_experts = example_layer.n_redundant_experts
495
496 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
497 return self.embed_tokens(input_ids)
498
499 def update_physical_experts_metadata(
500 self,
501 num_physical_experts: int,
502 num_local_physical_experts: int,
503 ) -> None:
504 assert self.num_local_physical_experts == num_local_physical_experts
505 self.num_physical_experts = num_physical_experts
506 self.num_local_physical_experts = num_local_physical_experts
507 self.num_redundant_experts = num_physical_experts - self.num_logical_experts
508 for layer in self.layers:
509 if isinstance(layer.mlp, HYV3MoEFused):
510 moe = layer.mlp
511 moe.n_local_physical_experts = num_local_physical_experts
512 moe.n_physical_experts = num_physical_experts
513 moe.n_redundant_experts = self.num_redundant_experts
514 moe.experts.update_expert_map()
515
516 def get_expert_mapping(self) -> list[tuple[str, str, int, str]]:
517 # Params for weights, fp8 weight scales, fp8 activation scales
518 # (param_name, weight_name, expert_id, shard_id)
519 return fused_moe_make_expert_params_mapping(
520 self,
521 ckpt_gate_proj_name="gate_proj",
522 ckpt_down_proj_name="down_proj",
523 ckpt_up_proj_name="up_proj",
524 num_experts=self.config.num_experts,
525 )
526
527 def forward(
528 self,
529 input_ids: torch.Tensor,
530 positions: torch.Tensor,
531 intermediate_tensors: IntermediateTensors | None = None,
532 inputs_embeds: torch.Tensor | None = None,
533 ) -> torch.Tensor | IntermediateTensors:
534 if get_pp_group().is_first_rank:
535 if inputs_embeds is not None:
536 hidden_states = inputs_embeds
537 else:
538 hidden_states = self.embed_input_ids(input_ids)
539 residual = None
540 else:
541 assert intermediate_tensors is not None
542 hidden_states = intermediate_tensors["hidden_states"]
543 residual = intermediate_tensors["residual"]
544
545 for idx, layer in enumerate(
546 islice(self.layers, self.start_layer, self.end_layer)
547 ):
548 hidden_states, residual = layer(positions, hidden_states, residual, idx=idx)
549 if not get_pp_group().is_last_rank:
550 return IntermediateTensors(
551 {"hidden_states": hidden_states, "residual": residual}
552 )
553
554 hidden_states = hidden_states + residual
555 residual = hidden_states
556
557 hidden_states = self.norm(hidden_states)
558
559 return hidden_states
560
561 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
562 stacked_params_mapping = [
563 # (param_name, shard_name, shard_id)
564 (".qkv_proj", ".q_proj", "q"),
565 (".qkv_proj", ".k_proj", "k"),
566 (".qkv_proj", ".v_proj", "v"),
567 (".gate_up_proj", ".gate_proj", 0),
568 (".gate_up_proj", ".up_proj", 1),
569 ]
570 params_dict = dict(self.named_parameters())
571 expert_params_mapping = self.get_expert_mapping()
572 loaded_params: set[str] = set()
573 for name, loaded_weight in weights:
574 if self.config.tie_word_embeddings and "lm_head.weight" in name:
575 continue
576 if "scale" in name:
577 # Remapping the name of FP8 kv-scale.
578 remapped_name = maybe_remap_kv_scale_name(name, params_dict)
579 if remapped_name is None:
580 continue
581 name = remapped_name
582 is_found = False
583 for param_name, weight_name, shard_id in stacked_params_mapping:
584 if weight_name not in name:
585 continue
586 if "mlp.experts" in name:
587 continue
588 name = name.replace(weight_name, param_name)
589 # Skip loading extra bias for GPTQ models.
590 if name.endswith(".bias") and name not in params_dict:
591 continue
592
593 # Skip layers on other devices.
594 if is_pp_missing_parameter(name, self):
595 continue
596
597 param = params_dict[name]
598 weight_loader = param.weight_loader
599 weight_loader(param, loaded_weight, shard_id)
600 loaded_params.add(name)
601 is_found = True
602 break
603 if is_found:
604 continue
605
606 if name.endswith(".bias") and name not in params_dict:
607 continue
608 is_expert_weight = False
609 for mapping in expert_params_mapping:
610 param_name, weight_name, expert_id, shard_id = mapping
611 if weight_name not in name:
612 continue
613 is_expert_weight = True
614 name_mapped = name.replace(weight_name, param_name)
615 # Skip layers on other devices.
616 if is_pp_missing_parameter(name_mapped, self):
617 continue
618
619 param = params_dict[name_mapped]
620 weight_loader = typing.cast(Callable[..., bool], param.weight_loader)
621 success = weight_loader(
622 param,
623 loaded_weight,
624 name_mapped,
625 shard_id=shard_id,
626 expert_id=expert_id,
627 return_success=True,
628 )
629 if success:
630 name = name_mapped
631 break
632 else:
633 if is_expert_weight:
634 # We've checked that this is an expert weight
635 # However it's not mapped locally to this rank
636 # So we simply skip it
637 continue
638 if name is None:
639 continue
640 if is_pp_missing_parameter(name, self):
641 continue
642 if "router.gate." in name:
643 name = name.replace("router.", "")
644
645 param = params_dict[name]
646 weight_loader = getattr(param, "weight_loader", default_weight_loader)
647 weight_loader(param, loaded_weight)
648 loaded_params.add(name)
649
650 return loaded_params
651
652
653 class HYV3ForCausalLM(nn.Module, SupportsPP, SupportsLoRA):
654 packed_modules_mapping = {
655 "qkv_proj": ["q_proj", "k_proj", "v_proj"],
656 "gate_up_proj": ["gate_proj", "up_proj"],
657 }
658
659 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
660 super().__init__()
661 config = vllm_config.model_config.hf_config
662 quant_config = vllm_config.quant_config
663 self.config = config
664 self.quant_config = quant_config
665
666 parallel_config = vllm_config.parallel_config
667 eplb_config = parallel_config.eplb_config
668 self.num_redundant_experts = eplb_config.num_redundant_experts
669
670 self.model = HYV3Model(
671 vllm_config=vllm_config, prefix=maybe_prefix(prefix, "model")
672 )
673 self.lm_head = ParallelLMHead(
674 config.vocab_size,
675 config.hidden_size,
676 quant_config=quant_config,
677 prefix=maybe_prefix(prefix, "lm_head"),
678 )
679 if self.config.tie_word_embeddings:
680 self.lm_head = self.lm_head.tie_weights(self.model.embed_tokens)
681 self.logits_processor = LogitsProcessor(config.vocab_size)
682 self.make_empty_intermediate_tensors = (
683 self.model.make_empty_intermediate_tensors
684 )
685
686 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
687 return self.model.embed_input_ids(input_ids)
688
689 def forward(
690 self,
691 input_ids: torch.Tensor,
692 positions: torch.Tensor,
693 intermediate_tensors: IntermediateTensors | None = None,
694 inputs_embeds: torch.Tensor | None = None,
695 ) -> torch.Tensor | IntermediateTensors:
696 hidden_states = self.model(
697 input_ids, positions, intermediate_tensors, inputs_embeds
698 )
699
700 return hidden_states
701
702 def compute_logits(
703 self,
704 hidden_states: torch.Tensor,
705 ) -> torch.Tensor | None:
706 logits = self.logits_processor(self.lm_head, hidden_states)
707 return logits
708
709 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
710 def _filter_weights(weights):
711 for name, weight in weights:
712 spec_layer = get_spec_layer_idx_from_weight_name(self.config, name)
713 if spec_layer is not None:
714 continue
715 yield name, weight
716
717 loader = AutoWeightsLoader(self)
718 return loader.load_weights(_filter_weights(weights))
719
720 def get_expert_mapping(self) -> list[tuple[str, str, int, str]]:
721 return self.model.get_expert_mapping()