@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 2c8b76c5cb
Fork 0

A high-throughput and memory-efficient inference and serving engine for LLMs

Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git

Synced Nov 4, 15:00 UTC

[Model][DSV4] Support base model (#41006)

Signed-off-by: Jee Jee Li <pandaleefree@gmail.com>

Jee Jee Li committed Apr 28, 2026 at 08:16 UTC 2c8b76c5cb2683f05650f20d90a63f3d9799e909
2 files changed +111 -23
vllm/model_executor/models/deepseek_v4.py
+93 -19
@@ -10,7 +10,7 @@ import torch.nn as nn
10 import torch.nn.functional as F
11
12 from vllm.compilation.decorators import support_torch_compile
13 -from vllm.config import VllmConfig
13 +from vllm.config import VllmConfig, get_current_vllm_config
14 from vllm.distributed import (
15 get_ep_group,
16 get_tensor_model_parallel_rank,
@@ -65,6 +65,8 @@ from .utils import (
65 maybe_prefix,
66 )
67
68 +_DEEPSEEK_V4_EXPERT_DTYPES = ("fp4", "fp8")
69 +
70
71 class DeepseekV4MLP(nn.Module):
72 def __init__(
@@ -118,16 +120,59 @@ class DeepseekV4MLP(nn.Module):
120
121
122 class DeepseekV4FP8Config(Fp8Config):
121 - """FP8 config that routes MoE layers to MXFP4 quantization.
122 -
123 - DeepSeek V4 checkpoints use FP8 for linear/attention layers but
124 - MXFP4 for MoE expert weights. This config inherits standard FP8
125 - behavior and overrides only the MoE dispatch.
123 + """FP8 config for DeepSeek V4 with expert-dtype-aware MoE dispatch.
124 +
125 + DeepSeek V4 checkpoints always use FP8 block quantization for
126 + linear/attention layers. The MoE expert weights vary by checkpoint:
127 + - ``expert_dtype="fp4"`` (e.g. DeepSeek-V4-Flash): MXFP4 experts
128 + with ue8m0 (e8m0fnu) FP8 linear scales.
129 + - ``expert_dtype="fp8"`` (e.g. DeepSeek-V4-Flash-Base): FP8 block
130 + experts with float32 FP8 linear scales.
131 +
132 + The dispatch and the linear scale dtype are both keyed off
133 + ``expert_dtype`` from the model's hf_config; missing values default
134 + to ``"fp4"`` so existing FP4 checkpoints stay unchanged.
135 +
136 + NOTE: ``expert_dtype`` is resolved lazily because this config is
137 + constructed during VllmConfig setup, before ``set_current_vllm_config``
138 + is active. Reading hf_config eagerly in ``__init__`` would always see
139 + the default ``"fp4"`` and silently misroute Flash-Base checkpoints.
140 """
141
142 def __init__(self, *args, **kwargs):
143 super().__init__(*args, **kwargs)
130 - self.is_scale_e8m0: bool = True
144 + self._resolved_expert_dtype: str | None = None
145 + # ``is_scale_e8m0`` is a property that resolves on first read,
146 + # by which time the current vllm_config has been set.
147 +
148 + @property
149 + def expert_dtype(self) -> str:
150 + if self._resolved_expert_dtype is None:
151 + try:
152 + hf_config = get_current_vllm_config().model_config.hf_config
153 + except Exception:
154 + # vllm_config not yet set; defer the decision until a
155 + # later call lands inside set_current_vllm_config.
156 + return "fp4"
157 + expert_dtype = getattr(hf_config, "expert_dtype", "fp4")
158 + if expert_dtype not in _DEEPSEEK_V4_EXPERT_DTYPES:
159 + raise ValueError(
160 + f"Unsupported DeepSeek V4 expert_dtype={expert_dtype!r}; "
161 + f"expected one of {_DEEPSEEK_V4_EXPERT_DTYPES}."
162 + )
163 + self._resolved_expert_dtype = expert_dtype
164 + from vllm.logger import init_logger
165 +
166 + init_logger(__name__).info_once(
167 + "DeepSeek V4 expert_dtype resolved to %r", expert_dtype
168 + )
169 + return self._resolved_expert_dtype
170 +
171 + @property
172 + def is_scale_e8m0(self) -> bool:
173 + # FP4 checkpoints store FP8 linear scales as e8m0fnu; FP8 expert
174 + # checkpoints (Flash-Base) store them as float32.
175 + return self.expert_dtype == "fp4"
176
177 @classmethod
178 def get_name(cls) -> QuantizationMethods:
@@ -155,11 +200,14 @@ class DeepseekV4FP8Config(Fp8Config):
200 fused_mapping=self.packed_modules_mapping,
201 ):
202 return UnquantizedFusedMoEMethod(layer.moe_config)
158 - return Mxfp4MoEMethod(layer.moe_config)
203 + if self.expert_dtype == "fp4":
204 + return Mxfp4MoEMethod(layer.moe_config)
205 + # expert_dtype == "fp8": fall through to Fp8Config which
206 + # returns Fp8MoEMethod with block-wise float32 scales.
207 return super().get_quant_method(layer, prefix)
208
209 def is_mxfp4_quant(self, prefix, layer):
162 - return isinstance(layer, FusedMoE)
210 + return isinstance(layer, FusedMoE) and self.expert_dtype == "fp4"
211
212
213 @triton.jit
@@ -689,6 +737,12 @@ class DeepseekV4MoE(nn.Module):
737 raise NotImplementedError(
738 "DeepSeek V4 MegaMoE currently supports sqrtsoftplus routing only."
739 )
740 + if self.use_mega_moe and getattr(config, "expert_dtype", "fp4") != "fp4":
741 + raise NotImplementedError(
742 + "DeepSeek V4 MegaMoE only supports fp4 experts; got expert_dtype="
743 + f"{config.expert_dtype!r}. Drop --kernel-config moe_backend="
744 + "deep_gemm_mega_moe for this checkpoint."
745 + )
746
747 self.gate = GateLinear(
748 config.hidden_size,
@@ -1410,10 +1464,24 @@ def hc_head(
1464 return y.to(dtype)
1465
1466
1413 -class DeepseekV4ForCausalLM(nn.Module):
1414 - model_cls = DeepseekV4Model
1415 -
1416 - hf_to_vllm_mapper = WeightsMapper(
1467 +def _make_deepseek_v4_weights_mapper(expert_dtype: str) -> WeightsMapper:
1468 + if expert_dtype == "fp4":
1469 + # MXFP4 experts use Mxfp4MoEMethod, which registers scales as
1470 + # ``w{1,2,3}_weight_scale`` (no _inv suffix). FP8 linear and
1471 + # shared experts use Fp8LinearMethod's block scales, which
1472 + # register as ``weight_scale_inv``.
1473 + scale_regex = {
1474 + re.compile(r"(\.experts\.\d+\.w[123])\.scale$"): r"\1.weight_scale",
1475 + re.compile(r"\.scale$"): ".weight_scale_inv",
1476 + }
1477 + else:
1478 + # FP8 experts use Fp8MoEMethod (block_quant=True), which registers
1479 + # scales as ``w{13,2}_weight_scale_inv``. Map all ``.scale`` keys
1480 + # there.
1481 + scale_regex = {
1482 + re.compile(r"\.scale$"): ".weight_scale_inv",
1483 + }
1484 + return WeightsMapper(
1485 orig_to_new_prefix={
1486 "layers.": "model.layers.",
1487 "embed.": "model.embed.",
@@ -1421,12 +1489,7 @@ class DeepseekV4ForCausalLM(nn.Module):
1489 "hc_head": "model.hc_head",
1490 "mtp.": "model.mtp.",
1491 },
1424 - orig_to_new_regex={
1425 - # Routed MoE expert scales: experts.N.wX.scale -> .weight_scale
1426 - re.compile(r"(\.experts\.\d+\.w[123])\.scale$"): r"\1.weight_scale",
1427 - # Everything else (FP8 linear + shared experts): .scale -> .weight_scale_inv
1428 - re.compile(r"\.scale$"): ".weight_scale_inv",
1429 - },
1492 + orig_to_new_regex=scale_regex,
1493 orig_to_new_suffix={
1494 "head.weight": "lm_head.weight",
1495 "embed.weight": "embed_tokens.weight",
@@ -1438,11 +1501,22 @@ class DeepseekV4ForCausalLM(nn.Module):
1501 },
1502 )
1503
1504 +
1505 +class DeepseekV4ForCausalLM(nn.Module):
1506 + model_cls = DeepseekV4Model
1507 +
1508 + # Default mapper assumes the original FP4-expert checkpoint layout.
1509 + # Overridden per-instance in __init__ when expert_dtype != "fp4".
1510 + hf_to_vllm_mapper = _make_deepseek_v4_weights_mapper("fp4")
1511 +
1512 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
1513 super().__init__()
1514
1515 config = vllm_config.model_config.hf_config
1516 self.config = config
1517 + expert_dtype = getattr(config, "expert_dtype", "fp4")
1518 + if expert_dtype != "fp4":
1519 + self.hf_to_vllm_mapper = _make_deepseek_v4_weights_mapper(expert_dtype)
1520
1521 self.model = self.model_cls(
1522 vllm_config=vllm_config, prefix=maybe_prefix(prefix, "model")
vllm/model_executor/models/deepseek_v4_mtp.py
+18 -4
@@ -48,9 +48,14 @@ from .utils import maybe_prefix
48
49 logger = init_logger(__name__)
50
51 -# MoE expert scales are fused into per-layer w13/w2 tensors; other FP8 linear
52 -# scales use `.weight_scale_inv`. Mirrors the regex in
53 -# DeepseekV4ForCausalLM.hf_to_vllm_mapper.
51 +# MoE expert scales are fused into per-layer w13/w2 tensors. The exact
52 +# parameter suffix depends on which FusedMoE method handles the experts:
53 +# - fp4 experts (Mxfp4MoEMethod) register ``w{1,2,3}_weight_scale``;
54 +# - fp8 experts (Fp8MoEMethod with block_quant=True) register
55 +# ``w{1,2,3}_weight_scale_inv``.
56 +# Other FP8 linear scales (including shared experts) always use
57 +# ``.weight_scale_inv``. Mirrors the per-instance mapper built by
58 +# ``_make_deepseek_v4_weights_mapper`` in deepseek_v4.py.
59 _EXPERT_SCALE_RE = re.compile(r"\.experts\.\d+\.w[123]\.scale$")
60
61
@@ -326,6 +331,15 @@ class DeepSeekV4MTP(nn.Module):
331 num_experts=self.config.n_routed_experts,
332 )
333
334 + # FP8 experts register ``..._weight_scale_inv`` (block_quant) while
335 + # FP4/MXFP4 experts register ``..._weight_scale``. Choose the suffix
336 + # for the rename below based on the model's expert dtype.
337 + expert_scale_suffix = (
338 + ".weight_scale"
339 + if getattr(self.config, "expert_dtype", "fp4") == "fp4"
340 + else ".weight_scale_inv"
341 + )
342 +
343 for name, loaded_weight in weights:
344 mtp_layer_idx = _find_mtp_layer_idx(name)
345 # V4 checkpoints store MTP weights as `mtp.{i}.*`; remap to
@@ -347,7 +361,7 @@ class DeepSeekV4MTP(nn.Module):
361 continue
362 if name.endswith(".scale"):
363 suffix = (
350 - ".weight_scale"
364 + expert_scale_suffix
365 if _EXPERT_SCALE_RE.search(name)
366 else ".weight_scale_inv"
367 )