Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 1 addition & 4 deletions .github/workflows/nightly_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -350,9 +350,6 @@ jobs:
- backend: "torchao"
marker: "torchao"
additional_deps: ["mslk"]
- backend: "optimum_quanto"
marker: "quanto"
additional_deps: []
- backend: "nvidia_modelopt"
marker: "modelopt"
additional_deps: []
Expand Down Expand Up @@ -428,7 +425,7 @@ jobs:
run: |
printf 'torch==2.10.0\ntorchvision==0.25.0\ntorchaudio==2.10.0\n' > "$UV_OVERRIDE"
uv pip install -e ".[quality]"
uv pip install -U bitsandbytes optimum_quanto
uv pip install -U bitsandbytes
uv pip uninstall transformers huggingface_hub && UV_PRERELEASE=allow uv pip install -U transformers@git+https://github.com/huggingface/transformers.git
uv pip install pytest-reportlog
- name: Environment
Expand Down
4 changes: 4 additions & 0 deletions docs/source/en/quantization/quanto.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ specific language governing permissions and limitations under the License.

# Quanto

> [!WARNING]
> The Quanto backend is deprecated and will be removed in version 1.0.0. Consider switching to one of the other
> supported [quantization backends](./overview), such as [bitsandbytes](./bitsandbytes) or [torchao](./torchao).

[Quanto](https://github.com/huggingface/optimum-quanto) is a PyTorch quantization backend for [Optimum](https://huggingface.co/docs/optimum/en/index). It has been designed with versatility and simplicity in mind:

- All features are available in eager mode (works with non-traceable models)
Expand Down
7 changes: 7 additions & 0 deletions src/diffusers/quantizers/quantization_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,13 @@ class QuantoConfig(QuantizationConfigMixin):
This is a wrapper class about all possible attributes and features that you can play with a model that has been
loaded using `quanto`.

<Tip warning={true}>

`QuantoConfig` is deprecated and will be removed in version 1.0.0. Consider switching to one of the other supported
quantization backends, such as [`BitsAndBytesConfig`] or [`TorchAoConfig`].

</Tip>

Args:
weights_dtype (`str`, *optional*, defaults to `"int8"`):
The target dtype for the weights after quantization. Supported values are ("float8","int8","int4","int2")
Expand Down
7 changes: 7 additions & 0 deletions src/diffusers/quantizers/quanto/quanto_quantizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@
class QuantoQuantizer(DiffusersQuantizer):
r"""
Diffusers Quantizer for Optimum Quanto

<Tip warning={true}>

The Quanto backend is deprecated and will be removed in version 1.0.0. Consider switching to one of the other
supported quantization backends, such as `bitsandbytes` or `torchao`.

</Tip>
"""

use_keep_in_fp32_modules = True
Expand Down
1 change: 0 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ def pytest_configure(config):
config.addinivalue_line("markers", "single_file: marks tests for single file checkpoint loading")
config.addinivalue_line("markers", "quantization: marks tests for quantization functionality")
config.addinivalue_line("markers", "bitsandbytes: marks tests for BitsAndBytes quantization functionality")
config.addinivalue_line("markers", "quanto: marks tests for Quanto quantization functionality")
config.addinivalue_line("markers", "torchao: marks tests for TorchAO quantization functionality")
config.addinivalue_line("markers", "gguf: marks tests for GGUF quantization functionality")
config.addinivalue_line("markers", "modelopt: marks tests for NVIDIA ModelOpt quantization functionality")
Expand Down
6 changes: 0 additions & 6 deletions tests/models/testing_utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,6 @@
NunchakuLiteTesterMixin,
QuantizationCompileTesterMixin,
QuantizationTesterMixin,
QuantoCompileTesterMixin,
QuantoConfigMixin,
QuantoTesterMixin,
SDNQCompileTesterMixin,
SDNQConfigMixin,
SDNQTesterMixin,
Expand Down Expand Up @@ -97,9 +94,6 @@
"TaylorSeerCacheTesterMixin",
"QuantizationCompileTesterMixin",
"QuantizationTesterMixin",
"QuantoCompileTesterMixin",
"QuantoConfigMixin",
"QuantoTesterMixin",
"run_nondeterministic",
"SDNQCompileTesterMixin",
"SDNQConfigMixin",
Expand Down
187 changes: 1 addition & 186 deletions tests/models/testing_utils/quantization.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
GGUFQuantizationConfig,
NunchakuLiteQuantizationConfig,
NVIDIAModelOptConfig,
QuantoConfig,
SDNQConfig,
TorchAoConfig,
)
Expand All @@ -34,22 +33,18 @@
is_gguf_available,
is_kernels_available,
is_nvidia_modelopt_available,
is_optimum_quanto_available,
is_peft_available,
is_torchao_available,
)

from ...testing_utils import (
assert_tensors_close,
backend_empty_cache,
backend_max_memory_allocated,
backend_reset_peak_memory_stats,
is_autoround,
is_bitsandbytes,
is_gguf,
is_modelopt,
is_quantization,
is_quanto,
is_sdnq,
is_torch_compile,
is_torchao,
Expand All @@ -59,7 +54,6 @@
require_bitsandbytes_version_greater,
require_gguf_version_greater_or_equal,
require_modelopt_version_greater_or_equal,
require_quanto,
require_sdnq,
require_torchao_version_greater_or_equal,
torch_device,
Expand All @@ -77,9 +71,6 @@
if is_bitsandbytes_available():
import bitsandbytes as bnb

if is_optimum_quanto_available():
from optimum.quanto import QLinear

if is_gguf_available():
pass

Expand Down Expand Up @@ -119,7 +110,7 @@ class QuantizationTesterMixin:
Backend-specific mixins should:
1. Implement _create_quantized_model(config_kwargs)
2. Implement _verify_if_layer_quantized(name, module, config_kwargs)
3. Define their config dict (e.g., BNB_CONFIGS, QUANTO_WEIGHT_TYPES, etc.)
3. Define their config dict (e.g., BNB_CONFIGS, TORCHAO_CONFIGS, etc.)
4. Use @pytest.mark.parametrize to create tests that call the common test methods below

Expected class attributes:
Expand Down Expand Up @@ -777,153 +768,6 @@ def test_bnb_cpu_device_map(self, config_name):
self._test_quantization_cpu_device_map(BitsAndBytesConfigMixin.BNB_CONFIGS[config_name])


@is_quantization
@is_quanto
@require_quanto
@require_accelerate
@require_accelerator
class QuantoConfigMixin:
"""
Base mixin providing Quanto quantization config and model creation.

Expected class attributes:
- model_class: The model class to test
- pretrained_model_name_or_path: Hub repository ID for the pretrained model
- pretrained_model_kwargs: (Optional) Dict of kwargs to pass to from_pretrained
"""

QUANTO_WEIGHT_TYPES = {
"float8": {"weights_dtype": "float8"},
"int8": {"weights_dtype": "int8"},
"int4": {"weights_dtype": "int4"},
"int2": {"weights_dtype": "int2"},
}

QUANTO_EXPECTED_MEMORY_REDUCTIONS = {
"float8": 1.5,
"int8": 1.5,
"int4": 3.0,
"int2": 7.0,
}

def _create_quantized_model(self, config_kwargs, **extra_kwargs):
config = QuantoConfig(**config_kwargs)
kwargs = getattr(self, "pretrained_model_kwargs", {}).copy()
kwargs["quantization_config"] = config
kwargs.update(extra_kwargs)
return self.model_class.from_pretrained(self.pretrained_model_name_or_path, **kwargs)

def _verify_if_layer_quantized(self, name, module, config_kwargs):
assert isinstance(module, QLinear), f"Layer {name} is not QLinear, got {type(module)}"

def _test_quantization_memory_footprint(self, config_kwargs, expected_memory_reduction=1.2):
"""Override to use max_memory_allocated for Quanto (get_memory_footprint doesn't reflect quantized _data)."""
# Measure unquantized model memory
backend_reset_peak_memory_stats(torch_device)
backend_empty_cache(torch_device)

model = self._load_unquantized_model()
model.to(torch_device)
mem = backend_max_memory_allocated(torch_device)

del model
gc.collect()
backend_empty_cache(torch_device)

# Measure quantized model memory
backend_reset_peak_memory_stats(torch_device)

model_quantized = self._create_quantized_model(config_kwargs)
model_quantized.to(torch_device)
mem_quantized = backend_max_memory_allocated(torch_device)

ratio = mem / mem_quantized
assert ratio >= expected_memory_reduction, (
f"Memory ratio {ratio:.2f} is less than expected ({expected_memory_reduction}x). unquantized={mem}, quantized={mem_quantized}"
)


@is_quanto
@require_quanto
@require_accelerate
@require_accelerator
class QuantoTesterMixin(QuantoConfigMixin, QuantizationTesterMixin):
"""
Mixin class for testing Quanto quantization on models.

Expected class attributes:
- model_class: The model class to test
- pretrained_model_name_or_path: Hub repository ID for the pretrained model
- pretrained_model_kwargs: (Optional) Dict of kwargs to pass to from_pretrained (e.g., {"subfolder": "transformer"})

Expected methods to be implemented by subclasses:
- get_dummy_inputs(): Returns dict of inputs to pass to the model forward pass

Optional class attributes:
- QUANTO_WEIGHT_TYPES: Dict of weight_type_name -> qtype

Pytest mark: quanto
Use `pytest -m "not quanto"` to skip these tests
"""

@pytest.mark.parametrize(
"weight_type_name",
list(QuantoConfigMixin.QUANTO_WEIGHT_TYPES.keys()),
ids=list(QuantoConfigMixin.QUANTO_WEIGHT_TYPES.keys()),
)
def test_quanto_quantization_num_parameters(self, weight_type_name):
self._test_quantization_num_parameters(QuantoConfigMixin.QUANTO_WEIGHT_TYPES[weight_type_name])

@pytest.mark.parametrize(
"weight_type_name",
list(QuantoConfigMixin.QUANTO_WEIGHT_TYPES.keys()),
ids=list(QuantoConfigMixin.QUANTO_WEIGHT_TYPES.keys()),
)
def test_quanto_quantization_memory_footprint(self, weight_type_name):
expected = QuantoConfigMixin.QUANTO_EXPECTED_MEMORY_REDUCTIONS.get(weight_type_name, 1.2)
self._test_quantization_memory_footprint(
QuantoConfigMixin.QUANTO_WEIGHT_TYPES[weight_type_name], expected_memory_reduction=expected
)

@pytest.mark.parametrize(
"weight_type_name",
list(QuantoConfigMixin.QUANTO_WEIGHT_TYPES.keys()),
ids=list(QuantoConfigMixin.QUANTO_WEIGHT_TYPES.keys()),
)
def test_quanto_quantization_inference(self, weight_type_name):
self._test_quantization_inference(QuantoConfigMixin.QUANTO_WEIGHT_TYPES[weight_type_name])

@pytest.mark.parametrize("weight_type_name", ["int8"], ids=["int8"])
def test_quanto_quantized_layers(self, weight_type_name):
self._test_quantized_layers(QuantoConfigMixin.QUANTO_WEIGHT_TYPES[weight_type_name])

@pytest.mark.parametrize("weight_type_name", ["int8"], ids=["int8"])
def test_quanto_quantization_lora_inference(self, weight_type_name):
self._test_quantization_lora_inference(QuantoConfigMixin.QUANTO_WEIGHT_TYPES[weight_type_name])

@pytest.mark.parametrize("weight_type_name", ["int8"], ids=["int8"])
def test_quanto_quantization_serialization(self, weight_type_name, tmp_path):
self._test_quantization_serialization(QuantoConfigMixin.QUANTO_WEIGHT_TYPES[weight_type_name], tmp_path)

def test_quanto_modules_to_not_convert(self):
"""Test that modules_to_not_convert parameter works correctly."""
modules_to_exclude = getattr(self, "modules_to_not_convert_for_test", None)
if modules_to_exclude is None:
pytest.skip("modules_to_not_convert_for_test not defined for this model")

self._test_quantization_modules_to_not_convert(
QuantoConfigMixin.QUANTO_WEIGHT_TYPES["int8"], modules_to_exclude
)

def test_quanto_device_map(self):
"""Test that device_map='auto' works correctly with quantization."""
self._test_quantization_device_map(QuantoConfigMixin.QUANTO_WEIGHT_TYPES["int8"])

def test_quanto_dequantize(self):
"""Test that dequantize() works correctly."""
self._test_dequantize(QuantoConfigMixin.QUANTO_WEIGHT_TYPES["int8"])


@is_quantization
@is_torchao
@require_accelerator
Expand Down Expand Up @@ -1599,35 +1443,6 @@ def test_bnb_torch_compile_with_group_offload(self, config_name):
self._test_torch_compile_with_group_offload(BitsAndBytesConfigMixin.BNB_CONFIGS[config_name])


@is_quanto
@require_quanto
@require_accelerate
@require_accelerator
class QuantoCompileTesterMixin(QuantoConfigMixin, QuantizationCompileTesterMixin):
"""
Mixin class for testing torch.compile with Quanto quantized models.

Expected class attributes:
- model_class: The model class to test
- pretrained_model_name_or_path: Hub repository ID for the pretrained model
- pretrained_model_kwargs: (Optional) Dict of kwargs to pass to from_pretrained

Expected methods to be implemented by subclasses:
- get_dummy_inputs(): Returns dict of inputs to pass to the model forward pass

Pytest mark: quanto
Use `pytest -m "not quanto"` to skip these tests
"""

@pytest.mark.parametrize("weight_type_name", ["int8"], ids=["int8"])
def test_quanto_torch_compile(self, weight_type_name):
self._test_torch_compile(QuantoConfigMixin.QUANTO_WEIGHT_TYPES[weight_type_name])

@pytest.mark.parametrize("weight_type_name", ["int8"], ids=["int8"])
def test_quanto_torch_compile_with_group_offload(self, weight_type_name):
self._test_torch_compile_with_group_offload(QuantoConfigMixin.QUANTO_WEIGHT_TYPES[weight_type_name])


@is_torchao
@require_accelerator
@require_torchao_version_greater_or_equal("0.7.0")
Expand Down
18 changes: 0 additions & 18 deletions tests/models/transformers/test_models_transformer_flux.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@
ModelOptCompileTesterMixin,
ModelOptTesterMixin,
ModelTesterMixin,
QuantoCompileTesterMixin,
QuantoTesterMixin,
SDNQCompileTesterMixin,
SDNQTesterMixin,
SingleFileTesterMixin,
Expand Down Expand Up @@ -406,18 +404,6 @@ def get_dummy_inputs(self):
return {k: v.to(self.torch_dtype) if torch.is_floating_point(v) else v for k, v in inputs.items()}


class TestFluxTransformerQuanto(FluxTransformerTesterConfig, QuantoTesterMixin):
"""Quanto quantization tests for Flux Transformer."""

@property
def pretrained_model_name_or_path(self):
return "hf-internal-testing/tiny-flux-transformer"

@property
def pretrained_model_kwargs(self):
return {}


class TestFluxTransformerTorchAo(FluxTransformerTesterConfig, TorchAoTesterMixin):
"""TorchAO quantization tests for Flux Transformer."""

Expand Down Expand Up @@ -473,10 +459,6 @@ def test_loading_gguf_diffusers_format(self):
model(**self.get_dummy_inputs())


class TestFluxTransformerQuantoCompile(FluxTransformerTesterConfig, QuantoCompileTesterMixin):
"""Quanto + compile tests for Flux Transformer."""


class TestFluxTransformerTorchAoCompile(FluxTransformerTesterConfig, TorchAoCompileTesterMixin):
"""TorchAO + compile tests for Flux Transformer."""

Expand Down
Loading
Loading