[Model] FP8 Support For Boogu-Image (#6925)

Signed-off-by: Dmaner <2663515256@qq.com>
This commit is contained in:
DMAN authored and GitHub committed 2026-09-06 04:48:38 +00:00
1 parent 1cd92553cf
commit 06541d1f52
15 files changed
+809 -78

No files matched your search

@@ -17,6 +17,7 @@ from huggingface_hub import snapshot_download
from safetensors.torch import save_file
from vllm.config.load import LoadConfig
import vllm_omni.diffusion.model_loader.diffusers_loader as loader_module
from vllm_omni.diffusion.config import get_current_diffusion_config, get_current_diffusion_config_or_none
from vllm_omni.diffusion.data import DiffusionParallelConfig, OmniDiffusionConfig
from vllm_omni.diffusion.lora.manager import LoRABackend
@@ -30,6 +31,7 @@ from vllm_omni.diffusion.model_loader.host_weights import source_identity as sou
from vllm_omni.diffusion.models.helios import HeliosPipeline
from vllm_omni.diffusion.models.host_weight_contract import FinalLayoutModelContract
from vllm_omni.diffusion.registry import initialize_model
from vllm_omni.quantization.component_config import ComponentQuantizationConfig
pytestmark = [pytest.mark.core_model, pytest.mark.diffusion, pytest.mark.cpu]
@@ -165,6 +167,43 @@ def _make_loader_with_weights(weight_names: list[str]) -> DiffusersPipelineLoade
return loader
def test_serialized_torchao_component_uses_pytorch_iterator(mocker):
torchao_config = SimpleNamespace(
get_name=lambda: "torchao",
is_checkpoint_torchao_serialized=True,
)
loader = _make_loader_with_weights([])
loader.quant_config = ComponentQuantizationConfig({"transformer": torchao_config})
loader.load_config.pt_load_map_location = "cpu"
files = ["/weights/model-10.bin", "/weights/model-2.bin"]
mocker.patch.object(loader, "_prepare_weights", return_value=("/weights", files, False))
pt_iterator = mocker.patch.object(
loader_module,
"pt_weights_iterator",
return_value=iter([("block.weight", torch.ones(1))]),
)
safetensors_iterator = mocker.patch.object(loader_module, "safetensors_weights_iterator")
multithread_iterator = mocker.patch.object(loader_module, "multi_thread_safetensors_weights_iterator")
source = DiffusersPipelineLoader.ComponentSource(
model_or_path="/weights",
subfolder=None,
revision=None,
prefix="transformer.",
)
weights = list(loader._get_weights_iterator(source))
pt_iterator.assert_called_once_with(
["/weights/model-2.bin", "/weights/model-10.bin"],
loader.load_config.use_tqdm_on_load,
"cpu",
)
safetensors_iterator.assert_not_called()
multithread_iterator.assert_not_called()
assert weights[0][0] == "transformer.block.weight"
assert torch.equal(weights[0][1], torch.ones(1))
def test_hwr_cold_publication_and_warm_restore_skip_ordinary_dit_loading(
tmp_path: Path,
monkeypatch,
@@ -434,7 +473,7 @@ def test_prepare_weights_honors_component_index_and_explicit_override(tmp_path,
assert folder == str(transformer)
assert [str(transformer / filename) for filename in indexed_files] == files
assert use_safetensors
assert hub_api.hf_hub_download.call_count == 2
assert hub_api.hf_hub_download.call_count == len(loader_mod.SAFETENSORS_INDEX_FILES)
hub_api.hf_hub_download.assert_any_call(
repo_id="org/model",
filename="transformer/diffusion_pytorch_model.safetensors.index.json",
@@ -493,6 +532,45 @@ def test_prepare_local_weights_honors_component_index(tmp_path):
assert use_safetensors
def test_prepare_local_bin_index_is_authoritative_and_safetensors_remains_preferred(tmp_path):
transformer = tmp_path / "transformer"
transformer.mkdir()
indexed_files = [f"diffusion_pytorch_model-{index:05d}-of-00002.bin" for index in (1, 2)]
stale_file = "diffusion_pytorch_model-00001-of-00008.bin"
(transformer / "diffusion_pytorch_model.bin.index.json").write_text(
json.dumps({"weight_map": {f"weight.{index}": filename for index, filename in enumerate(indexed_files)}})
)
for filename in (*indexed_files, stale_file):
(transformer / filename).touch()
_, files, use_safetensors = _make_loader_with_weights([])._prepare_weights(
tmp_path,
subfolder="transformer",
revision=None,
fall_back_to_pt=True,
allow_patterns_overrides=None,
)
assert files == [str(transformer / filename) for filename in indexed_files]
assert not use_safetensors
safetensors_file = "diffusion_pytorch_model.safetensors"
(transformer / "diffusion_pytorch_model.safetensors.index.json").write_text(
json.dumps({"weight_map": {"weight": safetensors_file}})
)
(transformer / safetensors_file).touch()
_, files, use_safetensors = _make_loader_with_weights([])._prepare_weights(
tmp_path,
subfolder="transformer",
revision=None,
fall_back_to_pt=True,
allow_patterns_overrides=None,
)
assert files == [str(transformer / safetensors_file)]
assert use_safetensors
def test_prepare_weights_rejects_polluted_offline_cache_without_index(tmp_path, mocker):
import vllm_omni.diffusion.model_loader.diffusers_loader as loader_mod
@@ -519,7 +597,9 @@ def test_prepare_weights_rejects_polluted_offline_cache_without_index(tmp_path,
allow_patterns_overrides=None,
)
assert hub_api.hf_hub_download.call_count == 2
assert hub_api.hf_hub_download.call_count == len(loader_mod.SAFETENSORS_INDEX_FILES) + len(
loader_mod.PT_INDEX_FILES
)
assert all(call.kwargs["local_files_only"] for call in hub_api.hf_hub_download.call_args_list)
@@ -330,6 +330,74 @@ def test_transformer_instantiates():
assert model.x_embedder.out_features == HIDDEN_SIZE
@pytest.fixture
def recording_quant_config():
from vllm.model_executor.layers.linear import UnquantizedLinearMethod
from vllm.model_executor.layers.quantization.base_config import QuantizationConfig
class RecordingQuantConfig(QuantizationConfig):
def __init__(self):
super().__init__()
self.prefixes: list[str] = []
@classmethod
def get_name(cls):
return "recording"
@classmethod
def get_supported_act_dtypes(cls):
return [torch.float32]
@classmethod
def get_min_capability(cls):
return 0
@classmethod
def get_config_filenames(cls):
return []
@classmethod
def from_config(cls, config):
return cls()
def get_quant_method(self, layer, prefix):
self.prefixes.append(prefix)
return UnquantizedLinearMethod()
return RecordingQuantConfig()
def test_transformer_propagates_quant_config_and_prefix(recording_quant_config):
from vllm.model_executor.layers.linear import LinearBase
from vllm_omni.diffusion.models.boogu_image.boogu_image_transformer import (
BooguImageTransformer2DModel,
)
model = BooguImageTransformer2DModel(
od_config=_tiny_od_config(),
quant_config=recording_quant_config,
prefix="transformer",
)
configured_prefixes = set()
for name, module in model.named_modules():
if isinstance(module, LinearBase):
qualified_name = f"transformer.{name}"
assert module.prefix == qualified_name
assert module.quant_config is recording_quant_config
configured_prefixes.add(qualified_name)
assert set(recording_quant_config.prefixes) == configured_prefixes
assert {name for name, module in model.named_modules() if isinstance(module, torch.nn.Linear)} == {
"x_embedder",
"ref_image_patch_embedder",
"time_caption_embed.timestep_embedder.linear_1",
"time_caption_embed.timestep_embedder.linear_2",
"time_caption_embed.caption_embedder.1",
}
def test_transformer_preprocesses_multiple_instruction_feature_layers():
from vllm_omni.diffusion.models.boogu_image.boogu_image_transformer import (
BooguImageTransformer2DModel,
@@ -83,6 +83,7 @@ def mock_dependencies(mocker, monkeypatch):
"processor": mock_processor,
"vae": mock_vae,
"scheduler": mock_scheduler,
"transformer_cls": mock_transformer_cls,
"transformer": mock_transformer_instance,
}
@@ -187,6 +188,28 @@ def test_constructor_weights_sources(boogu_pipeline):
assert source.fall_back_to_pt is True
def test_constructor_routes_only_transformer_config(mock_dependencies, mocker):
from vllm.model_executor.layers.quantization.base_config import QuantizationConfig
from vllm_omni.diffusion.models.boogu_image.pipeline_boogu_image import BooguImagePipeline
from vllm_omni.quantization.component_config import ComponentQuantizationConfig
transformer_config = mocker.MagicMock(spec=QuantizationConfig)
encoder_config = mocker.MagicMock(spec=QuantizationConfig)
od_config = OmniDiffusionConfig(
model="dummy-boogu",
tf_model_config=TransformerConfig(params={}),
dtype=torch.bfloat16,
quantization_config=ComponentQuantizationConfig(
{"transformer": transformer_config, "mllm": encoder_config, "vae": None}
),
)
BooguImagePipeline(od_config=od_config)
kwargs = mock_dependencies["transformer_cls"].call_args.kwargs
assert kwargs["quant_config"] is transformer_config
assert kwargs["prefix"] == "transformer"
@pytest.mark.parametrize(
("parallel_config", "cache_backend", "message"),
[
@@ -0,0 +1,58 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
import pytest
import torch
from vllm_omni.quantization import build_quant_config
from vllm_omni.quantization.component_config import ComponentQuantizationConfig
pytestmark = [pytest.mark.core_model, pytest.mark.cpu, pytest.mark.diffusion]
@pytest.mark.parametrize(
"transformer_spec",
[
{
"method": "torchao",
"quant_type": {
"default": {
"_type": "Float8WeightOnlyConfig",
"_version": 2,
"_data": {
"weight_dtype": {
"_type": "torch.dtype",
"_data": "float8_e4m3fn",
},
"set_inductor_config": False,
},
}
},
},
{"method": "torchao_float8_weight_only"},
],
ids=["serialized-json", "checkpoint-shorthand"],
)
def test_build_quant_config_torchao_checkpoint(transformer_spec):
quantization = pytest.importorskip("torchao.quantization")
result = build_quant_config({"transformer": transformer_spec})
assert isinstance(result, ComponentQuantizationConfig)
transformer = result.resolve("transformer")
assert transformer.get_name() == "torchao"
assert transformer.is_checkpoint_torchao_serialized is True
assert isinstance(transformer.torchao_config, quantization.Float8WeightOnlyConfig)
assert transformer.torchao_config.version == 2
assert transformer.torchao_config.weight_dtype is torch.float8_e4m3fn
assert transformer.torchao_config.set_inductor_config is False
def test_build_quant_config_torchao_runtime():
from vllm.model_executor.layers.quantization.torchao import TorchAOConfig
torchao_config = object()
result = build_quant_config("torchao", torchao_config=torchao_config)
assert isinstance(result, TorchAOConfig)
assert result.torchao_config is torchao_config
assert result.is_checkpoint_torchao_serialized is False