Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
e52950c
Refactor CompressedTensorsWNA16MarlinMoEMethod to use kernel abstract…
claude Apr 7, 2026
5887f85
wip
bnellnm May 13, 2026
f8d42ac
tweaks
bnellnm May 13, 2026
19cf0e7
combine with int_wna16.py + cleanups
bnellnm May 13, 2026
cbc26e3
review comments
bnellnm May 13, 2026
c114fe8
pass monolithic flag to maybe_make_pf
bnellnm May 14, 2026
eb74c1a
fix method name
bnellnm May 14, 2026
2cd4b0b
wip
bnellnm May 14, 2026
79da17c
wip
bnellnm May 14, 2026
fe3008d
refactor weight post processing
bnellnm May 14, 2026
1774254
cleanup
bnellnm May 14, 2026
cfb7aec
Merge remote-tracking branch 'origin/main' into wna16-oracle
bnellnm May 15, 2026
6224bed
try to fix doc
bnellnm May 15, 2026
e22637e
try to fix docs again
bnellnm May 15, 2026
05faaad
Merge remote-tracking branch 'origin/main' into wna16-oracle
bnellnm May 18, 2026
765e31c
add missing args to config
bnellnm May 20, 2026
d2d3b3d
Merge branch 'main' into wna16-oracle
bnellnm May 21, 2026
9da72db
fix typo
bnellnm May 21, 2026
0068f29
Merge remote-tracking branch 'nm-vllm/wna16-oracle' into wna16-oracle
bnellnm May 21, 2026
b879446
Merge remote-tracking branch 'origin/main' into wna16-oracle
bnellnm May 23, 2026
0aaa888
Merge remote-tracking branch 'origin/main' into wna16-oracle
bnellnm May 26, 2026
208eeea
Merge remote-tracking branch 'origin/main' into wna16-oracle
bnellnm May 28, 2026
a204a66
wip
bnellnm May 14, 2026
6d275a9
fix
bnellnm May 14, 2026
db41077
fix
bnellnm May 14, 2026
b3248d5
wip
bnellnm May 14, 2026
272bf3b
zero point handling
bnellnm May 14, 2026
d1e1213
fix
bnellnm May 14, 2026
e3a1503
fix
bnellnm May 15, 2026
f9fe9d8
fix merge
bnellnm May 18, 2026
1b9356b
fix lint
bnellnm May 18, 2026
0bde5a0
merge + review comments
bnellnm May 21, 2026
9f01de3
fix enums
bnellnm May 21, 2026
cf40bbf
fix
bnellnm May 22, 2026
00cbe82
fix
bnellnm May 22, 2026
0745aca
fixes
bnellnm May 23, 2026
98e9c2e
more fixes
bnellnm May 23, 2026
7946cd3
remove debugging code
bnellnm May 26, 2026
bed43d6
fix
bnellnm May 28, 2026
9c360d9
copy parallel support from trtllm_fp8
bnellnm May 28, 2026
847f004
Merge remote-tracking branch 'origin/main' into wna16-oracle
bnellnm May 28, 2026
e99fab7
Merge remote-tracking branch 'nm-vllm/wna16-oracle' into moe-wna16-or…
bnellnm May 28, 2026
d250740
Merge remote-tracking branch 'origin/main' into moe-wna16-oracle
bnellnm May 29, 2026
44bf4f2
remove cruft
bnellnm May 29, 2026
06ed947
Merge remote-tracking branch 'nm-vllm/moe-wna16-oracle' into fix-moe-…
bnellnm May 31, 2026
bc43114
fix int_wna16.py
bnellnm May 31, 2026
ff32874
Merge remote-tracking branch 'origin/main' into fix-moe-wna16-oracle
bnellnm Jun 2, 2026
ecce8d5
cleanup merge
bnellnm Jun 2, 2026
e659759
Merge remote-tracking branch 'origin/main' into fix-moe-wna16-oracle
bnellnm Jun 3, 2026
e0f7ad7
fix merge
bnellnm Jun 3, 2026
57642d6
move triton to the back
bnellnm Jun 3, 2026
18de29b
Merge remote-tracking branch 'origin/main' into fix-moe-wna16-oracle
bnellnm Jun 4, 2026
bdc241f
Merge remote-tracking branch 'origin/main' into fix-moe-wna16-oracle
bnellnm Jun 4, 2026
ee1d347
remove useless test
bnellnm Jun 5, 2026
3901126
disallow marlin for moe_wna16
bnellnm Jun 5, 2026
a40bae4
Merge remote-tracking branch 'origin/main' into fix-moe-wna16-oracle
bnellnm Jun 5, 2026
710eec1
fix lint
bnellnm Jun 5, 2026
e27a36a
Merge branch 'main' into fix-moe-wna16-oracle
bnellnm Jun 6, 2026
da4f604
Merge remote-tracking branch 'origin/main' into fix-moe-wna16-oracle
bnellnm Jun 10, 2026
93bdd71
Merge remote-tracking branch 'origin/main' into fix-moe-wna16-oracle
bnellnm Jun 15, 2026
edfbd4c
Merge remote-tracking branch 'origin/main' into fix-moe-wna16-oracle
bnellnm Jun 16, 2026
8b998f7
cleanup
bnellnm Jun 16, 2026
73a0c8e
revert zero point code
bnellnm Jun 17, 2026
302c238
fix qwen1.5 crash
bnellnm Jun 17, 2026
b723ecf
fix tp_size
bnellnm Jun 17, 2026
55134d4
try to fix cpu zp
bnellnm Jun 18, 2026
be21b02
fix
bnellnm Jun 18, 2026
368b9b1
Merge remote-tracking branch 'origin/main' into fix-moe-wna16-oracle
bnellnm Jun 18, 2026
6f315c2
revert config changes
bnellnm Jun 19, 2026
cf8fc01
don't use marlin method for cpu
bnellnm Jun 19, 2026
e166d0f
try again
bnellnm Jun 19, 2026
fea5141
Merge branch 'main' into fix-moe-wna16-oracle
bnellnm Jun 22, 2026
aff4fbc
Merge branch 'main' into fix-moe-wna16-oracle
bnellnm Jun 23, 2026
0847752
Merge remote-tracking branch 'origin/main' into fix-moe-wna16-oracle
bnellnm Jul 14, 2026
0ecf661
Merge remote-tracking branch 'nm-vllm/fix-moe-wna16-oracle' into fix-…
bnellnm Jul 14, 2026
4f11dbc
Merge remote-tracking branch 'origin/main' into fix-moe-wna16-oracle
bnellnm Jul 16, 2026
29610b5
don't try to load params that don't exist
bnellnm Jul 16, 2026
c7e71f4
revert change
bnellnm Jul 16, 2026
b4efaa4
Fix WNA16 MoE backend compatibility
mgoin Jul 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions tests/quantization/test_auto_gptq.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@
Run `pytest tests/quantization/test_auto_gptq.py -v -s`.
"""

from types import SimpleNamespace

import pytest
import torch

from tests.quantization.utils import is_quant_method_supported
from vllm.model_executor.layers.fused_moe import RoutedExperts
from vllm.model_executor.layers.quantization.auto_gptq import (
AutoGPTQConfig,
AutoGPTQLinearMethod,
AutoGPTQMoEMethod,
)

PROMPT = "On the surface of Mars, we found"
Expand Down Expand Up @@ -54,3 +58,78 @@ def check_model(model):
def test_auto_gptq_config_get_name():
"""Test that AutoGPTQConfig.get_name() returns 'auto_gptq'."""
assert AutoGPTQConfig.get_name() == "auto_gptq"


def test_auto_gptq_moe_creates_zero_initialized_expert_biases():
method = object.__new__(AutoGPTQMoEMethod)
method.quant_config = AutoGPTQConfig(4, 128, False, True, False, {}, {})
method.input_dtype = None
method.experts_cls = None
layer = torch.nn.Module()

method.create_weights(
layer=layer,
num_experts=2,
hidden_size=8,
intermediate_size_per_partition=4,
params_dtype=torch.float16,
intermediate_size_full=4,
weight_loader=lambda *args, **kwargs: None,
)

assert layer.w13_bias.shape == (2, 8)
assert layer.w2_bias.shape == (2, 8)
assert torch.count_nonzero(layer.w13_bias) == 0
assert torch.count_nonzero(layer.w2_bias) == 0


def test_routed_experts_loads_per_expert_biases():
class Loader:
quant_config = None
quant_method = object()
moe_config = SimpleNamespace(
is_act_and_mul=True,
tp_rank=0,
moe_parallel_config=SimpleNamespace(tp_size=1),
)
_get_hidden_dim = staticmethod(RoutedExperts._get_hidden_dim)
_narrow_expert_data_for_padding = staticmethod(
RoutedExperts._narrow_expert_data_for_padding
)
_load_w13 = RoutedExperts._load_w13
_loaded_expert_biases = set()

@staticmethod
def _map_global_expert_id_to_local_expert_id(expert_id):
return expert_id

loader = Loader()
w13_bias = torch.nn.Parameter(torch.zeros(1, 8), requires_grad=False)
w2_bias = torch.nn.Parameter(torch.zeros(1, 4), requires_grad=False)

for shard_id, loaded in (
("w1", torch.tensor([1.0, 2.0, 3.0, 4.0])),
("w3", torch.tensor([5.0, 6.0, 7.0, 8.0])),
):
assert RoutedExperts.weight_loader(
loader,
w13_bias,
loaded,
weight_name="model.layers.0.mlp.experts.w13_bias",
shard_id=shard_id,
expert_id=0,
return_success=True,
)

assert RoutedExperts.weight_loader(
loader,
w2_bias,
torch.tensor([9.0, 10.0, 11.0, 12.0]),
weight_name="model.layers.0.mlp.experts.w2_bias",
shard_id="w2",
expert_id=0,
return_success=True,
)
assert torch.equal(w13_bias, torch.arange(1, 9, dtype=torch.float32).reshape(1, 8))
assert torch.equal(w2_bias, torch.arange(9, 13, dtype=torch.float32).reshape(1, 4))
assert loader._loaded_expert_biases == {"w13_bias", "w2_bias"}
209 changes: 179 additions & 30 deletions tests/quantization/test_moe_wna16.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,45 +5,194 @@

import pytest
import torch
from compressed_tensors.quantization import (
ActivationOrdering,
QuantizationArgs,
QuantizationStrategy,
QuantizationType,
)

from vllm.model_executor.layers.fused_moe.activation import MoEActivation
from vllm.model_executor.layers.quantization.moe_wna16 import MoeWNA16Method
from vllm.platforms import current_platform
from vllm.model_executor.layers.fused_moe.oracle.int_wna16 import (
WNA16MoEBackend,
_backend_incompatibility_reason,
_convert_moe_wna16_humming_tensors,
convert_to_wna16_moe_kernel_format,
map_wna16_backend,
)
from vllm.model_executor.layers.quantization import moe_wna16
from vllm.model_executor.layers.quantization.auto_awq import AutoAWQConfig
from vllm.model_executor.layers.quantization.auto_gptq import AutoGPTQConfig
from vllm.model_executor.layers.quantization.moe_wna16 import (
MoeWNA16Config,
MoeWNA16Method,
)


@pytest.mark.skipif(not current_platform.is_cuda(), reason="Only test on CUDA")
def test_moe_wna16_apply_passes_layer_activation(monkeypatch):
captured_kwargs = {}
def test_map_wna16_backend_supports_triton():
assert map_wna16_backend("triton") == WNA16MoEBackend.TRITON

def fake_fused_experts(*args, **kwargs):
captured_kwargs.update(kwargs)
return torch.empty(1, 2)

monkeypatch.setattr(
"vllm.model_executor.layers.fused_moe.fused_experts",
fake_fused_experts,
@pytest.mark.parametrize(
("backend", "quant_config", "may_have_zp", "may_have_bias", "expected"),
[
(
WNA16MoEBackend.TRITON,
AutoAWQConfig(4, 128, True, False),
True,
False,
"AutoAWQ weight layout",
),
(
WNA16MoEBackend.TRITON,
AutoGPTQConfig(4, 128, True, True, False, {}, {}),
False,
False,
"activation ordering",
),
(
WNA16MoEBackend.TRITON,
QuantizationArgs(
num_bits=4,
type=QuantizationType.INT,
strategy=QuantizationStrategy.GROUP,
symmetric=True,
dynamic=False,
group_size=128,
actorder=ActivationOrdering.GROUP,
),
False,
False,
"activation ordering",
),
(
WNA16MoEBackend.TRITON,
AutoGPTQConfig(4, 128, False, True, False, {}, {}),
False,
True,
"bias",
),
(
WNA16MoEBackend.MARLIN,
MoeWNA16Config(
linear_quant_method="gptq",
weight_bits=4,
group_size=128,
has_zp=False,
lm_head_quantized=False,
modules_to_not_convert=None,
full_config={},
),
False,
False,
"MoeWNA16 checkpoint layout",
),
],
)
def test_wna16_oracle_rejects_incompatible_quant_structures(
backend, quant_config, may_have_zp, may_have_bias, expected
):
reason = _backend_incompatibility_reason(
backend=backend,
quant_config=quant_config,
may_have_zp=may_have_zp,
may_have_bias=may_have_bias,
)

assert reason is not None
assert expected in reason


def test_compressed_tensors_weights_are_transposed_for_triton():
quant_config = QuantizationArgs(
num_bits=4,
type=QuantizationType.INT,
strategy=QuantizationStrategy.GROUP,
symmetric=True,
dynamic=False,
group_size=32,
)
w13 = torch.arange(16, dtype=torch.int32).reshape(1, 2, 8)
w2 = torch.arange(12, dtype=torch.int32).reshape(1, 2, 6)
w13_scale = torch.arange(32, dtype=torch.float16).reshape(1, 4, 8)
w2_scale = torch.arange(18, dtype=torch.float16).reshape(1, 3, 6)

converted = convert_to_wna16_moe_kernel_format(
backend=WNA16MoEBackend.TRITON,
layer=torch.nn.Module(),
quant_config=quant_config,
input_dtype=None,
w13=w13,
w2=w2,
w13_scale=w13_scale,
w2_scale=w2_scale,
)

assert converted is not None
assert torch.equal(converted[0], w13.transpose(1, 2).contiguous().view(torch.uint8))
assert torch.equal(converted[1], w2.transpose(1, 2).contiguous().view(torch.uint8))
assert torch.equal(converted[2], w13_scale.transpose(1, 2).contiguous())
assert torch.equal(converted[3], w2_scale.transpose(1, 2).contiguous())


def test_moe_wna16_setup_forwards_selected_backend(monkeypatch):
method = object.__new__(MoeWNA16Method)
method.moe = SimpleNamespace(disable_inplace=False)
method.moe_quant_config = object()
layer = SimpleNamespace(
w13_qweight=torch.empty(1, 2),
w2_qweight=torch.empty(1, 2),
activation=MoEActivation.GELU_TANH,
apply_router_weight_on_input=False,
global_num_experts=1,
expert_map=None,
method.experts_cls = object
method.wna16_backend = WNA16MoEBackend.HUMMING
method.moe = object()
quant_config = object()
method.get_fused_moe_quant_config = lambda layer: quant_config
layer = SimpleNamespace(_expert_routing_tables=lambda: (None, None, None))
captured = {}
kernel = object()

def fake_make_wna16_moe_kernel(**kwargs):
captured.update(kwargs)
return kernel

monkeypatch.setattr(moe_wna16, "make_wna16_moe_kernel", fake_make_wna16_moe_kernel)

method._setup_kernel(layer)

assert method.moe_kernel is kernel
assert captured["backend"] == WNA16MoEBackend.HUMMING
assert captured["layer"] is layer


def test_moe_wna16_humming_adapter_repacks_uint8_tensors():
qweight = torch.arange(32, dtype=torch.uint8).reshape(1, 4, 8)
scales = torch.arange(16, dtype=torch.float16).reshape(1, 4, 4)
qzeros = torch.arange(16, dtype=torch.uint8).reshape(1, 8, 2)

converted = _convert_moe_wna16_humming_tensors(
{"qweight": qweight, "scales": scales, "qzeros": qzeros},
has_zero_point=True,
)

output = method.apply(
layer,
x=torch.empty(1, 2),
topk_weights=torch.empty(1, 1),
topk_ids=torch.empty(1, 1, dtype=torch.int32),
shared_experts=None,
shared_experts_input=None,
assert torch.equal(converted["weight"], qweight.view(torch.int32))
assert converted["weight"].shape == (1, 4, 2)
assert torch.equal(converted["weight_scale"], scales)
expected_qzeros = (
qzeros.transpose(-1, -2)
.contiguous()
.view(torch.int32)
.transpose(-1, -2)
.contiguous()
)
assert torch.equal(converted["zero_point"], expected_qzeros)
assert converted["zero_point"].shape == (1, 2, 2)


def test_moe_wna16_uses_humming_quant_config(monkeypatch):
from vllm.model_executor.layers.quantization.utils import humming_utils

method = object.__new__(MoeWNA16Method)
method.wna16_backend = WNA16MoEBackend.HUMMING
layer = object()
quant_config = object()
monkeypatch.setattr(
humming_utils,
"get_humming_moe_quant_config",
lambda actual_layer: quant_config if actual_layer is layer else None,
)

assert output.shape == (1, 2)
assert captured_kwargs["activation"] is MoEActivation.GELU_TANH
assert method.get_fused_moe_quant_config(layer) is quant_config
Loading
Loading