[Refactor] refactor humming linear and moe backends to use explicit layer configs (#49610)
Signed-off-by: Jinzhen Lin <jinzhen.ljz@antgroup.com> Co-authored-by: OpenAI Codex <noreply@openai.com>
Jinzhen Lin committed
Aug 8, 2026 at 01:03 UTC
fcde8e1460589849c8142d617420ccdc406d5bc9
37 files changed
+448
-341
requirements/cuda.txt
+1
-1
@@ -32,4 +32,4 @@ quack-kernels>=0.6.1 # Required for CUTLASS DSL 4.6 by MSA
32
tokenspeed-mla==0.1.8; platform_system == "Linux"
33
34
# Humming kernels for quantization gemm
35
-humming-kernels[cu13]==0.1.10
35
+humming-kernels[cu13]==0.1.12
tests/evals/gsm8k/configs/humming/NVIDIA-Nemotron-3-Nano-30B-A3B-NVFP4-humming.yaml
new
+9
@@ -0,0 +1,9 @@
1
+model_name: "nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-NVFP4"
2
+accuracy_threshold: 0.29
3
+num_questions: 1319
4
+num_fewshot: 5
5
+server_args: >-
6
+ --enforce-eager
7
+ --max-model-len 8192
8
+ --moe-backend humming
9
+ --linear-backend humming
tests/evals/gsm8k/configs/humming/Qwen3-4B-mixed-quant-RTN-humming.yaml
+1
-1
@@ -1,5 +1,5 @@
1
model_name: "nm-testing/Qwen3-4B-mixed-quant-RTN-wNaM"
2
-accuracy_threshold: 0.85
2
+accuracy_threshold: 0.78
3
num_questions: 1319
4
num_fewshot: 5
5
server_args: >-
tests/evals/gsm8k/configs/humming/config-act-int8.txt
+1
@@ -1,3 +1,4 @@
1
+gpt-oss-20b-humming.yaml
2
Qwen3-30B-A3B-Instruct-2507-quantized.w8a8-humming-act-int8.yaml
3
Qwen3-30B-A3B-GPTQ-Int4-humming-act-int8.yaml
4
Qwen3-30B-A3B-AWQ-humming.yaml
tests/evals/gsm8k/configs/humming/config.txt
+1
@@ -11,3 +11,4 @@ Qwen3-30B-A3B-NVFP4-humming.yaml
11
Qwen3-30B-A3B-AWQ-humming.yaml
12
Qwen3.5-35B-A3B-FP8-humming.yaml
13
Qwen3.5-35B-A3B-experts-int8-humming.yaml
14
+NVIDIA-Nemotron-3-Nano-30B-A3B-NVFP4-humming.yaml
tests/kernels/moe/test_moe.py
+9
-13
@@ -1265,11 +1265,10 @@ def _make_humming_indexed_experts(activation: MoEActivation):
1265
layer.intermediate_size_per_partition = intermediate_size
1266
quant_config = humming_utils.get_humming_moe_quant_config(layer)
1267
experts = HummingIndexedExperts(
1268
- layer,
1269
- moe_config,
1270
- quant_config,
1268
+ moe_config=moe_config,
1269
+ quant_config=quant_config,
1270
)
1272
- return experts
1271
+ return experts, layer
1272
1273
1274
@pytest.mark.parametrize("activation", list(MoEActivation))
@@ -1328,8 +1327,7 @@ def test_humming_delegates_to_instance_activation():
1327
def test_humming_gated_non_gated_shape_contract(activation: MoEActivation):
1328
from vllm.utils import humming
1329
1331
- experts = _make_humming_indexed_experts(activation)
1332
- layer = experts.layer
1330
+ experts, layer = _make_humming_indexed_experts(activation)
1331
moe_config = experts.moe_config
1332
top_k = moe_config.experts_per_token
1333
num_experts = moe_config.num_experts
@@ -1337,7 +1335,7 @@ def test_humming_gated_non_gated_shape_contract(activation: MoEActivation):
1335
intermediate_size = moe_config.intermediate_size
1336
gate_up_size = intermediate_size * 2 if activation.is_gated else intermediate_size
1337
1340
- w13_meta, w2_meta = (layer.humming_metas[name] for name in ("w13", "w2"))
1338
+ w13_meta, w2_meta = (experts.humming_configs[name] for name in ("w13", "w2"))
1339
for meta in (w13_meta, w2_meta):
1340
assert meta.a_dtype == humming.dtypes.bfloat16
1341
assert meta.b_dtype == humming.dtypes.float4e2m1
@@ -1364,7 +1362,7 @@ def test_humming_indexed_writes_supplied_output_buffer():
1362
from vllm.forward_context import set_forward_context
1363
1364
activation = MoEActivation.SILU
1367
- experts = _make_humming_indexed_experts(activation)
1365
+ experts, layer = _make_humming_indexed_experts(activation)
1366
moe_config = experts.moe_config
1367
num_tokens = 1
1368
top_k = moe_config.experts_per_token
@@ -1382,7 +1380,7 @@ def test_humming_indexed_writes_supplied_output_buffer():
1380
)
1381
1382
device = torch.device("cuda")
1385
- dtype = experts.layer.params_dtype
1383
+ dtype = layer.params_dtype
1384
workspace13 = torch.empty(workspace13_shape, dtype=dtype, device=device)
1385
workspace2 = torch.empty(workspace2_shape, dtype=dtype, device=device)
1386
hidden_states = torch.ones((num_tokens, hidden_size), dtype=dtype, device=device)
@@ -1394,14 +1392,12 @@ def test_humming_indexed_writes_supplied_output_buffer():
1392
device=device,
1393
)
1394
topk_ids = torch.arange(top_k, dtype=torch.int32, device=device).unsqueeze(0)
1397
- unused = torch.empty((num_experts, 0), device=device)
1398
-
1395
with set_forward_context(None, vllm_config, num_tokens=num_tokens):
1396
experts.apply(
1397
output=output,
1398
hidden_states=hidden_states,
1403
- w1=unused,
1404
- w2=unused,
1399
+ w1=layer.w13_weight,
1400
+ w2=layer.w2_weight,
1401
topk_weights=topk_weights,
1402
topk_ids=topk_ids,
1403
activation=activation,
tests/kernels/moe/test_ocp_mx_moe.py
-1
@@ -1489,7 +1489,6 @@ def test_rocm_mxfp4_moe_oracle(
1489
mxfp4_backend=backend,
1490
experts_cls=experts_cls,
1491
routing_tables=None,
1492
- layer=None,
1492
)
1493
1494
# Create inputs
tests/quantization/test_moe_wna16.py
+3
-2
@@ -161,7 +161,6 @@ def test_moe_wna16_setup_forwards_selected_backend(monkeypatch):
161
162
assert method.moe_kernel is kernel
163
assert captured["backend"] == WNA16MoEBackend.HUMMING
164
- assert captured["layer"] is layer
164
165
166
def test_moe_wna16_humming_adapter_repacks_uint8_tensors():
@@ -198,7 +197,9 @@ def test_moe_wna16_uses_humming_quant_config(monkeypatch):
197
monkeypatch.setattr(
198
humming_utils,
199
"get_humming_moe_quant_config",
201
- lambda actual_layer: quant_config if actual_layer is layer else None,
200
+ lambda actual_layer, *args, **kwargs: (
201
+ quant_config if actual_layer is layer else None
202
+ ),
203
)
204
205
assert method.get_fused_moe_quant_config(layer) is quant_config
vllm/model_executor/kernels/linear/mixed_precision/humming.py
+14
-9
@@ -28,7 +28,8 @@ class HummingLinearKernel(MPLinearKernel):
28
def process_weights_after_loading(self, layer: torch.nn.Module) -> None:
29
from vllm.model_executor.layers.quantization.utils.humming_utils import (
30
convert_linear_layer_to_humming_standard,
31
- prepare_humming_layer,
31
+ get_humming_linear_compute_config,
32
+ prepare_humming_linear_layer_config,
33
)
34
35
name_map = {"weight": self.w_q_name, "weight_scale": self.w_s_name}
@@ -46,9 +47,11 @@ class HummingLinearKernel(MPLinearKernel):
47
48
convert_linear_layer_to_humming_standard(layer=layer, name_map=name_map)
49
input_quant_config = getattr(layer, "_humming_input_quant_config", None)
49
- prepare_humming_layer(
50
+ self.layer_config = prepare_humming_linear_layer_config(
51
layer, quant_config, input_quant_config=input_quant_config
52
)
53
+ self.compute_config = get_humming_linear_compute_config()
54
+ self.locks = torch.zeros(1024, dtype=torch.int32, device=layer.weight.device)
55
56
def apply_weights(
57
self,
@@ -56,12 +59,14 @@ class HummingLinearKernel(MPLinearKernel):
59
x: torch.Tensor,
60
bias: torch.Tensor | None = None,
61
) -> torch.Tensor:
59
- from vllm.utils.humming import HummingMethod
62
+ from vllm.model_executor.layers.quantization.utils.humming_utils import (
63
+ apply_humming_linear,
64
+ )
65
61
- flatten_inputs = x.view(-1, x.size(-1))
62
- output = HummingMethod.forward_layer(
63
- layer=layer,
64
- inputs=flatten_inputs,
65
- compute_config=layer.compute_config,
66
+ return apply_humming_linear(
67
+ layer,
68
+ x,
69
+ layer_config=self.layer_config,
70
+ compute_config=self.compute_config,
71
+ locks=self.locks,
72
)
67
- return output.view(*x.shape[:-1], output.size(-1))
vllm/model_executor/kernels/linear/mxfp4/humming.py
+16
-10
@@ -5,11 +5,14 @@ import torch
5
6
from vllm.logger import init_logger
7
from vllm.model_executor.layers.quantization.utils.humming_utils import (
8
+ apply_humming_linear,
9
convert_linear_layer_to_humming_standard,
9
- prepare_humming_layer,
10
+ get_humming_linear_compute_config,
11
+ prepare_humming_linear_layer_config,
12
)
13
from vllm.model_executor.layers.quantization.utils.quant_utils import kMxfp4Dynamic
14
from vllm.platforms import current_platform
15
+from vllm.utils.import_utils import has_humming
16
17
from .base import MxFp4LinearKernel, MxFp4LinearLayerConfig
18
@@ -26,6 +29,9 @@ class HummingMxFp4LinearKernel(MxFp4LinearKernel):
29
if not current_platform.is_cuda():
30
return False, "Humming only supported on CUDA"
31
32
+ if not has_humming():
33
+ return False, "Humming is not installed"
34
+
35
if not current_platform.has_device_capability(75):
36
return False, "Humming only supported on SM75+"
37
@@ -56,7 +62,9 @@ class HummingMxFp4LinearKernel(MxFp4LinearKernel):
62
}
63
64
convert_linear_layer_to_humming_standard(layer=layer, name_map=name_map)
59
- prepare_humming_layer(layer, quant_config)
65
+ self.layer_config = prepare_humming_linear_layer_config(layer, quant_config)
66
+ self.compute_config = get_humming_linear_compute_config()
67
+ self.locks = torch.zeros(1024, dtype=torch.int32, device=layer.weight.device)
68
69
def apply_weights(
70
self,
@@ -64,12 +72,10 @@ class HummingMxFp4LinearKernel(MxFp4LinearKernel):
72
x: torch.Tensor,
73
bias: torch.Tensor | None = None,
74
) -> torch.Tensor:
67
- from vllm.utils.humming import HummingMethod
68
-
69
- flatten_inputs = x.view(-1, x.size(-1))
70
- output = HummingMethod.forward_layer(
71
- layer=layer,
72
- inputs=flatten_inputs,
73
- compute_config=layer.compute_config,
75
+ return apply_humming_linear(
76
+ layer,
77
+ x,
78
+ layer_config=self.layer_config,
79
+ compute_config=self.compute_config,
80
+ locks=self.locks,
81
)
75
- return output.view(*x.shape[:-1], output.size(-1))
vllm/model_executor/kernels/linear/mxfp8/humming.py
+16
-10
@@ -4,10 +4,13 @@
4
import torch
5
6
from vllm.model_executor.layers.quantization.utils.humming_utils import (
7
+ apply_humming_linear,
8
convert_linear_layer_to_humming_standard,
8
- prepare_humming_layer,
9
+ get_humming_linear_compute_config,
10
+ prepare_humming_linear_layer_config,
11
)
12
from vllm.platforms import current_platform
13
+from vllm.utils.import_utils import has_humming
14
15
from .Mxfp8LinearKernel import Mxfp8LinearKernel, Mxfp8LinearLayerConfig
16
@@ -22,6 +25,9 @@ class HummingMxfp8LinearKernel(Mxfp8LinearKernel):
25
if not current_platform.is_cuda():
26
return False, "Humming only supported on CUDA"
27
28
+ if not has_humming():
29
+ return False, "Humming is not installed"
30
+
31
if not current_platform.has_device_capability(75):
32
return False, "Humming only supported on SM75+"
33
@@ -44,7 +50,9 @@ class HummingMxfp8LinearKernel(Mxfp8LinearKernel):
50
}
51
52
convert_linear_layer_to_humming_standard(layer=layer, name_map=name_map)
47
- prepare_humming_layer(layer, quant_config)
53
+ self.layer_config = prepare_humming_linear_layer_config(layer, quant_config)
54
+ self.compute_config = get_humming_linear_compute_config()
55
+ self.locks = torch.zeros(1024, dtype=torch.int32, device=layer.weight.device)
56
57
def apply_weights(
58
self,
@@ -52,12 +60,10 @@ class HummingMxfp8LinearKernel(Mxfp8LinearKernel):
60
x: torch.Tensor,
61
bias: torch.Tensor | None = None,
62
) -> torch.Tensor:
55
- from vllm.utils.humming import HummingMethod
56
-
57
- flatten_inputs = x.view(-1, x.size(-1))
58
- output = HummingMethod.forward_layer(
59
- layer=layer,
60
- inputs=flatten_inputs,
61
- compute_config=layer.compute_config,
63
+ return apply_humming_linear(
64
+ layer,
65
+ x,
66
+ layer_config=self.layer_config,
67
+ compute_config=self.compute_config,
68
+ locks=self.locks,
69
)
63
- return output.view(*x.shape[:-1], output.size(-1))
vllm/model_executor/kernels/linear/nvfp4/humming.py
+16
-10
@@ -5,9 +5,12 @@ import torch
5
6
from vllm.logger import init_logger
7
from vllm.model_executor.layers.quantization.utils.humming_utils import (
8
- prepare_humming_layer,
8
+ apply_humming_linear,
9
+ get_humming_linear_compute_config,
10
+ prepare_humming_linear_layer_config,
11
)
12
from vllm.platforms import current_platform
13
+from vllm.utils.import_utils import has_humming
14
15
from .base import NvFp4LinearKernel, NvFp4LinearLayerConfig
16
@@ -24,6 +27,9 @@ class HummingNvFp4LinearKernel(NvFp4LinearKernel):
27
if not current_platform.is_cuda():
28
return False, "Humming only supported on CUDA"
29
30
+ if not has_humming():
31
+ return False, "Humming is not installed"
32
+
33
if not current_platform.has_device_capability(75):
34
return False, "Humming only supported on SM75+"
35
@@ -54,7 +60,9 @@ class HummingNvFp4LinearKernel(NvFp4LinearKernel):
60
layer.weight_global_scale = torch.nn.Parameter(
61
1.0 / layer.weight_global_scale, requires_grad=False
62
)
57
- prepare_humming_layer(layer, quant_config)
63
+ self.layer_config = prepare_humming_linear_layer_config(layer, quant_config)
64
+ self.compute_config = get_humming_linear_compute_config()
65
+ self.locks = torch.zeros(1024, dtype=torch.int32, device=layer.weight.device)
66
67
def apply_weights(
68
self,
@@ -62,12 +70,10 @@ class HummingNvFp4LinearKernel(NvFp4LinearKernel):
70
x: torch.Tensor,
71
bias: torch.Tensor | None = None,
72
) -> torch.Tensor:
65
- from vllm.utils.humming import HummingMethod
66
-
67
- flatten_inputs = x.view(-1, x.size(-1))
68
- output = HummingMethod.forward_layer(
69
- layer=layer,
70
- inputs=flatten_inputs,
71
- compute_config=layer.compute_config,
73
+ return apply_humming_linear(
74
+ layer,
75
+ x,
76
+ layer_config=self.layer_config,
77
+ compute_config=self.compute_config,
78
+ locks=self.locks,
79
)
73
- return output.view(*x.shape[:-1], output.size(-1))
vllm/model_executor/kernels/linear/scaled_mm/humming.py
+31
-23
@@ -5,10 +5,13 @@ import torch
5
6
from vllm.logger import init_logger
7
from vllm.model_executor.layers.quantization.utils.humming_utils import (
8
+ apply_humming_linear,
9
convert_linear_layer_to_humming_standard,
9
- prepare_humming_layer,
10
+ get_humming_linear_compute_config,
11
+ prepare_humming_linear_layer_config,
12
)
13
from vllm.platforms import current_platform
14
+from vllm.utils.import_utils import has_humming
15
16
from .ScaledMMLinearKernel import (
17
FP8ScaledMMLinearKernel,
@@ -30,6 +33,9 @@ class HummingFP8ScaledMMLinearKernel(FP8ScaledMMLinearKernel):
33
if not current_platform.is_cuda():
34
return False, "Humming only supported on CUDA"
35
36
+ if not has_humming():
37
+ return False, "Humming is not installed"
38
+
39
if not current_platform.has_device_capability(75):
40
return False, "Humming only supported on SM75+"
41
@@ -58,9 +64,6 @@ class HummingFP8ScaledMMLinearKernel(FP8ScaledMMLinearKernel):
64
scale_group_shape = self.config.weight_quant_key.scale.group_shape
65
if scale_group_shape.is_per_tensor():
66
quant_config["weight_scale_type"] = "tensor"
61
- if not hasattr(layer, "global_scale") and hasattr(layer, "weight_scale"):
62
- del name_map["weight_scale"]
63
- name_map["global_scale"] = "weight_scale"
67
elif scale_group_shape.is_per_channel():
68
quant_config["weight_scale_type"] = "channel"
69
elif scale_group_shape.is_per_group():
@@ -76,7 +79,9 @@ class HummingFP8ScaledMMLinearKernel(FP8ScaledMMLinearKernel):
79
name_map["weight_scale"] = "weight_scale_inv"
80
81
convert_linear_layer_to_humming_standard(layer=layer, name_map=name_map)
79
- prepare_humming_layer(layer, quant_config)
82
+ self.layer_config = prepare_humming_linear_layer_config(layer, quant_config)
83
+ self.compute_config = get_humming_linear_compute_config()
84
+ self.locks = torch.zeros(1024, dtype=torch.int32, device=layer.weight.device)
85
86
def apply_weights(
87
self,
@@ -84,15 +89,13 @@ class HummingFP8ScaledMMLinearKernel(FP8ScaledMMLinearKernel):
89
x: torch.Tensor,
90
bias: torch.Tensor | None = None,
91
) -> torch.Tensor:
87
- from vllm.utils.humming import HummingMethod
88
-
89
- flatten_inputs = x.view(-1, x.size(-1))
90
- output = HummingMethod.forward_layer(
91
- layer=layer,
92
- inputs=flatten_inputs,
93
- compute_config=layer.compute_config,
92
+ return apply_humming_linear(
93
+ layer,
94
+ x,
95
+ layer_config=self.layer_config,
96
+ compute_config=self.compute_config,
97
+ locks=self.locks,
98
)
95
- return output.view(*x.shape[:-1], output.size(-1))
99
100
def apply_scaled_mm(
101
self,
@@ -105,7 +108,9 @@ class HummingFP8ScaledMMLinearKernel(FP8ScaledMMLinearKernel):
108
bias: torch.Tensor | None,
109
output_shape: list,
110
) -> torch.Tensor:
108
- pass
111
+ raise NotImplementedError(
112
+ "HummingFP8ScaledMMLinearKernel uses apply_weights directly"
113
+ )
114
115
116
class HummingInt8ScaledMMLinearKernel(Int8ScaledMMLinearKernel):
@@ -118,6 +123,9 @@ class HummingInt8ScaledMMLinearKernel(Int8ScaledMMLinearKernel):
123
if not current_platform.is_cuda():
124
return False, "Humming only supported on CUDA"
125
126
+ if not has_humming():
127
+ return False, "Humming is not installed"
128
+
129
if not current_platform.has_device_capability(75):
130
return False, "Humming only supported on SM75+"
131
@@ -137,7 +145,9 @@ class HummingInt8ScaledMMLinearKernel(Int8ScaledMMLinearKernel):
145
weight.data = weight.data + 128
146
147
convert_linear_layer_to_humming_standard(layer=layer, name_map=name_map)
140
- prepare_humming_layer(layer, quant_config)
148
+ self.layer_config = prepare_humming_linear_layer_config(layer, quant_config)
149
+ self.compute_config = get_humming_linear_compute_config()
150
+ self.locks = torch.zeros(1024, dtype=torch.int32, device=layer.weight.device)
151
152
def apply_weights(
153
self,
@@ -145,12 +155,10 @@ class HummingInt8ScaledMMLinearKernel(Int8ScaledMMLinearKernel):
155
x: torch.Tensor,
156
bias: torch.Tensor | None = None,
157
) -> torch.Tensor:
148
- from vllm.utils.humming import HummingMethod
149
-
150
- flatten_inputs = x.view(-1, x.size(-1))
151
- output = HummingMethod.forward_layer(
152
- layer=layer,
153
- inputs=flatten_inputs,
154
- compute_config=layer.compute_config,
158
+ return apply_humming_linear(
159
+ layer,
160
+ x,
161
+ layer_config=self.layer_config,
162
+ compute_config=self.compute_config,
163
+ locks=self.locks,
164
)
156
- return output.view(*x.shape[:-1], output.size(-1))
vllm/model_executor/layers/fused_moe/experts/fused_humming_moe.py
+140
-92
@@ -4,7 +4,7 @@
4
5
import json
6
import math
7
-from typing import TYPE_CHECKING, Any
7
+from typing import TYPE_CHECKING, Any, cast
8
9
import torch
10
@@ -62,8 +62,15 @@ from vllm.utils.import_utils import has_humming
62
from vllm.v1.worker.workspace import current_workspace_manager
63
64
if TYPE_CHECKING:
65
- from vllm.model_executor.layers.fused_moe import RoutedExperts
66
- from vllm.utils.humming import GemmType as HummingGemmType
65
+ from vllm.model_executor.layers.quantization.utils.humming_utils import (
66
+ HummingMoEQuantConfig,
67
+ )
68
+ from vllm.utils.humming import (
69
+ GemmType as HummingGemmType,
70
+ )
71
+ from vllm.utils.humming import (
72
+ LayerConfig as HummingLayerConfig,
73
+ )
74
75
76
logger = init_logger(__name__)
@@ -88,15 +95,20 @@ def get_humming_moe_gemm_type() -> str:
95
class HummingExpertsBase(mk.FusedMoEExpertsModular):
96
def __init__(
97
self,
91
- layer: "RoutedExperts",
98
moe_config: FusedMoEConfig,
99
quant_config: FusedMoEQuantConfig,
100
max_num_tokens: int | None = None,
101
num_dispatchers: int | None = None,
102
):
97
- self.layer = layer
98
- self.num_experts = self.layer.local_num_experts
99
- self.global_num_experts = self.layer.global_num_experts
103
+ humming_quant_config = cast("HummingMoEQuantConfig", quant_config)
104
+ self.humming_configs: dict[str, HummingLayerConfig] = {
105
+ "w13": humming_quant_config.w1_humming_config,
106
+ "w2": humming_quant_config.w2_humming_config,
107
+ }
108
+ self.locks = torch.zeros(1024, dtype=torch.int32, device=moe_config.device)
109
+ self.num_experts = moe_config.num_local_experts
110
+ self.global_num_experts = moe_config.num_experts
111
+ self.quant_config = quant_config
112
self.init_humming_moe()
113
114
if self.is_batched():
@@ -111,31 +123,73 @@ class HummingExpertsBase(mk.FusedMoEExpertsModular):
123
self._permute_scratch: MoEPermuteScratch | None = None
124
125
def init_humming_moe(self):
114
- from vllm.utils.humming import HummingMethod
126
+ from vllm.utils.humming import get_heuristics_config
127
128
self.compute_config = {
129
"use_batch_invariant": envs.VLLM_BATCH_INVARIANT,
130
"use_f16_accum": envs.VLLM_HUMMING_USE_F16_ACCUM,
131
"gemm_type": self.humming_gemm_type().value,
132
}
121
- self.w13_tuning_config = HummingMethod.get_default_tuning_configs(
122
- layer=self.layer,
133
+ self.w13_tuning_config = get_heuristics_config(
134
+ layer_config=self.humming_configs["w13"],
135
use_f16_accum=envs.VLLM_HUMMING_USE_F16_ACCUM,
136
use_batch_invariant=envs.VLLM_BATCH_INVARIANT,
137
gemm_type=self.humming_gemm_type(),
126
- sublayer_name="w13",
138
)
128
- self.w2_tuning_config = HummingMethod.get_default_tuning_configs(
129
- layer=self.layer,
139
+ self.w2_tuning_config = get_heuristics_config(
140
+ layer_config=self.humming_configs["w2"],
141
use_f16_accum=envs.VLLM_HUMMING_USE_F16_ACCUM,
142
use_batch_invariant=envs.VLLM_BATCH_INVARIANT,
143
gemm_type=self.humming_gemm_type(),
133
- sublayer_name="w2",
144
)
145
self.compute_config_str = json.dumps(self.compute_config)
146
self.w13_tuning_config_str = json.dumps(self.w13_tuning_config)
147
self.w2_tuning_config_str = json.dumps(self.w2_tuning_config)
148
149
+ def quantize_input(
150
+ self,
151
+ sublayer_name: str,
152
+ inputs: torch.Tensor,
153
+ quanted_input: torch.Tensor | None,
154
+ ) -> tuple[torch.Tensor, torch.Tensor | None]:
155
+ from vllm.utils.humming import may_quant_input
156
+
157
+ return may_quant_input(
158
+ self.humming_configs[sublayer_name],
159
+ inputs=inputs,
160
+ quanted_input=quanted_input,
161
+ )
162
+
163
+ def humming_forward(
164
+ self,
165
+ sublayer_name: str,
166
+ inputs: torch.Tensor,
167
+ weight: torch.Tensor,
168
+ input_scale: torch.Tensor | None,
169
+ outputs: torch.Tensor,
170
+ **kwargs: Any,
171
+ ) -> torch.Tensor:
172
+ from vllm.utils.humming import humming_forward
173
+
174
+ is_w13 = sublayer_name == "w13"
175
+ return humming_forward(
176
+ self.humming_configs[sublayer_name],
177
+ inputs=inputs,
178
+ weight=weight,
179
+ weight_scale=(
180
+ self.quant_config.w1_scale if is_w13 else self.quant_config.w2_scale
181
+ ),
182
+ zero_point=(self.quant_config.w1_zp if is_w13 else self.quant_config.w2_zp),
183
+ bias=(self.quant_config.w1_bias if is_w13 else self.quant_config.w2_bias),
184
+ weight_scale_2=(
185
+ self.quant_config.g1_alphas if is_w13 else self.quant_config.g2_alphas
186
+ ),
187
+ input_scale=input_scale,
188
+ outputs=outputs,
189
+ locks=self.locks,
190
+ **kwargs,
191
+ )
192
+
193
def _get_permute_scratch(self) -> MoEPermuteScratch | None:
194
if self._permute_scratch is None and moe_permute_unpermute_supported():
195
self._permute_scratch = MoEPermuteScratch(
@@ -218,8 +272,7 @@ class HummingExpertsBase(mk.FusedMoEExpertsModular):
272
@property
273
def expects_unquantized_inputs(self) -> bool:
274
"""
221
- Humming kernels handle input quantization internally via
222
- HummingMethod.may_quant_input() in the apply() method.
275
+ Humming kernels handle input quantization internally in apply().
276
277
This property tells the prepare/finalize step to skip input
278
quantization (by setting defer_input_quant=True) and pass
@@ -255,6 +308,10 @@ class HummingExpertsBase(mk.FusedMoEExpertsModular):
308
def _supports_parallel_config(moe_parallel_config: FusedMoEParallelConfig) -> bool:
309
return True
310
311
+ @staticmethod
312
+ def _supports_batch_invariance() -> bool:
313
+ return True
314
+
315
def moe_problem_size(
316
self,
317
a1: torch.Tensor,
@@ -262,10 +319,8 @@ class HummingExpertsBase(mk.FusedMoEExpertsModular):
319
w2: torch.Tensor,
320
topk_ids: torch.Tensor,
321
) -> tuple[int, int, int, int, int]:
265
- from vllm.utils.humming import HummingLayerMeta
266
-
267
- meta1: HummingLayerMeta = self.layer.humming_metas["w13"]
268
- meta2: HummingLayerMeta = self.layer.humming_metas["w2"]
322
+ meta1 = self.humming_configs["w13"]
323
+ meta2 = self.humming_configs["w2"]
324
325
assert meta1.num_experts == meta2.num_experts
326
@@ -282,25 +337,25 @@ class HummingExpertsBase(mk.FusedMoEExpertsModular):
337
assert a1.size(0) == num_experts
338
num_tokens = a1.size(1)
339
285
- return (
286
- meta1.num_experts,
287
- num_tokens,
288
- # Logical intermediate width for both gated and non-gated activations
289
- self.layer.intermediate_size_per_partition,
290
- meta1.shape_k,
291
- top_k,
292
- )
340
+ intermediate_dim = meta2.shape_k - meta2.pad_shape_k
341
+ hidden_dim = meta1.shape_k - meta1.pad_shape_k
342
+ return meta1.num_experts, num_tokens, intermediate_dim, hidden_dim, top_k
343
344
def get_buffer_metas(self, M: int, topk: int, activation: MoEActivation):
345
from vllm.utils.humming import GemmType as HummingGemmType
346
from vllm.utils.humming import dtypes
347
348
num_experts = self.num_experts
299
- N = self.layer.intermediate_size_per_partition
300
- K = self.layer.hidden_size
349
+ w13_config = self.humming_configs["w13"]
350
+ w2_config = self.humming_configs["w2"]
351
+ gate_up_dim = w13_config.shape_n - w13_config.pad_shape_n
352
+ intermediate_dim = w2_config.shape_k - w2_config.pad_shape_k
353
+ K = w13_config.shape_k - w13_config.pad_shape_k
354
assert isinstance(num_experts, int)
302
- assert isinstance(N, int)
355
+ assert isinstance(gate_up_dim, int)
356
+ assert isinstance(intermediate_dim, int)
357
assert isinstance(K, int)
358
+ assert intermediate_dim == self.adjust_N_for_activation(gate_up_dim, activation)
359
360
# hidden_states
361
# (-> quanted_gate_up_input) (if not BF16/FP16 activation)
@@ -310,7 +365,8 @@ class HummingExpertsBase(mk.FusedMoEExpertsModular):
365
# -> down_output
366
# (-> output) (if not is_batched)
367
# Neighboring nodes are required to utilize distinct workspaces.
313
- # The output must be derived from workspace1.
368
+ # The final output buffer is supplied by the modular kernel and may
369
+ # alias workspace1.
370
371
output_shape: tuple[int, ...]
372
if self.is_batched():
@@ -327,10 +383,8 @@ class HummingExpertsBase(mk.FusedMoEExpertsModular):
383
real_shape_m = M * topk
384
output_shape = (M, K)
385
330
- gate_up_size = N * (2 if activation.is_gated else 1)
331
- down_input_size = N
332
- a_dtype = self.layer.humming_metas["w13"].a_dtype
333
- c_dtype = self.layer.humming_metas["w13"].c_dtype
386
+ a_dtype = self.humming_configs["w13"].a_dtype
387
+ c_dtype = self.humming_configs["w13"].c_dtype
388
num_bits = a_dtype.num_bits
389
torch_dtype_map = {
390
dtypes.float16: torch.float16,
@@ -348,15 +402,15 @@ class HummingExpertsBase(mk.FusedMoEExpertsModular):
402
"dtype": torch_dtype_map[a_dtype],
403
},
404
"gate_up_output": {
351
- "shape": (real_shape_m, gate_up_size),
405
+ "shape": (real_shape_m, gate_up_dim),
406
"dtype": torch_dtype_map[c_dtype],
407
},
408
"activation_output": {
355
- "shape": (real_shape_m, down_input_size),
409
+ "shape": (real_shape_m, intermediate_dim),
410
"dtype": torch_dtype_map[c_dtype],
411
},
412
"quanted_down_input": {
359
- "shape": (real_shape_m, down_input_size),
413
+ "shape": (real_shape_m, intermediate_dim),
414
"dtype": torch_dtype_map[a_dtype],
415
},
416
"down_output": {
@@ -414,7 +468,7 @@ class HummingExpertsBase(mk.FusedMoEExpertsModular):
468
469
output_key = "down_output" if self.is_batched() else "output"
470
output_shape = buffer_metas[output_key]["shape"]
417
- elem_size = self.layer.params_dtype.itemsize
471
+ elem_size = self.moe_config.in_dtype.itemsize
472
473
return (
474
(workspace1_nbytes // elem_size,),
@@ -438,7 +492,7 @@ class HummingExpertsBase(mk.FusedMoEExpertsModular):
492
def make_workspaces(self, M: int, topk: int, activation: MoEActivation):
493
shapes = self._workspace_shapes(M, topk, activation)
494
workspace1_shape, workspace2_shape, output_shape = shapes
441
- torch_dtype = self.layer.params_dtype
495
+ torch_dtype = self.moe_config.in_dtype
496
workspace1, workspace2 = current_workspace_manager().get_simultaneous(
497
(workspace1_shape, torch_dtype),
498
(workspace2_shape, torch_dtype),
@@ -600,12 +654,11 @@ class HummingIndexedExperts(HummingExpertsBase):
654
"""
655
Standard apply implementation for Humming indexed experts.
656
603
- Note: Humming kernels handle weights and quantization internally through
604
- the layer object, so w1, w2, a1q_scale, a2_scale parameters are not used.
605
- The output is written into workspace13 via the buffer management.
657
+ Humming performs activation quantization internally and consumes the
658
+ weights supplied by the modular kernel interface.
659
+ Results are written to the output buffer supplied by the modular
660
+ kernel, which may alias workspace13.
661
"""
607
- from vllm.utils.humming import HummingMethod
608
-
662
assert not apply_router_weight_on_input
663
664
hidden_states = hidden_states.view(-1, hidden_states.size(-1))
@@ -616,6 +669,7 @@ class HummingIndexedExperts(HummingExpertsBase):
669
topk_ids.size(1),
670
activation,
671
)
672
+ buffers["output"] = output
673
674
moe_kwargs1, moe_kwargs2 = self.prepare_humming_moe_kwargs(
675
topk_ids=topk_ids,
@@ -623,19 +677,18 @@ class HummingIndexedExperts(HummingExpertsBase):
677
expert_tokens_meta=expert_tokens_meta,
678
)
679
626
- inputs, input_scale = HummingMethod.may_quant_input(
627
- layer=self.layer,
680
+ inputs, input_scale = self.quantize_input(
681
+ "w13",
682
inputs=hidden_states,
683
quanted_input=buffers.get("quanted_gate_up_input", None),
630
- sublayer_name="w13",
684
)
685
633
- HummingMethod.forward_layer(
634
- layer=self.layer,
686
+ self.humming_forward(
687
+ "w13",
688
inputs=inputs,
689
+ weight=w1,
690
input_scale=input_scale,
691
outputs=buffers["gate_up_output"],
638
- sublayer_name="w13",
692
**moe_kwargs1,
693
)
694
@@ -645,19 +698,18 @@ class HummingIndexedExperts(HummingExpertsBase):
698
output=buffers["activation_output"],
699
)
700
648
- inputs, input_scale = HummingMethod.may_quant_input(
649
- layer=self.layer,
701
+ inputs, input_scale = self.quantize_input(
702
+ "w2",
703
inputs=buffers["activation_output"],
704
quanted_input=buffers.get("quanted_down_input", None),
652
- sublayer_name="w2",
705
)
706
655
- HummingMethod.forward_layer(
656
- layer=self.layer,
707
+ self.humming_forward(
708
+ "w2",
709
inputs=inputs,
710
+ weight=w2,
711
input_scale=input_scale,
712
outputs=buffers["down_output"].view(-1, hidden_states.size(-1)),
660
- sublayer_name="w2",
713
**moe_kwargs2,
714
)
715
@@ -705,12 +757,11 @@ class HummingGroupedExperts(HummingExpertsBase):
757
"""
758
Standard apply implementation for Humming grouped experts.
759
708
- Note: Humming kernels handle weights and quantization internally through
709
- the layer object, so w1, w2, a1q_scale, a2_scale parameters are not used.
710
- The output is written into workspace13 via the buffer management.
760
+ Humming performs activation quantization internally and consumes the
761
+ weights supplied by the modular kernel interface.
762
+ Results are written to the output buffer supplied by the modular
763
+ kernel, which may alias workspace13.
764
"""
712
- from vllm.utils.humming import HummingMethod
713
-
765
assert not apply_router_weight_on_input
766
767
valid_shape_m = self.estimate_local_valid_shape_m(topk_ids)
@@ -722,6 +773,7 @@ class HummingGroupedExperts(HummingExpertsBase):
773
topk_ids.size(1),
774
activation,
775
)
776
+ buffers["output"] = output
777
778
hidden_states, _, expert_first_token_offset, inv_perm, _ = moe_permute(
779
hidden_states=hidden_states,
@@ -733,23 +785,22 @@ class HummingGroupedExperts(HummingExpertsBase):
785
scratch=self._get_permute_scratch(),
786
)
787
736
- inputs, input_scale = HummingMethod.may_quant_input(
737
- layer=self.layer,
788
+ inputs, input_scale = self.quantize_input(
789
+ "w13",
790
inputs=hidden_states,
791
quanted_input=buffers.get("quanted_gate_up_input", None),
740
- sublayer_name="w13",
792
)
793
743
- HummingMethod.forward_layer(
744
- layer=self.layer,
794
+ self.humming_forward(
795
+ "w13",
796
inputs=inputs,
797
+ weight=w1,
798
input_scale=input_scale,
799
outputs=buffers["gate_up_output"],
800
valid_shape_m=valid_shape_m,
801
expert_layout=expert_first_token_offset,
802
compute_config=self.compute_config_str,
803
tuning_config=self.w13_tuning_config_str,
752
- sublayer_name="w13",
804
)
805
806
self.apply_activation(
@@ -758,23 +809,22 @@ class HummingGroupedExperts(HummingExpertsBase):
809
output=buffers["activation_output"],
810
)
811
761
- inputs, input_scale = HummingMethod.may_quant_input(
762
- layer=self.layer,
812
+ inputs, input_scale = self.quantize_input(
813
+ "w2",
814
inputs=buffers["activation_output"],
815
quanted_input=buffers.get("quanted_down_input", None),
765
- sublayer_name="w2",
816
)
817
768
- HummingMethod.forward_layer(
769
- layer=self.layer,
818
+ self.humming_forward(
819
+ "w2",
820
inputs=inputs,
821
+ weight=w2,
822
input_scale=input_scale,
823
outputs=buffers["down_output"],
824
valid_shape_m=valid_shape_m,
825
expert_layout=expert_first_token_offset,
826
compute_config=self.compute_config_str,
827
tuning_config=self.w2_tuning_config_str,
777
- sublayer_name="w2",
828
)
829
830
moe_unpermute(
@@ -821,12 +871,11 @@ class BatchedHummingGroupedExperts(HummingExpertsBase):
871
"""
872
Standard apply implementation for Humming batched grouped experts.
873
824
- Note: Humming kernels handle weights and quantization internally through
825
- the layer object, so w1, w2, a1q_scale, a2_scale parameters are not used.
826
- The output is written into workspace13 via the buffer management.
874
+ Humming performs activation quantization internally and consumes the
875
+ weights supplied by the modular kernel interface.
876
+ Results are written to the output buffer supplied by the modular
877
+ kernel, which may alias workspace13.
878
"""
828
- from vllm.utils.humming import HummingMethod
829
-
879
assert not apply_router_weight_on_input
880
assert expert_tokens_meta is not None
881
@@ -841,24 +890,24 @@ class BatchedHummingGroupedExperts(HummingExpertsBase):
890
topk_ids.size(1),
891
activation,
892
)
893
+ buffers["down_output"] = output
894
845
- inputs, input_scale = HummingMethod.may_quant_input(
846
- layer=self.layer,
895
+ inputs, input_scale = self.quantize_input(
896
+ "w13",
897
inputs=hidden_states,
898
quanted_input=buffers.get("quanted_gate_up_input", None),
849
- sublayer_name="w13",
899
)
900
852
- HummingMethod.forward_layer(
853
- layer=self.layer,
901
+ self.humming_forward(
902
+ "w13",
903
inputs=inputs,
904
+ weight=w1,
905
input_scale=input_scale,
906
outputs=buffers["gate_up_output"],
907
valid_shape_m=valid_shape_m,
908
expert_layout=expert_num_tokens,
909
compute_config=self.compute_config_str,
910
tuning_config=self.w13_tuning_config_str,
861
- sublayer_name="w13",
911
)
912
913
self.apply_activation(
@@ -867,21 +916,20 @@ class BatchedHummingGroupedExperts(HummingExpertsBase):
916
output=buffers["activation_output"],
917
)
918
870
- inputs, input_scale = HummingMethod.may_quant_input(
871
- layer=self.layer,
919
+ inputs, input_scale = self.quantize_input(
920
+ "w2",
921
inputs=buffers["activation_output"],
922
quanted_input=buffers.get("quanted_down_input", None),
874
- sublayer_name="w2",
923
)
924
877
- HummingMethod.forward_layer(
878
- layer=self.layer,
925
+ self.humming_forward(
926
+ "w2",
927
inputs=inputs,
928
+ weight=w2,
929
input_scale=input_scale,
930
outputs=output.view(-1, hidden_states.size(-1)),
931
valid_shape_m=valid_shape_m,
932
expert_layout=expert_num_tokens,
933
compute_config=self.compute_config_str,
934
tuning_config=self.w2_tuning_config_str,
886
- sublayer_name="w2",
935
)
vllm/model_executor/layers/fused_moe/oracle/fp8.py
+6
-9
@@ -619,7 +619,12 @@ def make_fp8_moe_quant_config(
619
)
620
621
assert isinstance(layer, RoutedExperts)
622
- return get_humming_moe_quant_config(layer)
622
+ return get_humming_moe_quant_config(
623
+ layer,
624
+ gemm1_alpha=gemm1_alpha,
625
+ gemm1_beta=gemm1_beta,
626
+ gemm1_clamp_limit=swiglu_limit,
627
+ )
628
629
# Flashinfer CUTLASS or HPC per-tensor uses single dq scale
630
# (alpha = w_scale * a_scale) and inverse a2 scale.
@@ -694,7 +699,6 @@ def make_fp8_moe_kernel(
699
experts_cls: type[mk.FusedMoEExperts],
700
fp8_backend: Fp8MoeBackend,
701
routing_tables: tuple[torch.Tensor, torch.Tensor, torch.Tensor] | None = None,
697
- layer: torch.nn.Module | None = None,
702
) -> mk.FusedMoEKernel:
703
# Create Prepare/Finalize.
704
prepare_finalize = maybe_make_prepare_finalize(
@@ -708,11 +712,6 @@ def make_fp8_moe_kernel(
712
713
logger.info_once("Using %s", prepare_finalize.__class__.__name__)
714
711
- extra_kwargs = {}
712
- if fp8_backend == Fp8MoeBackend.HUMMING:
713
- assert layer is not None
714
- extra_kwargs = {"layer": layer}
715
-
715
# Create Experts.
716
if prepare_finalize.activation_format == mk.FusedMoEActivationFormat.BatchedExperts:
717
max_num_tokens = prepare_finalize.max_num_tokens_per_rank()
@@ -722,13 +721,11 @@ def make_fp8_moe_kernel(
721
quant_config=moe_quant_config,
722
max_num_tokens=max_num_tokens,
723
num_dispatchers=prepare_finalize.num_dispatchers(),
725
- **extra_kwargs,
724
)
725
else:
726
experts = experts_cls(
727
moe_config=moe_config,
728
quant_config=moe_quant_config,
731
- **extra_kwargs,
729
)
730
731
kernel = mk.FusedMoEKernel(
vllm/model_executor/layers/fused_moe/oracle/int8.py
+9
-12
@@ -195,7 +195,12 @@ def make_int8_moe_quant_config(
195
)
196
197
assert isinstance(layer, RoutedExperts)
198
- return get_humming_moe_quant_config(layer)
198
+ return get_humming_moe_quant_config(
199
+ layer,
200
+ gemm1_alpha=getattr(layer, "swiglu_alpha", None),
201
+ gemm1_beta=getattr(layer, "swiglu_beta", None),
202
+ gemm1_clamp_limit=getattr(layer, "swiglu_limit", None),
203
+ )
204
205
if scales_absent and not per_act_token_quant:
206
return int8_w8a16_moe_quant_config(
@@ -251,9 +256,9 @@ def convert_to_int8_moe_kernel_format(
256
)
257
258
assert layer is not None
254
- # Humming reads canonical CT scales (w*_weight_scale) from the layer.
255
- # Online int8 produces per-channel (E, N) w*_scale; expose them as the
256
- # (E, N, 1) w*_weight_scale humming's loader expects.
259
+ # The Humming conversion expects canonical CT scale parameter names.
260
+ # Online int8 produces per-channel (E, N) w*_scale; expose them as
261
+ # (E, N, 1) w*_weight_scale tensors before conversion.
262
for sub in ("w13", "w2"):
263
if hasattr(layer, f"{sub}_weight_scale"):
264
continue
@@ -279,7 +284,6 @@ def make_int8_moe_kernel(
284
moe_config: FusedMoEConfig,
285
experts_cls: type[mk.FusedMoEExperts],
286
routing_tables: tuple[torch.Tensor, torch.Tensor, torch.Tensor] | None = None,
282
- layer: torch.nn.Module | None = None,
287
) -> mk.FusedMoEKernel:
288
# Create Prepare/Finalize.
289
prepare_finalize = maybe_make_prepare_finalize(
@@ -293,11 +297,6 @@ def make_int8_moe_kernel(
297
298
logger.info_once("Using %s", prepare_finalize.__class__.__name__)
299
296
- extra_kwargs = {}
297
- if int8_backend == Int8MoeBackend.HUMMING:
298
- assert layer is not None
299
- extra_kwargs = {"layer": layer}
300
-
300
# Create Experts.
301
if prepare_finalize.activation_format == mk.FusedMoEActivationFormat.BatchedExperts:
302
max_num_tokens = prepare_finalize.max_num_tokens_per_rank()
@@ -307,13 +306,11 @@ def make_int8_moe_kernel(
306
quant_config=moe_quant_config,
307
max_num_tokens=max_num_tokens,
308
num_dispatchers=prepare_finalize.num_dispatchers(),
310
- **extra_kwargs,
309
)
310
else:
311
experts = experts_cls(
312
moe_config=moe_config,
313
quant_config=moe_quant_config,
316
- **extra_kwargs,
314
)
315
316
kernel = mk.FusedMoEKernel(
vllm/model_executor/layers/fused_moe/oracle/int_wna16.py
+1
-5
@@ -358,7 +358,6 @@ def make_wna16_moe_kernel(
358
moe_config: FusedMoEConfig,
359
experts_cls: type[mk.FusedMoEExperts],
360
backend: WNA16MoEBackend = WNA16MoEBackend.MARLIN,
361
- layer: torch.nn.Module | None = None,
361
is_k_full: bool = False,
362
w13_g_idx: torch.Tensor | None = None,
363
w2_g_idx: torch.Tensor | None = None,
@@ -410,10 +409,7 @@ def make_wna16_moe_kernel(
409
logger.info_once("Using %s", experts_cls.__name__, scope="local")
410
411
extra_args: dict[str, Any] = {}
413
- if backend == WNA16MoEBackend.HUMMING:
414
- assert layer is not None
415
- extra_args = {"layer": layer}
416
- elif issubclass(experts_cls, MarlinExpertsBase):
412
+ if issubclass(experts_cls, MarlinExpertsBase):
413
extra_args = {
414
"w13_g_idx": w13_g_idx,
415
"w2_g_idx": w2_g_idx,
vllm/model_executor/layers/fused_moe/oracle/mxfp4.py
-8
@@ -1788,7 +1788,6 @@ def make_mxfp4_moe_kernel(
1788
experts_cls: type[mk.FusedMoEExperts],
1789
mxfp4_backend: Mxfp4MoeBackend,
1790
routing_tables: tuple[torch.Tensor, torch.Tensor, torch.Tensor] | None = None,
1791
- layer: RoutedExperts | None = None,
1791
) -> mk.FusedMoEKernel:
1792
"""Create a FusedMoEKernel for the given MXFP4 backend."""
1793
is_monolithic = issubclass(experts_cls, mk.FusedMoEExpertsMonolithic)
@@ -1805,11 +1804,6 @@ def make_mxfp4_moe_kernel(
1804
logger.info_once("Using %s", prepare_finalize.__class__.__name__)
1805
logger.info_once("Using %s", experts_cls.__name__)
1806
1808
- extra_kwargs = {}
1809
- if mxfp4_backend == Mxfp4MoeBackend.HUMMING:
1810
- assert layer is not None
1811
- extra_kwargs["layer"] = layer
1812
-
1807
# Create Experts.
1808
if prepare_finalize.activation_format == mk.FusedMoEActivationFormat.BatchedExperts:
1809
max_num_tokens = prepare_finalize.max_num_tokens_per_rank()
@@ -1819,13 +1813,11 @@ def make_mxfp4_moe_kernel(
1813
quant_config=moe_quant_config,
1814
max_num_tokens=max_num_tokens,
1815
num_dispatchers=prepare_finalize.num_dispatchers(),
1822
- **extra_kwargs,
1816
)
1817
else:
1818
experts = experts_cls(
1819
moe_config=moe_config,
1820
quant_config=moe_quant_config,
1828
- **extra_kwargs,
1821
)
1822
1823
kernel = mk.FusedMoEKernel(
vllm/model_executor/layers/fused_moe/oracle/nvfp4.py
+8
-7
@@ -398,10 +398,10 @@ def convert_to_nvfp4_moe_kernel_format(
398
a2_scale = None
399
w13 = layer.w13_weight
400
w13_scale = layer.w13_weight_scale
401
- w13_scale_2 = getattr(layer, "w13_global_scale", None)
401
+ w13_scale_2 = getattr(layer, "w13_weight_scale_2", None)
402
w2 = layer.w2_weight
403
w2_scale = layer.w2_weight_scale
404
- w2_scale_2 = getattr(layer, "w2_global_scale", None)
404
+ w2_scale_2 = getattr(layer, "w2_weight_scale_2", None)
405
elif nvfp4_backend == NvFp4MoeBackend.MARLIN:
406
a13_scale = None
407
a2_scale = None
@@ -485,7 +485,12 @@ def make_nvfp4_moe_quant_config(
485
)
486
487
assert isinstance(layer, RoutedExperts)
488
- return get_humming_moe_quant_config(layer)
488
+ return get_humming_moe_quant_config(
489
+ layer,
490
+ gemm1_alpha=getattr(layer, "swiglu_alpha", None),
491
+ gemm1_beta=getattr(layer, "swiglu_beta", None),
492
+ gemm1_clamp_limit=swiglu_limit,
493
+ )
494
elif backend == NvFp4MoeBackend.MARLIN:
495
return nvfp4_w4a16_moe_quant_config(
496
g1_alphas=w13_scale_2,
@@ -544,7 +549,6 @@ def make_nvfp4_moe_kernel(
549
experts_cls: type[mk.FusedMoEExperts],
550
backend: NvFp4MoeBackend,
551
routing_tables: tuple[torch.Tensor, torch.Tensor, torch.Tensor] | None = None,
547
- layer: torch.nn.Module | None = None,
552
per_token_activation: bool = False,
553
) -> mk.FusedMoEKernel:
554
# Create Prepare/Finalize.
@@ -560,9 +564,6 @@ def make_nvfp4_moe_kernel(
564
logger.info_once("Using %s", prepare_finalize.__class__.__name__)
565
566
extra_kwargs = {}
563
- if backend == NvFp4MoeBackend.HUMMING:
564
- assert layer is not None
565
- extra_kwargs = {"layer": layer}
567
if backend == NvFp4MoeBackend.FLASHINFER_TRTLLM and per_token_activation:
568
extra_kwargs["per_token_activation"] = True
569
vllm/model_executor/layers/quantization/auto_awq.py
+6
-2
@@ -751,7 +751,6 @@ class AutoAWQMoEMethod(FusedMoEMethodBase):
751
moe_config=self.moe,
752
experts_cls=self.experts_cls,
753
backend=self.wna16_moe_backend,
754
- layer=layer,
754
is_k_full=self.is_k_full,
755
w13_g_idx=getattr(layer, "w13_g_idx", None),
756
w2_g_idx=getattr(layer, "w2_g_idx", None),
@@ -766,7 +765,12 @@ class AutoAWQMoEMethod(FusedMoEMethodBase):
765
get_humming_moe_quant_config,
766
)
767
769
- return get_humming_moe_quant_config(layer)
768
+ return get_humming_moe_quant_config(
769
+ layer,
770
+ gemm1_alpha=getattr(layer, "swiglu_alpha", None),
771
+ gemm1_beta=getattr(layer, "swiglu_beta", None),
772
+ gemm1_clamp_limit=getattr(layer, "swiglu_limit", None),
773
+ )
774
return make_wna16_moe_quant_config(
775
w1_scale=layer.w13_scales,
776
w2_scale=layer.w2_scales,
vllm/model_executor/layers/quantization/auto_gptq.py
+6
-2
@@ -772,7 +772,6 @@ class AutoGPTQMoEMethod(FusedMoEMethodBase):
772
moe_config=self.moe,
773
experts_cls=self.experts_cls,
774
backend=self.wna16_moe_backend,
775
- layer=layer,
775
is_k_full=self.is_k_full,
776
w13_g_idx=getattr(layer, "w13_g_idx", None),
777
w2_g_idx=getattr(layer, "w2_g_idx", None),
@@ -787,7 +786,12 @@ class AutoGPTQMoEMethod(FusedMoEMethodBase):
786
get_humming_moe_quant_config,
787
)
788
790
- return get_humming_moe_quant_config(layer)
789
+ return get_humming_moe_quant_config(
790
+ layer,
791
+ gemm1_alpha=getattr(layer, "swiglu_alpha", None),
792
+ gemm1_beta=getattr(layer, "swiglu_beta", None),
793
+ gemm1_clamp_limit=getattr(layer, "swiglu_limit", None),
794
+ )
795
796
from vllm.model_executor.layers.fused_moe.config import (
797
gptq_marlin_moe_quant_config,
vllm/model_executor/layers/quantization/compressed_tensors/compressed_tensors_moe/compressed_tensors_moe_w4a4_nvfp4.py
-1
@@ -251,7 +251,6 @@ class CompressedTensorsW4A4Nvfp4MoEMethod(CompressedTensorsMoEMethod):
251
experts_cls=self.experts_cls,
252
backend=self.nvfp4_backend,
253
routing_tables=layer._expert_routing_tables(),
254
- layer=layer,
254
)
255
self.moe_kernel.fused_experts.process_weights_after_loading(layer)
256
vllm/model_executor/layers/quantization/compressed_tensors/compressed_tensors_moe/compressed_tensors_moe_w8a8_fp8.py
-1
@@ -339,7 +339,6 @@ class CompressedTensorsW8A8Fp8MoEMethod(CompressedTensorsMoEMethod):
339
fp8_backend=self.fp8_backend,
340
experts_cls=self.experts_cls,
341
routing_tables=layer._expert_routing_tables(),
342
- layer=layer,
342
)
343
344
def get_fused_moe_quant_config(self, layer: torch.nn.Module) -> FusedMoEQuantConfig:
vllm/model_executor/layers/quantization/compressed_tensors/compressed_tensors_moe/compressed_tensors_moe_w8a8_int8.py
-1
@@ -159,7 +159,6 @@ class CompressedTensorsW8A8Int8MoEMethod(CompressedTensorsMoEMethod):
159
moe_config=self.moe,
160
experts_cls=self.experts_cls,
161
routing_tables=layer._expert_routing_tables(),
162
- layer=layer,
162
)
163
self.moe_kernel.fused_experts.process_weights_after_loading(layer)
164
vllm/model_executor/layers/quantization/compressed_tensors/compressed_tensors_moe/compressed_tensors_moe_w8a8_mxfp8.py
-1
@@ -139,7 +139,6 @@ class CompressedTensorsW8A8Mxfp8MoEMethod(CompressedTensorsMoEMethod):
139
fp8_backend=self.fp8_backend,
140
experts_cls=self.experts_cls,
141
routing_tables=layer._expert_routing_tables(),
142
- layer=layer,
142
)
143
144
def get_fused_moe_quant_config(
vllm/model_executor/layers/quantization/fp8.py
-1
@@ -679,7 +679,6 @@ class Fp8MoEMethod(FusedMoEMethodBase):
679
fp8_backend=self.fp8_backend,
680
experts_cls=self.experts_cls,
681
routing_tables=layer._expert_routing_tables(),
682
- layer=layer,
682
)
683
684
def process_weights_after_loading(self, layer: RoutedExperts) -> None:
vllm/model_executor/layers/quantization/humming.py
+36
-37
@@ -1,6 +1,5 @@
1
# SPDX-License-Identifier: Apache-2.0
2
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-import json
3
import math
4
from collections.abc import Callable
5
from typing import TYPE_CHECKING, Any
@@ -32,6 +31,7 @@ from vllm.model_executor.layers.quantization.base_config import (
31
)
32
from vllm.model_executor.layers.quantization.utils.humming_utils import (
33
convert_to_humming_moe_kernel_format,
34
+ get_humming_linear_compute_config,
35
get_humming_moe_quant_config,
36
input_schema_to_quant_key,
37
make_humming_moe_kernel,
@@ -425,7 +425,6 @@ class HummingLinearMethod(LinearMethodBase):
425
for name, _ in list(layer.named_parameters()):
426
if name != "bias":
427
delattr(layer, name)
428
- delattr(layer, "locks")
428
self.__class__ = UnquantizedLinearMethod # type: ignore
429
tensor = torch.empty(
430
(
@@ -513,9 +512,6 @@ class HummingLinearMethod(LinearMethodBase):
512
param = prepare_param(tensor, name, extra_attrs)
513
setattr(layer, name, param)
514
516
- locks = torch.zeros(1024, dtype=torch.int32)
517
- layer.register_buffer("locks", locks)
518
-
515
if self.force_input_schema is not None:
516
self.input_schema = self.force_input_schema
517
@@ -574,9 +570,7 @@ class HummingLinearMethod(LinearMethodBase):
570
571
del tensors
572
577
- # prepare layer config from humming kernel
578
- _hm.HummingMethod.prepare_layer_meta(
579
- layer=layer,
573
+ self.layer_config = _hm.prepare_layer_config(
574
shape_n=layer.output_partition_sizes_sum,
575
shape_k=layer.input_size_per_partition,
576
weight_schema=self.weight_schema,
@@ -586,19 +580,17 @@ class HummingLinearMethod(LinearMethodBase):
580
has_bias=layer.has_bias,
581
torch_dtype=layer.param_dtype,
582
)
583
+ tensors = _hm.transform_humming_tensors(
584
+ self.layer_config, dict(layer.named_parameters())
585
+ )
586
+ for name, _ in list(layer.named_parameters()):
587
+ delattr(layer, name)
588
+ for name, tensor in tensors.items():
589
+ param = torch.nn.Parameter(tensor, requires_grad=False)
590
+ setattr(layer, name, param)
591
590
- # preprocess weight for inference
591
- _hm.HummingMethod.transform_humming_layer(layer)
592
-
593
- # compute_config: kernel configs that do not directly affect weights
594
- # but significantly impact kernel behavior or computation precision.
595
- # see https://github.com/inclusionAI/humming/blob/main/docs/config.md
596
- compute_config = {
597
- "use_batch_invariant": envs.VLLM_BATCH_INVARIANT,
598
- "use_f16_accum": envs.VLLM_HUMMING_USE_F16_ACCUM,
599
- "gemm_type": "dense",
600
- }
601
- self.compute_config = json.dumps(compute_config)
592
+ self.compute_config = get_humming_linear_compute_config()
593
+ self.locks = torch.zeros(1024, dtype=torch.int32, device=layer.weight.device)
594
595
def apply(
596
self,
@@ -606,10 +598,16 @@ class HummingLinearMethod(LinearMethodBase):
598
x: torch.Tensor,
599
bias: torch.Tensor | None = None,
600
) -> torch.Tensor:
609
- flatten_inputs = x.view(-1, x.size(-1))
610
- output = _hm.HummingMethod.forward_layer(
611
- layer=layer,
601
+ flatten_inputs = x.reshape(-1, x.size(-1))
602
+ output = _hm.humming_forward(
603
+ self.layer_config,
604
inputs=flatten_inputs,
605
+ weight=layer.weight,
606
+ weight_scale=getattr(layer, "weight_scale", None),
607
+ zero_point=getattr(layer, "zero_point", None),
608
+ bias=getattr(layer, "bias", None),
609
+ weight_scale_2=getattr(layer, "weight_scale_2", None),
610
+ locks=self.locks,
611
compute_config=self.compute_config,
612
)
613
output = output.view(*x.shape[:-1], output.size(-1))
@@ -726,12 +724,13 @@ class HummingMoEMethod(FusedMoEMethodBase):
724
# sublayer: a layer contains multiple sets of weights for quantized GEMM
725
# (e.g., weight, weight_scale, etc.).
726
# The weight names of sublayer start with the prefix "{sublayer_name}_"
727
+ w13_output_size = intermediate_size_per_partition * self.moe.w13_num_shards
728
layer.sublayer_configs = {
729
"w13": {
731
- "shape_n": intermediate_size_per_partition * self.moe.w13_num_shards,
730
+ "shape_n": w13_output_size,
731
"shape_k": hidden_size,
732
"tensors_attrs": self.weight_schema.get_padded_tensors_attrs(
734
- shape_n=intermediate_size_per_partition * self.moe.w13_num_shards,
733
+ shape_n=w13_output_size,
734
shape_k=hidden_size,
735
num_experts=num_experts,
736
param_dtype=params_dtype,
@@ -763,11 +762,14 @@ class HummingMoEMethod(FusedMoEMethodBase):
762
if self.force_input_schema is not None:
763
self.input_schema = self.force_input_schema
764
766
- locks = torch.zeros(1024, dtype=torch.int32)
767
- layer.register_buffer("locks", locks)
768
-
765
def get_fused_moe_quant_config(self, layer: RoutedExperts) -> FusedMoEQuantConfig:
770
- return get_humming_moe_quant_config(layer)
766
+ return get_humming_moe_quant_config(
767
+ layer,
768
+ self.humming_configs,
769
+ gemm1_alpha=getattr(layer, "swiglu_alpha", None),
770
+ gemm1_beta=getattr(layer, "swiglu_beta", None),
771
+ gemm1_clamp_limit=getattr(layer, "swiglu_limit", None),
772
+ )
773
774
def process_weights_after_loading(self, layer: RoutedExperts) -> None:
775
if getattr(self, "processed", False):
@@ -775,7 +777,7 @@ class HummingMoEMethod(FusedMoEMethodBase):
777
self.processed = True
778
779
# Convert weights to Humming kernel format
778
- convert_to_humming_moe_kernel_format(
780
+ self.humming_configs = convert_to_humming_moe_kernel_format(
781
layer=layer,
782
sublayer_configs=layer.sublayer_configs,
783
weight_schema=self.weight_schema,
@@ -791,7 +793,6 @@ class HummingMoEMethod(FusedMoEMethodBase):
793
self.moe_quant_config,
794
self.moe,
795
self.experts_cls,
794
- layer=layer,
796
routing_tables=layer._expert_routing_tables(),
797
)
798
@@ -814,13 +815,11 @@ class HummingMoEMethod(FusedMoEMethodBase):
815
3. Finalization (weight application & reduction - no-op for Humming
816
since it's already done internally)
817
817
- Humming handles all quantization, weight application, and reduction
818
- internally in the experts.apply() method via HummingMethod calls.
818
+ Humming handles quantization, weight application, and reduction
819
+ internally in the experts implementation.
820
820
- Note: Although w1/w2 weights are passed to the kernel for interface
821
- consistency, Humming's experts.apply() reads weights directly from
822
- the layer object via HummingMethod.forward_layer() and ignores the
823
- w1/w2 parameters.
821
+ Humming experts consume the weights and quantization tensors passed
822
+ through the standard modular kernel interface.
823
"""
824
assert self.moe_kernel is not None
825
return self.moe_kernel.apply(
vllm/model_executor/layers/quantization/modelopt.py
-3
@@ -886,7 +886,6 @@ class ModelOptFp8MoEMethod(FusedMoEMethodBase):
886
fp8_backend=self.fp8_backend,
887
experts_cls=self.experts_cls,
888
routing_tables=layer._expert_routing_tables(),
889
- layer=layer,
889
)
890
891
def process_weights_after_loading(self, layer: RoutedExperts) -> None:
@@ -1579,7 +1578,6 @@ class ModelOptNvFp4FusedMoE(FusedMoEMethodBase):
1578
experts_cls=self.experts_cls,
1579
backend=self.nvfp4_backend,
1580
routing_tables=layer._expert_routing_tables(),
1582
- layer=layer,
1581
)
1582
self.moe_kernel.fused_experts.process_weights_after_loading(layer)
1583
@@ -2058,7 +2056,6 @@ class ModelOptMxFp8FusedMoE(FusedMoEMethodBase):
2056
fp8_backend=self.mxfp8_backend,
2057
experts_cls=self.experts_cls,
2058
routing_tables=layer._expert_routing_tables(),
2061
- layer=layer,
2059
)
2060
2061
# No native MXFP8 MoE kernel on this device (e.g. gfx942): the emulation
vllm/model_executor/layers/quantization/moe_wna16.py
+6
-2
@@ -370,7 +370,12 @@ class MoeWNA16Method(FusedMoEMethodBase):
370
get_humming_moe_quant_config,
371
)
372
373
- return get_humming_moe_quant_config(layer)
373
+ return get_humming_moe_quant_config(
374
+ layer,
375
+ gemm1_alpha=getattr(layer, "swiglu_alpha", None),
376
+ gemm1_beta=getattr(layer, "swiglu_beta", None),
377
+ gemm1_clamp_limit=getattr(layer, "swiglu_limit", None),
378
+ )
379
380
has_zp = self.quant_config.has_zp
381
return make_wna16_moe_quant_config(
@@ -391,7 +396,6 @@ class MoeWNA16Method(FusedMoEMethodBase):
396
moe_config=self.moe,
397
experts_cls=self.experts_cls,
398
backend=self.wna16_backend,
394
- layer=layer,
399
routing_tables=layer._expert_routing_tables(),
400
)
401
vllm/model_executor/layers/quantization/mxfp4.py
-2
@@ -382,7 +382,6 @@ class GptOssMxfp4MoEMethod(FusedMoEMethodBase):
382
mxfp4_backend=self.mxfp4_backend,
383
experts_cls=self.experts_cls,
384
routing_tables=layer._expert_routing_tables(),
385
- layer=layer,
385
)
386
387
def process_weights_after_loading(self, layer: RoutedExperts) -> None:
@@ -773,7 +772,6 @@ class Mxfp4MoEMethod(FusedMoEMethodBase):
772
mxfp4_backend=self.mxfp4_backend,
773
experts_cls=self.experts_cls,
774
routing_tables=layer._expert_routing_tables(),
776
- layer=layer,
775
)
776
777
def _convert_k3_situ_weight_to_kernel_format(
vllm/model_executor/layers/quantization/online/fp8.py
-1
@@ -516,7 +516,6 @@ class _Fp8OnlineMoEBase(OnlineMoEMethodBase):
516
fp8_backend=self.fp8_backend,
517
experts_cls=self.experts_cls,
518
routing_tables=layer._expert_routing_tables(),
519
- layer=layer,
519
)
520
521
def get_fused_moe_quant_config(
vllm/model_executor/layers/quantization/online/int8.py
-1
@@ -117,7 +117,6 @@ class Int8OnlineMoEMethod(OnlineMoEMethodBase):
117
moe_config=self.moe,
118
experts_cls=self.experts_cls,
119
routing_tables=layer._expert_routing_tables(),
120
- layer=layer,
120
)
121
self.moe_kernel.fused_experts.process_weights_after_loading(layer)
122
vllm/model_executor/layers/quantization/online/mxfp8.py
-1
@@ -200,7 +200,6 @@ class Mxfp8OnlineMoEMethod(OnlineMoEMethodBase):
200
fp8_backend=self.fp8_backend,
201
experts_cls=self.experts_cls,
202
routing_tables=layer._expert_routing_tables(),
203
- layer=layer,
203
)
204
205
def get_fused_moe_quant_config(
vllm/model_executor/layers/quantization/online/nvfp4.py
-1
@@ -172,7 +172,6 @@ class Nvfp4OnlineMoEMethod(OnlineMoEMethodBase):
172
experts_cls=self.experts_cls,
173
backend=self.nvfp4_backend,
174
routing_tables=layer._expert_routing_tables(),
175
- layer=layer,
175
per_token_activation=True,
176
)
177
self.moe_kernel.fused_experts.process_weights_after_loading(layer)
vllm/model_executor/layers/quantization/quark/quark_moe.py
-2
@@ -804,7 +804,6 @@ class QuarkW8A8Int8MoEMethod(QuarkMoEMethod):
804
moe_config=self.moe,
805
experts_cls=self.experts_cls,
806
routing_tables=layer._expert_routing_tables(),
807
- layer=layer,
807
)
808
809
def get_fused_moe_quant_config(
@@ -1646,7 +1645,6 @@ class QuarkNvfp4MoEMethod(QuarkMoEMethod):
1645
experts_cls=self.experts_cls,
1646
backend=self.nvfp4_backend,
1647
routing_tables=layer._expert_routing_tables(),
1649
- layer=layer,
1648
)
1649
1650
def get_fused_moe_quant_config(
vllm/model_executor/layers/quantization/utils/humming_utils.py
+106
-67
@@ -1,6 +1,7 @@
1
# SPDX-License-Identifier: Apache-2.0
2
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
import json
4
+from dataclasses import dataclass
5
from typing import TYPE_CHECKING, Any
6
7
import regex as re
@@ -47,11 +48,19 @@ if TYPE_CHECKING:
48
GPTQWeightSchema,
49
HummingInputSchema,
50
HummingWeightSchema,
51
+ LayerConfig,
52
)
53
from vllm.utils.humming import dtypes as humming_dtypes
54
55
logger = init_logger(__name__)
56
57
+
58
+@dataclass(kw_only=True)
59
+class HummingMoEQuantConfig(FusedMoEQuantConfig):
60
+ w1_humming_config: "LayerConfig"
61
+ w2_humming_config: "LayerConfig"
62
+
63
+
64
if has_humming():
65
from vllm.utils.humming import dtypes as humming_dtypes
66
@@ -435,16 +444,17 @@ def convert_linear_layer_to_humming_standard(
444
setattr(layer, name, param)
445
446
438
-def prepare_humming_layer(
447
+def prepare_humming_linear_layer_config(
448
layer: LinearBase,
449
quant_config: dict,
450
input_quant_config: dict | None = None,
442
-):
451
+) -> "LayerConfig":
452
from vllm.utils.humming import (
453
BaseInputSchema,
454
BaseWeightSchema,
455
HummingInputSchema,
447
- HummingMethod,
456
+ prepare_layer_config,
457
+ transform_humming_tensors,
458
)
459
460
weight_schema = BaseWeightSchema.from_config(quant_config)
@@ -480,18 +490,8 @@ def prepare_humming_layer(
490
491
layer.weight_schema = weight_schema
492
483
- for name, _ in list(layer.named_parameters()):
484
- delattr(layer, name)
485
-
486
- for name, tensor in tensors.items():
487
- if isinstance(tensor, torch.nn.Parameter):
488
- tensor = tensor.data
489
- param = torch.nn.Parameter(tensor, requires_grad=False)
490
- setattr(layer, name, param)
491
-
492
- # Step 2: transform weight (humming standard format) for forwarding
493
- HummingMethod.prepare_layer_meta(
494
- layer=layer,
493
+ # Step 2: transform weight (humming standard format) for forwarding.
494
+ config = prepare_layer_config(
495
shape_n=sum(layer.output_partition_sizes),
496
shape_k=input_size_per_partition,
497
weight_schema=weight_schema,
@@ -501,20 +501,49 @@ def prepare_humming_layer(
501
has_bias=layer.has_bias,
502
torch_dtype=layer.params_dtype,
503
)
504
+ tensors = transform_humming_tensors(config, tensors)
505
+ for name, _ in list(layer.named_parameters()):
506
+ delattr(layer, name)
507
+ for name, tensor in tensors.items():
508
+ param = torch.nn.Parameter(tensor, requires_grad=False)
509
+ setattr(layer, name, param)
510
505
- HummingMethod.transform_humming_layer(layer)
506
- if not hasattr(layer, "locks"):
507
- device = layer.weight.device
508
- locks = torch.zeros(1024, dtype=torch.int32, device=device)
509
- layer.register_buffer("locks", locks)
511
+ return config
512
511
- compute_config = {
512
- "use_batch_invariant": envs.VLLM_BATCH_INVARIANT,
513
- "use_f16_accum": envs.VLLM_HUMMING_USE_F16_ACCUM,
514
- "gemm_type": "dense",
515
- }
513
517
- layer.compute_config = json.dumps(compute_config)
514
+def get_humming_linear_compute_config() -> str:
515
+ return json.dumps(
516
+ {
517
+ "use_batch_invariant": envs.VLLM_BATCH_INVARIANT,
518
+ "use_f16_accum": envs.VLLM_HUMMING_USE_F16_ACCUM,
519
+ "gemm_type": "dense",
520
+ }
521
+ )
522
+
523
+
524
+def apply_humming_linear(
525
+ layer: LinearBase,
526
+ x: torch.Tensor,
527
+ *,
528
+ layer_config: "LayerConfig",
529
+ compute_config: str,
530
+ locks: torch.Tensor,
531
+) -> torch.Tensor:
532
+ from vllm.utils.humming import humming_forward
533
+
534
+ flatten_inputs = x.reshape(-1, x.size(-1))
535
+ output = humming_forward(
536
+ layer_config,
537
+ inputs=flatten_inputs,
538
+ weight=layer.weight,
539
+ weight_scale=getattr(layer, "weight_scale", None),
540
+ zero_point=getattr(layer, "zero_point", None),
541
+ bias=getattr(layer, "bias", None),
542
+ weight_scale_2=getattr(layer, "weight_scale_2", None),
543
+ locks=locks,
544
+ compute_config=compute_config,
545
+ )
546
+ return output.view(*x.shape[:-1], output.size(-1))
547
548
549
def make_humming_moe_quant_config(
@@ -532,7 +561,9 @@ def make_humming_moe_quant_config(
561
gemm1_alpha: float | None = None,
562
gemm1_beta: float | None = None,
563
gemm1_clamp_limit: float | None = None,
535
-) -> FusedMoEQuantConfig:
564
+ humming_configs: dict[str, "LayerConfig"] | None = None,
565
+) -> HummingMoEQuantConfig:
566
+ assert humming_configs is not None
567
if quant_dtype is None:
568
a_quant_desc = FusedMoEQuantDesc(dtype=None)
569
else:
@@ -557,7 +588,7 @@ def make_humming_moe_quant_config(
588
bias=w2_bias,
589
)
590
560
- return FusedMoEQuantConfig(
591
+ return HummingMoEQuantConfig(
592
_a1=a_quant_desc,
593
_a2=a_quant_desc,
594
_w1=w1_quant_desc,
@@ -565,15 +596,20 @@ def make_humming_moe_quant_config(
596
gemm1_alpha=gemm1_alpha,
597
gemm1_beta=gemm1_beta,
598
gemm1_clamp_limit=gemm1_clamp_limit,
599
+ w1_humming_config=humming_configs["w13"],
600
+ w2_humming_config=humming_configs["w2"],
601
)
602
603
604
def get_humming_moe_quant_config(
605
layer: "RoutedExperts",
606
+ humming_configs: dict[str, "LayerConfig"] | None = None,
607
gemm1_alpha: float | None = None,
608
gemm1_beta: float | None = None,
609
gemm1_clamp_limit: float | None = None,
610
):
611
+ if humming_configs is None:
612
+ humming_configs = layer.humming_configs
613
input_schema = layer.input_schemas["w13"]
614
weight_schema = layer.weight_schemas["w13"]
615
@@ -600,13 +636,17 @@ def get_humming_moe_quant_config(
636
weight_dtype=str(weight_schema.b_dtype),
637
weight_group_shape=weight_group_shape,
638
w1_scale=getattr(layer, "w13_weight_scale", None),
603
- w1_gscale=getattr(layer, "w13_global_scale", None),
639
+ w1_gscale=getattr(layer, "w13_weight_scale_2", None),
640
w1_zp=getattr(layer, "w13_zero_point", None),
641
w1_bias=getattr(layer, "w13_bias", None),
642
w2_scale=getattr(layer, "w2_weight_scale", None),
607
- w2_gscale=getattr(layer, "w2_global_scale", None),
643
+ w2_gscale=getattr(layer, "w2_weight_scale_2", None),
644
w2_zp=getattr(layer, "w2_zero_point", None),
645
w2_bias=getattr(layer, "w2_bias", None),
646
+ gemm1_alpha=gemm1_alpha,
647
+ gemm1_beta=gemm1_beta,
648
+ gemm1_clamp_limit=gemm1_clamp_limit,
649
+ humming_configs=humming_configs,
650
)
651
652
@@ -677,7 +717,6 @@ def make_humming_moe_kernel(
717
moe_quant_config: FusedMoEQuantConfig,
718
moe_config: FusedMoEConfig,
719
experts_cls: type[mk.FusedMoEExperts],
680
- layer: "RoutedExperts",
720
routing_tables: tuple[torch.Tensor, torch.Tensor, torch.Tensor] | None = None,
721
) -> mk.FusedMoEKernel:
722
# Create Prepare/Finalize.
@@ -692,8 +731,6 @@ def make_humming_moe_kernel(
731
732
logger.info_once("Using %s", prepare_finalize.__class__.__name__)
733
695
- extra_args: dict[str, Any] = {"layer": layer}
696
-
734
# Create Experts.
735
if prepare_finalize.activation_format == mk.FusedMoEActivationFormat.BatchedExperts:
736
max_num_tokens = prepare_finalize.max_num_tokens_per_rank()
@@ -703,13 +740,11 @@ def make_humming_moe_kernel(
740
quant_config=moe_quant_config,
741
max_num_tokens=max_num_tokens,
742
num_dispatchers=prepare_finalize.num_dispatchers(),
706
- **extra_args,
743
)
744
else:
745
experts = experts_cls(
746
moe_config=moe_config,
747
quant_config=moe_quant_config,
712
- **extra_args,
748
)
749
750
kernel = mk.FusedMoEKernel(
@@ -822,16 +857,14 @@ def _prepare_and_transform_sublayer(
857
has_bias: bool,
858
num_experts: int,
859
param_dtype: torch.dtype,
825
-) -> None:
826
- """
827
- Prepare layer metadata and transform weights for a sublayer.
828
-
829
- This calls Humming's prepare_layer_meta and transform_humming_layer.
830
- """
831
- from vllm.utils.humming import HummingMethod
860
+) -> "LayerConfig":
861
+ """Prepare Humming configuration and transform one sublayer's tensors."""
862
+ from vllm.utils.humming import (
863
+ prepare_layer_config,
864
+ transform_humming_tensors,
865
+ )
866
833
- HummingMethod.prepare_layer_meta(
834
- layer=layer,
867
+ config = prepare_layer_config(
868
shape_n=shape_n,
869
shape_k=shape_k,
870
pad_n_to_multiple=256,
@@ -841,10 +874,13 @@ def _prepare_and_transform_sublayer(
874
has_bias=has_bias,
875
num_experts=num_experts,
876
torch_dtype=param_dtype,
844
- sublayer_name=sublayer_name,
877
)
846
-
847
- HummingMethod.transform_humming_layer(layer, sublayer_name=sublayer_name)
878
+ tensors = transform_humming_tensors(
879
+ config,
880
+ _extract_sublayer_tensors(layer, sublayer_name),
881
+ )
882
+ _replace_layer_parameters(layer, sublayer_name, tensors)
883
+ return config
884
885
886
def _process_single_sublayer(
@@ -858,7 +894,7 @@ def _process_single_sublayer(
894
num_experts: int,
895
param_dtype: torch.dtype,
896
force_weight_schema: Any | None = None,
861
-) -> tuple[Any, Any]:
897
+) -> tuple[Any, Any, "LayerConfig"]:
898
"""
899
Process a single sublayer: convert, optionally requant, prepare, and transform.
900
@@ -878,7 +914,7 @@ def _process_single_sublayer(
914
force_weight_schema: Optional schema to force requantization to
915
916
Returns:
881
- Tuple of (final_weight_schema, final_input_schema)
917
+ Tuple of the final weight schema, input schema, and Humming layer config.
918
"""
919
from vllm.utils.humming import HummingWeightSchema
920
@@ -910,7 +946,7 @@ def _process_single_sublayer(
946
del tensors
947
948
# Step 3: Prepare layer metadata and transform weights
913
- _prepare_and_transform_sublayer(
949
+ config = _prepare_and_transform_sublayer(
950
layer=layer,
951
sublayer_name=sublayer_name,
952
shape_n=shape_n,
@@ -922,7 +958,7 @@ def _process_single_sublayer(
958
param_dtype=param_dtype,
959
)
960
925
- return current_weight_schema, current_input_schema
961
+ return current_weight_schema, current_input_schema, config
962
963
964
def convert_to_humming_moe_kernel_format(
@@ -932,7 +968,7 @@ def convert_to_humming_moe_kernel_format(
968
weight_schema: Any | None = None,
969
input_schema: Any | None = None,
970
force_weight_schema: Any | None = None,
935
-) -> None:
971
+) -> dict[str, "LayerConfig"]:
972
"""
973
Convert MoE weights from checkpoint format to Humming kernel format.
974
@@ -959,6 +995,7 @@ def convert_to_humming_moe_kernel_format(
995
Side effects:
996
- Modifies layer parameters in place
997
- Sets layer.weight_schemas and layer.input_schemas
998
+ - Sets layer.humming_configs for quant config construction
999
"""
1000
1001
# Build schemas from quant_config if not provided
@@ -1005,25 +1042,27 @@ def convert_to_humming_moe_kernel_format(
1042
1043
layer.weight_schemas = {}
1044
layer.input_schemas = {}
1045
+ humming_configs = {}
1046
1047
for sublayer_name, configs in sublayer_configs.items():
1010
- final_weight_schema, final_input_schema = _process_single_sublayer(
1011
- layer=layer,
1012
- sublayer_name=sublayer_name,
1013
- shape_n=configs["shape_n"],
1014
- shape_k=configs["shape_k"],
1015
- weight_schema=weight_schema,
1016
- input_schema=input_schema,
1017
- has_bias=has_bias,
1018
- num_experts=num_experts,
1019
- param_dtype=param_dtype,
1020
- force_weight_schema=force_weight_schema,
1048
+ final_weight_schema, final_input_schema, humming_config = (
1049
+ _process_single_sublayer(
1050
+ layer=layer,
1051
+ sublayer_name=sublayer_name,
1052
+ shape_n=configs["shape_n"],
1053
+ shape_k=configs["shape_k"],
1054
+ weight_schema=weight_schema,
1055
+ input_schema=input_schema,
1056
+ has_bias=has_bias,
1057
+ num_experts=num_experts,
1058
+ param_dtype=param_dtype,
1059
+ force_weight_schema=force_weight_schema,
1060
+ )
1061
)
1062
1063
layer.weight_schemas[sublayer_name] = final_weight_schema
1064
layer.input_schemas[sublayer_name] = final_input_schema
1065
+ humming_configs[sublayer_name] = humming_config
1066
1026
- if not hasattr(layer, "locks"):
1027
- device = layer.w13_weight.device
1028
- locks = torch.zeros(1024, dtype=torch.int32, device=device)
1029
- layer.register_buffer("locks", locks)
1067
+ layer.humming_configs = humming_configs
1068
+ return humming_configs
vllm/utils/humming.py
+6
-2
@@ -15,9 +15,13 @@ _EXPORTS: dict[str, str] = {
15
"dtypes": "humming.dtypes",
16
"DataType": "humming.dtypes:DataType",
17
"GemmType": "humming.config:GemmType",
18
+ "LayerConfig": "humming.config:LayerConfig",
19
"WeightScaleType": "humming.config:WeightScaleType",
19
- "HummingMethod": "humming.layer:HummingMethod",
20
- "HummingLayerMeta": "humming.layer:HummingLayerMeta",
20
+ "humming_forward": "humming.forward:humming_forward",
21
+ "may_quant_input": "humming.forward:may_quant_input",
22
+ "prepare_layer_config": "humming.transform:prepare_layer_config",
23
+ "transform_humming_tensors": "humming.transform:transform_humming_tensors",
24
+ "get_heuristics_config": "humming.tune:get_heuristics_config",
25
"BaseInputSchema": "humming.schema:BaseInputSchema",
26
"BaseWeightSchema": "humming.schema:BaseWeightSchema",
27
"HummingInputSchema": "humming.schema:HummingInputSchema",