main
py 538 lines 20 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 """Inference-only Intern-S2-Mobius model."""
4
5 from collections.abc import Iterable
6 from itertools import islice
7
8 import torch
9 from torch import nn
10
11 from vllm.compilation.decorators import support_torch_compile
12 from vllm.config import VllmConfig, replace, set_current_vllm_config
13 from vllm.distributed import (
14 get_ep_group,
15 get_pp_group,
16 get_tensor_model_parallel_world_size,
17 tensor_model_parallel_all_gather,
18 tensor_model_parallel_reduce_scatter,
19 )
20 from vllm.model_executor.layers.fused_moe import (
21 FusedMoEFactory,
22 GateLinear,
23 )
24 from vllm.model_executor.layers.fusion.mm_input_norm import build_mm_input_norm
25 from vllm.model_executor.layers.linear import ReplicatedLinear
26 from vllm.model_executor.layers.logits_processor import LogitsProcessor
27 from vllm.model_executor.layers.mamba.gdn.qwen_gdn_linear_attn import (
28 QwenGatedDeltaNetAttention,
29 )
30 from vllm.model_executor.layers.vocab_parallel_embedding import (
31 ParallelLMHead,
32 VocabParallelEmbedding,
33 )
34 from vllm.multimodal import MULTIMODAL_REGISTRY
35 from vllm.sequence import IntermediateTensors
36 from vllm.tokenizers.registry import cached_tokenizer_from_config
37
38 from .interfaces import EagleModelMixin
39 from .interns2_preview import (
40 InternS2PreviewForConditionalGeneration,
41 InternS2PreviewProcessingInfo,
42 )
43 from .qwen2_moe import Qwen2MoeMLP
44 from .qwen3_5 import (
45 Qwen3_5ForCausalLMBase,
46 Qwen3_5Model,
47 Qwen3_5RMSNorm,
48 )
49 from .qwen3_5_mtp import Qwen3_5MoeMTP
50 from .qwen3_next import Qwen3NextAttention
51 from .qwen3_vl import (
52 Qwen3_VisionTransformer,
53 Qwen3VLDummyInputsBuilder,
54 Qwen3VLMultiModalProcessor,
55 )
56 from .utils import (
57 AutoWeightsLoader,
58 PPMissingLayer,
59 extract_layer_index,
60 make_empty_intermediate_tensors_factory,
61 make_layers,
62 maybe_prefix,
63 sequence_parallel_chunk,
64 )
65
66
67 class InternS2MobiusProcessingInfo(InternS2PreviewProcessingInfo):
68 pass
69
70
71 class InternS2MobiusMetaMoeBlock(nn.Module):
72 """A routed MoE bank shared by multiple decoder layers."""
73
74 def __init__(self, *, vllm_config: VllmConfig, prefix: str = "") -> None:
75 super().__init__()
76
77 config = vllm_config.model_config.hf_text_config
78 parallel_config = vllm_config.parallel_config
79
80 self.tp_size = get_tensor_model_parallel_world_size()
81 self.ep_group = get_ep_group().device_group
82 self.ep_rank = get_ep_group().rank_in_group
83 self.ep_size = self.ep_group.size()
84 self.n_routed_experts = config.num_experts
85 self.is_sequence_parallel = parallel_config.use_sequence_parallel_moe
86
87 if self.tp_size > self.n_routed_experts:
88 raise ValueError(
89 f"Tensor parallel size {self.tp_size} is greater than "
90 f"the number of experts {self.n_routed_experts}."
91 )
92
93 eplb_config = parallel_config.eplb_config
94 self.enable_eplb = parallel_config.enable_eplb
95 self.n_logical_experts = self.n_routed_experts
96 self.n_redundant_experts = eplb_config.num_redundant_experts
97 self.n_physical_experts = self.n_logical_experts + self.n_redundant_experts
98 self.n_local_physical_experts = self.n_physical_experts // self.ep_size
99
100 self.gate = GateLinear(
101 config.hidden_size,
102 config.num_experts,
103 prefix=f"{prefix}.gate",
104 )
105 self.experts = FusedMoEFactory(
106 gate=self.gate,
107 num_experts=config.num_experts,
108 top_k=config.num_experts_per_tok,
109 hidden_size=config.hidden_size,
110 intermediate_size=config.moe_intermediate_size,
111 renormalize=getattr(config, "norm_topk_prob", True),
112 quant_config=vllm_config.quant_config,
113 prefix=f"{prefix}.experts",
114 enable_eplb=self.enable_eplb,
115 num_redundant_experts=self.n_redundant_experts,
116 is_sequence_parallel=self.is_sequence_parallel,
117 activation=config.hidden_act,
118 )
119
120 def forward(
121 self,
122 hidden_states: torch.Tensor,
123 already_sequence_parallel: bool = False,
124 ) -> torch.Tensor:
125 orig_shape = hidden_states.shape
126 num_tokens, hidden_dim = hidden_states.shape
127 hidden_states = hidden_states.view(-1, hidden_dim)
128
129 if self.is_sequence_parallel and not already_sequence_parallel:
130 hidden_states = sequence_parallel_chunk(hidden_states)
131
132 final_hidden_states = self.experts(
133 hidden_states=hidden_states,
134 router_logits=hidden_states,
135 )
136
137 if self.is_sequence_parallel and not already_sequence_parallel:
138 final_hidden_states = tensor_model_parallel_all_gather(
139 final_hidden_states, 0
140 )
141 final_hidden_states = final_hidden_states[:num_tokens]
142
143 return final_hidden_states.view(orig_shape)
144
145
146 class InternS2MobiusSharedExpertBlock(nn.Module):
147 def __init__(self, *, vllm_config: VllmConfig, prefix: str = "") -> None:
148 super().__init__()
149
150 config = vllm_config.model_config.hf_text_config
151 is_sequence_parallel = vllm_config.parallel_config.use_sequence_parallel_moe
152 self.shared_expert_gate = ReplicatedLinear(
153 config.hidden_size,
154 1,
155 bias=False,
156 quant_config=None,
157 prefix=f"{prefix}.shared_expert_gate",
158 )
159 self.shared_expert = Qwen2MoeMLP(
160 hidden_size=config.hidden_size,
161 intermediate_size=config.shared_expert_intermediate_size,
162 hidden_act=config.hidden_act,
163 quant_config=vllm_config.quant_config,
164 expert_gate=self.shared_expert_gate,
165 is_sequence_parallel=is_sequence_parallel,
166 prefix=f"{prefix}.shared_expert",
167 )
168
169 def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
170 return self.shared_expert(hidden_states)
171
172
173 class InternS2MobiusDecoderLayer(nn.Module):
174 def __init__(
175 self,
176 vllm_config: VllmConfig,
177 layer_type: str,
178 prefix: str = "",
179 ) -> None:
180 super().__init__()
181
182 config = vllm_config.model_config.hf_text_config
183 model_config = vllm_config.model_config
184 parallel_config = vllm_config.parallel_config
185
186 self.layer_type = layer_type
187 self.layer_idx = extract_layer_index(prefix)
188 self.num_blocks = config.num_blocks
189 self.use_attn_reduce_scatter_for_moe = (
190 parallel_config.use_sequence_parallel_moe
191 and parallel_config.pipeline_parallel_size == 1
192 )
193
194 if self.layer_type == "linear_attention":
195 self.linear_attn = QwenGatedDeltaNetAttention(
196 config=config,
197 vllm_config=vllm_config,
198 prefix=f"{prefix}.linear_attn",
199 gqa_interleaved_layout=False,
200 reduce_results=not self.use_attn_reduce_scatter_for_moe,
201 )
202 elif self.layer_type == "full_attention":
203 self.self_attn = Qwen3NextAttention(
204 config,
205 model_config=model_config,
206 cache_config=vllm_config.cache_config,
207 quant_config=vllm_config.quant_config,
208 prefix=f"{prefix}.self_attn",
209 reduce_results=not self.use_attn_reduce_scatter_for_moe,
210 )
211 else:
212 raise ValueError(f"Invalid layer_type {self.layer_type}")
213
214 self.mlp = InternS2MobiusSharedExpertBlock(
215 vllm_config=vllm_config,
216 prefix=f"{prefix}.mlp",
217 )
218 self.input_layernorm = Qwen3_5RMSNorm(
219 config.hidden_size, eps=config.rms_norm_eps
220 )
221 self.post_attention_layernorm = Qwen3_5RMSNorm(
222 config.hidden_size, eps=config.rms_norm_eps
223 )
224
225 self.layer_scale = getattr(config, "layer_scale", False)
226 if self.layer_scale:
227 self.attn_layer_scale = nn.Parameter(torch.zeros(1, 1, config.hidden_size))
228 self.ffn_layer_scale = nn.Parameter(torch.zeros(1, 1, config.hidden_size))
229
230 def forward(
231 self,
232 hidden_states: torch.Tensor,
233 residual: torch.Tensor | None,
234 positions: torch.Tensor,
235 meta_mlp: nn.ModuleList,
236 ) -> tuple[torch.Tensor, torch.Tensor]:
237 full_num_tokens = positions.shape[-1]
238
239 if residual is None:
240 residual = hidden_states
241 hidden_states = self.input_layernorm(hidden_states)
242 else:
243 hidden_states, residual = self.input_layernorm(hidden_states, residual)
244
245 if self.use_attn_reduce_scatter_for_moe:
246 hidden_states = tensor_model_parallel_all_gather(hidden_states, 0)
247 hidden_states = hidden_states[:full_num_tokens]
248
249 if self.layer_type == "linear_attention":
250 hidden_states = self.linear_attn(hidden_states=hidden_states)
251 else:
252 hidden_states = self.self_attn(
253 hidden_states=hidden_states,
254 positions=positions,
255 )
256
257 if self.layer_scale:
258 scale = self.attn_layer_scale.to(hidden_states.dtype)
259 hidden_states = hidden_states * (scale[0] + 1)
260
261 if self.use_attn_reduce_scatter_for_moe:
262 tp_world_size = get_tensor_model_parallel_world_size()
263 sp_pad = (-hidden_states.shape[0]) % tp_world_size
264 hidden_states = torch.nn.functional.pad(hidden_states, (0, 0, 0, sp_pad))
265 hidden_states = tensor_model_parallel_reduce_scatter(hidden_states, 0)
266
267 hidden_states, residual = self.post_attention_layernorm(hidden_states, residual)
268 block_idx = self.layer_idx % self.num_blocks
269 routed_output = meta_mlp[block_idx](
270 hidden_states,
271 already_sequence_parallel=self.use_attn_reduce_scatter_for_moe,
272 )
273 hidden_states = routed_output + self.mlp(hidden_states)
274
275 if self.layer_scale:
276 scale = self.ffn_layer_scale.to(hidden_states.dtype)
277 hidden_states = hidden_states * (scale[0] + 1)
278
279 return hidden_states, residual
280
281
282 @support_torch_compile(
283 dynamic_arg_dims={
284 "input_ids": 0,
285 "positions": -1,
286 "intermediate_tensors": 0,
287 "inputs_embeds": 0,
288 }
289 )
290 class InternS2MobiusModel(nn.Module, EagleModelMixin):
291 hf_to_vllm_mapper = Qwen3_5Model.hf_to_vllm_mapper
292
293 def __init__(self, *, vllm_config: VllmConfig, prefix: str = "") -> None:
294 nn.Module.__init__(self)
295
296 config = vllm_config.model_config.hf_text_config
297 self.config = config
298 self.quant_config = vllm_config.quant_config
299 self.num_redundant_experts = (
300 vllm_config.parallel_config.eplb_config.num_redundant_experts
301 )
302 self.vocab_size = config.vocab_size
303 self.embed_tokens = VocabParallelEmbedding(
304 self.vocab_size,
305 config.hidden_size,
306 )
307 self.meta_mlp = nn.ModuleList(
308 InternS2MobiusMetaMoeBlock(
309 vllm_config=vllm_config,
310 prefix=f"{prefix}.meta_mlp.{idx}",
311 )
312 for idx in range(config.num_blocks)
313 )
314
315 def get_layer(prefix: str) -> InternS2MobiusDecoderLayer:
316 return InternS2MobiusDecoderLayer(
317 vllm_config,
318 layer_type=config.layer_types[extract_layer_index(prefix)],
319 prefix=prefix,
320 )
321
322 self.start_layer, self.end_layer, self.layers = make_layers(
323 config.num_hidden_layers,
324 get_layer,
325 prefix=f"{prefix}.layers",
326 )
327 self.make_empty_intermediate_tensors = make_empty_intermediate_tensors_factory(
328 ["hidden_states", "residual"], config.hidden_size
329 )
330
331 if get_pp_group().is_last_rank:
332 self.norm = Qwen3_5RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
333 else:
334 self.norm = PPMissingLayer()
335
336 self.aux_hidden_state_layers: tuple[int, ...] = ()
337
338 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
339 return self.embed_tokens(input_ids)
340
341 @property
342 def use_sequence_parallel(self) -> bool:
343 return self.layers[self.start_layer].use_attn_reduce_scatter_for_moe
344
345 def forward(
346 self,
347 input_ids: torch.Tensor | None,
348 positions: torch.Tensor,
349 intermediate_tensors: IntermediateTensors | None = None,
350 inputs_embeds: torch.Tensor | None = None,
351 ) -> torch.Tensor | IntermediateTensors | tuple[torch.Tensor, list[torch.Tensor]]:
352 if get_pp_group().is_first_rank:
353 hidden_states = (
354 inputs_embeds
355 if inputs_embeds is not None
356 else self.embed_input_ids(input_ids)
357 )
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 full_num_tokens = positions.shape[-1]
365 if self.use_sequence_parallel:
366 hidden_states = sequence_parallel_chunk(hidden_states)
367 assert residual is None
368
369 aux_hidden_states = self._maybe_add_hidden_state([], 0, hidden_states, residual)
370 for layer_idx, layer in enumerate(
371 islice(self.layers, self.start_layer, self.end_layer),
372 start=self.start_layer,
373 ):
374 hidden_states, residual = layer(
375 positions=positions,
376 hidden_states=hidden_states,
377 residual=residual,
378 meta_mlp=self.meta_mlp,
379 )
380 self._maybe_add_hidden_state(
381 aux_hidden_states,
382 layer_idx + 1,
383 hidden_states,
384 residual,
385 )
386
387 if not get_pp_group().is_last_rank:
388 return IntermediateTensors(
389 {"hidden_states": hidden_states, "residual": residual}
390 )
391 hidden_states, _ = self.norm(hidden_states, residual)
392 if self.use_sequence_parallel:
393 if aux_hidden_states:
394 hidden_size = hidden_states.shape[-1]
395 hidden_states = torch.cat([hidden_states, *aux_hidden_states], dim=-1)
396 hidden_states = tensor_model_parallel_all_gather(hidden_states, 0)
397 hidden_states = hidden_states[:full_num_tokens]
398 hidden_states, *aux_hidden_states = hidden_states.split(
399 hidden_size, dim=-1
400 )
401 else:
402 hidden_states = tensor_model_parallel_all_gather(hidden_states, 0)
403 hidden_states = hidden_states[:full_num_tokens]
404 if aux_hidden_states:
405 return hidden_states, aux_hidden_states
406 return hidden_states
407
408 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
409 loader = AutoWeightsLoader(self)
410 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
411
412
413 class InternS2MobiusForCausalLM(Qwen3_5ForCausalLMBase):
414 def __init__(self, *, vllm_config: VllmConfig, prefix: str = "") -> None:
415 config = vllm_config.model_config.hf_text_config
416 self.vllm_config = vllm_config
417 self.model_config = vllm_config.model_config
418 self.quant_config = vllm_config.quant_config
419 self.scheduler_config = vllm_config.scheduler_config
420
421 nn.Module.__init__(self)
422 self.config = config
423 self.model = InternS2MobiusModel(
424 vllm_config=vllm_config,
425 prefix=maybe_prefix(prefix, "model"),
426 )
427
428 if get_pp_group().is_last_rank:
429 self.lm_head = ParallelLMHead(
430 config.vocab_size,
431 config.hidden_size,
432 quant_config=self.quant_config,
433 prefix=maybe_prefix(prefix, "lm_head"),
434 )
435 if config.tie_word_embeddings:
436 self.lm_head = self.lm_head.tie_weights(self.model.embed_tokens)
437 else:
438 self.lm_head = PPMissingLayer()
439
440 self.logits_processor = LogitsProcessor(config.vocab_size)
441 self.make_empty_intermediate_tensors = (
442 self.model.make_empty_intermediate_tensors
443 )
444
445
446 class InternS2MobiusMTP(Qwen3_5MoeMTP):
447 def __init__(self, *, vllm_config: VllmConfig, prefix: str = "") -> None:
448 speculative_config = vllm_config.speculative_config
449 if speculative_config is None or speculative_config.draft_model_config is None:
450 raise ValueError(
451 "Intern-S2-Mobius MTP requires a draft model configuration."
452 )
453
454 draft_vllm_config = replace(
455 vllm_config,
456 model_config=speculative_config.draft_model_config,
457 )
458 with set_current_vllm_config(draft_vllm_config, prefix=prefix):
459 super().__init__(vllm_config=draft_vllm_config, prefix=prefix)
460
461
462 @MULTIMODAL_REGISTRY.register_processor(
463 Qwen3VLMultiModalProcessor,
464 info=InternS2MobiusProcessingInfo,
465 dummy_inputs=Qwen3VLDummyInputsBuilder,
466 )
467 class InternS2MobiusForConditionalGeneration(InternS2PreviewForConditionalGeneration):
468 def __init__(self, *, vllm_config: VllmConfig, prefix: str = "model") -> None:
469 nn.Module.__init__(self)
470
471 config = vllm_config.model_config.hf_config
472 if getattr(config, "image_token_index", None) is None:
473 config.image_token_index = config.image_token_id
474 quant_config = vllm_config.quant_config
475 multimodal_config = vllm_config.model_config.get_multimodal_config()
476
477 self.config = config
478 self.model_config = vllm_config.model_config
479 self.multimodal_config = multimodal_config
480 self.use_data_parallel = multimodal_config.mm_encoder_tp_mode == "data"
481 self.is_multimodal_pruning_enabled = (
482 multimodal_config.is_multimodal_pruning_enabled()
483 )
484 self.video_pruning_rate = multimodal_config.video_pruning_rate
485 self._tokenizer = cached_tokenizer_from_config(vllm_config.model_config)
486
487 self.use_deepstack = False
488
489 with self._mark_tower_model(vllm_config, {"image", "video"}):
490 self.visual = Qwen3_VisionTransformer(
491 config.vision_config,
492 norm_eps=getattr(config, "rms_norm_eps", 1e-6),
493 quant_config=quant_config,
494 input_norm=build_mm_input_norm(self.model_config),
495 prefix=maybe_prefix(prefix, "visual"),
496 )
497
498 with self._mark_language_model(vllm_config):
499 self.language_model = InternS2MobiusForCausalLM(
500 vllm_config=vllm_config,
501 prefix=maybe_prefix(prefix, "language_model"),
502 )
503
504 self.make_empty_intermediate_tensors = (
505 self.language_model.make_empty_intermediate_tensors
506 )
507 self.set_moe_parameters()
508
509 def set_moe_parameters(self) -> None:
510 meta_mlp = self.language_model.model.meta_mlp
511 if not meta_mlp:
512 raise RuntimeError("Intern-S2-Mobius requires at least one MoE bank.")
513
514 self.moe_layers = [moe.experts for moe in meta_mlp]
515 example_moe = meta_mlp[0]
516 self.num_moe_layers = len(self.moe_layers)
517 self.num_expert_groups = 1
518 self.num_shared_experts = 0
519 self.num_logical_experts = example_moe.n_logical_experts
520 self.num_physical_experts = example_moe.n_physical_experts
521 self.num_local_physical_experts = example_moe.n_local_physical_experts
522 self.num_routed_experts = example_moe.n_routed_experts
523 self.num_redundant_experts = example_moe.n_redundant_experts
524
525 def update_physical_experts_metadata(
526 self,
527 num_physical_experts: int,
528 num_local_physical_experts: int,
529 ) -> None:
530 assert self.num_local_physical_experts == num_local_physical_experts
531 self.num_physical_experts = num_physical_experts
532 self.num_local_physical_experts = num_local_physical_experts
533 self.num_redundant_experts = num_physical_experts - self.num_logical_experts
534 for moe in self.language_model.model.meta_mlp:
535 moe.n_local_physical_experts = num_local_physical_experts
536 moe.n_physical_experts = num_physical_experts
537 moe.n_redundant_experts = self.num_redundant_experts
538 moe.experts.update_expert_map()