[MoE] Use GateLinear for all MoE models (#58234)

Signed-off-by: Jee Jee Li <jeejeelee@inferact.ai>

Jee Jee Li committed Sep 23, 2026 at 13:40 UTC de6674b0023b218ca1d95c903a11befcbf27f7c6
34 files changed +221 -225
vllm/model_executor/layers/fused_moe/router/gate_linear.py
+53 -13
@@ -5,7 +5,11 @@ from torch.nn.parameter import Parameter
5
6 import vllm._custom_ops as ops
7 from vllm.model_executor.custom_op import PluggableLayer
8 -from vllm.model_executor.layers.linear import ReplicatedLinear
8 +from vllm.model_executor.layers.linear import (
9 + ReplicatedLinear,
10 + UnquantizedLinearMethod,
11 +)
12 +from vllm.model_executor.layers.quantization import QuantizationConfig
13 from vllm.platforms import current_platform
14 from vllm.utils.torch_utils import direct_register_custom_op
15
@@ -25,12 +29,18 @@ class GateLinear(ReplicatedLinear):
29 The ``out_dtype`` attribute is mutable and can be set after init
30 (e.g. when the required dtype depends on the expert quantization
31 method which is only known later).
32 +
33 + A ``quant_config`` that actually quantizes the gate disables every
34 + specialized tier, leaving plain ``ReplicatedLinear`` behavior.
35 """
36
37 # (hidden_size, num_experts) pairs with an instantiated fp32 kernel:
38 # (3072, 256) -> MiniMax-M2/M2.5, (6144, 128) -> MiniMax-M3
39 FP32_SUPPORTED_SHAPES = {(3072, 256), (6144, 128)}
40 FP32_MAX_TOKENS = 32
41 + # Largest batch for which tier 1 beats the cuBLAS epilogue. Subclasses
42 + # whose router shape stays ahead further up the range may raise it.
43 + LL_BF16_MAX_TOKENS = 16
44
45 def __init__(
46 self,
@@ -40,7 +50,10 @@ class GateLinear(ReplicatedLinear):
50 out_dtype: torch.dtype | None = None,
51 params_dtype: torch.dtype | None = None,
52 force_fp32_compute: bool = False,
53 + skip_bias_add: bool = False,
54 + quant_config: QuantizationConfig | None = None,
55 prefix: str = "",
56 + return_bias: bool = True,
57 ):
58 is_hopper = current_platform.is_device_capability((9, 0))
59 is_blackwell = current_platform.is_device_capability_family(100)
@@ -72,17 +85,25 @@ class GateLinear(ReplicatedLinear):
85 input_size,
86 output_size,
87 bias=bias,
88 + skip_bias_add=skip_bias_add,
89 params_dtype=params_dtype,
76 - quant_config=None,
90 + quant_config=quant_config,
91 prefix=prefix,
92 + return_bias=return_bias,
93 )
94 self.out_dtype = out_dtype
95
96 + # A quantized gate exposes no plain ``weight``, so every specialized
97 + # tier below is disabled and forward falls back to ReplicatedLinear.
98 + self.is_unquantized = isinstance(self.quant_method, UnquantizedLinearMethod)
99 + can_use_specialized_kernels &= self.is_unquantized
100 +
101 self.allow_specialized_router_gemm = can_use_specialized_kernels
102
103 # fp32 specialized kernel eligibility (exact dims, fp32 weight)
104 self.allow_fp32_router_gemm = (
85 - not bias
105 + self.is_unquantized
106 + and not bias
107 and self.weight.dtype == torch.float32
108 and (
109 (
@@ -94,7 +115,8 @@ class GateLinear(ReplicatedLinear):
115 )
116 )
117 self.allow_bf16x3_router_gemm = (
97 - not bias
118 + self.is_unquantized
119 + and not bias
120 and self.weight.dtype == torch.float32
121 and current_platform.is_cuda()
122 and is_blackwell
@@ -108,7 +130,7 @@ class GateLinear(ReplicatedLinear):
130 # applies on any CUDA-alike device (no bias, since torch.mm has no bias
131 # term). The specialized-kernel gate above excludes family-120 Blackwell
132 # (GB10 / DGX Spark), which this tier still covers. See #49921.
111 - self._router_gemm_no_bias = not bias
133 + self._router_gemm_no_bias = self.is_unquantized and not bias
134 self._router_gemm_cublas_capable = (
135 current_platform.is_cuda() or current_platform.is_rocm()
136 ) and self._router_gemm_no_bias
@@ -162,17 +184,26 @@ class GateLinear(ReplicatedLinear):
184 and is_available()
185 )
186
187 + def _return(
188 + self, output: torch.Tensor
189 + ) -> torch.Tensor | tuple[torch.Tensor, Parameter | None]:
190 + return output if not self.return_bias else (output, None)
191 +
192 def forward(
193 self, x: torch.Tensor
194 ) -> torch.Tensor | tuple[torch.Tensor, Parameter | None]:
195 # Tier 1: cuteDSL ll_bf16_gemm (SM90+, any dims)
169 - if self.allow_ll_bf16_gemm and x.shape[0] <= 16 and x.dtype == torch.bfloat16:
196 + if (
197 + self.allow_ll_bf16_gemm
198 + and x.shape[0] <= self.LL_BF16_MAX_TOKENS
199 + and x.dtype == torch.bfloat16
200 + ):
201 from vllm.model_executor.kernels.linear.cute_dsl.ll_bf16 import (
202 ll_bf16_gemm,
203 )
204
205 output = ll_bf16_gemm(x, self.weight)
175 - return output, None
206 + return self._return(output)
207
208 # Tier 2: fp32 specialized kernel (model-specific shapes, M<=32)
209 # Dispatch is wrapped in a custom op so that torch.compile/CUDA-graph
@@ -184,7 +215,7 @@ class GateLinear(ReplicatedLinear):
215 output = torch.ops.vllm.fp32_router_gemm_dispatch(
216 x, self.weight, self.allow_bf16x3_router_gemm
217 )
187 - return output, None
218 + return self._return(output)
219
220 # Tier 3: bf16x3 CuteDSL kernel for fp32 router weights
221 if self.allow_bf16x3_router_gemm and x.dtype == torch.bfloat16:
@@ -193,20 +224,29 @@ class GateLinear(ReplicatedLinear):
224 )
225
226 output = bf16x3_router_gemm(x, self.weight)
196 - return output, None
227 + return self._return(output)
228
229 # Tier 4: cuBLAS bf16→fp32
230 if self.allow_cublas_router_gemm and x.dtype == torch.bfloat16:
231 output = torch.mm(x, self.weight.T, out_dtype=torch.float32)
201 - return output, None
232 + return self._return(output)
233
234 # Tier 5: F.linear (ReplicatedLinear)
204 - if self.out_dtype is not None and x.dtype != self.weight.dtype:
235 + if (
236 + self.out_dtype is not None
237 + and self.is_unquantized
238 + and x.dtype != self.weight.dtype
239 + ):
240 x = x.to(self.weight.dtype)
206 - output, output_bias = super().forward(x)
241 + base_output = super().forward(x)
242 + output_bias: Parameter | None = None
243 + if isinstance(base_output, tuple):
244 + output, output_bias = base_output
245 + else:
246 + output = base_output
247 if self.out_dtype is not None and output.dtype != self.out_dtype:
248 output = output.to(self.out_dtype)
209 - return output, output_bias
249 + return output if not self.return_bias else (output, output_bias)
250
251
252 _FP32_ROUTER_GEMM_MAX_TOKENS = GateLinear.FP32_MAX_TOKENS
vllm/model_executor/models/AXK1.py
+2 -3
@@ -44,6 +44,7 @@ from vllm.logger import init_logger
44 from vllm.model_executor.layers.attention import Attention
45 from vllm.model_executor.layers.fused_moe import (
46 FusedMoEFactory,
47 + GateLinear,
48 fused_moe_make_expert_params_mapping,
49 )
50 from vllm.model_executor.layers.fused_moe.utils import (
@@ -128,11 +129,9 @@ class AXK1MoE(nn.Module):
129 "Only silu is supported for now."
130 )
131
131 - self.gate = ReplicatedLinear(
132 + self.gate = GateLinear(
133 config.hidden_size,
134 config.n_routed_experts,
134 - bias=False,
135 - quant_config=None,
135 prefix=f"{prefix}.gate",
136 )
137 if config.topk_method == "noaux_tc":
vllm/model_executor/models/afmoe.py
+6 -4
@@ -19,6 +19,7 @@ from vllm.logger import init_logger
19 from vllm.model_executor.layers.attention import Attention
20 from vllm.model_executor.layers.fused_moe import (
21 FusedMoEFactory,
22 + GateLinear,
23 MoERunner,
24 )
25 from vllm.model_executor.layers.layernorm import RMSNorm
@@ -82,11 +83,12 @@ class AfmoeMoE(nn.Module):
83 )
84
85 # Router gate
85 - self.gate = nn.Linear(
86 + self.gate = GateLinear(
87 config.hidden_size,
88 config.num_experts,
88 - bias=False,
89 - dtype=torch.float32,
89 + out_dtype=torch.float32,
90 + params_dtype=torch.float32,
91 + prefix=f"{prefix}.gate",
92 )
93 self.expert_bias = nn.Parameter(
94 torch.empty(config.num_experts, dtype=torch.float32)
@@ -140,7 +142,7 @@ class AfmoeMoE(nn.Module):
142 num_tokens, hidden_dim = hidden_states.shape
143 hidden_states = hidden_states.view(-1, hidden_dim)
144
143 - router_logits = self.gate(hidden_states.to(dtype=torch.float32))
145 + router_logits, _ = self.gate(hidden_states)
146
147 final_hidden_states = self.experts(
148 hidden_states=hidden_states, router_logits=router_logits
vllm/model_executor/models/bailing_moe.py
+9 -5
@@ -41,7 +41,10 @@ from vllm.distributed import (
41 )
42 from vllm.model_executor.layers.activation import SiluAndMul
43 from vllm.model_executor.layers.attention import Attention
44 -from vllm.model_executor.layers.fused_moe import FusedMoEFactory
44 +from vllm.model_executor.layers.fused_moe import (
45 + FusedMoEFactory,
46 + GateLinear,
47 +)
48 from vllm.model_executor.layers.layernorm import RMSNorm
49 from vllm.model_executor.layers.linear import (
50 MergedColumnParallelLinear,
@@ -243,11 +246,12 @@ class BailingMoE(nn.Module):
246 else:
247 self.router_dtype = torch.bfloat16
248
246 - self.gate = nn.Linear(
249 + self.gate = GateLinear(
250 self.hidden_size,
251 self.num_experts,
249 - bias=False,
250 - dtype=self.router_dtype,
252 + out_dtype=self.router_dtype,
253 + params_dtype=self.router_dtype,
254 + prefix=f"{prefix}.gate",
255 )
256
257 if getattr(config, "moe_router_enable_expert_bias", False):
@@ -312,7 +316,7 @@ class BailingMoE(nn.Module):
316 hidden_states = hidden_states.view(-1, hidden_size)
317
318 # router_logits: (num_tokens, n_experts)
315 - router_logits = self.gate(hidden_states.to(self.router_dtype))
319 + router_logits, _ = self.gate(hidden_states)
320 router_logits = router_logits.to(hidden_states.dtype)
321
322 final_hidden_states = self.experts(
vllm/model_executor/models/bailing_moe_linear.py
+12 -35
@@ -5,7 +5,6 @@ from collections.abc import Callable, Iterable
5
6 import torch
7 import torch.nn as nn
8 -import torch.nn.functional as F
8 from transformers.configuration_utils import PretrainedConfig
9
10 from vllm.compilation.decorators import support_torch_compile
@@ -19,6 +18,7 @@ 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
@@ -229,37 +229,6 @@ class BailingMoeV25MLAAttention(nn.Module):
229 return self.mla_attn(positions, hidden_states)
230
231
232 -class BailingMoEGate(nn.Module):
233 - def __init__(
234 - self,
235 - config: PretrainedConfig,
236 - params_dtype: torch.dtype | None = None,
237 - prefix: str = "",
238 - ):
239 - super().__init__()
240 - if params_dtype is None:
241 - params_dtype = torch.get_default_dtype()
242 - self.params_dtype = params_dtype
243 - self.weight = nn.Parameter(
244 - torch.empty(
245 - (config.num_experts, config.hidden_size),
246 - dtype=self.params_dtype,
247 - ),
248 - )
249 - if getattr(config, "moe_router_enable_expert_bias", False):
250 - self.expert_bias = nn.Parameter(
251 - torch.empty((config.num_experts,), dtype=torch.float32),
252 - )
253 - else:
254 - self.expert_bias = None
255 -
256 - def forward(self, hidden_states):
257 - logits = F.linear(hidden_states.to(self.weight.dtype), self.weight, None).to(
258 - hidden_states.dtype
259 - )
260 - return logits
261 -
262 -
232 class BailingMoeV25(nn.Module):
233 """Bailing MoE v2.5 - standalone implementation for linear attention model."""
234
@@ -296,11 +265,19 @@ class BailingMoeV25(nn.Module):
265 self.router_dtype = torch.bfloat16
266
267 # Gate for routing
299 - self.gate = BailingMoEGate(
300 - config=config,
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 )
@@ -357,7 +334,7 @@ class BailingMoeV25(nn.Module):
334 hidden_states = hidden_states.contiguous().view(-1, hidden_size)
335
336 # router_logits: (num_tokens, n_experts)
360 - router_logits = self.gate(hidden_states.to(self.router_dtype))
337 + router_logits, _ = self.gate(hidden_states)
338 router_logits = router_logits.to(hidden_states.dtype)
339
340 final_hidden_states = self.experts(
vllm/model_executor/models/bailing_moe_v3.py
+12 -25
@@ -16,7 +16,6 @@ from typing import TypeGuard
16 import regex as re
17 import torch
18 import torch.nn as nn
19 -import torch.nn.functional as F
19 from einops import rearrange
20 from transformers.configuration_utils import PretrainedConfig
21
@@ -32,6 +31,7 @@ from vllm.model_executor.custom_op import PluggableLayer
31 from vllm.model_executor.layers.activation import SiluAndMul, SwigluStepAndMul
32 from vllm.model_executor.layers.fused_moe import (
33 FusedMoEFactory,
34 + GateLinear,
35 fused_moe_make_expert_params_mapping,
36 )
37 from vllm.model_executor.layers.layernorm import RMSNorm
@@ -1118,28 +1118,6 @@ class BailingMoeV3KimiDeltaAttention(PluggableLayer, MambaBase):
1118 core_attn_out[0, :num_actual_tokens] = out[0, :num_actual_tokens]
1119
1120
1121 -class BailingMoeV3Gate(nn.Module):
1122 - def __init__(
1123 - self,
1124 - config: PretrainedConfig,
1125 - params_dtype: torch.dtype | None = None,
1126 - ) -> None:
1127 - super().__init__()
1128 - if params_dtype is None:
1129 - params_dtype = torch.float32
1130 - self.weight = nn.Parameter(
1131 - torch.empty((config.num_experts, config.hidden_size), dtype=params_dtype)
1132 - )
1133 - self.expert_bias = nn.Parameter(
1134 - torch.empty((config.num_experts,), dtype=torch.float32)
1135 - )
1136 -
1137 - def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
1138 - return F.linear(hidden_states.to(self.weight.dtype), self.weight).to(
1139 - hidden_states.dtype
1140 - )
1141 -
1142 -
1121 class BailingMoeV3MoE(nn.Module):
1122 def __init__(
1123 self,
@@ -1153,7 +1131,16 @@ class BailingMoeV3MoE(nn.Module):
1131 self.top_k = config.num_experts_per_tok
1132 self.hidden_size = config.hidden_size
1133 self.routed_scaling_factor = getattr(config, "routed_scaling_factor", 1.0)
1156 - self.gate = BailingMoeV3Gate(config)
1134 + self.gate = GateLinear(
1135 + config.hidden_size,
1136 + config.num_experts,
1137 + out_dtype=torch.float32,
1138 + params_dtype=torch.float32,
1139 + prefix=f"{prefix}.gate",
1140 + )
1141 + self.gate.expert_bias = nn.Parameter(
1142 + torch.empty((config.num_experts,), dtype=torch.float32)
1143 + )
1144 self.expert_swiglu_limit = _get_layer_swiglu_limit(
1145 getattr(config, "expert_swiglu_limit_list", None), layer_id
1146 )
@@ -1196,7 +1183,7 @@ class BailingMoeV3MoE(nn.Module):
1183 def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
1184 num_tokens, hidden_size = hidden_states.shape
1185 hidden_states = hidden_states.contiguous().view(-1, hidden_size)
1199 - router_logits = self.gate(hidden_states.to(torch.float32))
1186 + router_logits, _ = self.gate(hidden_states)
1187 hidden_states = self.experts(
1188 hidden_states=hidden_states, router_logits=router_logits
1189 )
vllm/model_executor/models/bert_with_rope.py
+6 -4
@@ -18,7 +18,11 @@ from vllm.model_executor.layers.activation import get_act_and_mul_fn, get_act_fn
18 from vllm.model_executor.layers.attention import (
19 EncoderOnlyAttention,
20 )
21 -from vllm.model_executor.layers.fused_moe import activation_without_mul, fused_topk
21 +from vllm.model_executor.layers.fused_moe import (
22 + GateLinear,
23 + activation_without_mul,
24 + fused_topk,
25 +)
26 from vllm.model_executor.layers.linear import (
27 ColumnParallelLinear,
28 MergedColumnParallelLinear,
@@ -254,9 +258,7 @@ class NomicMoE(nn.Module):
258 params_dtype = torch.get_default_dtype()
259 self.params_dtype = params_dtype
260
257 - self.router = ReplicatedLinear(
258 - self.hidden_size, self.num_total_experts, bias=False
259 - )
261 + self.router = GateLinear(self.hidden_size, self.num_total_experts)
262 self.w1 = nn.Parameter(
263 torch.empty(
264 self.num_total_experts,
vllm/model_executor/models/cohere2_moe.py
+5 -5
@@ -16,11 +16,13 @@ from vllm.distributed import (
16 )
17 from vllm.model_executor.layers.activation import SiluAndMul
18 from vllm.model_executor.layers.attention import Attention
19 -from vllm.model_executor.layers.fused_moe import FusedMoEFactory
19 +from vllm.model_executor.layers.fused_moe import (
20 + FusedMoEFactory,
21 + GateLinear,
22 +)
23 from vllm.model_executor.layers.linear import (
24 MergedColumnParallelLinear,
25 QKVParallelLinear,
23 - ReplicatedLinear,
26 RowParallelLinear,
27 )
28 from vllm.model_executor.layers.logits_processor import LogitsProcessor
@@ -275,12 +277,10 @@ class Cohere2Moe(nn.Module):
277 else:
278 self.custom_routing_function = None
279
278 - self.gate = ReplicatedLinear(
280 + self.gate = GateLinear(
281 config.hidden_size,
282 config.num_experts,
281 - bias=False,
283 params_dtype=params_dtype,
283 - quant_config=None,
284 prefix=f"{prefix}.gate",
285 )
286
vllm/model_executor/models/dbrx.py
+2 -4
@@ -18,11 +18,11 @@ from vllm.distributed import (
18 from vllm.model_executor.layers.attention import Attention
19 from vllm.model_executor.layers.fused_moe import (
20 FusedMoEFactory,
21 + GateLinear,
22 RoutedExperts,
23 )
24 from vllm.model_executor.layers.linear import (
25 QKVParallelLinear,
25 - ReplicatedLinear,
26 RowParallelLinear,
27 )
28 from vllm.model_executor.layers.logits_processor import LogitsProcessor
@@ -62,12 +62,10 @@ class DbrxRouter(nn.Module):
62 self.tp_size = get_tensor_model_parallel_world_size()
63 self.num_total_experts = config.ffn_config.moe_num_experts
64 self.d_model = config.d_model
65 - self.layer = ReplicatedLinear(
65 + self.layer = GateLinear(
66 self.d_model,
67 self.num_total_experts,
68 - bias=False,
68 params_dtype=params_dtype,
70 - quant_config=None,
69 )
70
71 def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
vllm/model_executor/models/ernie45_moe.py
+8 -6
@@ -41,12 +41,15 @@ from vllm.distributed import (
41 from vllm.logger import init_logger
42 from vllm.model_executor.layers.activation import SiluAndMul
43 from vllm.model_executor.layers.attention import Attention
44 -from vllm.model_executor.layers.fused_moe import FusedMoEFactory, MoERunner
44 +from vllm.model_executor.layers.fused_moe import (
45 + FusedMoEFactory,
46 + GateLinear,
47 + MoERunner,
48 +)
49 from vllm.model_executor.layers.layernorm import RMSNorm
50 from vllm.model_executor.layers.linear import (
51 MergedColumnParallelLinear,
52 QKVParallelLinear,
49 - ReplicatedLinear,
53 RowParallelLinear,
54 )
55 from vllm.model_executor.layers.logits_processor import LogitsProcessor
@@ -150,12 +153,11 @@ class Ernie4_5_MoeMoE(nn.Module):
153 f"the number of experts {config.moe_num_experts}."
154 )
155
153 - self.gate = ReplicatedLinear(
156 + self.gate = GateLinear(
157 config.hidden_size,
158 config.moe_num_experts,
156 - bias=False,
159 + out_dtype=torch.float32,
160 params_dtype=torch.float32,
158 - quant_config=None,
161 prefix=f"{prefix}.gate",
162 )
163
@@ -199,7 +201,7 @@ class Ernie4_5_MoeMoE(nn.Module):
201 hidden_dim = hidden_states.shape[-1]
202 hidden_states = hidden_states.view(-1, hidden_dim)
203
202 - router_logits, _ = self.gate(hidden_states.to(dtype=torch.float32))
204 + router_logits, _ = self.gate(hidden_states)
205
206 final_hidden_states = self.experts(
207 hidden_states=hidden_states, router_logits=router_logits
vllm/model_executor/models/exaone_moe.py
+5 -5
@@ -30,11 +30,13 @@ from vllm.distributed import (
30 get_tensor_model_parallel_world_size,
31 )
32 from vllm.model_executor.layers.attention import Attention
33 -from vllm.model_executor.layers.fused_moe import FusedMoEFactory
33 +from vllm.model_executor.layers.fused_moe import (
34 + FusedMoEFactory,
35 + GateLinear,
36 +)
37 from vllm.model_executor.layers.layernorm import RMSNorm
38 from vllm.model_executor.layers.linear import (
39 QKVParallelLinear,
37 - ReplicatedLinear,
40 RowParallelLinear,
41 )
42 from vllm.model_executor.layers.logits_processor import LogitsProcessor
@@ -84,11 +86,9 @@ class ExaoneMoe(nn.Module):
86 f"the number of experts {config.num_experts}."
87 )
88
87 - self.gate = ReplicatedLinear(
89 + self.gate = GateLinear(
90 config.hidden_size,
91 config.num_experts,
90 - bias=False,
91 - quant_config=None,
92 prefix=f"{prefix}.gate",
93 )
94
vllm/model_executor/models/glm4_moe.py
+6 -7
@@ -43,6 +43,7 @@ from vllm.model_executor.layers.activation import SiluAndMul
43 from vllm.model_executor.layers.attention import Attention
44 from vllm.model_executor.layers.fused_moe import (
45 FusedMoEFactory,
46 + GateLinear,
47 )
48 from vllm.model_executor.layers.fused_moe.utils import (
49 is_model_fused_shared_expert_compatible,
@@ -137,14 +138,12 @@ class Glm4MoE(nn.Module):
138 f"Unsupported activation: {config.hidden_act}. "
139 "Only silu is supported for now."
140 )
140 - # NOTE In the transformers implementation, the gate isn't an nn.Linear,
141 - # so we cannot use ReplicatedLinear here.
142 - # See: https://github.com/huggingface/transformers/blob/v4.55.1/src/transformers/models/glm4_moe/modeling_glm4_moe.py#L260
143 - self.gate = nn.Linear(
141 + self.gate = GateLinear(
142 config.hidden_size,
143 config.n_routed_experts,
146 - bias=False,
147 - dtype=torch.float32,
144 + out_dtype=torch.float32,
145 + params_dtype=torch.float32,
146 + prefix=f"{prefix}.gate",
147 )
148 self.gate.e_score_correction_bias = nn.Parameter(
149 torch.empty(config.n_routed_experts, dtype=torch.float32)
@@ -212,7 +211,7 @@ class Glm4MoE(nn.Module):
211 hidden_states = hidden_states.view(-1, hidden_dim)
212
213 # router_logits: (num_tokens, n_experts)
215 - router_logits = self.gate(hidden_states.to(dtype=torch.float32))
214 + router_logits, _ = self.gate(hidden_states)
215
216 final_hidden_states = self.experts(
217 hidden_states=hidden_states, router_logits=router_logits
vllm/model_executor/models/gpt_oss.py
+2 -3
@@ -22,6 +22,7 @@ from vllm.distributed import (
22 from vllm.model_executor.layers.attention import Attention
23 from vllm.model_executor.layers.fused_moe import (
24 FusedMoEFactory,
25 + GateLinear,
26 fused_moe_make_expert_params_mapping,
27 )
28 from vllm.model_executor.layers.fused_moe.config import FusedMoEParallelConfig
@@ -29,7 +30,6 @@ from vllm.model_executor.layers.fused_moe.routed_experts import RoutedExperts
30 from vllm.model_executor.layers.layernorm import RMSNorm
31 from vllm.model_executor.layers.linear import (
32 QKVParallelLinear,
32 - ReplicatedLinear,
33 RowParallelLinear,
34 )
35 from vllm.model_executor.layers.logits_processor import LogitsProcessor
@@ -377,11 +377,10 @@ class MLPBlock(torch.nn.Module):
377 self.hidden_size = config.hidden_size
378 self.experts_per_token = config.num_experts_per_tok
379 self.world_size = dist.get_world_size() if dist.is_initialized() else 1
380 - self.router = ReplicatedLinear(
380 + self.router = GateLinear(
381 config.hidden_size,
382 config.num_local_experts,
383 bias=True,
384 - quant_config=None,
384 prefix=f"{prefix}.router",
385 return_bias=False,
386 )
vllm/model_executor/models/granitemoe.py
+5 -5
@@ -39,11 +39,13 @@ from vllm.distributed import (
39 tensor_model_parallel_all_gather,
40 )
41 from vllm.model_executor.layers.attention import Attention
42 -from vllm.model_executor.layers.fused_moe import FusedMoEFactory
42 +from vllm.model_executor.layers.fused_moe import (
43 + FusedMoEFactory,
44 + GateLinear,
45 +)
46 from vllm.model_executor.layers.layernorm import RMSNorm
47 from vllm.model_executor.layers.linear import (
48 QKVParallelLinear,
46 - ReplicatedLinear,
49 RowParallelLinear,
50 )
51 from vllm.model_executor.layers.logits_processor import LogitsProcessor
@@ -94,12 +96,10 @@ class GraniteMoeMoE(nn.Module):
96 self.is_sequence_parallel = is_sequence_parallel
97
98 # Gate always runs at half / full precision for now.
97 - self.gate = ReplicatedLinear(
99 + self.gate = GateLinear(
100 hidden_size,
101 num_experts,
100 - bias=False,
102 params_dtype=params_dtype,
102 - quant_config=None,
103 prefix=f"{prefix}.gate",
104 )
105
vllm/model_executor/models/interns1_pro.py
+2 -3
@@ -43,12 +43,12 @@ from vllm.model_executor.layers.activation import SiluAndMul
43 from vllm.model_executor.layers.attention import Attention
44 from vllm.model_executor.layers.fused_moe import (
45 FusedMoEFactory,
46 + GateLinear,
47 )
48 from vllm.model_executor.layers.layernorm import RMSNorm
49 from vllm.model_executor.layers.linear import (
50 MergedColumnParallelLinear,
51 QKVParallelLinear,
51 - ReplicatedLinear,
52 RowParallelLinear,
53 )
54 from vllm.model_executor.layers.logits_processor import LogitsProcessor
@@ -181,10 +181,9 @@ class InternS1ProMoeSparseMoeBlock(nn.Module):
181 custom_routing_function=self._custom_routing_function,
182 )
183
184 - self.gate = ReplicatedLinear(
184 + self.gate = GateLinear(
185 config.hidden_size,
186 config.num_experts,
187 - bias=False,
187 prefix=f"{prefix}.gate",
188 )
189
vllm/model_executor/models/interns2_mobius.py
+5 -4
@@ -17,7 +17,10 @@ from vllm.distributed import (
17 tensor_model_parallel_all_gather,
18 tensor_model_parallel_reduce_scatter,
19 )
20 -from vllm.model_executor.layers.fused_moe import FusedMoEFactory
20 +from vllm.model_executor.layers.fused_moe import (
21 + FusedMoEFactory,
22 + GateLinear,
23 +)
24 from vllm.model_executor.layers.linear import ReplicatedLinear
25 from vllm.model_executor.layers.logits_processor import LogitsProcessor
26 from vllm.model_executor.layers.mamba.gdn.qwen_gdn_linear_attn import (
@@ -93,11 +96,9 @@ class InternS2MobiusMetaMoeBlock(nn.Module):
96 self.n_physical_experts = self.n_logical_experts + self.n_redundant_experts
97 self.n_local_physical_experts = self.n_physical_experts // self.ep_size
98
96 - self.gate = ReplicatedLinear(
99 + self.gate = GateLinear(
100 config.hidden_size,
101 config.num_experts,
99 - bias=False,
100 - quant_config=None,
102 prefix=f"{prefix}.gate",
103 )
104 self.experts = FusedMoEFactory(
vllm/model_executor/models/jamba.py
+2 -4
@@ -16,11 +16,11 @@ from vllm.distributed.parallel_state import get_pp_group
16 from vllm.model_executor.layers.attention import Attention
17 from vllm.model_executor.layers.fused_moe import (
18 FusedMoEFactory,
19 + GateLinear,
20 )
21 from vllm.model_executor.layers.layernorm import RMSNorm
22 from vllm.model_executor.layers.linear import (
23 QKVParallelLinear,
23 - ReplicatedLinear,
24 RowParallelLinear,
25 )
26 from vllm.model_executor.layers.logits_processor import LogitsProcessor
@@ -74,11 +74,9 @@ class JambaMoE(nn.Module):
74 self.intermediate_size = config.intermediate_size
75
76 if self.num_total_experts > 1:
77 - self.router = ReplicatedLinear(
77 + self.router = GateLinear(
78 self.hidden_size,
79 self.num_total_experts,
80 - bias=False,
81 - quant_config=None,
80 params_dtype=params_dtype,
81 prefix=f"{prefix}.router",
82 )
vllm/model_executor/models/k2_horizon.py
+2 -1
@@ -49,6 +49,7 @@ from vllm.model_executor.layers.activation import SiluAndMul
49 from vllm.model_executor.layers.attention import Attention
50 from vllm.model_executor.layers.fused_moe import (
51 FusedMoEFactory,
52 + GateLinear,
53 fused_moe_make_expert_params_mapping,
54 )
55 from vllm.model_executor.layers.fused_moe.config import (
@@ -398,7 +399,7 @@ class K2HorizonSparseMoeBlock(nn.Module):
399 self.physical_expert_start + self.n_local_physical_experts
400 )
401
401 - self.gate = ReplicatedLinear(
402 + self.gate = GateLinear(
403 config.hidden_size,
404 config.num_experts,
405 bias=config.moe_gate_bias,
vllm/model_executor/models/laguna.py
+5 -5
@@ -19,12 +19,14 @@ from vllm.distributed import (
19 )
20 from vllm.logger import init_logger
21 from vllm.model_executor.layers.attention import Attention
22 -from vllm.model_executor.layers.fused_moe import FusedMoEFactory
22 +from vllm.model_executor.layers.fused_moe import (
23 + FusedMoEFactory,
24 + GateLinear,
25 +)
26 from vllm.model_executor.layers.layernorm import RMSNorm
27 from vllm.model_executor.layers.linear import (
28 ColumnParallelLinear,
29 QKVParallelLinear,
27 - ReplicatedLinear,
30 RowParallelLinear,
31 )
32 from vllm.model_executor.layers.logits_processor import LogitsProcessor
@@ -171,11 +173,9 @@ class LagunaMoE(nn.Module):
173 self.n_physical_experts = self.n_logical_experts + self.n_redundant_experts
174 self.n_local_physical_experts = self.n_physical_experts // self.ep_size
175 # Router gate
174 - self.gate = ReplicatedLinear(
176 + self.gate = GateLinear(
177 config.hidden_size,
178 config.num_experts,
177 - bias=False,
178 - quant_config=None,
179 prefix=f"{prefix}.gate",
180 )
181
vllm/model_executor/models/lfm2_moe.py
+2 -3
@@ -17,12 +17,12 @@ from vllm.model_executor.layers.activation import SiluAndMul
17 from vllm.model_executor.layers.attention import Attention
18 from vllm.model_executor.layers.fused_moe import (
19 FusedMoEFactory,
20 + GateLinear,
21 )
22 from vllm.model_executor.layers.layernorm import RMSNorm
23 from vllm.model_executor.layers.linear import (
24 MergedColumnParallelLinear,
25 QKVParallelLinear,
25 - ReplicatedLinear,
26 RowParallelLinear,
27 )
28 from vllm.model_executor.layers.logits_processor import LogitsProcessor
@@ -125,10 +125,9 @@ class Lfm2MoeSparseMoeBlock(nn.Module):
125 self.n_physical_experts = self.n_logical_experts + self.n_redundant_experts
126 self.n_local_physical_experts = self.n_physical_experts // self.ep_size
127
128 - self.gate = ReplicatedLinear(
128 + self.gate = GateLinear(
129 config.hidden_size,
130 config.num_experts,
131 - bias=False,
131 quant_config=quant_config,
132 prefix=f"{prefix}.gate",
133 )
vllm/model_executor/models/llama4.py
+2 -4
@@ -38,12 +38,12 @@ from vllm.model_executor.layers.attention import (
38 )
39 from vllm.model_executor.layers.fused_moe import (
40 FusedMoEFactory,
41 + GateLinear,
42 fused_moe_make_expert_params_mapping,
43 )
44 from vllm.model_executor.layers.layernorm import RMSNorm
45 from vllm.model_executor.layers.linear import (
46 QKVParallelLinear,
46 - ReplicatedLinear,
47 RowParallelLinear,
48 )
49 from vllm.model_executor.layers.quantization import QuantizationConfig
@@ -98,11 +98,9 @@ class Llama4MoE(nn.Module):
98 self.ep_size = self.ep_group.size()
99
100 intermediate_size_moe = config.intermediate_size
101 - self.router = ReplicatedLinear(
101 + self.router = GateLinear(
102 config.hidden_size,
103 config.num_local_experts,
104 - bias=False,
105 - quant_config=None,
104 prefix=f"{prefix}.router",
105 )
106
vllm/model_executor/models/longcat_flash.py
+4 -6
@@ -48,12 +48,12 @@ from vllm.logger import init_logger
48 from vllm.model_executor.layers.activation import SiluAndMul
49 from vllm.model_executor.layers.fused_moe import (
50 FusedMoEFactory,
51 + GateLinear,
52 fused_moe_make_expert_params_mapping,
53 )
54 from vllm.model_executor.layers.layernorm import RMSNorm
55 from vllm.model_executor.layers.linear import (
56 MergedColumnParallelLinear,
56 - ReplicatedLinear,
57 RowParallelLinear,
58 )
59 from vllm.model_executor.layers.logits_processor import LogitsProcessor
@@ -254,12 +254,12 @@ class LongcatRouter(nn.Module):
254 else config.num_experts[0]
255 )
256 self.n_routed_experts = self.n_routed_experts + zero_expert_num
257 - self.classifier = ReplicatedLinear(
257 + self.classifier = GateLinear(
258 config.hidden_size,
259 self.n_routed_experts,
260 bias=config.router_bias,
261 + out_dtype=router_params_dtype,
262 params_dtype=router_params_dtype,
262 - quant_config=None,
263 prefix=f"{prefix}.classifier",
264 )
265 self.e_score_correction_bias = nn.Parameter(
@@ -331,9 +331,7 @@ class LongcatMoe(nn.Module):
331 else:
332 hidden_states_padded = hidden_states
333
334 - router_logits_full = self.router(
335 - hidden_states_padded.to(self.router_params_dtype)
336 - )
334 + router_logits_full = self.router(hidden_states_padded)
335
336 # MoERunner handles routing memoization and zero expert computation
337 # internally. Pass full router_logits (including zero experts) so that
vllm/model_executor/models/minicpm.py
+6 -5
@@ -43,12 +43,15 @@ from vllm.distributed import (
43 )
44 from vllm.model_executor.layers.activation import FatreluAndMul, SiluAndMul
45 from vllm.model_executor.layers.attention import Attention
46 -from vllm.model_executor.layers.fused_moe import fused_experts, fused_topk
46 +from vllm.model_executor.layers.fused_moe import (
47 + GateLinear,
48 + fused_experts,
49 + fused_topk,
50 +)
51 from vllm.model_executor.layers.layernorm import RMSNorm
52 from vllm.model_executor.layers.linear import (
53 MergedColumnParallelLinear,
54 QKVParallelLinear,
51 - ReplicatedLinear,
55 RowParallelLinear,
56 )
57 from vllm.model_executor.layers.logits_processor import LogitsProcessor
@@ -109,12 +112,10 @@ class MiniCPMMoE(nn.Module):
112 params_dtype = torch.get_default_dtype()
113 self.params_dtype = params_dtype
114
112 - self.gate = ReplicatedLinear(
115 + self.gate = GateLinear(
116 self.hidden_size,
117 self.num_total_experts,
115 - bias=False,
118 params_dtype=self.params_dtype,
117 - quant_config=None,
119 prefix=f"{prefix}.gate",
120 )
121
vllm/model_executor/models/mixtral.py
+5 -5
@@ -39,11 +39,13 @@ from vllm.distributed import (
39 get_tensor_model_parallel_world_size,
40 )
41 from vllm.model_executor.layers.attention import Attention
42 -from vllm.model_executor.layers.fused_moe import FusedMoEFactory
42 +from vllm.model_executor.layers.fused_moe import (
43 + FusedMoEFactory,
44 + GateLinear,
45 +)
46 from vllm.model_executor.layers.layernorm import RMSNorm
47 from vllm.model_executor.layers.linear import (
48 QKVParallelLinear,
46 - ReplicatedLinear,
49 RowParallelLinear,
50 )
51 from vllm.model_executor.layers.logits_processor import LogitsProcessor
@@ -106,12 +108,10 @@ class MixtralMoE(nn.Module):
108 self.n_local_physical_experts = self.n_physical_experts // self.ep_size
109 # Gate always runs at half / full precision for now.
110
109 - self.gate = ReplicatedLinear(
111 + self.gate = GateLinear(
112 hidden_size,
113 num_experts,
112 - bias=False,
114 params_dtype=params_dtype,
114 - quant_config=None,
115 prefix=f"{prefix}.gate",
116 )
117
vllm/model_executor/models/moondream3.py
+6 -4
@@ -28,12 +28,15 @@ from vllm.model_executor.layers.attention import Attention
28 from vllm.model_executor.layers.attention.mm_encoder_attention import (
29 MMEncoderAttention,
30 )
31 -from vllm.model_executor.layers.fused_moe import MoEActivation, fused_experts
31 +from vllm.model_executor.layers.fused_moe import (
32 + GateLinear,
33 + MoEActivation,
34 + fused_experts,
35 +)
36 from vllm.model_executor.layers.fused_moe.config import biased_moe_quant_config
37 from vllm.model_executor.layers.linear import (
38 ColumnParallelLinear,
39 QKVParallelLinear,
36 - ReplicatedLinear,
40 RowParallelLinear,
41 )
42 from vllm.model_executor.layers.logits_processor import LogitsProcessor
@@ -453,11 +456,10 @@ class Moondream3TextMoE(nn.Module):
456 self.num_local_experts = self.experts_per_rank
457
458 # Router (gate) - use ReplicatedLinear for compatibility
456 - self.gate = ReplicatedLinear(
459 + self.gate = GateLinear(
460 hidden_size,
461 num_experts,
462 bias=True,
460 - quant_config=None,
463 prefix=f"{prefix}.gate",
464 )
465
vllm/model_executor/models/olmoe.py
+5 -5
@@ -32,11 +32,13 @@ from vllm.distributed import (
32 from vllm.distributed.utils import split_tensor_along_last_dim
33 from vllm.logger import init_logger
34 from vllm.model_executor.layers.attention import Attention
35 -from vllm.model_executor.layers.fused_moe import FusedMoEFactory
35 +from vllm.model_executor.layers.fused_moe import (
36 + FusedMoEFactory,
37 + GateLinear,
38 +)
39 from vllm.model_executor.layers.layernorm import RMSNorm
40 from vllm.model_executor.layers.linear import (
41 QKVParallelLinear,
39 - ReplicatedLinear,
42 RowParallelLinear,
43 )
44 from vllm.model_executor.layers.logits_processor import LogitsProcessor
@@ -84,11 +86,9 @@ class OlmoeMoE(nn.Module):
86 self.hidden_size = hidden_size
87
88 # Gate always runs at half / full precision for now.
87 - self.gate = ReplicatedLinear(
89 + self.gate = GateLinear(
90 hidden_size,
91 num_experts,
90 - bias=False,
91 - quant_config=None,
92 prefix=f"{prefix}.gate",
93 )
94
vllm/model_executor/models/openpangu.py
+5 -4
@@ -43,7 +43,10 @@ from vllm.model_executor.layers.attention import (
43 Attention,
44 StaticSinkAttention,
45 )
46 -from vllm.model_executor.layers.fused_moe import FusedMoEFactory
46 +from vllm.model_executor.layers.fused_moe import (
47 + FusedMoEFactory,
48 + GateLinear,
49 +)
50 from vllm.model_executor.layers.layernorm import RMSNorm
51 from vllm.model_executor.layers.linear import (
52 ColumnParallelLinear,
@@ -149,11 +152,9 @@ class OpenPanguMoE(nn.Module):
152 self.is_sequence_parallel = parallel_config.use_sequence_parallel_moe
153 check_ffn_act_fn(config.hidden_act)
154
152 - self.gate = ReplicatedLinear(
155 + self.gate = GateLinear(
156 config.hidden_size,
157 config.n_routed_experts,
155 - bias=False,
156 - quant_config=None,
158 prefix=f"{prefix}.gate",
159 )
160 if (
vllm/model_executor/models/param2moe.py
+10 -12
@@ -22,7 +22,6 @@ from collections.abc import Iterable, Iterator
22 from itertools import islice
23
24 import torch
25 -import torch.nn.functional as F
25 from torch import nn
26
27 from vllm.config import CacheConfig, VllmConfig
@@ -34,6 +33,7 @@ from vllm.model_executor.layers.activation import SiluAndMul
33 from vllm.model_executor.layers.attention import Attention
34 from vllm.model_executor.layers.fused_moe import (
35 FusedMoEFactory,
36 + GateLinear,
37 MoERunner,
38 )
39 from vllm.model_executor.layers.layernorm import RMSNorm
@@ -289,10 +289,12 @@ class Param2MoEMoEBlock(nn.Module):
289 self.norm_expert_prob: bool = getattr(config, "norm_topk_prob", True)
290 self.score_function: str = getattr(config, "score_function", "sigmoid")
291
292 - self.gate = nn.Linear(
292 + self.gate = GateLinear(
293 self.hidden_size,
294 self.num_experts,
295 - bias=False,
295 + out_dtype=torch.float32,
296 + params_dtype=torch.float32,
297 + prefix=f"{prefix}.gate",
298 )
299
300 if getattr(config, "moe_router_enable_expert_bias", True):
@@ -350,15 +352,11 @@ class Param2MoEMoEBlock(nn.Module):
352 num_tokens, hidden_dim = hidden_states.shape
353 hidden_states = hidden_states.view(-1, hidden_dim)
354
353 - # Router: both input and weight must be float32 for numerical
354 - # stability (mirrors the original Param2MoEGate behaviour).
355 - # The gate nn.Linear weight lives in the model dtype (bfloat16),
356 - # so we must cast both explicitly via F.linear instead of calling
357 - # self.gate() which would hit a dtype mismatch.
358 - router_logits = F.linear(
359 - hidden_states.float(),
360 - self.gate.weight.float(),
361 - ).to(hidden_states.dtype)
355 + # Router logits are accumulated in float32 for numerical stability
356 + # (mirrors the original Param2MoEGate behaviour) and handed to the
357 + # experts in the activation dtype.
358 + router_logits, _ = self.gate(hidden_states)
359 + router_logits = router_logits.to(hidden_states.dtype)
360
361 expert_output = self.experts(
362 hidden_states=hidden_states,
vllm/model_executor/models/phimoe.py
+5 -5
@@ -35,10 +35,12 @@ from vllm.compilation.decorators import support_torch_compile
35 from vllm.config import CacheConfig, VllmConfig
36 from vllm.distributed import get_pp_group, get_tensor_model_parallel_world_size
37 from vllm.model_executor.layers.attention import Attention
38 -from vllm.model_executor.layers.fused_moe import FusedMoEFactory
38 +from vllm.model_executor.layers.fused_moe import (
39 + FusedMoEFactory,
40 + GateLinear,
41 +)
42 from vllm.model_executor.layers.linear import (
43 QKVParallelLinear,
41 - ReplicatedLinear,
44 RowParallelLinear,
45 )
46 from vllm.model_executor.layers.logits_processor import LogitsProcessor
@@ -262,12 +264,10 @@ class PhiMoE(nn.Module):
264 self.hidden_size = hidden_size
265
266 # Gate always runs at half / full precision for now.
265 - self.gate = ReplicatedLinear(
267 + self.gate = GateLinear(
268 hidden_size,
269 num_experts,
268 - bias=False,
270 params_dtype=params_dtype,
270 - quant_config=None,
271 prefix=f"{prefix}.gate",
272 )
273
vllm/model_executor/models/qwen2_moe.py
+5 -4
@@ -40,7 +40,10 @@ from vllm.distributed import get_pp_group, get_tensor_model_parallel_world_size
40 from vllm.logger import init_logger
41 from vllm.model_executor.layers.activation import SiluAndMul
42 from vllm.model_executor.layers.attention import Attention
43 -from vllm.model_executor.layers.fused_moe import FusedMoEFactory
43 +from vllm.model_executor.layers.fused_moe import (
44 + FusedMoEFactory,
45 + GateLinear,
46 +)
47 from vllm.model_executor.layers.layernorm import RMSNorm
48 from vllm.model_executor.layers.linear import (
49 MergedColumnParallelLinear,
@@ -136,11 +139,9 @@ class Qwen2MoeSparseMoeBlock(nn.Module):
139 f"the number of experts {config.num_experts}."
140 )
141
139 - self.gate = ReplicatedLinear(
142 + self.gate = GateLinear(
143 config.hidden_size,
144 config.num_experts,
142 - bias=False,
143 - quant_config=None,
145 prefix=f"{prefix}.gate",
146 )
147
vllm/model_executor/models/qwen3_moe.py
+5 -3
@@ -42,7 +42,10 @@ from vllm.distributed import (
42 from vllm.logger import init_logger
43 from vllm.model_executor.layers.activation import SiluAndMul
44 from vllm.model_executor.layers.attention import Attention
45 -from vllm.model_executor.layers.fused_moe import FusedMoEFactory
45 +from vllm.model_executor.layers.fused_moe import (
46 + FusedMoEFactory,
47 + GateLinear,
48 +)
49 from vllm.model_executor.layers.layernorm import RMSNorm
50 from vllm.model_executor.layers.linear import (
51 MergedColumnParallelLinear,
@@ -164,10 +167,9 @@ class Qwen3MoeSparseMoeBlock(nn.Module):
167 self.n_physical_experts = self.n_logical_experts + self.n_redundant_experts
168 self.n_local_physical_experts = self.n_physical_experts // self.ep_size
169
167 - self.gate = ReplicatedLinear(
170 + self.gate = GateLinear(
171 config.hidden_size,
172 config.num_experts,
170 - bias=False,
173 quant_config=quant_config,
174 prefix=f"{prefix}.gate",
175 )
vllm/model_executor/models/qwen3_next.py
+5 -4
@@ -18,7 +18,10 @@ from vllm.distributed import (
18 tensor_model_parallel_reduce_scatter,
19 )
20 from vllm.model_executor.layers.attention import Attention
21 -from vllm.model_executor.layers.fused_moe import FusedMoEFactory
21 +from vllm.model_executor.layers.fused_moe import (
22 + FusedMoEFactory,
23 + GateLinear,
24 +)
25 from vllm.model_executor.layers.fused_moe.utils import (
26 is_model_fused_shared_expert_compatible,
27 resolve_layer_fused_shared_expert,
@@ -180,11 +183,9 @@ class Qwen3NextSparseMoeBlock(nn.Module):
183 self.n_physical_experts = self.n_logical_experts + self.n_redundant_experts
184 self.n_local_physical_experts = self.n_physical_experts // self.ep_size
185
183 - self.gate = ReplicatedLinear(
186 + self.gate = GateLinear(
187 config.hidden_size,
188 config.num_experts,
186 - bias=False,
187 - quant_config=None,
189 prefix=f"{prefix}.gate",
190 )
191
vllm/model_executor/models/step3_text.py
+2 -3
@@ -20,6 +20,7 @@ from vllm.model_executor.layers.activation import SiluAndMul
20 from vllm.model_executor.layers.attention import Attention
21 from vllm.model_executor.layers.fused_moe import (
22 FusedMoEFactory,
23 + GateLinear,
24 )
25 from vllm.model_executor.layers.layernorm import RMSNorm
26 from vllm.model_executor.layers.linear import (
@@ -77,11 +78,9 @@ class FusedMoEBlock(nn.Module):
78 quant_config=quant_config,
79 prefix=f"{prefix}.experts",
80 )
80 - self.gate = ReplicatedLinear(
81 + self.gate = GateLinear(
82 config.hidden_size,
83 config.moe_num_experts,
83 - bias=False,
84 - quant_config=None,
84 prefix=f"{prefix}.gate",
85 )
86
vllm/model_executor/models/step3p5.py
+5 -17
@@ -8,7 +8,6 @@ from typing import Any
8
9 import torch
10 from torch import nn
11 -from torch.nn.parameter import Parameter
11
12 from vllm.compilation.decorators import support_torch_compile
13 from vllm.config import CacheConfig, VllmConfig
@@ -25,6 +24,7 @@ from vllm.model_executor.layers.activation import SiluAndMul, SwigluStepAndMul
24 from vllm.model_executor.layers.attention import Attention
25 from vllm.model_executor.layers.fused_moe import (
26 FusedMoEFactory,
27 + GateLinear,
28 MoERunner,
29 fused_moe_make_expert_params_mapping,
30 )
@@ -33,7 +33,6 @@ from vllm.model_executor.layers.linear import (
33 ColumnParallelLinear,
34 MergedColumnParallelLinear,
35 QKVParallelLinear,
36 - ReplicatedLinear,
36 RowParallelLinear,
37 )
38 from vllm.model_executor.layers.logits_processor import LogitsProcessor
@@ -68,17 +67,6 @@ from .utils import (
67 logger = init_logger(__name__)
68
69
71 -class FP32ReplicatedLinear(ReplicatedLinear):
72 - """Use FP32 for higher precision."""
73 -
74 - def forward(
75 - self,
76 - x: torch.Tensor,
77 - ) -> torch.Tensor | tuple[torch.Tensor, Parameter | None]:
78 - assert self.params_dtype == torch.float32
79 - return super().forward(x.to(torch.float32))
80 -
81 -
70 class Step3p5MLP(nn.Module):
71 def __init__(
72 self,
@@ -326,12 +314,12 @@ class FusedMoEBlock(nn.Module):
314 f"the number of experts {config.moe_num_experts}."
315 )
316
329 - self.gate = FP32ReplicatedLinear(
317 + # Router logits are accumulated in FP32 for higher precision.
318 + self.gate = GateLinear(
319 config.hidden_size,
320 config.moe_num_experts,
332 - bias=False,
333 - quant_config=None,
334 - params_dtype=torch.float32, # Use FP32 for higher precision.
321 + out_dtype=torch.float32,
322 + params_dtype=torch.float32,
323 prefix=f"{prefix}.gate",
324 )
325 self.use_moe_router_bias = config.use_moe_router_bias