1
0
mirror of https://github.com/huggingface/diffusers.git synced 2026-10-24 20:59:27 +03:00
Files
diffusers/tests/quantization/bnb/test_4bit.py
Sayak Paul 425b113c21 [tests] refactor pipeline-level quantization tests (#14435)
* fix(torchao): route root-level tensors around safetensors reconstruction

Models with parameters at the root of the module tree (e.g. Wan's
`scale_shift_table`) crashed torchao's `unflatten_tensor_state_dict`
when loading serialized checkpoints, since flattened tensor names are
assumed to carry a module prefix. Filter such tensors and their
metadata entries out of the reconstruction and merge them back
unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(bnb): defer 8-bit weights split from their SCB stats across shards

Sharded serialization can place an 8-bit weight and its `SCB`
statistics in different shard files, in which case the shard-by-shard
loader failed with "Missing quantization component `SCB`". Hold the
incomplete half of the pair back until its counterpart arrives with a
later shard, mirroring the torchao pending mechanism, and disable
parallel shard loading for prequantized 8-bit checkpoints.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* [tests] extend model-level quantization tester mixins

Migrate remaining model-level coverage from tests/quantization into the
tester mixins so it runs for every wired model:

- base: buffer-placement assertions in the device-map test, and an
  opt-in sharded-serialization test enabled by setting
  `sharded_serialization_config`
- bnb: serialization across all configs (sharded included), dtype
  assignment and adapter training for 8-bit, device moves preserving
  the memory footprint, corrupted-state-dict loading error, and a fixed
  modules-to-not-convert test (BitsAndBytesConfig only exposes
  llm_int8_skip_modules; the old test passed an unsupported kwarg and
  only survived by being skipped)
- torchao: custom device maps with cpu/disk offload, generalized from
  the Flux-specific test
- gguf: the diffusers-format single-file loading path, wired into the
  Flux model tests

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* [tests] fix model-level quantization test wiring

- SD3.5: the quantized testers reused the random-init dummy inputs
  (4 latent channels, fp32) while the tiny Hub checkpoint has
  in_channels=8 and the quantizers load the model in half precision;
  give them matching inputs and relax the 4-bit memory expectation for
  the tiny checkpoint.
- QwenImage / Flux2: the quantized testers had no Hub checkpoint wired
  at all, so every test errored; point them at
  hf-internal-testing/tiny-qwenimage-pipe and tiny-flux2 with matching
  inputs.
- NucleusMoE: no tiny checkpoint exists on the Hub yet; comment the
  testers out like the LTX ones.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* [tests] split tests/quantization into pipeline-level and backend-level tiers

Pipeline-level quantization tests (pipeline quality slices, cpu offload,
LoRA loading, compile, PipelineQuantizationConfig) move to
tests/pipelines/testing_utils/quantization.py, marked per backend so the
nightly CI can select them with `pytest -m`. tests/quantization keeps
only backend-level tests that fit neither tier: config validation,
utility warnings, and GGUF CUDA kernel correctness. Tests already
covered by the model-level mixins are dropped.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* [ci] select nightly quantization tests by marker across test tiers

Each backend job now runs `pytest -m <marker>` over tests/models,
tests/quantization, and tests/pipelines/testing_utils/quantization.py,
giving the model-level mixin tests a nightly home with the backend
dependencies installed. The torchao job additionally installs mslk.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: sayak@huggingface.co <sayak@ip-10-53-90-45.ec2.internal>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-18 20:53:32 +02:00

81 lines
2.7 KiB
Python

# coding=utf-8
# Copyright 2026 The HuggingFace Team Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import gc
import pytest
import torch
from diffusers import BitsAndBytesConfig
from diffusers.utils import logging
from ...testing_utils import (
CaptureLogger,
backend_empty_cache,
is_bitsandbytes,
is_bitsandbytes_available,
is_quantization,
require_accelerate,
require_bitsandbytes_version_greater,
require_torch,
require_torch_accelerator,
slow,
torch_device,
)
if is_bitsandbytes_available():
from diffusers.quantizers.bitsandbytes.utils import replace_with_bnb_linear
# Model-level BitsAndBytes tests live in `tests/models/testing_utils/quantization.py` and
# pipeline-level ones in `tests/pipelines/testing_utils/quantization.py`. This module covers
# backend behavior that fits neither: config validation, loading error paths, and utility warnings.
@is_quantization
@is_bitsandbytes
@require_bitsandbytes_version_greater("0.43.2")
@require_accelerate
@require_torch
@require_torch_accelerator
@slow
class TestBnB4BitBasic:
model_name = "stabilityai/stable-diffusion-3-medium-diffusers"
@pytest.fixture(autouse=True)
def _setup_basic(self):
gc.collect()
backend_empty_cache(torch_device)
yield
gc.collect()
backend_empty_cache(torch_device)
def test_bnb_4bit_wrong_config(self):
r"""
Test whether creating a bnb config with unsupported values leads to errors.
"""
with pytest.raises(ValueError):
_ = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_storage="add")
def test_bnb_4bit_logs_warning_for_no_quantization(self):
model_with_no_linear = torch.nn.Sequential(torch.nn.Conv2d(4, 4, 3), torch.nn.ReLU())
quantization_config = BitsAndBytesConfig(load_in_4bit=True)
logger = logging.get_logger("diffusers.quantizers.bitsandbytes.utils")
logger.setLevel(30)
with CaptureLogger(logger) as cap_logger:
_ = replace_with_bnb_linear(model_with_no_linear, quantization_config=quantization_config)
assert (
"You are loading your model in 8bit or 4bit but no linear modules were found in your model."
in cap_logger.out
)