[Quantization] add humming moe backend to all dense/moe oracles (#41652)
Signed-off-by: Jinzhen Lin <jinzhen.ljz@antgroup.com> Co-authored-by: mgoin <mgoin64@gmail.com>
Jinzhen Lin committed
Jul 7, 2026 at 04:36 UTC
d891b9bd51ce726a1bff24a72d03090057718789
73 files changed
+1336
-122
.buildkite/test_areas/lm_eval.yaml
+60
-12
@@ -150,9 +150,9 @@ steps:
150
commands:
151
- pytest -s -v evals/gsm8k/test_gsm8k_correctness.py --config-list-file=evals/gsm8k/configs/moe-refactor-dp-ep/config-b200.txt
152
153
-- label: LM Eval Humming (A100 - TEMPORARY)
154
- key: lm-eval-humming-a100
155
- timeout_in_minutes: 30
153
+- label: LM Eval Humming f16 (A100 - TEMPORARY)
154
+ key: lm-eval-humming-f16-a100
155
+ timeout_in_minutes: 120
156
device: a100
157
optional: true
158
num_devices: 1
@@ -160,13 +160,29 @@ steps:
160
- vllm/model_executor/layers/quantization/humming.py
161
- vllm/model_executor/layers/quantization/utils/humming_utils.py
162
- vllm/model_executor/layers/fused_moe/experts/fused_humming_moe.py
163
- - vllm/model_executor/layers/fused_moe/oracle/mxfp4.py
163
+ - vllm/model_executor/layers/fused_moe/oracle/
164
+ - vllm/model_executor/kernels/linear/
165
commands:
166
- pytest -s -v evals/gsm8k/test_gsm8k_correctness.py --config-list-file=evals/gsm8k/configs/humming/config.txt
167
167
-- label: LM Eval Humming (H100 - TEMPORARY)
168
- key: lm-eval-humming-h100
169
- timeout_in_minutes: 30
168
+- label: LM Eval Humming Act int8 (A100 - TEMPORARY)
169
+ key: lm-eval-humming-act-a100
170
+ timeout_in_minutes: 120
171
+ device: a100
172
+ optional: true
173
+ num_devices: 1
174
+ source_file_dependencies:
175
+ - vllm/model_executor/layers/quantization/humming.py
176
+ - vllm/model_executor/layers/quantization/utils/humming_utils.py
177
+ - vllm/model_executor/layers/fused_moe/experts/fused_humming_moe.py
178
+ - vllm/model_executor/layers/fused_moe/oracle/
179
+ - vllm/model_executor/kernels/linear/
180
+ commands:
181
+ - pytest -s -v evals/gsm8k/test_gsm8k_correctness.py --config-list-file=evals/gsm8k/configs/humming/config-act-int8.txt
182
+
183
+- label: LM Eval Humming f16 (H100 - TEMPORARY)
184
+ key: lm-eval-humming-f16-h100
185
+ timeout_in_minutes: 120
186
device: h100
187
optional: true
188
num_devices: 1
@@ -174,14 +190,30 @@ steps:
190
- vllm/model_executor/layers/quantization/humming.py
191
- vllm/model_executor/layers/quantization/utils/humming_utils.py
192
- vllm/model_executor/layers/fused_moe/experts/fused_humming_moe.py
177
- - vllm/model_executor/layers/fused_moe/oracle/mxfp4.py
193
+ - vllm/model_executor/layers/fused_moe/oracle/
194
+ - vllm/model_executor/kernels/linear/
195
commands:
196
- pytest -s -v evals/gsm8k/test_gsm8k_correctness.py --config-list-file=evals/gsm8k/configs/humming/config.txt
197
+
198
+- label: LM Eval Humming Act fp8/int8 (H100 - TEMPORARY)
199
+ key: lm-eval-humming-act-h100
200
+ timeout_in_minutes: 120
201
+ device: h100
202
+ optional: true
203
+ num_devices: 1
204
+ source_file_dependencies:
205
+ - vllm/model_executor/layers/quantization/humming.py
206
+ - vllm/model_executor/layers/quantization/utils/humming_utils.py
207
+ - vllm/model_executor/layers/fused_moe/experts/fused_humming_moe.py
208
+ - vllm/model_executor/layers/fused_moe/oracle/
209
+ - vllm/model_executor/kernels/linear/
210
+ commands:
211
- pytest -s -v evals/gsm8k/test_gsm8k_correctness.py --config-list-file=evals/gsm8k/configs/humming/config-act-fp8.txt
212
+ - pytest -s -v evals/gsm8k/test_gsm8k_correctness.py --config-list-file=evals/gsm8k/configs/humming/config-act-int8.txt
213
182
-- label: LM Eval Humming (B200 - TEMPORARY)
183
- key: lm-eval-humming-b200
184
- timeout_in_minutes: 30
214
+- label: LM Eval Humming f16 (B200 - TEMPORARY)
215
+ key: lm-eval-humming-f16-b200
216
+ timeout_in_minutes: 120
217
device: b200-k8s
218
optional: true
219
num_devices: 1
@@ -189,10 +221,26 @@ steps:
221
- vllm/model_executor/layers/quantization/humming.py
222
- vllm/model_executor/layers/quantization/utils/humming_utils.py
223
- vllm/model_executor/layers/fused_moe/experts/fused_humming_moe.py
192
- - vllm/model_executor/layers/fused_moe/oracle/mxfp4.py
224
+ - vllm/model_executor/layers/fused_moe/oracle/
225
+ - vllm/model_executor/kernels/linear/
226
commands:
227
- pytest -s -v evals/gsm8k/test_gsm8k_correctness.py --config-list-file=evals/gsm8k/configs/humming/config.txt
228
+
229
+- label: LM Eval Humming Act fp8/int8 (B200 - TEMPORARY)
230
+ key: lm-eval-humming-act-b200
231
+ timeout_in_minutes: 120
232
+ device: b200-k8s
233
+ optional: true
234
+ num_devices: 1
235
+ source_file_dependencies:
236
+ - vllm/model_executor/layers/quantization/humming.py
237
+ - vllm/model_executor/layers/quantization/utils/humming_utils.py
238
+ - vllm/model_executor/layers/fused_moe/experts/fused_humming_moe.py
239
+ - vllm/model_executor/layers/fused_moe/oracle/
240
+ - vllm/model_executor/kernels/linear/
241
+ commands:
242
- pytest -s -v evals/gsm8k/test_gsm8k_correctness.py --config-list-file=evals/gsm8k/configs/humming/config-act-fp8.txt
243
+ - pytest -s -v evals/gsm8k/test_gsm8k_correctness.py --config-list-file=evals/gsm8k/configs/humming/config-act-int8.txt
244
245
- label: LM Eval TurboQuant KV Cache
246
key: lm-eval-turboquant-kv-cache
requirements/cuda.txt
+1
-1
@@ -28,4 +28,4 @@ quack-kernels>=0.3.3
28
tokenspeed-mla==0.1.2; platform_system == "Linux"
29
30
# Humming kernels for quantization gemm
31
-humming-kernels[cu13]==0.1.6
31
+humming-kernels[cu13]==0.1.10
tests/evals/gsm8k/configs/humming/Qwen2-1.5B-Instruct-FP8W8-humming-act-fp8.yaml
new
+10
@@ -0,0 +1,10 @@
1
+model_name: "nm-testing/Qwen2-1.5B-Instruct-FP8W8"
2
+accuracy_threshold: 0.55
3
+num_questions: 1319
4
+num_fewshot: 5
5
+server_args: >-
6
+ --enforce-eager
7
+ --max-model-len 8192
8
+ --linear-backend humming
9
+env:
10
+ VLLM_HUMMING_INPUT_QUANT_CONFIG: '{"dtype":"float8e4m3"}'
tests/evals/gsm8k/configs/humming/Qwen2-1.5B-Instruct-FP8W8-humming.yaml
new
+8
@@ -0,0 +1,8 @@
1
+model_name: "nm-testing/Qwen2-1.5B-Instruct-FP8W8"
2
+accuracy_threshold: 0.55
3
+num_questions: 1319
4
+num_fewshot: 5
5
+server_args: >-
6
+ --enforce-eager
7
+ --max-model-len 8192
8
+ --linear-backend humming
tests/evals/gsm8k/configs/humming/Qwen3-0.6B-MXFP8-humming-act-fp8.yaml
new
+10
@@ -0,0 +1,10 @@
1
+model_name: "mgoin/Qwen3-0.6B-MXFP8"
2
+accuracy_threshold: 0.39
3
+num_questions: 1319
4
+num_fewshot: 5
5
+server_args: >-
6
+ --enforce-eager
7
+ --max-model-len 8192
8
+ --linear-backend humming
9
+env:
10
+ VLLM_HUMMING_INPUT_QUANT_CONFIG: '{"dtype":"float8e4m3"}'
tests/evals/gsm8k/configs/humming/Qwen3-0.6B-MXFP8-humming.yaml
new
+8
@@ -0,0 +1,8 @@
1
+model_name: "mgoin/Qwen3-0.6B-MXFP8"
2
+accuracy_threshold: 0.39
3
+num_questions: 1319
4
+num_fewshot: 5
5
+server_args: >-
6
+ --enforce-eager
7
+ --max-model-len 8192
8
+ --linear-backend humming
tests/evals/gsm8k/configs/humming/Qwen3-30B-A3B-AWQ-humming-act-fp8.yaml
new
+13
@@ -0,0 +1,13 @@
1
+model_name: "QuixiAI/Qwen3-30B-A3B-AWQ"
2
+accuracy_threshold: 0.90
3
+num_questions: 1319
4
+num_fewshot: 5
5
+gen_prefix: " <think>\n\n</think>\n"
6
+server_args: >-
7
+ --enforce-eager
8
+ --max-model-len 8192
9
+ --moe-backend humming
10
+ --linear-backend humming
11
+ --dtype bfloat16
12
+env:
13
+ VLLM_HUMMING_INPUT_QUANT_CONFIG: '{"dtype":"float8e4m3"}'
tests/evals/gsm8k/configs/humming/Qwen3-30B-A3B-AWQ-humming-act-int8.yaml
new
+13
@@ -0,0 +1,13 @@
1
+model_name: "QuixiAI/Qwen3-30B-A3B-AWQ"
2
+accuracy_threshold: 0.90
3
+num_questions: 1319
4
+num_fewshot: 5
5
+gen_prefix: " <think>\n\n</think>\n"
6
+server_args: >-
7
+ --enforce-eager
8
+ --max-model-len 8192
9
+ --moe-backend humming
10
+ --linear-backend humming
11
+ --dtype bfloat16
12
+env:
13
+ VLLM_HUMMING_INPUT_QUANT_CONFIG: '{"dtype":"int8"}'
tests/evals/gsm8k/configs/humming/Qwen3-30B-A3B-AWQ-humming.yaml
new
+11
@@ -0,0 +1,11 @@
1
+model_name: "QuixiAI/Qwen3-30B-A3B-AWQ"
2
+accuracy_threshold: 0.90
3
+num_questions: 1319
4
+num_fewshot: 5
5
+gen_prefix: " <think>\n\n</think>\n"
6
+server_args: >-
7
+ --enforce-eager
8
+ --max-model-len 8192
9
+ --moe-backend humming
10
+ --linear-backend humming
11
+ --dtype bfloat16
tests/evals/gsm8k/configs/humming/Qwen3-30B-A3B-FP8-block-humming-act-fp8.yaml
new
+11
@@ -0,0 +1,11 @@
1
+model_name: "nm-testing/Qwen3-30B-A3B-FP8-block"
2
+accuracy_threshold: 0.86
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
10
+env:
11
+ VLLM_HUMMING_INPUT_QUANT_CONFIG: '{"dtype":"float8e4m3"}'
tests/evals/gsm8k/configs/humming/Qwen3-30B-A3B-FP8-block-humming.yaml
new
+9
@@ -0,0 +1,9 @@
1
+model_name: "nm-testing/Qwen3-30B-A3B-FP8-block"
2
+accuracy_threshold: 0.86
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-30B-A3B-Fp8-v1-humming-act-fp8.yaml
new
+11
@@ -0,0 +1,11 @@
1
+model_name: "nm-testing/Qwen3-30B-A3B-Fp8-v1"
2
+accuracy_threshold: 0.86
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
10
+env:
11
+ VLLM_HUMMING_INPUT_QUANT_CONFIG: '{"dtype":"float8e4m3"}'
tests/evals/gsm8k/configs/humming/Qwen3-30B-A3B-Fp8-v1-humming.yaml
new
+9
@@ -0,0 +1,9 @@
1
+model_name: "nm-testing/Qwen3-30B-A3B-Fp8-v1"
2
+accuracy_threshold: 0.86
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-30B-A3B-GPTQ-Int4-humming-act-fp8.yaml
new
+11
@@ -0,0 +1,11 @@
1
+model_name: "Qwen/Qwen3-30B-A3B-GPTQ-Int4"
2
+accuracy_threshold: 0.86
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
10
+env:
11
+ VLLM_HUMMING_INPUT_QUANT_CONFIG: '{"dtype":"float8e4m3"}'
tests/evals/gsm8k/configs/humming/Qwen3-30B-A3B-GPTQ-Int4-humming-act-int8.yaml
new
+11
@@ -0,0 +1,11 @@
1
+model_name: "Qwen/Qwen3-30B-A3B-GPTQ-Int4"
2
+accuracy_threshold: 0.86
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
10
+env:
11
+ VLLM_HUMMING_INPUT_QUANT_CONFIG: '{"dtype":"int8"}'
tests/evals/gsm8k/configs/humming/Qwen3-30B-A3B-GPTQ-Int4-humming.yaml
new
+9
@@ -0,0 +1,9 @@
1
+model_name: "Qwen/Qwen3-30B-A3B-GPTQ-Int4"
2
+accuracy_threshold: 0.86
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-30B-A3B-Instruct-2507-quantized.w8a8-humming-act-int8.yaml
new
+11
@@ -0,0 +1,11 @@
1
+model_name: "RedHatAI/Qwen3-30B-A3B-Instruct-2507-quantized.w8a8"
2
+accuracy_threshold: 0.86
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
10
+env:
11
+ VLLM_HUMMING_INPUT_QUANT_CONFIG: '{"dtype":"int8"}'
tests/evals/gsm8k/configs/humming/Qwen3-30B-A3B-Instruct-2507-quantized.w8a8-humming.yaml
new
+9
@@ -0,0 +1,9 @@
1
+model_name: "RedHatAI/Qwen3-30B-A3B-Instruct-2507-quantized.w8a8"
2
+accuracy_threshold: 0.86
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-30B-A3B-MXFP4A16-humming-act-fp8.yaml
+1
-2
@@ -5,8 +5,7 @@ num_fewshot: 5
5
server_args: >-
6
--enforce-eager
7
--max-model-len 8192
8
- --tensor-parallel-size 1
8
--quantization humming
10
- --kernel-config.enable_flashinfer_autotune=False
9
+ --linear-backend humming
10
env:
11
VLLM_HUMMING_INPUT_QUANT_CONFIG: '{"dtype":"float8e4m3"}'
tests/evals/gsm8k/configs/humming/Qwen3-30B-A3B-MXFP4A16-humming.yaml
+1
-2
@@ -5,6 +5,5 @@ num_fewshot: 5
5
server_args: >-
6
--enforce-eager
7
--max-model-len 8192
8
- --tensor-parallel-size 1
8
--quantization humming
10
- --kernel-config.enable_flashinfer_autotune=False
9
+ --linear-backend humming
tests/evals/gsm8k/configs/humming/Qwen3-30B-A3B-NVFP4-humming.yaml
new
+9
@@ -0,0 +1,9 @@
1
+model_name: "nvidia/Qwen3-30B-A3B-NVFP4"
2
+accuracy_threshold: 0.86
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-30B-A3B-int5wc-hadamard-humming-act-fp8.yaml
new
+13
@@ -0,0 +1,13 @@
1
+model_name: "Qwen/Qwen3-30B-A3B"
2
+accuracy_threshold: 0.80
3
+num_questions: 1319
4
+num_fewshot: 5
5
+server_args: >-
6
+ --enforce-eager
7
+ --max-model-len 8192
8
+ --tensor-parallel-size 1
9
+ --quantization humming
10
+ --kernel-config.enable_flashinfer_autotune=False
11
+env:
12
+ VLLM_HUMMING_ONLINE_QUANT_CONFIG: '{"dtype":"int5","hadamard_block_size":-1}'
13
+ VLLM_HUMMING_INPUT_QUANT_CONFIG: '{"dtype":"float8e4m3"}'
tests/evals/gsm8k/configs/humming/Qwen3-30B-A3B-int5wc-hadamard-humming-act-int8.yaml
new
+13
@@ -0,0 +1,13 @@
1
+model_name: "Qwen/Qwen3-30B-A3B"
2
+accuracy_threshold: 0.80
3
+num_questions: 1319
4
+num_fewshot: 5
5
+server_args: >-
6
+ --enforce-eager
7
+ --max-model-len 8192
8
+ --tensor-parallel-size 1
9
+ --quantization humming
10
+ --kernel-config.enable_flashinfer_autotune=False
11
+env:
12
+ VLLM_HUMMING_ONLINE_QUANT_CONFIG: '{"dtype":"int5","hadamard_block_size":-1}'
13
+ VLLM_HUMMING_INPUT_QUANT_CONFIG: '{"dtype":"int8"}'
tests/evals/gsm8k/configs/humming/Qwen3-30B-A3B-int5wc-hadamard-humming.yaml
new
+12
@@ -0,0 +1,12 @@
1
+model_name: "Qwen/Qwen3-30B-A3B"
2
+accuracy_threshold: 0.80
3
+num_questions: 1319
4
+num_fewshot: 5
5
+server_args: >-
6
+ --enforce-eager
7
+ --max-model-len 8192
8
+ --tensor-parallel-size 1
9
+ --quantization humming
10
+ --kernel-config.enable_flashinfer_autotune=False
11
+env:
12
+ VLLM_HUMMING_ONLINE_QUANT_CONFIG: '{"dtype":"int5","hadamard_block_size":-1}'
tests/evals/gsm8k/configs/humming/Qwen3.5-35B-A3B-FP8-humming-act-fp8.yaml
new
+12
@@ -0,0 +1,12 @@
1
+model_name: "Qwen/Qwen3.5-35B-A3B-FP8"
2
+accuracy_threshold: 0.90
3
+num_questions: 1319
4
+num_fewshot: 5
5
+gen_prefix: " <think>\n\n</think>\n"
6
+server_args: >-
7
+ --enforce-eager
8
+ --max-model-len 8192
9
+ --moe-backend humming
10
+ --linear-backend humming
11
+env:
12
+ VLLM_HUMMING_INPUT_QUANT_CONFIG: '{"dtype":"float8e4m3"}'
tests/evals/gsm8k/configs/humming/Qwen3.5-35B-A3B-FP8-humming.yaml
new
+10
@@ -0,0 +1,10 @@
1
+model_name: "Qwen/Qwen3.5-35B-A3B-FP8"
2
+accuracy_threshold: 0.90
3
+num_questions: 1319
4
+num_fewshot: 5
5
+gen_prefix: " <think>\n\n</think>\n"
6
+server_args: >-
7
+ --enforce-eager
8
+ --max-model-len 8192
9
+ --moe-backend humming
10
+ --linear-backend humming
tests/evals/gsm8k/configs/humming/Qwen3.5-35B-A3B-experts-int8-humming-act-int8.yaml
new
+12
@@ -0,0 +1,12 @@
1
+model_name: "Qwen/Qwen3.5-35B-A3B"
2
+accuracy_threshold: 0.90
3
+num_questions: 1319
4
+num_fewshot: 5
5
+gen_prefix: " <think>\n\n</think>\n"
6
+server_args: >-
7
+ --enforce-eager
8
+ --max-model-len 8192
9
+ --moe-backend humming
10
+ --quantization experts_int8
11
+env:
12
+ VLLM_HUMMING_INPUT_QUANT_CONFIG: '{"dtype":"int8"}'
tests/evals/gsm8k/configs/humming/Qwen3.5-35B-A3B-experts-int8-humming.yaml
new
+10
@@ -0,0 +1,10 @@
1
+model_name: "Qwen/Qwen3.5-35B-A3B"
2
+accuracy_threshold: 0.90
3
+num_questions: 1319
4
+num_fewshot: 5
5
+gen_prefix: " <think>\n\n</think>\n"
6
+server_args: >-
7
+ --enforce-eager
8
+ --max-model-len 8192
9
+ --moe-backend humming
10
+ --quantization experts_int8
tests/evals/gsm8k/configs/humming/Qwen3.5-4B-quantized.w4a16-humming-act-fp8.yaml
new
+10
@@ -0,0 +1,10 @@
1
+model_name: "RedHatAI/Qwen3.5-4B-quantized.w4a16"
2
+accuracy_threshold: 0.82
3
+num_questions: 1319
4
+num_fewshot: 5
5
+gen_prefix: " <think>\n\n</think>\n"
6
+server_args: >-
7
+ --enforce-eager
8
+ --max-model-len 8192
9
+env:
10
+ VLLM_HUMMING_INPUT_QUANT_CONFIG: '{"dtype":"float8e4m3"}'
tests/evals/gsm8k/configs/humming/Qwen3.5-4B-quantized.w4a16-humming-act-int8.yaml
new
+11
@@ -0,0 +1,11 @@
1
+model_name: "RedHatAI/Qwen3.5-4B-quantized.w4a16"
2
+accuracy_threshold: 0.82
3
+num_questions: 1319
4
+num_fewshot: 5
5
+gen_prefix: " <think>\n\n</think>\n"
6
+server_args: >-
7
+ --enforce-eager
8
+ --max-model-len 8192
9
+ --linear-backend humming
10
+env:
11
+ VLLM_HUMMING_INPUT_QUANT_CONFIG: '{"dtype":"int8"}'
tests/evals/gsm8k/configs/humming/Qwen3.5-4B-quantized.w4a16-humming.yaml
new
+9
@@ -0,0 +1,9 @@
1
+model_name: "RedHatAI/Qwen3.5-4B-quantized.w4a16"
2
+accuracy_threshold: 0.82
3
+num_questions: 1319
4
+num_fewshot: 5
5
+gen_prefix: " <think>\n\n</think>\n"
6
+server_args: >-
7
+ --enforce-eager
8
+ --max-model-len 8192
9
+ --linear-backend humming
tests/evals/gsm8k/configs/humming/Qwen3.6-35B-A3B-NVFP4-humming.yaml
new
+10
@@ -0,0 +1,10 @@
1
+model_name: "RedHatAI/Qwen3.6-35B-A3B-NVFP4"
2
+accuracy_threshold: 0.91
3
+num_questions: 1319
4
+num_fewshot: 5
5
+gen_prefix: " <think>\n\n</think>\n"
6
+server_args: >-
7
+ --enforce-eager
8
+ --max-model-len 8192
9
+ --moe-backend humming
10
+ --linear-backend humming
tests/evals/gsm8k/configs/humming/config-act-fp8.txt
+7
@@ -1,2 +1,9 @@
1
gpt-oss-20b-humming-act-fp8.yaml
2
Qwen3-30B-A3B-MXFP4A16-humming-act-fp8.yaml
3
+Qwen2-1.5B-Instruct-FP8W8-humming-act-fp8.yaml
4
+Qwen3-0.6B-MXFP8-humming-act-fp8.yaml
5
+Qwen3-30B-A3B-Fp8-v1-humming-act-fp8.yaml
6
+Qwen3-30B-A3B-FP8-block-humming-act-fp8.yaml
7
+Qwen3-30B-A3B-GPTQ-Int4-humming-act-fp8.yaml
8
+Qwen3-30B-A3B-AWQ-humming.yaml
9
+Qwen3.5-35B-A3B-FP8-humming-act-fp8.yaml
tests/evals/gsm8k/configs/humming/config-act-int8.txt
new
+4
@@ -0,0 +1,4 @@
1
+Qwen3-30B-A3B-Instruct-2507-quantized.w8a8-humming-act-int8.yaml
2
+Qwen3-30B-A3B-GPTQ-Int4-humming-act-int8.yaml
3
+Qwen3-30B-A3B-AWQ-humming.yaml
4
+Qwen3.5-35B-A3B-experts-int8-humming-act-int8.yaml
tests/evals/gsm8k/configs/humming/config-int5wc-hadamard.txt
new
+3
@@ -0,0 +1,3 @@
1
+Qwen3-30B-A3B-int5wc-hadamard-humming.yaml
2
+Qwen3-30B-A3B-int5wc-hadamard-humming-act-fp8.yaml
3
+Qwen3-30B-A3B-int5wc-hadamard-humming-act-int8.yaml
tests/evals/gsm8k/configs/humming/config.txt
+11
@@ -1,2 +1,13 @@
1
gpt-oss-20b-humming.yaml
2
Qwen3-30B-A3B-MXFP4A16-humming.yaml
3
+Qwen2-1.5B-Instruct-FP8W8-humming.yaml
4
+Qwen3-0.6B-MXFP8-humming.yaml
5
+Qwen3.6-35B-A3B-NVFP4-humming.yaml
6
+Qwen3-30B-A3B-Fp8-v1-humming.yaml
7
+Qwen3-30B-A3B-FP8-block-humming.yaml
8
+Qwen3-30B-A3B-GPTQ-Int4-humming.yaml
9
+Qwen3-30B-A3B-Instruct-2507-quantized.w8a8-humming.yaml
10
+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
tests/evals/gsm8k/configs/humming/gpt-oss-20b-humming-act-fp8.yaml
-1
@@ -5,7 +5,6 @@ num_fewshot: 5
5
server_args: >-
6
--enforce-eager
7
--max-model-len 8192
8
- --tensor-parallel-size 1
8
--moe-backend humming
9
env:
10
VLLM_HUMMING_INPUT_QUANT_CONFIG: '{"dtype":"float8e4m3"}'
tests/evals/gsm8k/configs/humming/gpt-oss-20b-humming.yaml
-1
@@ -5,5 +5,4 @@ num_fewshot: 5
5
server_args: >-
6
--enforce-eager
7
--max-model-len 8192
8
- --tensor-parallel-size 1
8
--moe-backend humming
tests/evals/gsm8k/gsm8k_eval.py
+8
-4
@@ -146,6 +146,7 @@ async def call_vllm_chat_api(
146
def _build_gsm8k_prompts(
147
num_questions: int = 1319,
148
num_shots: int = 5,
149
+ gen_prefix: str = "",
150
) -> tuple[list[str], list[int]]:
151
"""Build few-shot GSM8K completion prompts and ground-truth labels."""
152
if num_questions == 0:
@@ -157,14 +158,15 @@ def _build_gsm8k_prompts(
158
for i in range(num_shots):
159
few_shot_examples += (
160
f"Question: {train_data[i]['question']}\n"
160
- f"Answer: {train_data[i]['answer']}\n\n"
161
+ f"Answer:{gen_prefix} {train_data[i]['answer']}\n\n"
162
)
163
164
prompts = []
165
labels = []
166
for i in range(num_questions):
167
prompts.append(
167
- few_shot_examples + f"Question: {test_data[i]['question']}\nAnswer:"
168
+ few_shot_examples
169
+ + f"Question: {test_data[i]['question']}\nAnswer:{gen_prefix}"
170
)
171
labels.append(get_answer_value(test_data[i]["answer"]))
172
@@ -213,6 +215,7 @@ def evaluate_gsm8k(
215
temperature: float = 0.0,
216
seed: int | None = 42,
217
request_timeout_seconds: float = 600,
218
+ gen_prefix: str = "",
219
) -> dict[str, float | int]:
220
"""
221
Evaluate GSM8K accuracy using vLLM serve endpoint.
@@ -220,7 +223,7 @@ def evaluate_gsm8k(
223
Returns dict with accuracy, invalid_rate, latency, etc.
224
"""
225
base_url = f"{host}:{port}"
223
- prompts, labels = _build_gsm8k_prompts(num_questions, num_shots)
226
+ prompts, labels = _build_gsm8k_prompts(num_questions, num_shots, gen_prefix)
227
num_questions = len(prompts)
228
229
async def run_async_evaluation():
@@ -278,6 +281,7 @@ def evaluate_gsm8k_offline(
281
num_shots: int = 5,
282
max_tokens: int = 256,
283
temperature: float = 0.0,
284
+ gen_prefix: str = "",
285
) -> dict[str, float | int]:
286
"""Evaluate GSM8K accuracy using an offline vllm.LLM object.
287
@@ -286,7 +290,7 @@ def evaluate_gsm8k_offline(
290
"""
291
from vllm import SamplingParams
292
289
- prompts, labels = _build_gsm8k_prompts(num_questions, num_shots)
293
+ prompts, labels = _build_gsm8k_prompts(num_questions, num_shots, gen_prefix)
294
295
sampling_params = SamplingParams(
296
temperature=temperature,
tests/evals/gsm8k/test_gsm8k_correctness.py
+1
@@ -70,6 +70,7 @@ def run_gsm8k_eval(eval_config: dict, server_url: str) -> dict:
70
host=host,
71
port=port,
72
request_timeout_seconds=request_timeout_seconds,
73
+ gen_prefix=eval_config.get("gen_prefix", ""),
74
)
75
76
return results
vllm/config/kernel.py
+1
@@ -147,6 +147,7 @@ LinearBackend = Literal[
147
"flashinfer_cudnn",
148
"flashinfer_b12x",
149
"marlin",
150
+ "humming",
151
"triton",
152
"deep_gemm",
153
"torch",
vllm/config/model.py
+1
@@ -999,6 +999,7 @@ class ModelConfig:
999
"modelopt",
1000
"modelopt_fp4",
1001
"modelopt_mxfp8",
1002
+ "mxfp8",
1003
"modelopt_mixed",
1004
# Ensure heavy backends are probed last to avoid unnecessary
1005
# imports during override detection (e.g., MXFP4 imports Triton)
vllm/model_executor/kernels/linear/__init__.py
+29
-1
@@ -74,6 +74,9 @@ from vllm.model_executor.kernels.linear.mxfp4 import (
74
from vllm.model_executor.kernels.linear.mxfp4.flashinfer import (
75
FlashInferMxFp4LinearKernel,
76
)
77
+from vllm.model_executor.kernels.linear.mxfp4.humming import (
78
+ HummingMxFp4LinearKernel,
79
+)
80
from vllm.model_executor.kernels.linear.mxfp4.marlin import (
81
MarlinMxFp4LinearKernel,
82
)
@@ -91,6 +94,9 @@ from vllm.model_executor.kernels.linear.mxfp8.flashinfer import (
94
FlashInferCutedslMxfp8LinearKernel,
95
FlashInferCutlassMxfp8LinearKernel,
96
)
97
+from vllm.model_executor.kernels.linear.mxfp8.humming import (
98
+ HummingMxfp8LinearKernel,
99
+)
100
from vllm.model_executor.kernels.linear.mxfp8.marlin import (
101
MarlinMxfp8LinearKernel,
102
)
@@ -120,6 +126,9 @@ from vllm.model_executor.kernels.linear.nvfp4.flashinfer import (
126
FlashInferCutlassNvFp4LinearKernel,
127
FlashInferTrtllmNvFp4LinearKernel,
128
)
129
+from vllm.model_executor.kernels.linear.nvfp4.humming import (
130
+ HummingNvFp4LinearKernel,
131
+)
132
from vllm.model_executor.kernels.linear.nvfp4.marlin import (
133
MarlinNvFp4LinearKernel,
134
)
@@ -154,6 +163,10 @@ from vllm.model_executor.kernels.linear.scaled_mm.flashinfer import (
163
FlashInferFp8DeepGEMMDynamicBlockScaledKernel,
164
FlashInferFP8ScaledMMLinearKernel,
165
)
166
+from vllm.model_executor.kernels.linear.scaled_mm.humming import (
167
+ HummingFP8ScaledMMLinearKernel,
168
+ HummingInt8ScaledMMLinearKernel,
169
+)
170
from vllm.model_executor.kernels.linear.scaled_mm.marlin import (
171
MarlinFP8ScaledMMLinearKernel,
172
)
@@ -225,6 +238,14 @@ _LINEAR_BACKEND_KERNEL_MAP: dict[str, set[type]] = {
238
"flashinfer_b12x": {
239
FlashInferB12xNvFp4LinearKernel,
240
},
241
+ "humming": {
242
+ HummingFP8ScaledMMLinearKernel,
243
+ HummingInt8ScaledMMLinearKernel,
244
+ HummingLinearKernel,
245
+ HummingMxfp8LinearKernel,
246
+ HummingMxFp4LinearKernel,
247
+ HummingNvFp4LinearKernel,
248
+ },
249
"marlin": {
250
MarlinFP8ScaledMMLinearKernel,
251
MarlinLinearKernel,
@@ -292,6 +313,7 @@ _POSSIBLE_INT8_KERNELS: dict[PlatformEnum, list[type[Int8ScaledMMLinearKernel]]]
313
PlatformEnum.CUDA: [
314
CutlassInt8ScaledMMLinearKernel,
315
TritonInt8ScaledMMLinearKernel,
316
+ HummingInt8ScaledMMLinearKernel,
317
],
318
PlatformEnum.ROCM: [AiterInt8ScaledMMLinearKernel, TritonInt8ScaledMMLinearKernel],
319
}
@@ -304,6 +326,7 @@ _POSSIBLE_FP8_KERNELS: dict[PlatformEnum, list[type[FP8ScaledMMLinearKernel]]] =
326
CutlassFP8ScaledMMLinearKernel,
327
PerTensorTorchFP8ScaledMMLinearKernel,
328
ChannelWiseTorchFP8ScaledMMLinearKernel,
329
+ HummingFP8ScaledMMLinearKernel,
330
],
331
PlatformEnum.ROCM: [
332
AiterHipbMMPerTokenFp8ScaledMMLinearKernel,
@@ -335,6 +358,7 @@ _POSSIBLE_FP8_BLOCK_KERNELS: dict[
358
CutlassFp8BlockScaledMMKernel,
359
MarlinFP8ScaledMMLinearKernel,
360
TritonFp8BlockScaledMMKernel,
361
+ HummingFP8ScaledMMLinearKernel,
362
],
363
PlatformEnum.ROCM: [
364
AiterFp8BlockScaledMMKernel,
@@ -351,6 +375,7 @@ _POSSIBLE_FP8_BLOCK_KERNELS: dict[
375
376
_POSSIBLE_WFP8A16_KERNELS: dict[PlatformEnum, list[type[FP8ScaledMMLinearKernel]]] = {
377
PlatformEnum.CUDA: [
378
+ HummingFP8ScaledMMLinearKernel,
379
MarlinFP8ScaledMMLinearKernel,
380
],
381
PlatformEnum.ROCM: [
@@ -371,10 +396,10 @@ _POSSIBLE_KERNELS: dict[PlatformEnum, list[type[MPLinearKernel]]] = {
396
MacheteLinearKernel,
397
AllSparkLinearKernel,
398
MarlinLinearKernel,
374
- HummingLinearKernel,
399
ConchLinearKernel,
400
ExllamaLinearKernel,
401
TritonW4A16LinearKernel,
402
+ HummingLinearKernel,
403
],
404
PlatformEnum.ROCM: [
405
RDNA3W4A16LinearKernel,
@@ -400,6 +425,7 @@ _POSSIBLE_MXFP8_KERNELS: dict[PlatformEnum, list[type[Mxfp8LinearKernel]]] = {
425
FlashInferCutlassMxfp8LinearKernel,
426
MarlinMxfp8LinearKernel,
427
EmulationMxfp8LinearKernel,
428
+ HummingMxfp8LinearKernel,
429
],
430
PlatformEnum.ROCM: [
431
# Native CDNA4 (gfx950) MX linear; is_supported() gates to gfx95x and
@@ -426,6 +452,7 @@ _POSSIBLE_NVFP4_KERNELS: dict[PlatformEnum, list[type[NvFp4LinearKernel]]] = {
452
FlashInferCudnnNvFp4LinearKernel,
453
FbgemmNvFp4LinearKernel,
454
EmulationNvFp4LinearKernel,
455
+ HummingNvFp4LinearKernel,
456
],
457
PlatformEnum.ROCM: [
458
EmulationNvFp4LinearKernel,
@@ -436,6 +463,7 @@ _POSSIBLE_MXFP4_KERNELS: dict[PlatformEnum, list[type[MxFp4LinearKernel]]] = {
463
PlatformEnum.CUDA: [
464
FlashInferMxFp4LinearKernel,
465
MarlinMxFp4LinearKernel,
466
+ HummingMxFp4LinearKernel,
467
],
468
PlatformEnum.XPU: [
469
XPUMxFp4LinearKernel,
vllm/model_executor/kernels/linear/mixed_precision/__init__.py
+4
@@ -19,6 +19,9 @@ from vllm.model_executor.kernels.linear.mixed_precision.dynamic_4bit import (
19
from vllm.model_executor.kernels.linear.mixed_precision.exllama import (
20
ExllamaLinearKernel,
21
)
22
+from vllm.model_executor.kernels.linear.mixed_precision.humming import (
23
+ HummingLinearKernel,
24
+)
25
from vllm.model_executor.kernels.linear.mixed_precision.machete import (
26
MacheteLinearKernel,
27
)
@@ -52,6 +55,7 @@ __all__ = [
55
"CutlassW4A8LinearKernel",
56
"Dynamic4bitLinearKernel",
57
"ExllamaLinearKernel",
58
+ "HummingLinearKernel",
59
"MacheteLinearKernel",
60
"MarlinLinearKernel",
61
"RDNA3W4A16LinearKernel",
vllm/model_executor/kernels/linear/mixed_precision/humming.py
+5
-2
@@ -23,8 +23,6 @@ class HummingLinearKernel(MPLinearKernel):
23
return False, "Humming is not installed"
24
if c.has_g_idx:
25
return False, "Humming does not support act-order (g_idx)"
26
- if c.zero_points:
27
- return False, "Humming linear kernel only supports symmetric weights"
26
return True, None
27
28
def process_weights_after_loading(self, layer: torch.nn.Module) -> None:
@@ -41,6 +39,11 @@ class HummingLinearKernel(MPLinearKernel):
39
"group_size": 0 if group_size == -1 else group_size,
40
}
41
42
+ if self.config.zero_points:
43
+ assert self.w_zp_name is not None
44
+ name_map["zero_point"] = self.w_zp_name
45
+ quant_config["has_zero_point"] = True
46
+
47
convert_linear_layer_to_humming_standard(layer=layer, name_map=name_map)
48
prepare_humming_layer(layer, quant_config)
49
vllm/model_executor/kernels/linear/mxfp4/humming.py
new
+63
@@ -0,0 +1,63 @@
1
+# SPDX-License-Identifier: Apache-2.0
2
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
+
4
+import torch
5
+
6
+from vllm.model_executor.layers.quantization.utils.humming_utils import (
7
+ convert_linear_layer_to_humming_standard,
8
+ prepare_humming_layer,
9
+)
10
+from vllm.platforms import current_platform
11
+
12
+from .base import MxFp4LinearKernel, MxFp4LinearLayerConfig
13
+
14
+
15
+class HummingMxFp4LinearKernel(MxFp4LinearKernel):
16
+ """Humming GEMM Kernel for MXFP4."""
17
+
18
+ @classmethod
19
+ def is_supported(
20
+ cls, compute_capability: int | None = None
21
+ ) -> tuple[bool, str | None]:
22
+ if not current_platform.is_cuda():
23
+ return False, "Humming only supported on CUDA"
24
+
25
+ if not current_platform.has_device_capability(75):
26
+ return False, "Humming only supported on SM75+"
27
+
28
+ return True, None
29
+
30
+ @classmethod
31
+ def can_implement(cls, c: MxFp4LinearLayerConfig) -> tuple[bool, str | None]:
32
+ return True, None
33
+
34
+ def process_weights_after_loading(self, layer: torch.nn.Module) -> None:
35
+ layer.weight_scale.data = layer.weight_scale.data.view(torch.float8_e8m0fnu)
36
+ name_map = {"weight": "weight", "weight_scale": "weight_scale"}
37
+
38
+ quant_config = {
39
+ "quant_method": "humming",
40
+ "dtype": "float4e2m1",
41
+ "scale_dtype": "float8e8m0",
42
+ "group_size": 32,
43
+ "weight_scale_type": "group",
44
+ }
45
+
46
+ convert_linear_layer_to_humming_standard(layer=layer, name_map=name_map)
47
+ prepare_humming_layer(layer, quant_config)
48
+
49
+ def apply_weights(
50
+ self,
51
+ layer: torch.nn.Module,
52
+ x: torch.Tensor,
53
+ bias: torch.Tensor | None = None,
54
+ ) -> 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,
62
+ )
63
+ return output.view(*x.shape[:-1], output.size(-1))
vllm/model_executor/kernels/linear/mxfp8/humming.py
new
+63
@@ -0,0 +1,63 @@
1
+# SPDX-License-Identifier: Apache-2.0
2
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
+
4
+import torch
5
+
6
+from vllm.model_executor.layers.quantization.utils.humming_utils import (
7
+ convert_linear_layer_to_humming_standard,
8
+ prepare_humming_layer,
9
+)
10
+from vllm.platforms import current_platform
11
+
12
+from .Mxfp8LinearKernel import Mxfp8LinearKernel, Mxfp8LinearLayerConfig
13
+
14
+
15
+class HummingMxfp8LinearKernel(Mxfp8LinearKernel):
16
+ """Humming GEMM Kernel for MXFP8."""
17
+
18
+ @classmethod
19
+ def is_supported(
20
+ cls, compute_capability: int | None = None
21
+ ) -> tuple[bool, str | None]:
22
+ if not current_platform.is_cuda():
23
+ return False, "Humming only supported on CUDA"
24
+
25
+ if not current_platform.has_device_capability(75):
26
+ return False, "Humming only supported on SM75+"
27
+
28
+ return True, None
29
+
30
+ @classmethod
31
+ def can_implement(cls, c: Mxfp8LinearLayerConfig) -> tuple[bool, str | None]:
32
+ return True, None
33
+
34
+ def process_weights_after_loading(self, layer: torch.nn.Module) -> None:
35
+ layer.weight_scale.data = layer.weight_scale.data.view(torch.float8_e8m0fnu)
36
+ name_map = {"weight": "weight", "weight_scale": "weight_scale"}
37
+
38
+ quant_config = {
39
+ "quant_method": "humming",
40
+ "dtype": "float8e4m3",
41
+ "scale_dtype": "float8e8m0",
42
+ "group_size": 32,
43
+ "weight_scale_type": "group",
44
+ }
45
+
46
+ convert_linear_layer_to_humming_standard(layer=layer, name_map=name_map)
47
+ prepare_humming_layer(layer, quant_config)
48
+
49
+ def apply_weights(
50
+ self,
51
+ layer: torch.nn.Module,
52
+ x: torch.Tensor,
53
+ bias: torch.Tensor | None = None,
54
+ ) -> 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,
62
+ )
63
+ return output.view(*x.shape[:-1], output.size(-1))
vllm/model_executor/kernels/linear/nvfp4/humming.py
new
+73
@@ -0,0 +1,73 @@
1
+# SPDX-License-Identifier: Apache-2.0
2
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
+
4
+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,
9
+)
10
+from vllm.platforms import current_platform
11
+
12
+from .base import NvFp4LinearKernel, NvFp4LinearLayerConfig
13
+
14
+logger = init_logger(__name__)
15
+
16
+
17
+class HummingNvFp4LinearKernel(NvFp4LinearKernel):
18
+ """Humming GEMM Kernel for NVFP4."""
19
+
20
+ @classmethod
21
+ def is_supported(
22
+ cls, compute_capability: int | None = None
23
+ ) -> tuple[bool, str | None]:
24
+ if not current_platform.is_cuda():
25
+ return False, "Humming only supported on CUDA"
26
+
27
+ if not current_platform.has_device_capability(75):
28
+ return False, "Humming only supported on SM75+"
29
+
30
+ return True, None
31
+
32
+ @classmethod
33
+ def can_implement(cls, config: NvFp4LinearLayerConfig) -> tuple[bool, str | None]:
34
+ return True, None
35
+
36
+ def process_weights_after_loading(self, layer: torch.nn.Module) -> None:
37
+ # Route through humming's compressed-tensors nvfp4 loader (same path as
38
+ # the MoE oracle); the native group_tensor schema mishandles a scalar
39
+ # global scale.
40
+ quant_config = {
41
+ "quant_method": "compressed-tensors",
42
+ "format": "nvfp4-pack-quantized",
43
+ "type": "float",
44
+ "num_bits": 4,
45
+ "strategy": "group",
46
+ "group_size": 16,
47
+ }
48
+ # CT pack-quantized reads `weight_packed`; the scheme renamed it to `weight`.
49
+ if not hasattr(layer, "weight_packed"):
50
+ layer.weight_packed = layer.weight
51
+ del layer.weight
52
+ # The CT linear scheme inverts the global scale (1/scale) for
53
+ # marlin/cutlass; humming wants the original.
54
+ layer.weight_global_scale = torch.nn.Parameter(
55
+ 1.0 / layer.weight_global_scale, requires_grad=False
56
+ )
57
+ prepare_humming_layer(layer, quant_config)
58
+
59
+ def apply_weights(
60
+ self,
61
+ layer: torch.nn.Module,
62
+ x: torch.Tensor,
63
+ bias: torch.Tensor | None = None,
64
+ ) -> 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,
72
+ )
73
+ return output.view(*x.shape[:-1], output.size(-1))
vllm/model_executor/kernels/linear/scaled_mm/humming.py
new
+156
@@ -0,0 +1,156 @@
1
+# SPDX-License-Identifier: Apache-2.0
2
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
+
4
+import torch
5
+
6
+from vllm.logger import init_logger
7
+from vllm.model_executor.layers.quantization.utils.humming_utils import (
8
+ convert_linear_layer_to_humming_standard,
9
+ prepare_humming_layer,
10
+)
11
+from vllm.platforms import current_platform
12
+
13
+from .ScaledMMLinearKernel import (
14
+ FP8ScaledMMLinearKernel,
15
+ FP8ScaledMMLinearLayerConfig,
16
+ Int8ScaledMMLinearKernel,
17
+ Int8ScaledMMLinearLayerConfig,
18
+)
19
+
20
+logger = init_logger(__name__)
21
+
22
+
23
+class HummingFP8ScaledMMLinearKernel(FP8ScaledMMLinearKernel):
24
+ """Humming GEMM Kernel for FP8."""
25
+
26
+ @classmethod
27
+ def is_supported(
28
+ cls, compute_capability: int | None = None
29
+ ) -> tuple[bool, str | None]:
30
+ if not current_platform.is_cuda():
31
+ return False, "Humming only supported on CUDA"
32
+
33
+ if not current_platform.has_device_capability(75):
34
+ return False, "Humming only supported on SM75+"
35
+
36
+ return True, None
37
+
38
+ @classmethod
39
+ def can_implement(
40
+ cls, config: FP8ScaledMMLinearLayerConfig
41
+ ) -> tuple[bool, str | None]:
42
+ return True, None
43
+
44
+ def process_weights_after_loading(self, layer: torch.nn.Module) -> None:
45
+ from vllm.utils.humming import dtypes
46
+
47
+ name_map = {"weight": "weight", "weight_scale": "weight_scale"}
48
+ scale_torch_dtype = self.config.weight_quant_key.scale.dtype
49
+ scale_dtype = dtypes.DataType.from_torch_dtype(scale_torch_dtype)
50
+
51
+ quant_config = {
52
+ "quant_method": "humming",
53
+ "dtype": "float8e4m3",
54
+ "scale_dtype": scale_dtype,
55
+ }
56
+
57
+ assert self.config.weight_quant_key.scale2 is None
58
+ scale_group_shape = self.config.weight_quant_key.scale.group_shape
59
+ if scale_group_shape.is_per_tensor():
60
+ 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"
64
+ elif scale_group_shape.is_per_channel():
65
+ quant_config["weight_scale_type"] = "channel"
66
+ elif scale_group_shape.is_per_group():
67
+ quant_config["weight_scale_type"] = "group"
68
+ quant_config["group_size"] = scale_group_shape.col
69
+ else:
70
+ assert scale_group_shape.row > 0 and scale_group_shape.col > 0
71
+ quant_config["weight_scale_type"] = "block"
72
+ quant_config["weight_scale_group_size_n"] = scale_group_shape.row
73
+ quant_config["weight_scale_group_size"] = scale_group_shape.col
74
+
75
+ if hasattr(layer, "weight_scale_inv"):
76
+ name_map["weight_scale"] = "weight_scale_inv"
77
+
78
+ convert_linear_layer_to_humming_standard(layer=layer, name_map=name_map)
79
+ prepare_humming_layer(layer, quant_config)
80
+
81
+ def apply_weights(
82
+ self,
83
+ layer: torch.nn.Module,
84
+ x: torch.Tensor,
85
+ bias: torch.Tensor | None = None,
86
+ ) -> 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,
94
+ )
95
+ return output.view(*x.shape[:-1], output.size(-1))
96
+
97
+ def apply_scaled_mm(
98
+ self,
99
+ *,
100
+ A: torch.Tensor,
101
+ B: torch.Tensor,
102
+ out_dtype: torch.dtype,
103
+ As: torch.Tensor,
104
+ Bs: torch.Tensor,
105
+ bias: torch.Tensor | None,
106
+ output_shape: list,
107
+ ) -> torch.Tensor:
108
+ pass
109
+
110
+
111
+class HummingInt8ScaledMMLinearKernel(Int8ScaledMMLinearKernel):
112
+ """Humming GEMM Kernel for INT8."""
113
+
114
+ @classmethod
115
+ def is_supported(
116
+ cls, compute_capability: int | None = None
117
+ ) -> tuple[bool, str | None]:
118
+ if not current_platform.is_cuda():
119
+ return False, "Humming only supported on CUDA"
120
+
121
+ if not current_platform.has_device_capability(75):
122
+ return False, "Humming only supported on SM75+"
123
+
124
+ return True, None
125
+
126
+ @classmethod
127
+ def can_implement(
128
+ cls, config: Int8ScaledMMLinearLayerConfig
129
+ ) -> tuple[bool, str | None]:
130
+ return True, None
131
+
132
+ def process_weights_after_loading(self, layer: torch.nn.Module) -> None:
133
+ weight_name, weight_scale_name, *_ = self.layer_param_names
134
+ name_map = {"weight": weight_name, "weight_scale": weight_scale_name}
135
+ quant_config = {"quant_method": "humming", "dtype": "int8"}
136
+ weight = getattr(layer, weight_name)
137
+ weight.data = weight.data + 128
138
+
139
+ convert_linear_layer_to_humming_standard(layer=layer, name_map=name_map)
140
+ prepare_humming_layer(layer, quant_config)
141
+
142
+ def apply_weights(
143
+ self,
144
+ layer: torch.nn.Module,
145
+ x: torch.Tensor,
146
+ bias: torch.Tensor | None = None,
147
+ ) -> 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,
155
+ )
156
+ return output.view(*x.shape[:-1], output.size(-1))
vllm/model_executor/layers/fused_moe/experts/fused_humming_moe.py
+32
-10
@@ -38,15 +38,20 @@ from vllm.model_executor.layers.fused_moe.utils import (
38
)
39
from vllm.model_executor.layers.quantization.utils.quant_utils import (
40
QuantKey,
41
+ kFp8Dynamic128Sym,
42
kFp8DynamicTokenSym,
43
kFp8Static128BlockSym,
44
kFp8StaticChannelSym,
45
+ kFp8StaticTensorSym,
46
kInt4Static,
47
+ kInt8DynamicTokenSym,
48
kInt8Static,
49
+ kInt8StaticChannelSym,
50
kMxfp4Dynamic,
51
kMxfp4Static,
52
kMxfp8Dynamic,
53
kMxfp8Static,
54
+ kNvfp4Dynamic,
55
kNvfp4Static,
56
)
57
from vllm.platforms import current_platform
@@ -61,9 +66,9 @@ if TYPE_CHECKING:
66
logger = init_logger(__name__)
67
68
64
-def get_humming_moe_gemm_type() -> str | None:
69
+def get_humming_moe_gemm_type() -> str:
70
env_gemm_type: str | None = envs.VLLM_HUMMING_MOE_GEMM_TYPE
66
- gemm_type = None
71
+ gemm_type = "indexed"
72
if env_gemm_type is not None:
73
env_gemm_type = env_gemm_type.lower()
74
if env_gemm_type == "indexed":
@@ -87,7 +92,7 @@ class HummingExpertsBase(mk.FusedMoEExpertsModular):
92
num_dispatchers: int | None = None,
93
):
94
self.layer = layer
90
- self.num_experts = self.layer.num_experts
95
+ self.num_experts = self.layer.local_num_experts
96
self.global_num_experts = self.layer.global_num_experts
97
self.init_humming_moe()
98
@@ -186,6 +191,24 @@ class HummingExpertsBase(mk.FusedMoEExpertsModular):
191
(kInt4Static, kFp8DynamicTokenSym),
192
(kInt8Static, None),
193
(kInt8Static, kFp8DynamicTokenSym),
194
+ # Checkpoint-driven (weight, activation) pairs the dense/MoE oracles
195
+ # pass. Humming defers input quant (see expects_unquantized_inputs),
196
+ # so the activation key does not constrain support.
197
+ # fp8 (compressed-tensors / native / modelopt)
198
+ (kFp8StaticChannelSym, kFp8StaticTensorSym),
199
+ (kFp8StaticChannelSym, kFp8Dynamic128Sym),
200
+ (kFp8StaticTensorSym, None),
201
+ (kFp8StaticTensorSym, kFp8DynamicTokenSym),
202
+ (kFp8StaticTensorSym, kFp8StaticTensorSym),
203
+ (kFp8StaticTensorSym, kFp8Dynamic128Sym),
204
+ (kFp8Static128BlockSym, kFp8Dynamic128Sym),
205
+ # int8 (compressed-tensors w8a8 / experts_int8)
206
+ (kInt8StaticChannelSym, None),
207
+ (kInt8StaticChannelSym, kInt8DynamicTokenSym),
208
+ # nvfp4 (compressed-tensors / modelopt / quark)
209
+ (kNvfp4Static, kNvfp4Dynamic),
210
+ # mxfp8 (compressed-tensors / modelopt / online)
211
+ (kMxfp8Static, kMxfp8Dynamic),
212
]
213
return (weight_key, activation_key) in SUPPORTED_W_A
214
@@ -463,13 +486,12 @@ class HummingExpertsBase(mk.FusedMoEExpertsModular):
486
assert hasattr(cls, "humming_gemm_type")
487
gemm_type = cls.humming_gemm_type().value.lower()
488
preferred_gemm_type = get_humming_moe_gemm_type()
466
- if preferred_gemm_type is not None:
467
- supported = preferred_gemm_type.lower() == gemm_type
468
- if not supported:
469
- reason = (
470
- f"preferred gemm type {preferred_gemm_type} != "
471
- f"supported gemm type {gemm_type}"
472
- )
489
+ supported = preferred_gemm_type.lower() == gemm_type
490
+ if not supported:
491
+ reason = (
492
+ f"preferred gemm type {preferred_gemm_type} != "
493
+ f"supported gemm type {gemm_type}"
494
+ )
495
496
return supported, reason
497
vllm/model_executor/layers/fused_moe/oracle/fp8.py
+81
@@ -1,6 +1,7 @@
1
# SPDX-License-Identifier: Apache-2.0
2
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
from enum import Enum
4
+from typing import Any
5
6
import torch
7
@@ -45,6 +46,7 @@ class Fp8MoeBackend(Enum):
46
DEEPGEMM = "DEEPGEMM"
47
BATCHED_DEEPGEMM = "BATCHED_DEEPGEMM"
48
MARLIN = "MARLIN"
49
+ HUMMING = "HUMMING"
50
TRITON = "TRITON"
51
BATCHED_TRITON = "BATCHED_TRITON"
52
AITER = "AITER"
@@ -83,6 +85,7 @@ def _get_priority_backends(
85
Fp8MoeBackend.VLLM_CUTLASS,
86
Fp8MoeBackend.TRITON,
87
Fp8MoeBackend.MARLIN,
88
+ Fp8MoeBackend.HUMMING,
89
Fp8MoeBackend.BATCHED_DEEPGEMM,
90
Fp8MoeBackend.BATCHED_VLLM_CUTLASS,
91
Fp8MoeBackend.BATCHED_TRITON,
@@ -162,6 +165,19 @@ def backend_to_kernel_cls(
165
166
return [BatchedDeepGemmExperts]
167
168
+ elif backend == Fp8MoeBackend.HUMMING:
169
+ from vllm.model_executor.layers.fused_moe.experts.fused_humming_moe import (
170
+ BatchedHummingGroupedExperts,
171
+ HummingGroupedExperts,
172
+ HummingIndexedExperts,
173
+ )
174
+
175
+ return [
176
+ BatchedHummingGroupedExperts,
177
+ HummingGroupedExperts,
178
+ HummingIndexedExperts,
179
+ ]
180
+
181
elif backend == Fp8MoeBackend.MARLIN:
182
from vllm.model_executor.layers.fused_moe.experts.marlin_moe import (
183
MarlinExperts,
@@ -240,6 +256,7 @@ def map_fp8_backend(runner_backend: MoEBackend) -> Fp8MoeBackend:
256
"flashinfer_trtllm": Fp8MoeBackend.FLASHINFER_TRTLLM,
257
"flashinfer_cutlass": Fp8MoeBackend.FLASHINFER_CUTLASS,
258
"marlin": Fp8MoeBackend.MARLIN,
259
+ "humming": Fp8MoeBackend.HUMMING,
260
"aiter": Fp8MoeBackend.AITER,
261
"hpc": Fp8MoeBackend.HPC,
262
}
@@ -402,6 +419,41 @@ def select_fp8_moe_backend(
419
return Fp8MoeBackend.NONE, None
420
421
422
+def _humming_fp8_weight_schema(
423
+ layer: RoutedExperts, weight: torch.Tensor, weight_scale: torch.Tensor
424
+) -> dict[str, Any]:
425
+ """Build the humming weight schema from the canonical on-device fp8/mxfp8
426
+ tensors (scale dtype/shape, block size), not the producing quant method."""
427
+ # mxfp8: e8m0 group-32 scales (stored as uint8 bytes or e8m0). humming has
428
+ # no compressed-tensors mxfp8 loader; its modelopt schema fits both sources.
429
+ if weight_scale.dtype in (torch.uint8, torch.float8_e8m0fnu):
430
+ return {"quant_method": "modelopt", "quant_algo": "mxfp8"}
431
+
432
+ if hasattr(layer, "w13_weight_scale_inv"):
433
+ assert hasattr(layer, "weight_block_size")
434
+ return {"quant_method": "fp8", "weight_block_size": layer.weight_block_size}
435
+
436
+ # fp8 (e4m3): recover the strategy from the scale layout (block from
437
+ # weight_block_size, else channel vs tensor by per-expert scale count).
438
+ config: dict[str, Any] = {
439
+ "quant_method": "compressed-tensors",
440
+ "format": "float-quantized",
441
+ "type": "float",
442
+ "num_bits": 8,
443
+ "symmetric": True,
444
+ }
445
+ weight_block_size = getattr(layer, "weight_block_size", None)
446
+ num_experts, num_output = weight.shape[0], weight.shape[-2]
447
+ if weight_block_size is not None:
448
+ config["strategy"] = "block"
449
+ config["block_structure"] = list(weight_block_size)
450
+ elif weight_scale.numel() >= num_experts * num_output:
451
+ config["strategy"] = "channel"
452
+ else:
453
+ config["strategy"] = "tensor"
454
+ return config
455
+
456
+
457
def convert_to_fp8_moe_kernel_format(
458
fp8_backend: Fp8MoeBackend,
459
# TODO(bnell): replace layer with weight_block_size
@@ -429,6 +481,18 @@ def convert_to_fp8_moe_kernel_format(
481
w13, w2, w13_scale, w2_scale = rocm_aiter_ops.shuffle_mxfp8_moe_weights(
482
w13, w2, w13_scale, w2_scale
483
)
484
+ elif fp8_backend == Fp8MoeBackend.HUMMING:
485
+ from vllm.model_executor.layers.quantization.utils.humming_utils import (
486
+ convert_to_humming_moe_kernel_format,
487
+ )
488
+
489
+ convert_to_humming_moe_kernel_format(
490
+ layer, quant_config=_humming_fp8_weight_schema(layer, w13, w13_scale)
491
+ )
492
+ w13 = layer.w13_weight
493
+ w2 = layer.w2_weight
494
+ w13_scale = layer.w13_weight_scale
495
+ w2_scale = layer.w2_weight_scale
496
elif fp8_backend == Fp8MoeBackend.MARLIN:
497
weight_block_size = getattr(layer, "weight_block_size", None)
498
if weight_block_size == [1, 32]:
@@ -511,6 +575,7 @@ def make_fp8_moe_quant_config(
575
swiglu_limit: float | None = None,
576
gemm1_alpha: float | None = None,
577
gemm1_beta: float | None = None,
578
+ layer: torch.nn.Module | None = None,
579
) -> FusedMoEQuantConfig:
580
"""
581
Create FusedMoEQuantConfig for the specified FP8 Backend.
@@ -537,6 +602,14 @@ def make_fp8_moe_quant_config(
602
gemm1_beta=gemm1_beta,
603
gemm1_clamp_limit=swiglu_limit,
604
)
605
+ elif fp8_backend == Fp8MoeBackend.HUMMING:
606
+ from vllm.model_executor.layers.fused_moe import RoutedExperts
607
+ from vllm.model_executor.layers.quantization.utils.humming_utils import (
608
+ get_humming_moe_quant_config,
609
+ )
610
+
611
+ assert isinstance(layer, RoutedExperts)
612
+ return get_humming_moe_quant_config(layer)
613
614
# Flashinfer CUTLASS or HPC per-tensor uses single dq scale
615
# (alpha = w_scale * a_scale) and inverse a2 scale.
@@ -600,6 +673,7 @@ def make_fp8_moe_kernel(
673
experts_cls: type[mk.FusedMoEExperts],
674
fp8_backend: Fp8MoeBackend,
675
routing_tables: tuple[torch.Tensor, torch.Tensor, torch.Tensor] | None = None,
676
+ layer: torch.nn.Module | None = None,
677
) -> mk.FusedMoEKernel:
678
# Create Prepare/Finalize.
679
prepare_finalize = maybe_make_prepare_finalize(
@@ -613,6 +687,11 @@ def make_fp8_moe_kernel(
687
688
logger.info_once("Using %s", prepare_finalize.__class__.__name__)
689
690
+ extra_kwargs = {}
691
+ if fp8_backend == Fp8MoeBackend.HUMMING:
692
+ assert layer is not None
693
+ extra_kwargs = {"layer": layer}
694
+
695
# Create Experts.
696
if prepare_finalize.activation_format == mk.FusedMoEActivationFormat.BatchedExperts:
697
max_num_tokens = prepare_finalize.max_num_tokens_per_rank()
@@ -622,11 +701,13 @@ def make_fp8_moe_kernel(
701
quant_config=moe_quant_config,
702
max_num_tokens=max_num_tokens,
703
num_dispatchers=prepare_finalize.num_dispatchers(),
704
+ **extra_kwargs,
705
)
706
else:
707
experts = experts_cls(
708
moe_config=moe_config,
709
quant_config=moe_quant_config,
710
+ **extra_kwargs,
711
)
712
713
kernel = mk.FusedMoEKernel(
vllm/model_executor/layers/fused_moe/oracle/int8.py
+82
-1
@@ -2,6 +2,7 @@
2
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4
from enum import Enum
5
+from typing import Any
6
7
import torch
8
@@ -22,6 +23,7 @@ from vllm.model_executor.layers.quantization.utils.quant_utils import (
23
kInt8DynamicTokenSym,
24
kInt8StaticChannelSym,
25
)
26
+from vllm.model_executor.utils import replace_parameter
27
from vllm.platforms import current_platform
28
29
logger = init_logger(__name__)
@@ -29,6 +31,7 @@ logger = init_logger(__name__)
31
32
class Int8MoeBackend(Enum):
33
TRITON = "TRITON"
34
+ HUMMING = "HUMMING"
35
CPU = "CPU"
36
37
@@ -40,6 +43,7 @@ def _get_priority_backends(
43
"""
44
_AVAILABLE_BACKENDS = [
45
Int8MoeBackend.TRITON,
46
+ Int8MoeBackend.HUMMING,
47
Int8MoeBackend.CPU,
48
]
49
@@ -62,6 +66,19 @@ def backend_to_kernel_cls(
66
67
return [TritonExperts]
68
69
+ elif backend == Int8MoeBackend.HUMMING:
70
+ from vllm.model_executor.layers.fused_moe.experts.fused_humming_moe import (
71
+ BatchedHummingGroupedExperts,
72
+ HummingGroupedExperts,
73
+ HummingIndexedExperts,
74
+ )
75
+
76
+ return [
77
+ BatchedHummingGroupedExperts,
78
+ HummingGroupedExperts,
79
+ HummingIndexedExperts,
80
+ ]
81
+
82
elif backend == Int8MoeBackend.CPU:
83
from vllm.model_executor.layers.fused_moe.experts.cpu_moe import (
84
CPUExpertsInt8,
@@ -77,6 +94,7 @@ def map_int8_backend(runner_backend: MoEBackend) -> Int8MoeBackend:
94
"""Map user's MoEBackend to Int8MoeBackend."""
95
mapping = {
96
"triton": Int8MoeBackend.TRITON,
97
+ "humming": Int8MoeBackend.HUMMING,
98
}
99
if backend := mapping.get(runner_backend):
100
return backend
@@ -163,6 +181,7 @@ def select_int8_moe_backend(
181
182
183
def make_int8_moe_quant_config(
184
+ int8_backend: Int8MoeBackend,
185
w1_scale: torch.Tensor,
186
w2_scale: torch.Tensor,
187
a1_scale: torch.Tensor | None = None,
@@ -170,11 +189,21 @@ def make_int8_moe_quant_config(
189
w1_bias: torch.Tensor | None = None,
190
w2_bias: torch.Tensor | None = None,
191
per_act_token_quant: bool = False,
192
+ layer: torch.nn.Module | None = None,
193
) -> FusedMoEQuantConfig:
194
assert (a1_scale is None and a2_scale is None) or (
195
a1_scale is not None and a2_scale is not None
196
), "a1_scale and a2_scale must both be provided or both be None"
197
198
+ if int8_backend == Int8MoeBackend.HUMMING:
199
+ from vllm.model_executor.layers.fused_moe import RoutedExperts
200
+ from vllm.model_executor.layers.quantization.utils.humming_utils import (
201
+ get_humming_moe_quant_config,
202
+ )
203
+
204
+ assert isinstance(layer, RoutedExperts)
205
+ return get_humming_moe_quant_config(layer)
206
+
207
if a1_scale is None or a2_scale is None:
208
return int8_w8a16_moe_quant_config(
209
w1_scale=w1_scale,
@@ -196,13 +225,56 @@ def make_int8_moe_quant_config(
225
)
226
227
228
+def _humming_int8_weight_schema(
229
+ weight: torch.Tensor, weight_scale: torch.Tensor
230
+) -> dict[str, Any]:
231
+ """Build the humming compressed-tensors int8 schema from the canonical
232
+ on-device tensors; humming does the signed-int8 -> native conversion."""
233
+ config: dict[str, Any] = {
234
+ "quant_method": "compressed-tensors",
235
+ "format": "int-quantized",
236
+ "type": "int",
237
+ "num_bits": 8,
238
+ "symmetric": True,
239
+ "strategy": "channel",
240
+ }
241
+ num_experts, num_output = weight.shape[0], weight.shape[-2]
242
+ if weight_scale.numel() < num_experts * num_output:
243
+ config["strategy"] = "tensor"
244
+ return config
245
+
246
+
247
def convert_to_int8_moe_kernel_format(
248
int8_backend: Int8MoeBackend,
249
w13: torch.Tensor,
250
w2: torch.Tensor,
251
+ layer: torch.nn.Module | None = None,
252
+ w13_scale: torch.Tensor | None = None,
253
) -> tuple[torch.Tensor, torch.Tensor]:
254
"""Convert INT8 MoE weights to backend-specific kernel format."""
205
- if int8_backend == Int8MoeBackend.CPU:
255
+ if int8_backend == Int8MoeBackend.HUMMING:
256
+ from vllm.model_executor.layers.quantization.utils.humming_utils import (
257
+ convert_to_humming_moe_kernel_format,
258
+ )
259
+
260
+ assert layer is not None
261
+ # Humming reads canonical CT scales (w*_weight_scale) from the layer.
262
+ # Online int8 produces per-channel (E, N) w*_scale; expose them as the
263
+ # (E, N, 1) w*_weight_scale humming's loader expects.
264
+ for sub in ("w13", "w2"):
265
+ if hasattr(layer, f"{sub}_weight_scale"):
266
+ continue
267
+ scale = getattr(layer, f"{sub}_scale").data
268
+ if scale.dim() < 3:
269
+ scale = scale.unsqueeze(-1)
270
+ replace_parameter(layer, f"{sub}_weight_scale", scale)
271
+ delattr(layer, f"{sub}_scale")
272
+ convert_to_humming_moe_kernel_format(
273
+ layer,
274
+ quant_config=_humming_int8_weight_schema(w13, layer.w13_weight_scale),
275
+ )
276
+ return layer.w13_weight, layer.w2_weight
277
+ elif int8_backend == Int8MoeBackend.CPU:
278
from vllm.model_executor.layers.fused_moe.experts.cpu_moe import (
279
prepare_int8_moe_layer_for_cpu,
280
)
@@ -215,10 +287,12 @@ def convert_to_int8_moe_kernel_format(
287
288
289
def make_int8_moe_kernel(
290
+ int8_backend: Int8MoeBackend,
291
moe_quant_config: FusedMoEQuantConfig,
292
moe_config: FusedMoEConfig,
293
experts_cls: type[mk.FusedMoEExperts],
294
routing_tables: tuple[torch.Tensor, torch.Tensor, torch.Tensor] | None = None,
295
+ layer: torch.nn.Module | None = None,
296
) -> mk.FusedMoEKernel:
297
# Create Prepare/Finalize.
298
prepare_finalize = maybe_make_prepare_finalize(
@@ -232,6 +306,11 @@ def make_int8_moe_kernel(
306
307
logger.info_once("Using %s", prepare_finalize.__class__.__name__)
308
309
+ extra_kwargs = {}
310
+ if int8_backend == Int8MoeBackend.HUMMING:
311
+ assert layer is not None
312
+ extra_kwargs = {"layer": layer}
313
+
314
# Create Experts.
315
if prepare_finalize.activation_format == mk.FusedMoEActivationFormat.BatchedExperts:
316
max_num_tokens = prepare_finalize.max_num_tokens_per_rank()
@@ -241,11 +320,13 @@ def make_int8_moe_kernel(
320
quant_config=moe_quant_config,
321
max_num_tokens=max_num_tokens,
322
num_dispatchers=prepare_finalize.num_dispatchers(),
323
+ **extra_kwargs,
324
)
325
else:
326
experts = experts_cls(
327
moe_config=moe_config,
328
quant_config=moe_quant_config,
329
+ **extra_kwargs,
330
)
331
332
kernel = mk.FusedMoEKernel(
vllm/model_executor/layers/fused_moe/oracle/int_wna16.py
+111
-21
@@ -11,6 +11,7 @@ from compressed_tensors.quantization import (
11
12
import vllm._custom_ops as ops
13
import vllm.model_executor.layers.fused_moe.modular_kernel as mk
14
+from vllm.config.kernel import MoEBackend
15
from vllm.logger import init_logger
16
from vllm.model_executor.layers.fused_moe.config import (
17
FusedMoEConfig,
@@ -46,6 +47,7 @@ logger = init_logger(__name__)
47
class WNA16MoEBackend(Enum):
48
MARLIN = "MARLIN"
49
BATCHED_MARLIN = "BATCHED_MARLIN"
50
+ HUMMING = "HUMMING"
51
CPU = "CPU"
52
FLASHINFER_TRTLLM = "FLASHINFER_TRTLLM"
53
XPU = "XPU"
@@ -55,7 +57,19 @@ def backend_to_kernel_cls(
57
backend: WNA16MoEBackend,
58
) -> list[type[mk.FusedMoEExperts]]:
59
"""Return the experts class for the given backend, or None for NONE."""
58
- if backend == WNA16MoEBackend.MARLIN:
60
+ if backend == WNA16MoEBackend.HUMMING:
61
+ from vllm.model_executor.layers.fused_moe.experts.fused_humming_moe import (
62
+ BatchedHummingGroupedExperts,
63
+ HummingGroupedExperts,
64
+ HummingIndexedExperts,
65
+ )
66
+
67
+ return [
68
+ BatchedHummingGroupedExperts,
69
+ HummingGroupedExperts,
70
+ HummingIndexedExperts,
71
+ ]
72
+ elif backend == WNA16MoEBackend.MARLIN:
73
return [MarlinExperts]
74
elif backend == WNA16MoEBackend.BATCHED_MARLIN:
75
return [BatchedMarlinExperts]
@@ -90,10 +104,26 @@ def _get_priority_backends() -> list[WNA16MoEBackend]:
104
WNA16MoEBackend.FLASHINFER_TRTLLM,
105
WNA16MoEBackend.MARLIN,
106
WNA16MoEBackend.BATCHED_MARLIN,
107
+ WNA16MoEBackend.HUMMING,
108
]
109
return _AVAILABLE_BACKENDS
110
111
112
+def map_wna16_backend(runner_backend: MoEBackend) -> WNA16MoEBackend:
113
+ """Map user's MoEBackend to WNA16MoEBackend."""
114
+ mapping = {
115
+ "marlin": WNA16MoEBackend.MARLIN,
116
+ "humming": WNA16MoEBackend.HUMMING,
117
+ "flashinfer_trtllm": WNA16MoEBackend.FLASHINFER_TRTLLM,
118
+ }
119
+ if backend := mapping.get(runner_backend):
120
+ return backend
121
+ raise ValueError(
122
+ f"moe_backend='{runner_backend}' is not supported for WNA16 MoE. "
123
+ f"Expected one of {list(mapping.keys())}."
124
+ )
125
+
126
+
127
def select_wna16_moe_backend(
128
config: FusedMoEConfig,
129
weight_key: QuantKey,
@@ -146,6 +176,14 @@ def select_wna16_moe_backend(
176
return backend, k_cls
177
raise ValueError(_make_log_unsupported(backend, reason))
178
179
+ # Handle explicit moe_backend from user.
180
+ runner_backend = config.moe_backend
181
+ if runner_backend != "auto":
182
+ requested_backend = map_wna16_backend(runner_backend)
183
+ return _return_or_raise(
184
+ requested_backend, config, weight_key, None, activation_format
185
+ )
186
+
187
# Select kernels in order of backend.
188
AVAILABLE_BACKENDS = _get_priority_backends()
189
@@ -210,6 +248,8 @@ def make_wna16_moe_kernel(
248
moe_quant_config: FusedMoEQuantConfig,
249
moe_config: FusedMoEConfig,
250
experts_cls: type[mk.FusedMoEExperts],
251
+ backend: WNA16MoEBackend = WNA16MoEBackend.MARLIN,
252
+ layer: torch.nn.Module | None = None,
253
is_k_full: bool = False,
254
w13_g_idx: torch.Tensor | None = None,
255
w2_g_idx: torch.Tensor | None = None,
@@ -228,14 +268,18 @@ def make_wna16_moe_kernel(
268
)
269
270
# Currently, we only support TrtLlmMxint4ExpertsMonolithic, MarlinExperts,
231
- # BatchedMarlinExperts, XPUExpertsWNA16, and CPUExpertsInt4
232
- assert experts_cls in (
271
+ # BatchedMarlinExperts, XPUExpertsWNA16, CPUExpertsInt4, and the Humming
272
+ # grouped/indexed experts.
273
+ allowed_experts: tuple[type[mk.FusedMoEExperts], ...] = (
274
MarlinExperts,
275
BatchedMarlinExperts,
276
TrtLlmMxint4ExpertsMonolithic,
277
XPUExpertsWNA16,
278
CPUExpertsInt4,
279
)
280
+ if backend == WNA16MoEBackend.HUMMING:
281
+ allowed_experts += tuple(backend_to_kernel_cls(WNA16MoEBackend.HUMMING))
282
+ assert experts_cls in allowed_experts
283
284
is_monolithic = experts_cls.is_monolithic()
285
@@ -251,7 +295,10 @@ def make_wna16_moe_kernel(
295
logger.info_once("Using %s", prepare_finalize.__class__.__name__, scope="local")
296
297
extra_args: dict[str, Any] = {}
254
- if issubclass(experts_cls, MarlinExpertsBase):
298
+ if backend == WNA16MoEBackend.HUMMING:
299
+ assert layer is not None
300
+ extra_args = {"layer": layer}
301
+ elif issubclass(experts_cls, MarlinExpertsBase):
302
extra_args = {
303
"w13_g_idx": w13_g_idx,
304
"w2_g_idx": w2_g_idx,
@@ -941,6 +988,35 @@ def _process_weights_xpu(
988
)
989
990
991
+def _humming_wna16_weight_schema(
992
+ quant_config: QuantizationConfig | QuantizationArgs | None,
993
+) -> dict[str, Any]:
994
+ """Humming weight schema for a WNA16 checkpoint, derived from the quant
995
+ config rather than the running kernel."""
996
+ from vllm.model_executor.layers.quantization.auto_awq import AutoAWQConfig
997
+ from vllm.model_executor.layers.quantization.auto_gptq import AutoGPTQConfig
998
+
999
+ if isinstance(quant_config, AutoAWQConfig):
1000
+ return {
1001
+ "quant_method": "awq",
1002
+ "bits": quant_config.weight_bits,
1003
+ "group_size": quant_config.group_size,
1004
+ "zero_point": quant_config.zero_point,
1005
+ }
1006
+ if isinstance(quant_config, AutoGPTQConfig):
1007
+ return {
1008
+ "quant_method": "gptq",
1009
+ "bits": quant_config.weight_bits,
1010
+ "group_size": quant_config.group_size,
1011
+ "desc_act": quant_config.desc_act,
1012
+ "sym": quant_config.is_sym,
1013
+ }
1014
+ raise TypeError(
1015
+ "Humming WNA16 MoE requires AutoAWQConfig or AutoGPTQConfig, "
1016
+ f"got {type(quant_config).__name__}."
1017
+ )
1018
+
1019
+
1020
def convert_to_wna16_moe_kernel_format(
1021
backend: WNA16MoEBackend,
1022
layer: torch.nn.Module,
@@ -956,26 +1032,30 @@ def convert_to_wna16_moe_kernel_format(
1032
w2_qzeros: torch.Tensor | None = None,
1033
w13_bias: torch.Tensor | None = None,
1034
w2_bias: torch.Tensor | None = None,
959
-) -> tuple[
960
- torch.Tensor, # w13_qweight
961
- torch.Tensor, # w2_qweight
962
- torch.Tensor, # w13_scales
963
- torch.Tensor, # w2_scales
964
- torch.Tensor | None, # w13_g_idx
965
- torch.Tensor | None, # w2_g_idx
966
- torch.Tensor | None, # w13_g_idx_sort_indices
967
- torch.Tensor | None, # w2_g_idx_sort_indices
968
- torch.Tensor | None, # w13_qzeros
969
- torch.Tensor | None, # w2_qzeros
970
- torch.Tensor | None, # w13_input_global_scale
971
- torch.Tensor | None, # w2_input_global_scale
972
- torch.Tensor | None, # w13_bias
973
- torch.Tensor | None, # w2_bias
974
-]:
1035
+) -> (
1036
+ tuple[
1037
+ torch.Tensor, # w13_qweight
1038
+ torch.Tensor, # w2_qweight
1039
+ torch.Tensor, # w13_scales
1040
+ torch.Tensor, # w2_scales
1041
+ torch.Tensor | None, # w13_g_idx
1042
+ torch.Tensor | None, # w2_g_idx
1043
+ torch.Tensor | None, # w13_g_idx_sort_indices
1044
+ torch.Tensor | None, # w2_g_idx_sort_indices
1045
+ torch.Tensor | None, # w13_qzeros
1046
+ torch.Tensor | None, # w2_qzeros
1047
+ torch.Tensor | None, # w13_input_global_scale
1048
+ torch.Tensor | None, # w2_input_global_scale
1049
+ torch.Tensor | None, # w13_bias
1050
+ torch.Tensor | None, # w2_bias
1051
+ ]
1052
+ | None
1053
+):
1054
"""Dispatch weight post-processing to the appropriate per-backend handler.
1055
1056
To add a new backend, implement a ``_process_weights_<name>`` helper and
978
- add a branch here.
1057
+ add a branch here. Backends that rewrite the layer's parameters in place
1058
+ (e.g. Humming) return ``None``; the caller then skips the param scatter.
1059
1060
Args:
1061
backend: the selected ``WNA16MoEBackend``.
@@ -983,6 +1063,16 @@ def convert_to_wna16_moe_kernel_format(
1063
quant_config: the ``QuantizationConfig`` for this layer.
1064
input_dtype: optional activation dtype, usually should be 16 bit.
1065
"""
1066
+ if backend == WNA16MoEBackend.HUMMING:
1067
+ from vllm.model_executor.layers.quantization.utils.humming_utils import (
1068
+ convert_to_humming_moe_kernel_format,
1069
+ )
1070
+
1071
+ convert_to_humming_moe_kernel_format(
1072
+ layer, quant_config=_humming_wna16_weight_schema(quant_config)
1073
+ )
1074
+ return None
1075
+
1076
if backend in (
1077
WNA16MoEBackend.MARLIN,
1078
WNA16MoEBackend.BATCHED_MARLIN,
vllm/model_executor/layers/fused_moe/oracle/mxfp8.py
+2
@@ -25,6 +25,7 @@ _SUPPORTED_BACKENDS = (
25
# is_supported_config passes (gfx950 + flydsl installed + not EP). On other
26
# devices / no flydsl / EP it is skipped and native is used.
27
Fp8MoeBackend.AITER_MXFP8,
28
+ Fp8MoeBackend.HUMMING,
29
)
30
31
_BACKEND_NAME_MAP: dict[str, Fp8MoeBackend] = {
@@ -34,6 +35,7 @@ _BACKEND_NAME_MAP: dict[str, Fp8MoeBackend] = {
35
"xpu": Fp8MoeBackend.XPU,
36
"aiter": Fp8MoeBackend.AITER_MXFP8,
37
"triton": Fp8MoeBackend.TRITON_MXFP8,
38
+ "humming": Fp8MoeBackend.HUMMING,
39
}
40
41
vllm/model_executor/layers/fused_moe/oracle/nvfp4.py
+69
-1
@@ -43,6 +43,7 @@ class NvFp4MoeBackend(Enum):
43
FLASHINFER_B12X = "FLASHINFER_B12X"
44
VLLM_CUTLASS = "VLLM_CUTLASS"
45
MARLIN = "MARLIN"
46
+ HUMMING = "HUMMING"
47
EMULATION = "EMULATION"
48
49
@@ -119,6 +120,18 @@ def backend_to_kernel_cls(
120
)
121
122
return [MarlinExperts]
123
+ elif backend == NvFp4MoeBackend.HUMMING:
124
+ from vllm.model_executor.layers.fused_moe.experts.fused_humming_moe import (
125
+ BatchedHummingGroupedExperts,
126
+ HummingGroupedExperts,
127
+ HummingIndexedExperts,
128
+ )
129
+
130
+ return [
131
+ BatchedHummingGroupedExperts,
132
+ HummingGroupedExperts,
133
+ HummingIndexedExperts,
134
+ ]
135
elif backend == NvFp4MoeBackend.EMULATION:
136
from vllm.model_executor.layers.fused_moe.experts.nvfp4_emulation_moe import (
137
Nvfp4QuantizationEmulationTritonExperts,
@@ -138,6 +151,7 @@ def map_nvfp4_backend(runner_backend: MoEBackend) -> NvFp4MoeBackend:
151
"flashinfer_cutedsl": NvFp4MoeBackend.FLASHINFER_CUTEDSL,
152
"flashinfer_b12x": NvFp4MoeBackend.FLASHINFER_B12X,
153
"marlin": NvFp4MoeBackend.MARLIN,
154
+ "humming": NvFp4MoeBackend.HUMMING,
155
"emulation": NvFp4MoeBackend.EMULATION,
156
}
157
if backend := mapping.get(runner_backend):
@@ -169,6 +183,7 @@ def select_nvfp4_moe_backend(
183
NvFp4MoeBackend.FLASHINFER_CUTLASS,
184
NvFp4MoeBackend.VLLM_CUTLASS,
185
NvFp4MoeBackend.MARLIN,
186
+ NvFp4MoeBackend.HUMMING,
187
NvFp4MoeBackend.EMULATION,
188
]
189
@@ -346,6 +361,41 @@ def convert_to_nvfp4_moe_kernel_format(
361
a2_scale=a2_scale,
362
is_act_and_mul=is_act_and_mul,
363
)
364
+ elif nvfp4_backend == NvFp4MoeBackend.HUMMING:
365
+ from vllm.model_executor.layers.quantization.utils.humming_utils import (
366
+ convert_to_humming_moe_kernel_format,
367
+ )
368
+
369
+ # Discriminate the source checkpoint layout by its global-scale param:
370
+ # compressed-tensors uses *_weight_global_scale, modelopt *_weight_scale_2.
371
+ # The logical schema is identical (nvfp4 group-16); only the on-layer
372
+ # param names differ. TODO: normalize both methods to a single canonical
373
+ # layout upstream so the oracle needs neither the probe nor the re-alias.
374
+ if hasattr(layer, "w13_weight_global_scale"):
375
+ quant_config = {
376
+ "quant_method": "compressed-tensors",
377
+ "format": "nvfp4-pack-quantized",
378
+ "type": "float",
379
+ "num_bits": 4,
380
+ "strategy": "group",
381
+ "group_size": 16,
382
+ }
383
+ # CT pack-quantized reads `weight_packed`; the method renamed it to
384
+ # `weight`. Re-alias (convert replaces all params anyway).
385
+ layer.w13_weight_packed = layer.w13_weight
386
+ layer.w2_weight_packed = layer.w2_weight
387
+ else:
388
+ quant_config = {"quant_method": "modelopt", "quant_algo": "nvfp4"}
389
+
390
+ convert_to_humming_moe_kernel_format(layer, quant_config=quant_config)
391
+ a13_scale = None
392
+ a2_scale = None
393
+ w13 = layer.w13_weight
394
+ w13_scale = layer.w13_weight_scale
395
+ w13_scale_2 = getattr(layer, "w13_global_scale", None)
396
+ w2 = layer.w2_weight
397
+ w2_scale = layer.w2_weight_scale
398
+ w2_scale_2 = getattr(layer, "w2_global_scale", None)
399
elif nvfp4_backend == NvFp4MoeBackend.MARLIN:
400
a13_scale = None
401
a2_scale = None
@@ -418,8 +468,17 @@ def make_nvfp4_moe_quant_config(
468
a13_scale: torch.Tensor,
469
a2_scale: torch.Tensor,
470
swiglu_limit: float | None = None,
471
+ layer: torch.nn.Module | None = None,
472
) -> FusedMoEQuantConfig:
422
- if backend == NvFp4MoeBackend.MARLIN:
473
+ if backend == NvFp4MoeBackend.HUMMING:
474
+ from vllm.model_executor.layers.fused_moe import RoutedExperts
475
+ from vllm.model_executor.layers.quantization.utils.humming_utils import (
476
+ get_humming_moe_quant_config,
477
+ )
478
+
479
+ assert isinstance(layer, RoutedExperts)
480
+ return get_humming_moe_quant_config(layer)
481
+ elif backend == NvFp4MoeBackend.MARLIN:
482
return nvfp4_w4a16_moe_quant_config(
483
g1_alphas=w13_scale_2,
484
g2_alphas=w2_scale_2,
@@ -467,7 +526,9 @@ def make_nvfp4_moe_kernel(
526
moe_quant_config: FusedMoEQuantConfig,
527
moe_config: FusedMoEConfig,
528
experts_cls: type[mk.FusedMoEExperts],
529
+ backend: NvFp4MoeBackend,
530
routing_tables: tuple[torch.Tensor, torch.Tensor, torch.Tensor] | None = None,
531
+ layer: torch.nn.Module | None = None,
532
) -> mk.FusedMoEKernel:
533
# Create Prepare/Finalize.
534
prepare_finalize = maybe_make_prepare_finalize(
@@ -481,6 +542,11 @@ def make_nvfp4_moe_kernel(
542
543
logger.info_once("Using %s", prepare_finalize.__class__.__name__)
544
545
+ extra_kwargs = {}
546
+ if backend == NvFp4MoeBackend.HUMMING:
547
+ assert layer is not None
548
+ extra_kwargs = {"layer": layer}
549
+
550
# Create Experts.
551
if prepare_finalize.activation_format == mk.FusedMoEActivationFormat.BatchedExperts:
552
max_num_tokens = prepare_finalize.max_num_tokens_per_rank()
@@ -490,11 +556,13 @@ def make_nvfp4_moe_kernel(
556
quant_config=moe_quant_config,
557
max_num_tokens=max_num_tokens,
558
num_dispatchers=prepare_finalize.num_dispatchers(),
559
+ **extra_kwargs,
560
)
561
else:
562
experts = experts_cls(
563
moe_config=moe_config,
564
quant_config=moe_quant_config,
565
+ **extra_kwargs,
566
)
567
568
kernel = mk.FusedMoEKernel(
vllm/model_executor/layers/fused_moe/oracle/unquantized.py
+3
-1
@@ -232,7 +232,9 @@ def select_unquantized_moe_backend(
232
raise ValueError(_make_log_unsupported(backend, reason))
233
234
runner_backend = moe_config.moe_backend
235
- if runner_backend != "auto":
235
+ # 'humming' is quantization-only; an unquantized layer (e.g. excluded via
236
+ # modules_to_not_convert) falls through to auto instead of erroring.
237
+ if runner_backend not in ["auto", "humming"]:
238
requested_backend = map_unquantized_backend(runner_backend)
239
if (
240
activation_format == mk.FusedMoEActivationFormat.BatchedExperts
vllm/model_executor/layers/quantization/auto_awq.py
+34
-18
@@ -26,6 +26,7 @@ from vllm.model_executor.layers.fused_moe import (
26
UnquantizedFusedMoEMethod,
27
)
28
from vllm.model_executor.layers.fused_moe.oracle.int_wna16 import (
29
+ WNA16MoEBackend,
30
convert_to_wna16_moe_kernel_format,
31
make_wna16_moe_kernel,
32
make_wna16_moe_quant_config,
@@ -663,6 +664,26 @@ class AutoAWQMoEMethod(FusedMoEMethodBase):
664
layer.workspace = marlin_make_workspace_new(device, 4)
665
666
def process_weights_after_loading(self, layer: RoutedExperts) -> None:
667
+ converted = convert_to_wna16_moe_kernel_format(
668
+ backend=self.wna16_moe_backend,
669
+ layer=layer,
670
+ quant_config=self.quant_config,
671
+ input_dtype=self.input_dtype,
672
+ w13=layer.w13_qweight,
673
+ w2=layer.w2_qweight,
674
+ w13_scale=layer.w13_scales,
675
+ w2_scale=layer.w2_scales,
676
+ w13_qzeros=layer.w13_qzeros,
677
+ w2_qzeros=layer.w2_qzeros,
678
+ w13_bias=getattr(layer, "w13_bias", None),
679
+ w2_bias=getattr(layer, "w2_bias", None),
680
+ )
681
+
682
+ if converted is None:
683
+ # Backend rewrote the layer's params in place (e.g. Humming).
684
+ self._setup_kernel(layer)
685
+ return
686
+
687
(
688
w13,
689
w2,
@@ -678,20 +699,7 @@ class AutoAWQMoEMethod(FusedMoEMethodBase):
699
w2_input_global_scale,
700
w13_bias,
701
w2_bias,
681
- ) = convert_to_wna16_moe_kernel_format(
682
- backend=self.wna16_moe_backend,
683
- layer=layer,
684
- quant_config=self.quant_config,
685
- input_dtype=self.input_dtype,
686
- w13=layer.w13_qweight,
687
- w2=layer.w2_qweight,
688
- w13_scale=layer.w13_scales,
689
- w2_scale=layer.w2_scales,
690
- w13_qzeros=layer.w13_qzeros,
691
- w2_qzeros=layer.w2_qzeros,
692
- w13_bias=getattr(layer, "w13_bias", None),
693
- w2_bias=getattr(layer, "w2_bias", None),
694
- )
702
+ ) = converted
703
704
replace_parameter(layer, "w13_qweight", w13)
705
replace_parameter(layer, "w2_qweight", w2)
@@ -734,6 +742,8 @@ class AutoAWQMoEMethod(FusedMoEMethodBase):
742
moe_quant_config=self.moe_quant_config,
743
moe_config=self.moe,
744
experts_cls=self.experts_cls,
745
+ backend=self.wna16_moe_backend,
746
+ layer=layer,
747
is_k_full=self.is_k_full,
748
w13_g_idx=getattr(layer, "w13_g_idx", None),
749
w2_g_idx=getattr(layer, "w2_g_idx", None),
@@ -743,6 +753,12 @@ class AutoAWQMoEMethod(FusedMoEMethodBase):
753
)
754
755
def get_fused_moe_quant_config(self, layer: RoutedExperts) -> FusedMoEQuantConfig:
756
+ if self.wna16_moe_backend == WNA16MoEBackend.HUMMING:
757
+ from vllm.model_executor.layers.quantization.utils.humming_utils import (
758
+ get_humming_moe_quant_config,
759
+ )
760
+
761
+ return get_humming_moe_quant_config(layer)
762
return make_wna16_moe_quant_config(
763
w1_scale=layer.w13_scales,
764
w2_scale=layer.w2_scales,
@@ -783,8 +799,8 @@ class AutoAWQMoEMethod(FusedMoEMethodBase):
799
assert self.moe_kernel is not None
800
return self.moe_kernel.apply(
801
hidden_states=x,
786
- w1=layer.w13_qweight,
787
- w2=layer.w2_qweight,
802
+ w1=layer.w13_weight,
803
+ w2=layer.w2_weight,
804
topk_weights=topk_weights,
805
topk_ids=topk_ids,
806
activation=layer.activation,
@@ -806,8 +822,8 @@ class AutoAWQMoEMethod(FusedMoEMethodBase):
822
assert self.moe_kernel is not None
823
return self.moe_kernel.apply_monolithic(
824
hidden_states=x,
809
- w1=layer.w13_qweight,
810
- w2=layer.w2_qweight,
825
+ w1=layer.w13_weight,
826
+ w2=layer.w2_weight,
827
router_logits=router_logits,
828
activation=layer.activation,
829
global_num_experts=layer.global_num_experts,
vllm/model_executor/layers/quantization/auto_gptq.py
+40
-20
@@ -658,6 +658,26 @@ class AutoGPTQMoEMethod(FusedMoEMethodBase):
658
"W8A8-INT8 is not supported by marlin kernel."
659
)
660
661
+ converted = convert_to_wna16_moe_kernel_format(
662
+ backend=self.wna16_moe_backend,
663
+ layer=layer,
664
+ quant_config=self.quant_config,
665
+ input_dtype=self.input_dtype,
666
+ w13=layer.w13_qweight,
667
+ w2=layer.w2_qweight,
668
+ w13_scale=layer.w13_scales,
669
+ w2_scale=layer.w2_scales,
670
+ w13_g_idx=layer.w13_g_idx,
671
+ w2_g_idx=layer.w2_g_idx,
672
+ w13_bias=getattr(layer, "w13_bias", None),
673
+ w2_bias=getattr(layer, "w2_bias", None),
674
+ )
675
+
676
+ if converted is None:
677
+ # Backend rewrote the layer's params in place (e.g. Humming).
678
+ self._setup_kernel(layer)
679
+ return
680
+
681
(
682
w13,
683
w2,
@@ -673,20 +693,7 @@ class AutoGPTQMoEMethod(FusedMoEMethodBase):
693
w2_input_global_scale,
694
w13_bias,
695
w2_bias,
676
- ) = convert_to_wna16_moe_kernel_format(
677
- backend=self.wna16_moe_backend,
678
- layer=layer,
679
- quant_config=self.quant_config,
680
- input_dtype=self.input_dtype,
681
- w13=layer.w13_qweight,
682
- w2=layer.w2_qweight,
683
- w13_scale=layer.w13_scales,
684
- w2_scale=layer.w2_scales,
685
- w13_g_idx=layer.w13_g_idx,
686
- w2_g_idx=layer.w2_g_idx,
687
- w13_bias=getattr(layer, "w13_bias", None),
688
- w2_bias=getattr(layer, "w2_bias", None),
689
- )
696
+ ) = converted
697
698
replace_parameter(layer, "w13_qweight", w13)
699
replace_parameter(layer, "w2_qweight", w2)
@@ -733,6 +740,10 @@ class AutoGPTQMoEMethod(FusedMoEMethodBase):
740
"w2_bias", torch.nn.Parameter(w2_bias, requires_grad=False)
741
)
742
743
+ # The modular kernel reads w13_weight/w2_weight; marlin keeps *_qweight.
744
+ layer.w13_weight = layer.w13_qweight
745
+ layer.w2_weight = layer.w2_qweight
746
+
747
self._setup_kernel(layer)
748
749
def _setup_kernel(self, layer: RoutedExperts) -> None:
@@ -743,15 +754,24 @@ class AutoGPTQMoEMethod(FusedMoEMethodBase):
754
moe_quant_config=self.moe_quant_config,
755
moe_config=self.moe,
756
experts_cls=self.experts_cls,
757
+ backend=self.wna16_moe_backend,
758
+ layer=layer,
759
is_k_full=self.is_k_full,
747
- w13_g_idx=layer.w13_g_idx,
748
- w2_g_idx=layer.w2_g_idx,
760
+ w13_g_idx=getattr(layer, "w13_g_idx", None),
761
+ w2_g_idx=getattr(layer, "w2_g_idx", None),
762
w13_g_idx_sort_indices=getattr(layer, "w13_g_idx_sort_indices", None),
763
w2_g_idx_sort_indices=getattr(layer, "w2_g_idx_sort_indices", None),
764
routing_tables=layer._expert_routing_tables(),
765
)
766
767
def get_fused_moe_quant_config(self, layer: RoutedExperts) -> FusedMoEQuantConfig:
768
+ if self.wna16_moe_backend == WNA16MoEBackend.HUMMING:
769
+ from vllm.model_executor.layers.quantization.utils.humming_utils import (
770
+ get_humming_moe_quant_config,
771
+ )
772
+
773
+ return get_humming_moe_quant_config(layer)
774
+
775
from vllm.model_executor.layers.fused_moe.config import (
776
gptq_marlin_moe_quant_config,
777
)
@@ -795,8 +815,8 @@ class AutoGPTQMoEMethod(FusedMoEMethodBase):
815
assert self.moe_kernel is not None
816
return self.moe_kernel.apply(
817
hidden_states=x,
798
- w1=layer.w13_qweight,
799
- w2=layer.w2_qweight,
818
+ w1=layer.w13_weight,
819
+ w2=layer.w2_weight,
820
topk_weights=topk_weights,
821
topk_ids=topk_ids,
822
activation=layer.activation,
@@ -818,8 +838,8 @@ class AutoGPTQMoEMethod(FusedMoEMethodBase):
838
assert self.moe_kernel is not None
839
return self.moe_kernel.apply_monolithic(
840
hidden_states=x,
821
- w1=layer.w13_qweight,
822
- w2=layer.w2_qweight,
841
+ w1=layer.w13_weight,
842
+ w2=layer.w2_weight,
843
router_logits=router_logits,
844
activation=layer.activation,
845
global_num_experts=layer.global_num_experts,
vllm/model_executor/layers/quantization/compressed_tensors/compressed_tensors_moe/compressed_tensors_moe_w4a4_nvfp4.py
+3
@@ -236,7 +236,9 @@ class CompressedTensorsW4A4Nvfp4MoEMethod(CompressedTensorsMoEMethod):
236
moe_quant_config=self.moe_quant_config,
237
moe_config=self.moe,
238
experts_cls=self.experts_cls,
239
+ backend=self.nvfp4_backend,
240
routing_tables=layer._expert_routing_tables(),
241
+ layer=layer,
242
)
243
self.moe_kernel.fused_experts.process_weights_after_loading(layer)
244
@@ -259,6 +261,7 @@ class CompressedTensorsW4A4Nvfp4MoEMethod(CompressedTensorsMoEMethod):
261
a13_scale=layer.w13_input_scale,
262
a2_scale=layer.w2_input_scale,
263
swiglu_limit=getattr(layer, "swiglu_limit", None),
264
+ layer=layer,
265
)
266
267
def apply_monolithic(
vllm/model_executor/layers/quantization/compressed_tensors/compressed_tensors_moe/compressed_tensors_moe_w8a8_fp8.py
+4
-2
@@ -338,6 +338,7 @@ class CompressedTensorsW8A8Fp8MoEMethod(CompressedTensorsMoEMethod):
338
fp8_backend=self.fp8_backend,
339
experts_cls=self.experts_cls,
340
routing_tables=layer._expert_routing_tables(),
341
+ layer=layer,
342
)
343
344
def maybe_make_prepare_finalize(
@@ -355,12 +356,13 @@ class CompressedTensorsW8A8Fp8MoEMethod(CompressedTensorsMoEMethod):
356
fp8_backend=self.fp8_backend,
357
w1_scale=layer.w13_weight_scale,
358
w2_scale=layer.w2_weight_scale,
358
- a1_scale=layer.w13_input_scale,
359
- a2_scale=layer.w2_input_scale,
359
+ a1_scale=getattr(layer, "w13_input_scale", None),
360
+ a2_scale=getattr(layer, "w2_input_scale", None),
361
per_act_token_quant=is_per_token,
362
per_out_ch_quant=is_per_token,
363
block_shape=self.weight_block_size,
364
swiglu_limit=getattr(layer, "swiglu_limit", None),
365
+ layer=layer,
366
)
367
368
def apply_monolithic(
vllm/model_executor/layers/quantization/compressed_tensors/compressed_tensors_moe/compressed_tensors_moe_w8a8_int8.py
+6
@@ -146,6 +146,8 @@ class CompressedTensorsW8A8Int8MoEMethod(CompressedTensorsMoEMethod):
146
int8_backend=self.int8_backend,
147
w13=layer.w13_weight,
148
w2=layer.w2_weight,
149
+ layer=layer,
150
+ w13_scale=layer.w13_weight_scale,
151
)
152
replace_parameter(layer, "w13_weight", w13)
153
replace_parameter(layer, "w2_weight", w2)
@@ -153,10 +155,12 @@ class CompressedTensorsW8A8Int8MoEMethod(CompressedTensorsMoEMethod):
155
self.moe_quant_config = self.get_fused_moe_quant_config(layer)
156
assert self.experts_cls is not None
157
self.moe_kernel = make_int8_moe_kernel(
158
+ int8_backend=self.int8_backend,
159
moe_quant_config=self.moe_quant_config,
160
moe_config=self.moe,
161
experts_cls=self.experts_cls,
162
routing_tables=layer._expert_routing_tables(),
163
+ layer=layer,
164
)
165
166
def maybe_make_prepare_finalize(
@@ -170,11 +174,13 @@ class CompressedTensorsW8A8Int8MoEMethod(CompressedTensorsMoEMethod):
174
175
def get_fused_moe_quant_config(self, layer: torch.nn.Module) -> FusedMoEQuantConfig:
176
return make_int8_moe_quant_config(
177
+ int8_backend=self.int8_backend,
178
w1_scale=layer.w13_weight_scale,
179
w2_scale=layer.w2_weight_scale,
180
a1_scale=layer.w13_input_scale,
181
a2_scale=layer.w2_input_scale,
182
per_act_token_quant=True,
183
+ layer=layer,
184
)
185
186
def apply(
vllm/model_executor/layers/quantization/compressed_tensors/compressed_tensors_moe/compressed_tensors_moe_w8a8_mxfp8.py
+2
@@ -140,6 +140,7 @@ class CompressedTensorsW8A8Mxfp8MoEMethod(CompressedTensorsMoEMethod):
140
fp8_backend=self.fp8_backend,
141
experts_cls=self.experts_cls,
142
routing_tables=layer._expert_routing_tables(),
143
+ layer=layer,
144
)
145
146
def get_fused_moe_quant_config(
@@ -155,6 +156,7 @@ class CompressedTensorsW8A8Mxfp8MoEMethod(CompressedTensorsMoEMethod):
156
swiglu_limit=getattr(layer, "swiglu_limit", None),
157
gemm1_alpha=getattr(layer, "swiglu_alpha", None),
158
gemm1_beta=getattr(layer, "swiglu_beta", None),
159
+ layer=layer,
160
)
161
162
def maybe_make_prepare_finalize(
vllm/model_executor/layers/quantization/compressed_tensors/compressed_tensors_moe/compressed_tensors_moe_wna16_marlin.py
+22
-14
@@ -416,6 +416,27 @@ class CompressedTensorsWNA16MarlinMoEMethod(CompressedTensorsMoEMethod):
416
def process_weights_after_loading(self, layer: torch.nn.Module) -> None:
417
# Process weights using the shared oracle infrastructure
418
is_flashinfer = self.wna16_backend == WNA16MoEBackend.FLASHINFER_TRTLLM
419
+ converted = convert_to_wna16_moe_kernel_format(
420
+ backend=self.wna16_backend,
421
+ layer=layer,
422
+ quant_config=self.weight_quant,
423
+ input_dtype=self.marlin_input_dtype,
424
+ w13=layer.w13_weight_packed,
425
+ w2=layer.w2_weight_packed,
426
+ w13_scale=layer.w13_weight_scale,
427
+ w2_scale=layer.w2_weight_scale,
428
+ w13_g_idx=layer.w13_weight_g_idx,
429
+ w2_g_idx=layer.w2_weight_g_idx,
430
+ w13_qzeros=getattr(layer, "w13_weight_zero_point", None),
431
+ w2_qzeros=getattr(layer, "w2_weight_zero_point", None),
432
+ )
433
+ if converted is None:
434
+ # In-place backends (e.g. Humming) are not wired through this
435
+ # marlin-only method; fail clearly rather than unpacking None.
436
+ raise NotImplementedError(
437
+ f"{type(self).__name__} does not support the "
438
+ f"{self.wna16_backend.value} MoE backend."
439
+ )
440
(
441
w13_qweight,
442
w2_qweight,
@@ -431,20 +452,7 @@ class CompressedTensorsWNA16MarlinMoEMethod(CompressedTensorsMoEMethod):
452
w2_input_global_scale,
453
_, # w13_bias
454
_, # w2_bias
434
- ) = convert_to_wna16_moe_kernel_format(
435
- backend=self.wna16_backend,
436
- layer=layer,
437
- quant_config=self.weight_quant,
438
- input_dtype=self.marlin_input_dtype,
439
- w13=layer.w13_weight_packed,
440
- w2=layer.w2_weight_packed,
441
- w13_scale=layer.w13_weight_scale,
442
- w2_scale=layer.w2_weight_scale,
443
- w13_g_idx=layer.w13_weight_g_idx,
444
- w2_g_idx=layer.w2_weight_g_idx,
445
- w13_qzeros=getattr(layer, "w13_weight_zero_point", None),
446
- w2_qzeros=getattr(layer, "w2_weight_zero_point", None),
447
- )
455
+ ) = converted
456
457
# Replace common parameters
458
replace_parameter(layer, "w13_weight_packed", w13_qweight)
vllm/model_executor/layers/quantization/compressed_tensors/schemes/compressed_tensors_w8a16_fp8.py
+8
@@ -137,8 +137,16 @@ class CompressedTensorsW8A16Fp8(CompressedTensorsScheme):
137
"weight_scale",
138
convert_to_channelwise(layer.weight_scale, layer.logical_widths),
139
)
140
+ self.strategy = QuantizationStrategy.CHANNEL
141
+ self.weight_quant_key = STRATEGY_TO_WEIGHT_QUANT_KEY[self.strategy]
142
+ self.linear_kernel.config.weight_quant_key = self.weight_quant_key
143
+
144
# Canonicalize to (K, N) for the kernel.
145
replace_parameter(layer, "weight", layer.weight.t())
146
+ # Preserve the dim tags dropped by the transpose so layout-aware
147
+ # kernels see (K, N).
148
+ layer.weight.input_dim = 0
149
+ layer.weight.output_dim = 1
150
151
self.linear_kernel.process_weights_after_loading(layer)
152
vllm/model_executor/layers/quantization/compressed_tensors/schemes/compressed_tensors_w8a8_fp8.py
+4
@@ -181,6 +181,10 @@ class CompressedTensorsW8A8Fp8(CompressedTensorsScheme):
181
182
# required by torch.compile to be torch.nn.Parameter
183
layer.weight = Parameter(weight.data, requires_grad=False)
184
+ # Preserve the dim tags dropped by the transpose so layout-aware
185
+ # kernels (humming) see (K, N) instead of assuming (N, K).
186
+ layer.weight.input_dim = 0
187
+ layer.weight.output_dim = 1
188
layer.weight_scale = Parameter(weight_scale.data, requires_grad=False)
189
if input_scale is not None:
190
layer.input_scale = Parameter(input_scale.data, requires_grad=False)
vllm/model_executor/layers/quantization/fp8.py
+2
@@ -714,6 +714,7 @@ class Fp8MoEMethod(FusedMoEMethodBase):
714
fp8_backend=self.fp8_backend,
715
experts_cls=self.experts_cls,
716
routing_tables=layer._expert_routing_tables(),
717
+ layer=layer,
718
)
719
720
def process_weights_after_loading(self, layer: RoutedExperts) -> None:
@@ -786,6 +787,7 @@ class Fp8MoEMethod(FusedMoEMethodBase):
787
swiglu_limit=getattr(layer, "swiglu_limit", None),
788
gemm1_alpha=getattr(layer, "swiglu_alpha", None),
789
gemm1_beta=getattr(layer, "swiglu_beta", None),
790
+ layer=layer,
791
)
792
793
# Inject biases into the quant config if the model has them
vllm/model_executor/layers/quantization/modelopt.py
+7
@@ -905,6 +905,7 @@ class ModelOptFp8MoEMethod(FusedMoEMethodBase):
905
fp8_backend=self.fp8_backend,
906
experts_cls=self.experts_cls,
907
routing_tables=layer._expert_routing_tables(),
908
+ layer=layer,
909
)
910
911
def process_weights_after_loading(self, layer: RoutedExperts) -> None:
@@ -951,6 +952,7 @@ class ModelOptFp8MoEMethod(FusedMoEMethodBase):
952
a1_scale=a1_scale,
953
a2_scale=a2_scale,
954
swiglu_limit=getattr(layer, "swiglu_limit", None),
955
+ layer=layer,
956
)
957
958
def apply_monolithic(
@@ -1602,7 +1604,9 @@ class ModelOptNvFp4FusedMoE(FusedMoEMethodBase):
1604
moe_quant_config=self.moe_quant_config,
1605
moe_config=self.moe,
1606
experts_cls=self.experts_cls,
1607
+ backend=self.nvfp4_backend,
1608
routing_tables=layer._expert_routing_tables(),
1609
+ layer=layer,
1610
)
1611
self.moe_kernel.fused_experts.process_weights_after_loading(layer)
1612
@@ -1616,6 +1620,7 @@ class ModelOptNvFp4FusedMoE(FusedMoEMethodBase):
1620
a13_scale=layer.w13_input_scale,
1621
a2_scale=layer.w2_input_scale,
1622
swiglu_limit=getattr(layer, "swiglu_limit", None),
1623
+ layer=layer,
1624
)
1625
1626
@property
@@ -2162,6 +2167,7 @@ class ModelOptMxFp8FusedMoE(FusedMoEMethodBase):
2167
fp8_backend=self.mxfp8_backend,
2168
experts_cls=self.experts_cls,
2169
routing_tables=layer._expert_routing_tables(),
2170
+ layer=layer,
2171
)
2172
2173
# No native MXFP8 MoE kernel on this device (e.g. gfx942): the emulation
@@ -2207,6 +2213,7 @@ class ModelOptMxFp8FusedMoE(FusedMoEMethodBase):
2213
swiglu_limit=getattr(layer, "swiglu_limit", None),
2214
gemm1_alpha=getattr(layer, "swiglu_alpha", None),
2215
gemm1_beta=getattr(layer, "swiglu_beta", None),
2216
+ layer=layer,
2217
)
2218
2219
def apply_monolithic(
vllm/model_executor/layers/quantization/online/fp8.py
+2
@@ -458,6 +458,7 @@ class _Fp8OnlineMoEBase(OnlineMoEMethodBase):
458
fp8_backend=self.fp8_backend,
459
experts_cls=self.experts_cls,
460
routing_tables=layer._expert_routing_tables(),
461
+ layer=layer,
462
)
463
464
def get_fused_moe_quant_config(
@@ -486,6 +487,7 @@ class _Fp8OnlineMoEBase(OnlineMoEMethodBase):
487
swiglu_limit=getattr(layer, "swiglu_limit", None),
488
gemm1_alpha=getattr(layer, "swiglu_alpha", None),
489
gemm1_beta=getattr(layer, "swiglu_beta", None),
490
+ layer=layer,
491
)
492
493
vllm/model_executor/layers/quantization/online/int8.py
+17
-2
@@ -13,6 +13,7 @@ if TYPE_CHECKING:
13
14
from vllm.model_executor.layers.fused_moe import RoutedExperts
15
from vllm.model_executor.layers.fused_moe.oracle.int8 import (
16
+ convert_to_int8_moe_kernel_format,
17
make_int8_moe_kernel,
18
make_int8_moe_quant_config,
19
select_int8_moe_backend,
@@ -92,22 +93,36 @@ class Int8OnlineMoEMethod(OnlineMoEMethodBase):
93
replace_parameter(layer, "w2_scale", w2_scale)
94
95
def _setup_kernel(self, layer: RoutedExperts) -> None:
96
+ w13, w2 = convert_to_int8_moe_kernel_format(
97
+ int8_backend=self.int8_backend,
98
+ w13=layer.w13_weight,
99
+ w2=layer.w2_weight,
100
+ layer=layer,
101
+ w13_scale=layer.w13_scale,
102
+ )
103
+ replace_parameter(layer, "w13_weight", w13)
104
+ replace_parameter(layer, "w2_weight", w2)
105
+
106
self.moe_quant_config = self.get_fused_moe_quant_config(layer)
107
assert self.moe_quant_config is not None
108
assert self.experts_cls is not None
109
self.moe_kernel = make_int8_moe_kernel(
110
+ int8_backend=self.int8_backend,
111
moe_quant_config=self.moe_quant_config,
112
moe_config=self.moe,
113
experts_cls=self.experts_cls,
114
routing_tables=layer._expert_routing_tables(),
115
+ layer=layer,
116
)
117
118
def get_fused_moe_quant_config(
119
self, layer: torch.nn.Module
120
) -> "FusedMoEQuantConfig | None":
121
return make_int8_moe_quant_config(
109
- w1_scale=layer.w13_scale,
110
- w2_scale=layer.w2_scale,
122
+ int8_backend=self.int8_backend,
123
+ w1_scale=getattr(layer, "w13_scale", None),
124
+ w2_scale=getattr(layer, "w2_scale", None),
125
w1_bias=getattr(layer, "w13_bias", None),
126
w2_bias=getattr(layer, "w2_bias", None),
127
+ layer=layer,
128
)
vllm/model_executor/layers/quantization/online/mxfp8.py
+2
@@ -200,6 +200,7 @@ 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,
204
)
205
206
def get_fused_moe_quant_config(
@@ -226,6 +227,7 @@ class Mxfp8OnlineMoEMethod(OnlineMoEMethodBase):
227
swiglu_limit=getattr(layer, "swiglu_limit", None),
228
gemm1_alpha=getattr(layer, "swiglu_alpha", None),
229
gemm1_beta=getattr(layer, "swiglu_beta", None),
230
+ layer=layer,
231
)
232
233
def process_weights_after_loading(self, layer: Module) -> None:
vllm/model_executor/layers/quantization/quark/quark_moe.py
+3
@@ -1562,7 +1562,9 @@ class QuarkNvfp4MoEMethod(QuarkMoEMethod):
1562
moe_quant_config=self.moe_quant_config,
1563
moe_config=self.moe,
1564
experts_cls=self.experts_cls,
1565
+ backend=self.nvfp4_backend,
1566
routing_tables=layer._expert_routing_tables(),
1567
+ layer=layer,
1568
)
1569
1570
def get_fused_moe_quant_config(
@@ -1576,6 +1578,7 @@ class QuarkNvfp4MoEMethod(QuarkMoEMethod):
1578
w2_scale_2=layer.w2_weight_scale_2,
1579
a13_scale=layer.w13_input_scale_2,
1580
a2_scale=layer.w2_input_scale_2,
1581
+ layer=layer,
1582
)
1583
1584
def apply(
vllm/model_executor/layers/quantization/utils/humming_utils.py
+4
-6
@@ -764,7 +764,7 @@ def _convert_sublayer_to_humming(
764
Returns:
765
Tuple of (converted_weight_schema, converted_input_schema)
766
"""
767
- from humming.schema import HummingWeightSchema
767
+ from vllm.utils.humming import HummingWeightSchema
768
769
if isinstance(weight_schema, HummingWeightSchema):
770
# Already in Humming format
@@ -814,7 +814,7 @@ def _prepare_and_transform_sublayer(
814
815
This calls Humming's prepare_layer_meta and transform_humming_layer.
816
"""
817
- from humming.layer import HummingMethod
817
+ from vllm.utils.humming import HummingMethod
818
819
HummingMethod.prepare_layer_meta(
820
layer=layer,
@@ -866,7 +866,7 @@ def _process_single_sublayer(
866
Returns:
867
Tuple of (final_weight_schema, final_input_schema)
868
"""
869
- from humming.schema import HummingWeightSchema
869
+ from vllm.utils.humming import HummingWeightSchema
870
871
# Step 1: Convert from checkpoint format to humming format if needed
872
current_weight_schema, current_input_schema = _convert_sublayer_to_humming(
@@ -958,12 +958,10 @@ def convert_to_humming_moe_kernel_format(
958
"Must provide either weight_schema/input_schema or quant_config"
959
)
960
961
- from humming.layer import HummingInputSchema
962
- from humming.schema import BaseWeightSchema
963
-
961
from vllm.model_executor.layers.quantization.utils.humming_utils import (
962
humming_is_layer_skipped,
963
)
964
+ from vllm.utils.humming import BaseWeightSchema, HummingInputSchema
965
966
if weight_schema is None:
967
weight_schema = BaseWeightSchema.from_config(quant_config)
vllm/model_executor/warmup/deep_gemm_warmup.py
+9
@@ -11,6 +11,9 @@ from tqdm import tqdm
11
12
import vllm.envs as envs
13
from vllm.distributed.parallel_state import get_dp_group, is_global_first_rank
14
+from vllm.model_executor.kernels.linear.scaled_mm.deep_gemm import (
15
+ DeepGemmFp8BlockScaledMMKernel,
16
+)
17
from vllm.model_executor.layers.fused_moe import MoERunner
18
from vllm.model_executor.layers.fused_moe.deep_gemm_utils import (
19
compute_aligned_M_and_alignment,
@@ -147,6 +150,12 @@ def _fp8_linear_may_use_deep_gemm(module: torch.nn.Module) -> bool:
150
):
151
return False
152
153
+ if not isinstance(
154
+ getattr(module.quant_method, "fp8_linear", None),
155
+ DeepGemmFp8BlockScaledMMKernel,
156
+ ):
157
+ return False
158
+
159
w, _, block_sizes = _extract_data_from_linear_base_module(module)
160
return (
161
block_sizes == get_mk_alignment_for_contiguous_layout()