# SPDX-License-Identifier: Apache-2.0 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project """Unit tests for diffusion GGUF quantization config and linear method.""" from __future__ import annotations from types import SimpleNamespace import pytest import torch from vllm.model_executor.layers.linear import LinearBase from vllm.model_executor.layers.quantization.gguf import UNQUANTIZED_TYPES, UnquantizedLinearMethod from vllm_omni.quantization import build_quant_config from vllm_omni.quantization.gguf_config import ( DiffusionGGUFConfig, DiffusionGGUFLinearMethod, dequant_gemm_gguf, ) pytestmark = [pytest.mark.core_model, pytest.mark.diffusion, pytest.mark.cpu] def test_gguf_config_creation_and_delegation(): config = DiffusionGGUFConfig( gguf_model="weights.gguf", unquantized_modules=["proj_out"], ) assert config.gguf_model == "weights.gguf" assert config.unquantized_modules == ["proj_out"] assert config.get_name() == "gguf" def test_build_quant_config_builds_gguf_config(): config = build_quant_config( "gguf", gguf_model="repo/model-Q4_0.gguf", unquantized_modules=["norm_out"], ) assert isinstance(config, DiffusionGGUFConfig) assert config.gguf_model == "repo/model-Q4_0.gguf" assert config.unquantized_modules == ["norm_out"] def test_gguf_vllm_config_returns_diffusion_linear_method_for_linear_layers(): linear = object.__new__(LinearBase) method = DiffusionGGUFConfig(unquantized_modules=[]).get_quant_method(linear, "transformer.img_in") assert isinstance(method, DiffusionGGUFLinearMethod) def test_gguf_vllm_config_respects_unquantized_modules(): linear = object.__new__(LinearBase) method = DiffusionGGUFConfig(unquantized_modules=["proj_out"]).get_quant_method(linear, "transformer.proj_out") assert isinstance(method, UnquantizedLinearMethod) def test_gguf_vllm_config_returns_none_for_non_linear_layers(): method = DiffusionGGUFConfig(unquantized_modules=[]).get_quant_method(torch.nn.LayerNorm(4), "norm") assert method is None def test_dequant_gemm_gguf_uses_plain_matmul_for_unquantized_types(): qweight_type = next(iter(UNQUANTIZED_TYPES)) x = torch.tensor([[1.0, 2.0]], dtype=torch.float32) qweight = torch.tensor([[3.0, 4.0], [5.0, 6.0]], dtype=torch.float32) out = dequant_gemm_gguf(x, qweight, qweight_type) assert torch.allclose(out, x @ qweight.T) def test_diffusion_gguf_linear_method_applies_bias_on_unquantized_weight(): qweight_type = next(iter(UNQUANTIZED_TYPES)) method = DiffusionGGUFLinearMethod(DiffusionGGUFConfig(unquantized_modules=[])) layer = SimpleNamespace( qweight=torch.tensor([[1.0, 2.0], [3.0, 4.0]], dtype=torch.float32), qweight_type=SimpleNamespace(weight_type=qweight_type), ) x = torch.tensor([[[1.0, 0.5]]], dtype=torch.float32) bias = torch.tensor([0.25, -0.5], dtype=torch.float32) out = method.apply(layer, x, bias) expected = x @ layer.qweight.T + bias assert torch.allclose(out, expected) def test_diffusion_gguf_linear_method_concatenates_sharded_outputs(): qweight_type = next(iter(UNQUANTIZED_TYPES)) method = DiffusionGGUFLinearMethod(DiffusionGGUFConfig(unquantized_modules=[])) qweight = torch.nn.Parameter( torch.tensor( [ [1.0, 0.0], [0.0, 1.0], [2.0, 0.0], [0.0, 2.0], ], dtype=torch.float32, ), requires_grad=False, ) qweight.shard_id = ["left", "right"] qweight.shard_offset_map = { "left": (0, 2, 2), "right": (2, 4, 2), } layer = SimpleNamespace( qweight=qweight, qweight_type=SimpleNamespace( shard_weight_type={ "left": qweight_type, "right": qweight_type, } ), ) x = torch.tensor([[1.5, 2.0]], dtype=torch.float32) out = method.apply(layer, x) expected_q = x @ qweight[:2].T expected_k = x @ qweight[2:4].T assert torch.allclose(out, torch.cat([expected_q, expected_k], dim=-1))