chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
"""Contract tests for the QuantizedActivation linear-kernel integration."""
|
||||
|
||||
import pytest
|
||||
import torch
|
||||
|
||||
from vllm.model_executor.kernels.linear import (
|
||||
_POSSIBLE_FP8_BLOCK_KERNELS,
|
||||
_POSSIBLE_FP8_KERNELS,
|
||||
_POSSIBLE_INT8_KERNELS,
|
||||
_POSSIBLE_NVFP4_KERNELS,
|
||||
)
|
||||
from vllm.model_executor.kernels.linear.nvfp4.base import (
|
||||
NvFp4LinearKernel,
|
||||
NvFp4LinearLayerConfig,
|
||||
)
|
||||
from vllm.model_executor.kernels.linear.nvfp4.flashinfer import (
|
||||
FlashInferCutlassNvFp4LinearKernel,
|
||||
FlashInferTrtllmNvFp4LinearKernel,
|
||||
)
|
||||
from vllm.model_executor.kernels.linear.scaled_mm.cutlass import (
|
||||
CutlassFP8ScaledMMLinearKernel,
|
||||
)
|
||||
from vllm.model_executor.kernels.linear.scaled_mm.flashinfer import (
|
||||
FlashInferFP8ScaledMMLinearKernel,
|
||||
)
|
||||
from vllm.model_executor.kernels.linear.scaled_mm.ScaledMMLinearKernel import (
|
||||
FP8ScaledMMLinearLayerConfig,
|
||||
Int8ScaledMMLinearKernel,
|
||||
Int8ScaledMMLinearLayerConfig,
|
||||
)
|
||||
from vllm.model_executor.layers.fusion.quant_activation import (
|
||||
QuantizedActivation,
|
||||
as_quantized_activation,
|
||||
expose_input_quant_key,
|
||||
)
|
||||
from vllm.model_executor.layers.quantization.utils.quant_utils import (
|
||||
kFp8StaticTensorSym,
|
||||
kNvfp4Dynamic,
|
||||
)
|
||||
from vllm.platforms import current_platform
|
||||
|
||||
# The only backends that consume a pre-quantized activation.
|
||||
SUPPORTING = {
|
||||
CutlassFP8ScaledMMLinearKernel,
|
||||
FlashInferFP8ScaledMMLinearKernel,
|
||||
FlashInferCutlassNvFp4LinearKernel,
|
||||
}
|
||||
|
||||
|
||||
def _all_kernel_classes() -> list[type]:
|
||||
seen: dict[type, None] = {}
|
||||
for registry in (
|
||||
_POSSIBLE_FP8_KERNELS,
|
||||
_POSSIBLE_FP8_BLOCK_KERNELS,
|
||||
_POSSIBLE_INT8_KERNELS,
|
||||
_POSSIBLE_NVFP4_KERNELS,
|
||||
):
|
||||
for kernels in registry.values():
|
||||
for cls in kernels:
|
||||
seen.setdefault(cls, None)
|
||||
return list(seen)
|
||||
|
||||
|
||||
def _probe(cls: type):
|
||||
"""A bare kernel instance with a plausible config, so input_quant_key()
|
||||
can be queried without the hardware-gated constructor."""
|
||||
obj = cls.__new__(cls) # type: ignore[call-overload]
|
||||
if issubclass(cls, NvFp4LinearKernel):
|
||||
obj.config = NvFp4LinearLayerConfig()
|
||||
elif issubclass(cls, Int8ScaledMMLinearKernel):
|
||||
obj.config = Int8ScaledMMLinearLayerConfig(
|
||||
is_static_input_scheme=True, is_channelwise=False, input_symmetric=True
|
||||
)
|
||||
else:
|
||||
obj.config = FP8ScaledMMLinearLayerConfig(
|
||||
weight_quant_key=kFp8StaticTensorSym,
|
||||
activation_quant_key=kFp8StaticTensorSym,
|
||||
weight_shape=(16, 16),
|
||||
input_dtype=torch.bfloat16,
|
||||
out_dtype=torch.bfloat16,
|
||||
)
|
||||
return obj
|
||||
|
||||
|
||||
def _resolved_apply_weights(cls: type):
|
||||
for base in cls.__mro__:
|
||||
if "apply_weights" in base.__dict__:
|
||||
return base.__dict__["apply_weights"]
|
||||
raise AssertionError(f"{cls.__name__} has no apply_weights in its MRO")
|
||||
|
||||
|
||||
def test_only_known_backends_support_prequantized_input():
|
||||
declarers = {c for c in _all_kernel_classes() if _probe(c).input_quant_key()}
|
||||
assert declarers == SUPPORTING
|
||||
|
||||
|
||||
def test_supporting_backend_declares_consume_via_helper():
|
||||
for cls in SUPPORTING:
|
||||
fn = _resolved_apply_weights(cls)
|
||||
assert "as_quantized_activation" in fn.__code__.co_names, cls.__name__
|
||||
|
||||
|
||||
def test_bridge_marks_supporting_and_skips_others():
|
||||
supported = _probe(FlashInferCutlassNvFp4LinearKernel)
|
||||
layer = torch.nn.Module()
|
||||
expose_input_quant_key(layer, supported)
|
||||
assert layer.input_quant_key == kNvfp4Dynamic
|
||||
|
||||
unsupported = _probe(FlashInferTrtllmNvFp4LinearKernel)
|
||||
assert unsupported.input_quant_key() is None
|
||||
layer = torch.nn.Module()
|
||||
expose_input_quant_key(layer, unsupported)
|
||||
assert not hasattr(layer, "input_quant_key")
|
||||
|
||||
|
||||
def test_as_quantized_activation_validates_key():
|
||||
qa = QuantizedActivation(
|
||||
data=torch.zeros(2, 4, dtype=current_platform.fp8_dtype()),
|
||||
scale=torch.tensor(1.0),
|
||||
orig_dtype=torch.bfloat16,
|
||||
orig_shape=torch.Size([2, 4]),
|
||||
quant_key=kFp8StaticTensorSym,
|
||||
)
|
||||
with pytest.raises(AssertionError):
|
||||
as_quantized_activation(qa, kNvfp4Dynamic)
|
||||
with pytest.raises(AssertionError):
|
||||
as_quantized_activation(qa, None)
|
||||
assert as_quantized_activation(torch.zeros(2, 4), kFp8StaticTensorSym) is None
|
||||
assert as_quantized_activation(qa, kFp8StaticTensorSym) is qa
|
||||
Reference in New Issue
Block a user