Repository navigation
[Quantization] Add FLUX.2-dev Mistral TE online FP8 support #5136
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| from unittest.mock import Mock, patch | ||
|
|
||
| import pytest | ||
| import torch | ||
|
|
||
| from vllm_omni.diffusion.models.flux2.pipeline_flux2 import ( | ||
| Flux2Pipeline, | ||
| _resolve_component_quant_config, | ||
| ) | ||
|
|
||
| pytestmark = [pytest.mark.core_model, pytest.mark.cpu] | ||
|
|
||
|
|
||
| def test_resolve_component_quant_config_routes_components(): | ||
| text_encoder_config = object() | ||
| component_config = Mock() | ||
| component_config.resolve.side_effect = { | ||
| "text_encoder": text_encoder_config, | ||
| "transformer": None, | ||
| }.get | ||
|
|
||
| assert _resolve_component_quant_config(component_config, "text_encoder") is text_encoder_config | ||
| assert _resolve_component_quant_config(component_config, "transformer") is None | ||
|
|
||
|
|
||
| def test_resolve_component_quant_config_preserves_global_config(): | ||
| global_config = object() | ||
| assert _resolve_component_quant_config(global_config, "transformer") is global_config | ||
| assert _resolve_component_quant_config(None, "text_encoder") is None | ||
|
|
||
|
|
||
| def test_offload_transformer_before_text_encoder_weights(): | ||
| pipeline = object.__new__(Flux2Pipeline) | ||
| pipeline.transformer = Mock() | ||
| weights = [ | ||
| ("transformer.layer.weight", torch.empty(1)), | ||
| ("text_encoder.layer.weight", torch.empty(1)), | ||
| ("text_encoder.layer.bias", torch.empty(1)), | ||
| ] | ||
|
|
||
| iterator = iter(pipeline._offload_transformer_before_text_encoder(weights)) | ||
| assert next(iterator)[0] == "transformer.layer.weight" | ||
| pipeline.transformer.to.assert_not_called() | ||
|
|
||
| with patch("vllm_omni.diffusion.models.flux2.pipeline_flux2.current_omni_platform.empty_cache") as empty_cache: | ||
| assert next(iterator)[0] == "text_encoder.layer.weight" | ||
| assert next(iterator)[0] == "text_encoder.layer.bias" | ||
|
|
||
| pipeline.transformer.to.assert_called_once_with("cpu") | ||
| empty_cache.assert_called_once_with() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -82,6 +82,7 @@ class QualityTestConfig: | |
| gpu: str = "H100" # minimum GPU requirement | ||
| negative_prompt: str = "" | ||
| guidance_scale: float | None = None | ||
| enable_cpu_offload: bool = False | ||
|
|
||
| def baseline_ref(self) -> str: | ||
| return self.baseline_model or self.model or "" | ||
|
|
@@ -181,6 +182,18 @@ def validate(self) -> None: | |
| max_lpips=0.20, | ||
| num_inference_steps=10, | ||
| ), | ||
| QualityTestConfig( | ||
| id="fp8_flux2_dev_text_encoder", | ||
| model="black-forest-labs/FLUX.2-dev", | ||
| quantization={"text_encoder": "fp8", "transformer": None, "vae": None}, | ||
| task="t2i", | ||
| prompt="a cup of coffee on a wooden table, morning light", | ||
| max_lpips=0.15, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Was this exact 10-step case run? The PR only reports 50-step A/B results, so the 0.15 threshold isn't validated yet.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just did offline test with 10 steps, and put in PR description, can you help check?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks good, thanks! |
||
| num_inference_steps=10, | ||
| enable_cpu_offload=True, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why we use enable_cpu_offload here?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. enable_cpu_offload=True is here for VRAM, not for the FP8 quality comparison itself. FLUX.2-dev (Mistral TE + BF16 DiT + VAE) exceeds ~80 GiB on a single H100 without offload — we hit OOM when running this case with offload disabled. That matches our docs and the TE-FP8 validation recipe: https://github.com/vllm-project/vllm-omni/blob/main/docs/user_guide/examples/offline_inference/text_to_image.md — “FLUX.2-dev … >80 (CPU offload required)” Happy to add a one-line comment on the config if that would help future readers.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense, thanks! |
||
| height=1024, | ||
| width=1024, | ||
| ), | ||
| QualityTestConfig( | ||
| id="fp8_qwen_image", | ||
| model="Qwen/Qwen-Image", | ||
|
|
@@ -459,7 +472,10 @@ def test_quantization_quality(config: QualityTestConfig): | |
| generate_fn = _generate_video if config.task == "t2v" else _generate_image | ||
|
|
||
| # --- BF16 baseline --- | ||
| omni_bl = Omni(model=config.baseline_ref()) | ||
| bl_kwargs: dict = {"model": config.baseline_ref()} | ||
| if config.enable_cpu_offload: | ||
| bl_kwargs["enable_cpu_offload"] = True | ||
| omni_bl = Omni(**bl_kwargs) | ||
| baseline_out, bl_mem = generate_fn(omni_bl, config) | ||
| omni_bl.shutdown() | ||
| del omni_bl | ||
|
|
@@ -468,10 +484,13 @@ def test_quantization_quality(config: QualityTestConfig): | |
|
|
||
| # --- Quantized --- | ||
| quantization = config.quantization_ref() | ||
| qt_kwargs: dict = {"model": config.quantized_ref()} | ||
| if config.enable_cpu_offload: | ||
| qt_kwargs["enable_cpu_offload"] = True | ||
| if quantization is None: | ||
| omni_qt = Omni(model=config.quantized_ref()) | ||
| omni_qt = Omni(**qt_kwargs) | ||
| else: | ||
| omni_qt = Omni(model=config.quantized_ref(), quantization_config=quantization) | ||
| omni_qt = Omni(**qt_kwargs, quantization_config=quantization) | ||
| quant_out, qt_mem = generate_fn(omni_qt, config) | ||
| omni_qt.shutdown() | ||
| del omni_qt | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.