[core] add torch compile for diffusion (#684)

Signed-off-by: zjy0516 <riverclouds.zhu@qq.com>
This commit is contained in:
Jiangyun Zhu authored and GitHub committed 2026-01-09 04:05:44 +13:00
1 parent cddcc400d3
commit c784b3e07d
15 files changed
+134 -25

No files matched your search

+41
View File
@@ -0,0 +1,41 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
from typing import Any
import torch.nn as nn
from vllm.logger import init_logger
logger = init_logger(__name__)
def regionally_compile(model: nn.Module, *compile_args: Any, **compile_kwargs: Any) -> nn.Module:
"""
Apply regional compilation to a PyTorch model.
Args:
model: The PyTorch model instance to compile
*compile_args: Positional arguments forwarded to torch.compile
**compile_kwargs: Keyword arguments forwarded to torch.compile
Returns:
The same model instance (modified in-place)
"""
# Get the list of repeated blocks from the model
repeated_blocks = getattr(model, "_repeated_blocks", None)
if not repeated_blocks:
logger.warning("Regional compilation skipped because the model does not define `_repeated_blocks`.")
return model
# Check if we have modules with the specified class names
has_compiled_region = False
for submod in model.modules():
if submod.__class__.__name__ in repeated_blocks:
# Compile this submodule
submod.compile(*compile_args, **compile_kwargs)
has_compiled_region = True
if not has_compiled_region:
logger.warning(f"Regional compilation skipped because {repeated_blocks} classes are not found in the model.")
return model
+1 -1
View File
@@ -303,7 +303,7 @@ class OmniDiffusionConfig:
skip_time_steps: int = 15
# Compilation
enable_torch_compile: bool = False
enforce_eager: bool = False
# Enable sleep mode
enable_sleep_mode: bool = False
+43 -17
View File
@@ -8,10 +8,15 @@ from collections.abc import Callable, Iterable
from dataclasses import dataclass
from typing import Any
import PIL.Image
from vllm.logger import init_logger
from vllm_omni.diffusion.data import SHUTDOWN_MESSAGE, OmniDiffusionConfig
from vllm_omni.diffusion.registry import get_diffusion_post_process_func, get_diffusion_pre_process_func
from vllm_omni.diffusion.registry import (
DiffusionModelRegistry,
get_diffusion_post_process_func,
get_diffusion_pre_process_func,
)
from vllm_omni.diffusion.request import OmniDiffusionRequest
from vllm_omni.diffusion.scheduler import Scheduler, scheduler
from vllm_omni.outputs import OmniRequestOutput
@@ -20,6 +25,13 @@ from vllm_omni.utils.platform_utils import get_diffusion_worker_class
logger = init_logger(__name__)
def supports_image_input(model_class_name: str) -> bool:
model_cls = DiffusionModelRegistry._try_load_model_cls(model_class_name)
if model_cls is None:
return False
return bool(getattr(model_cls, "support_image_input", False))
@dataclass
class BackgroundResources:
"""
@@ -70,6 +82,12 @@ class DiffusionEngine:
self._processes: list[mp.Process] = []
self._closed = False
self._make_client()
try:
self._dummy_run()
except Exception as e:
logger.error(f"Dummy run failed: {e}")
self.close()
raise e
def step(self, requests: list[OmniDiffusionRequest]):
try:
@@ -272,6 +290,30 @@ class DiffusionEngine:
def add_req_and_wait_for_response(self, requests: list[OmniDiffusionRequest]):
return scheduler.add_req(requests)
def _dummy_run(self):
"""A dummy run to warm up the model."""
prompt = "dummy run"
num_inference_steps = 1
height = 1024
width = 1024
if supports_image_input(self.od_config.model_class_name):
# Provide a dummy image input if the model supports it
dummy_image = PIL.Image.new("RGB", (width, height), color=(0, 0, 0))
else:
dummy_image = None
req = OmniDiffusionRequest(
prompt=prompt,
height=height,
width=width,
pil_image=dummy_image,
num_inference_steps=num_inference_steps,
num_outputs_per_prompt=1,
)
logger.info("dummy run to warm up the model")
requests = self.pre_process_func([req]) if self.pre_process_func is not None else [req]
self.add_req_and_wait_for_response(requests)
def collective_rpc(
self,
method: str | Callable,
@@ -343,22 +385,6 @@ class DiffusionEngine:
logger.error(f"RPC call failed: {e}")
raise
def _dummy_run(self):
"""A dummy run to warm up the model."""
prompt = "dummy run"
num_inference_steps = 1
height = 1024
width = 1024
req = OmniDiffusionRequest(
prompt=prompt,
height=height,
width=width,
num_inference_steps=num_inference_steps,
num_outputs_per_prompt=1,
)
logger.info("dummy run to warm up the model")
self.add_req_and_wait_for_response([req])
def close(self) -> None:
self._finalizer()
+12
View File
@@ -0,0 +1,12 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
from typing import (
ClassVar,
Protocol,
runtime_checkable,
)
@runtime_checkable
class SupportImageInput(Protocol):
support_image_input: ClassVar[bool] = True
@@ -353,6 +353,11 @@ class LongCatImageTransformer2DModel(nn.Module):
The Transformer model introduced in Flux.
"""
_repeated_blocks = [
"LongCatImageTransformerBlock",
"LongCatImageSingleTransformerBlock",
]
def __init__(
self,
od_config: OmniDiffusionConfig,
@@ -28,6 +28,7 @@ from vllm.model_executor.models.utils import AutoWeightsLoader
from vllm_omni.diffusion.data import DiffusionOutput, OmniDiffusionConfig
from vllm_omni.diffusion.distributed.utils import get_local_device
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
from vllm_omni.diffusion.models.interface import SupportImageInput
from vllm_omni.diffusion.models.longcat_image.longcat_image_transformer import (
LongCatImageTransformer2DModel,
)
@@ -196,7 +197,7 @@ def split_quotation(prompt, quote_pairs=None):
return result
class LongCatImageEditPipeline(nn.Module):
class LongCatImageEditPipeline(nn.Module, SupportImageInput):
def __init__(
self,
*,
@@ -365,6 +365,8 @@ class OvisImageTransformer2DModel(nn.Module):
The dimensions to use for the rotary positional embeddings.
"""
_repeated_blocks = ["OvisImageTransformerBlock", "OvisImageSingleTransformerBlock"]
def __init__(
self,
od_config: OmniDiffusionConfig,
@@ -32,6 +32,7 @@ from vllm_omni.diffusion.distributed.parallel_state import (
)
from vllm_omni.diffusion.distributed.utils import get_local_device
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
from vllm_omni.diffusion.models.interface import SupportImageInput
from vllm_omni.diffusion.models.qwen_image.pipeline_qwen_image import calculate_shift
from vllm_omni.diffusion.models.qwen_image.qwen_image_transformer import (
QwenImageTransformer2DModel,
@@ -195,6 +196,7 @@ def retrieve_latents(
class QwenImageEditPipeline(
nn.Module,
SupportImageInput,
):
def __init__(
self,
@@ -30,6 +30,7 @@ from vllm_omni.diffusion.distributed.parallel_state import (
)
from vllm_omni.diffusion.distributed.utils import get_local_device
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
from vllm_omni.diffusion.models.interface import SupportImageInput
from vllm_omni.diffusion.models.qwen_image.pipeline_qwen_image import calculate_shift
from vllm_omni.diffusion.models.qwen_image.pipeline_qwen_image_edit import (
calculate_dimensions,
@@ -156,9 +157,7 @@ def get_qwen_image_edit_plus_post_process_func(
return post_process_func
class QwenImageEditPlusPipeline(
nn.Module,
):
class QwenImageEditPlusPipeline(nn.Module, SupportImageInput):
def __init__(
self,
*,
@@ -29,6 +29,7 @@ from vllm_omni.diffusion.distributed.parallel_state import (
)
from vllm_omni.diffusion.distributed.utils import get_local_device
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
from vllm_omni.diffusion.models.interface import SupportImageInput
from vllm_omni.diffusion.models.qwen_image.autoencoder_kl_qwenimage import (
AutoencoderKLQwenImage,
)
@@ -170,9 +171,7 @@ def retrieve_latents(
raise AttributeError("Could not access latents of provided encoder_output")
class QwenImageLayeredPipeline(
nn.Module,
):
class QwenImageLayeredPipeline(nn.Module, SupportImageInput):
def __init__(
self,
*,
@@ -677,6 +677,11 @@ class QwenImageTransformer2DModel(CachedTransformer):
The dimensions to use for the rotary positional embeddings.
"""
# the small and frequently-repeated block(s) of a model
# -- typically a transformer layer
# used for torch compile optimizations
_repeated_blocks = ["QwenImageTransformerBlock"]
def __init__(
self,
od_config: OmniDiffusionConfig,
@@ -321,6 +321,8 @@ class SD3Transformer2DModel(nn.Module):
The Transformer model introduced in [Stable Diffusion 3](https://huggingface.co/papers/2403.03206).
"""
_repeated_blocks = ["SD3TransformerBlock"]
def __init__(
self,
od_config: OmniDiffusionConfig,
@@ -515,6 +515,8 @@ class WanTransformer3DModel(nn.Module):
pos_embed_seq_len: Optional position embedding sequence length
"""
_repeated_blocks = ["WanTransformerBlock"]
def __init__(
self,
patch_size: tuple[int, int, int] = (1, 2, 2),
@@ -344,6 +344,8 @@ class RopeEmbedder:
class ZImageTransformer2DModel(nn.Module):
_repeated_blocks = ["ZImageTransformerBlock"]
def __init__(
self,
all_patch_size=(2,),
+11
View File
@@ -14,6 +14,7 @@ from vllm.logger import init_logger
from vllm.utils.mem_utils import DeviceMemoryProfiler, GiB_bytes
from vllm_omni.diffusion.cache.selector import get_cache_backend
from vllm_omni.diffusion.compile import regionally_compile
from vllm_omni.diffusion.data import (
DiffusionOutput,
OmniDiffusionConfig,
@@ -100,6 +101,16 @@ class GPUWorker:
)
logger.info(f"Worker {self.rank}: Model loaded successfully.")
if not self.od_config.enforce_eager:
try:
self.pipeline.transformer = regionally_compile(
self.pipeline.transformer,
dynamic=True,
)
logger.info(f"Worker {self.rank}: Model compiled with torch.compile.")
except Exception as e:
logger.warning(f"Worker {self.rank}: torch.compile failed with error: {e}. Using eager mode.")
# Setup cache backend based on type (both backends use enable()/reset() interface)
self.cache_backend = get_cache_backend(self.od_config.cache_backend, self.od_config.cache_config)