Files
wehub-resource-sync 7ce4c8e27e
pre-commit / pre-run-check (push) Has been cancelled
pre-commit / pre-commit (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:55:37 +08:00

232 lines
8.1 KiB
Python

# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
"""Tests for AutoAWQConfig behavior after unification.
These tests verify the bug fixes for:
1. CPU platform override conflict (auto_awq should not override on CPU)
2. MoE fallback compatibility (full_config["quant_method"] should be "awq")
3. Config attribute consistency
4. End-to-end quantization method loading (auto_awq loads and runs correctly)
Note: Tests that require importing the full auto_awq module (which has GPU-dependent
imports) should use subprocess or be run in a GPU environment.
"""
from __future__ import annotations
import pytest
import torch
from tests.quantization.utils import is_quant_method_supported
def _get_auto_awq_config_source() -> str:
"""Read the AutoAWQConfig class source code for isolated testing."""
import inspect
import vllm.model_executor.layers.quantization.auto_awq as auto_awq_module
return inspect.getsource(auto_awq_module.AutoAWQConfig)
class TestAutoAWQConfigFromConfig:
"""Tests for AutoAWQConfig.from_config behavior.
These tests require GPU environment to import the full module.
They are skipped on non-GPU platforms.
"""
def test_full_config_quant_method_is_awq_for_moe_fallback(self):
"""full_config should have quant_method='awq' for MoE fallback compatibility.
MoeWNA16Config only accepts 'gptq' or 'awq' as linear_quant_method.
If full_config has 'auto_awq', the MoE fallback will fail.
"""
from vllm.model_executor.layers.quantization.auto_awq import AutoAWQConfig
config = {
"w_bit": 4,
"q_group_size": 128,
"zero_point": True,
"lm_head": False,
}
awq_config = AutoAWQConfig.from_config(config)
# Verify quant_method is 'awq' for MoE fallback
assert awq_config.full_config["quant_method"] == "awq", (
f"Expected quant_method='awq', got {awq_config.full_config['quant_method']}"
)
def test_full_config_preserves_other_fields(self):
"""full_config should preserve all original config fields."""
from vllm.model_executor.layers.quantization.auto_awq import AutoAWQConfig
config = {
"w_bit": 4,
"q_group_size": 128,
"zero_point": True,
"lm_head": False,
"custom_field": "custom_value",
}
awq_config = AutoAWQConfig.from_config(config)
assert awq_config.full_config["w_bit"] == 4
assert awq_config.full_config["q_group_size"] == 128
assert awq_config.full_config["zero_point"] is True
assert awq_config.full_config["lm_head"] is False
assert awq_config.full_config["custom_field"] == "custom_value"
def test_full_config_is_copy_not_original(self):
"""full_config should be a copy, not the original dict."""
from vllm.model_executor.layers.quantization.auto_awq import AutoAWQConfig
config = {
"w_bit": 4,
"q_group_size": 128,
"zero_point": True,
"lm_head": False,
}
original_quant_method = config.get("quant_method")
AutoAWQConfig.from_config(config)
# Original config should not be modified
assert config.get("quant_method") == original_quant_method
class TestAutoAWQConfigAttributes:
"""Tests for AutoAWQConfig attribute consistency.
These tests require GPU environment to import the full module.
They are skipped on non-GPU platforms.
"""
def test_config_attributes_match_input(self):
"""Config attributes should match input values."""
from vllm.model_executor.layers.quantization.auto_awq import AutoAWQConfig
awq_config = AutoAWQConfig(
weight_bits=4,
group_size=128,
zero_point=True,
lm_head_quantized=False,
modules_to_not_convert=["lm_head"],
)
assert awq_config.weight_bits == 4
assert awq_config.group_size == 128
assert awq_config.zero_point is True
assert awq_config.lm_head_quantized is False
assert awq_config.modules_to_not_convert == ["lm_head"]
def test_pack_factor_for_4bit(self):
"""Pack factor should be 8 for 4-bit quantization."""
from vllm.model_executor.layers.quantization.auto_awq import AutoAWQConfig
awq_config = AutoAWQConfig(
weight_bits=4,
group_size=128,
zero_point=True,
lm_head_quantized=False,
)
assert awq_config.pack_factor == 8 # 32 // 4
class TestAutoAWQConfigOverrideLogic:
"""Tests for override logic by parsing source code (no GPU import required)."""
def _get_auto_awq_source(self) -> str:
"""Read the auto_awq.py source file."""
import inspect
import pathlib
import vllm.model_executor.layers.quantization.auto_awq as auto_awq_module
source_path = inspect.getfile(auto_awq_module)
return pathlib.Path(source_path).read_text()
def test_cpu_check_in_override_method(self):
"""override_quantization_method should check current_platform.is_cpu()."""
source = self._get_auto_awq_source()
# Verify the CPU check exists in override method
assert "current_platform.is_cpu()" in source, (
"override_quantization_method should check is_cpu()"
)
assert "return None" in source, (
"override_quantization_method should return None on CPU"
)
def test_quant_method_normalization_in_from_config(self):
"""from_config should normalize quant_method to 'awq' for MoE fallback."""
source = self._get_auto_awq_source()
# Verify the normalization exists
assert (
'"quant_method"] = "awq"' in source or "'quant_method'] = 'awq'" in source
), "from_config should set quant_method='awq' in full_config"
# =============================================================================
# End-to-end integration tests (require GPU environment)
# =============================================================================
PROMPT = "On the surface of Mars, we found"
# Small AWQ model for testing - using Qwen2 1.5B which has official AWQ checkpoint
AWQ_MODELS = [
"Qwen/Qwen2-1.5B-Instruct-AWQ",
]
@pytest.mark.skipif(
not is_quant_method_supported("auto_awq"),
reason="auto_awq is not supported on this GPU type.",
)
@pytest.mark.parametrize("model_id", AWQ_MODELS)
def test_auto_awq_quantization_method(vllm_runner, model_id: str, monkeypatch):
"""Test that quantization='auto_awq' loads and runs correctly."""
monkeypatch.setenv("VLLM_ALLOW_INSECURE_SERIALIZATION", "1")
with vllm_runner(
model_id,
dtype=torch.float16,
quantization="auto_awq",
max_model_len=2048,
enforce_eager=True,
) as llm:
def check_model(model):
from vllm.model_executor.layers.quantization.auto_awq import (
AutoAWQLinearMethod,
AutoAWQMarlinLinearMethod,
)
for name, submodule in model.named_modules():
if name == "model.layers.0.self_attn.qkv_proj":
# Should use either AutoAWQLinearMethod (Triton) or
# AutoAWQMarlinLinearMethod (Marlin) depending on hardware
assert isinstance(
submodule.quant_method,
(AutoAWQLinearMethod, AutoAWQMarlinLinearMethod),
), (
f"Expected AutoAWQLinearMethod or AutoAWQMarlinLinearMethod "
f"for {name}, got {type(submodule.quant_method)}"
)
break
llm.apply_model(check_model)
outputs = llm.generate_greedy([PROMPT], max_tokens=8)
assert outputs
assert len(outputs[0][1]) > 0
def test_auto_awq_config_get_name():
"""Test that AutoAWQConfig.get_name() returns 'auto_awq'."""
from vllm.model_executor.layers.quantization.auto_awq import AutoAWQConfig
assert AutoAWQConfig.get_name() == "auto_awq"