[Feat] add diffusion pipeline profiler and progress bar support to FluxKontextPipeline et.al (#2489)

Signed-off-by: Lancer <maruixiang6688@gmail.com>
This commit is contained in:
Lancer authored and GitHub committed 2026-04-05 15:16:11 +08:00
1 parent 0824edefd5
commit 832952b2be
4 files changed
+203 -163

No files matched your search

@@ -31,6 +31,8 @@ from vllm_omni.diffusion.models.flux import (
)
from vllm_omni.diffusion.models.flux.flux_pipeline_mixin import FluxPipelineMixin
from vllm_omni.diffusion.models.interface import SupportImageInput
from vllm_omni.diffusion.models.progress_bar import ProgressBarMixin
from vllm_omni.diffusion.profiler.diffusion_pipeline_profiler import DiffusionPipelineProfilerMixin
from vllm_omni.diffusion.request import OmniDiffusionRequest
from vllm_omni.diffusion.utils.tf_utils import get_transformer_config_kwargs
from vllm_omni.logger import init_logger
@@ -67,7 +69,9 @@ def get_flux_kontext_post_process_func(od_config: OmniDiffusionConfig) -> Callab
return post_process_func
class FluxKontextPipeline(nn.Module, FluxPipelineMixin, SupportImageInput):
class FluxKontextPipeline(
nn.Module, FluxPipelineMixin, SupportImageInput, ProgressBarMixin, DiffusionPipelineProfilerMixin
):
"""FLUX.1-Kontext pipeline for image editing with text guidance."""
support_image_input = True
@@ -148,6 +152,10 @@ class FluxKontextPipeline(nn.Module, FluxPipelineMixin, SupportImageInput):
self._callback_tensor_inputs = ["latents", "prompt_embeds"]
self.latent_channels = self.vae.config.latent_channels if hasattr(self.vae, "config") else 16
self.setup_diffusion_pipeline_profiler(
enable_diffusion_pipeline_profiler=self.od_config.enable_diffusion_pipeline_profiler
)
def _get_t5_prompt_embeds(
self,
prompt: str | list[str] = None,
@@ -635,58 +643,61 @@ class FluxKontextPipeline(nn.Module, FluxPipelineMixin, SupportImageInput):
# 5. Denoising loop
self.scheduler.set_begin_index(0)
for i, t in enumerate(timesteps):
if self.interrupt:
continue
with self.progress_bar(total=len(timesteps)) as pbar:
for i, t in enumerate(timesteps):
if self.interrupt:
continue
latent_model_input = latents
if image_latents is not None:
latent_model_input = torch.cat([latents, image_latents], dim=1)
timestep = t.expand(latents.shape[0]).to(latents.dtype)
latent_model_input = latents
if image_latents is not None:
latent_model_input = torch.cat([latents, image_latents], dim=1)
timestep = t.expand(latents.shape[0]).to(latents.dtype)
noise_pred = self.transformer(
hidden_states=latent_model_input,
timestep=timestep / 1000,
guidance=guidance,
pooled_projections=pooled_prompt_embeds,
encoder_hidden_states=prompt_embeds,
txt_ids=text_ids,
img_ids=latent_ids,
joint_attention_kwargs=self.joint_attention_kwargs,
return_dict=False,
)[0]
noise_pred = noise_pred[:, : latents.size(1)]
if do_true_cfg:
neg_noise_pred = self.transformer(
noise_pred = self.transformer(
hidden_states=latent_model_input,
timestep=timestep / 1000,
guidance=guidance,
pooled_projections=negative_pooled_prompt_embeds,
encoder_hidden_states=negative_prompt_embeds,
txt_ids=negative_text_ids,
pooled_projections=pooled_prompt_embeds,
encoder_hidden_states=prompt_embeds,
txt_ids=text_ids,
img_ids=latent_ids,
joint_attention_kwargs=self.joint_attention_kwargs,
return_dict=False,
)[0]
neg_noise_pred = neg_noise_pred[:, : latents.size(1)]
noise_pred = neg_noise_pred + true_cfg_scale * (noise_pred - neg_noise_pred)
noise_pred = noise_pred[:, : latents.size(1)]
latents_dtype = latents.dtype
latents = self.scheduler.step(noise_pred, t, latents, return_dict=False)[0]
if do_true_cfg:
neg_noise_pred = self.transformer(
hidden_states=latent_model_input,
timestep=timestep / 1000,
guidance=guidance,
pooled_projections=negative_pooled_prompt_embeds,
encoder_hidden_states=negative_prompt_embeds,
txt_ids=negative_text_ids,
img_ids=latent_ids,
joint_attention_kwargs=self.joint_attention_kwargs,
return_dict=False,
)[0]
neg_noise_pred = neg_noise_pred[:, : latents.size(1)]
noise_pred = neg_noise_pred + true_cfg_scale * (noise_pred - neg_noise_pred)
if latents.dtype != latents_dtype:
if torch.backends.mps.is_available():
latents = latents.to(latents_dtype)
latents_dtype = latents.dtype
latents = self.scheduler.step(noise_pred, t, latents, return_dict=False)[0]
if callback_on_step_end is not None:
callback_kwargs = {}
for k in callback_on_step_end_tensor_inputs:
callback_kwargs[k] = locals()[k]
callback_outputs = callback_on_step_end(self, i, t, callback_kwargs)
if latents.dtype != latents_dtype:
if torch.backends.mps.is_available():
latents = latents.to(latents_dtype)
latents = callback_outputs.pop("latents", latents)
prompt_embeds = callback_outputs.pop("prompt_embeds", prompt_embeds)
if callback_on_step_end is not None:
callback_kwargs = {}
for k in callback_on_step_end_tensor_inputs:
callback_kwargs[k] = locals()[k]
callback_outputs = callback_on_step_end(self, i, t, callback_kwargs)
latents = callback_outputs.pop("latents", latents)
prompt_embeds = callback_outputs.pop("prompt_embeds", prompt_embeds)
pbar.update()
if output_type == "latent":
image = latents
else:
@@ -29,6 +29,8 @@ 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.flux2 import Flux2Transformer2DModel
from vllm_omni.diffusion.models.interface import SupportImageInput
from vllm_omni.diffusion.models.progress_bar import ProgressBarMixin
from vllm_omni.diffusion.profiler.diffusion_pipeline_profiler import DiffusionPipelineProfilerMixin
from vllm_omni.diffusion.request import OmniDiffusionRequest
from vllm_omni.diffusion.utils.tf_utils import get_transformer_config_kwargs
from vllm_omni.model_executor.model_loader.weight_utils import download_weights_from_hf_specific
@@ -331,7 +333,7 @@ def retrieve_latents(encoder_output: torch.Tensor, generator: torch.Generator =
raise AttributeError("Could not access latents of provided encoder_output")
class Flux2Pipeline(nn.Module, SupportImageInput):
class Flux2Pipeline(nn.Module, SupportImageInput, ProgressBarMixin, DiffusionPipelineProfilerMixin):
"""Flux2 pipeline for text-to-image generation."""
_callback_tensor_inputs = ["latents", "prompt_embeds"]
@@ -389,6 +391,10 @@ class Flux2Pipeline(nn.Module, SupportImageInput):
self._guidance_scale = None
self._attention_kwargs = None
self._num_timesteps = None
self.setup_diffusion_pipeline_profiler(
enable_diffusion_pipeline_profiler=self.od_config.enable_diffusion_pipeline_profiler
)
self._current_timestep = None
self._interrupt = False
@@ -1027,48 +1033,51 @@ class Flux2Pipeline(nn.Module, SupportImageInput):
# We set the index here to remove DtoH sync, helpful especially during compilation.
# Check out more details here: https://github.com/huggingface/diffusers/pull/11696
self.scheduler.set_begin_index(0)
for i, t in enumerate(timesteps):
if self.interrupt:
continue
with self.progress_bar(total=len(timesteps)) as pbar:
for i, t in enumerate(timesteps):
if self.interrupt:
continue
self._current_timestep = t
timestep = t.expand(latents.shape[0]).to(latents.dtype)
self._current_timestep = t
timestep = t.expand(latents.shape[0]).to(latents.dtype)
latent_model_input = latents.to(self.transformer.dtype)
latent_image_ids = latent_ids
latent_model_input = latents.to(self.transformer.dtype)
latent_image_ids = latent_ids
if image_latents is not None:
latent_model_input = torch.cat([latents, image_latents], dim=1).to(self.transformer.dtype)
latent_image_ids = torch.cat([latent_ids, image_latent_ids], dim=1)
if image_latents is not None:
latent_model_input = torch.cat([latents, image_latents], dim=1).to(self.transformer.dtype)
latent_image_ids = torch.cat([latent_ids, image_latent_ids], dim=1)
noise_pred = self.transformer(
hidden_states=latent_model_input, # (B, image_seq_len, C)
timestep=timestep / 1000,
guidance=guidance_tensor,
encoder_hidden_states=prompt_embeds,
txt_ids=text_ids, # B, text_seq_len, 4
img_ids=latent_image_ids, # B, image_seq_len, 4
joint_attention_kwargs=self.attention_kwargs,
return_dict=False,
)[0]
noise_pred = self.transformer(
hidden_states=latent_model_input, # (B, image_seq_len, C)
timestep=timestep / 1000,
guidance=guidance_tensor,
encoder_hidden_states=prompt_embeds,
txt_ids=text_ids, # B, text_seq_len, 4
img_ids=latent_image_ids, # B, image_seq_len, 4
joint_attention_kwargs=self.attention_kwargs,
return_dict=False,
)[0]
noise_pred = noise_pred[:, : latents.size(1) :]
noise_pred = noise_pred[:, : latents.size(1) :]
# compute the previous noisy sample x_t -> x_t-1
latents_dtype = latents.dtype
latents = self.scheduler.step(noise_pred, t, latents, return_dict=False)[0]
# compute the previous noisy sample x_t -> x_t-1
latents_dtype = latents.dtype
latents = self.scheduler.step(noise_pred, t, latents, return_dict=False)[0]
if latents.dtype != latents_dtype and torch.backends.mps.is_available():
latents = latents.to(latents_dtype)
if latents.dtype != latents_dtype and torch.backends.mps.is_available():
latents = latents.to(latents_dtype)
if callback_on_step_end is not None:
callback_kwargs = {}
for k in callback_on_step_end_tensor_inputs:
callback_kwargs[k] = locals()[k]
callback_outputs = callback_on_step_end(self, i, t, callback_kwargs)
if callback_on_step_end is not None:
callback_kwargs = {}
for k in callback_on_step_end_tensor_inputs:
callback_kwargs[k] = locals()[k]
callback_outputs = callback_on_step_end(self, i, t, callback_kwargs)
latents = callback_outputs.pop("latents", latents)
prompt_embeds = callback_outputs.pop("prompt_embeds", prompt_embeds)
latents = callback_outputs.pop("latents", latents)
prompt_embeds = callback_outputs.pop("prompt_embeds", prompt_embeds)
pbar.update()
self._current_timestep = None
@@ -24,7 +24,9 @@ from vllm_omni.diffusion.distributed.cfg_parallel import CFGParallelMixin
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.hunyuan_video.hunyuan_video_15_transformer import HunyuanVideo15Transformer3DModel
from vllm_omni.diffusion.models.progress_bar import ProgressBarMixin
from vllm_omni.diffusion.models.t5_encoder import T5EncoderModel
from vllm_omni.diffusion.profiler.diffusion_pipeline_profiler import DiffusionPipelineProfilerMixin
from vllm_omni.diffusion.request import OmniDiffusionRequest
from vllm_omni.diffusion.utils.tf_utils import get_transformer_config_kwargs
from vllm_omni.platforms import current_omni_platform
@@ -81,7 +83,7 @@ def get_hunyuan_video_15_post_process_func(od_config: OmniDiffusionConfig):
return post_process_func
class HunyuanVideo15Pipeline(nn.Module, CFGParallelMixin):
class HunyuanVideo15Pipeline(nn.Module, CFGParallelMixin, ProgressBarMixin, DiffusionPipelineProfilerMixin):
def __init__(
self,
*,
@@ -173,6 +175,10 @@ class HunyuanVideo15Pipeline(nn.Module, CFGParallelMixin):
self._num_timesteps = None
self._current_timestep = None
self.setup_diffusion_pipeline_profiler(
enable_diffusion_pipeline_profiler=self.od_config.enable_diffusion_pipeline_profiler
)
@property
def guidance_scale(self):
return self._guidance_scale
@@ -445,60 +451,63 @@ class HunyuanVideo15Pipeline(nn.Module, CFGParallelMixin):
timesteps = self.scheduler.timesteps
self._num_timesteps = len(timesteps)
for i, t in enumerate(timesteps):
self._current_timestep = t
with self.progress_bar(total=len(timesteps)) as pbar:
for i, t in enumerate(timesteps):
self._current_timestep = t
latent_model_input = torch.cat([latents, cond_latents, mask], dim=1)
timestep = t.expand(latent_model_input.shape[0]).to(latent_model_input.dtype)
latent_model_input = torch.cat([latents, cond_latents, mask], dim=1)
timestep = t.expand(latent_model_input.shape[0]).to(latent_model_input.dtype)
timestep_r = None
if self.use_meanflow:
if i == len(timesteps) - 1:
timestep_r = torch.tensor([0.0], device=device)
else:
timestep_r = timesteps[i + 1]
timestep_r = timestep_r.expand(latents.shape[0]).to(latents.dtype)
timestep_r = None
if self.use_meanflow:
if i == len(timesteps) - 1:
timestep_r = torch.tensor([0.0], device=device)
else:
timestep_r = timesteps[i + 1]
timestep_r = timestep_r.expand(latents.shape[0]).to(latents.dtype)
positive_kwargs = {
"hidden_states": latent_model_input,
"timestep": timestep,
"timestep_r": timestep_r,
"encoder_hidden_states": prompt_embeds,
"encoder_attention_mask": prompt_embeds_mask,
"encoder_hidden_states_2": prompt_embeds_2,
"encoder_attention_mask_2": prompt_embeds_mask_2,
"image_embeds": image_embeds,
"return_dict": False,
}
negative_kwargs = None
if do_cfg and negative_prompt_embeds is not None:
negative_kwargs = {
positive_kwargs = {
"hidden_states": latent_model_input,
"timestep": timestep,
"timestep_r": timestep_r,
"encoder_hidden_states": negative_prompt_embeds,
"encoder_attention_mask": negative_prompt_embeds_mask,
"encoder_hidden_states_2": negative_prompt_embeds_2,
"encoder_attention_mask_2": negative_prompt_embeds_mask_2,
"encoder_hidden_states": prompt_embeds,
"encoder_attention_mask": prompt_embeds_mask,
"encoder_hidden_states_2": prompt_embeds_2,
"encoder_attention_mask_2": prompt_embeds_mask_2,
"image_embeds": image_embeds,
"return_dict": False,
}
noise_pred = self.predict_noise_maybe_with_cfg(
do_true_cfg=do_cfg and negative_kwargs is not None,
true_cfg_scale=guidance_scale,
positive_kwargs=positive_kwargs,
negative_kwargs=negative_kwargs,
cfg_normalize=req.sampling_params.cfg_normalize,
)
negative_kwargs = None
if do_cfg and negative_prompt_embeds is not None:
negative_kwargs = {
"hidden_states": latent_model_input,
"timestep": timestep,
"timestep_r": timestep_r,
"encoder_hidden_states": negative_prompt_embeds,
"encoder_attention_mask": negative_prompt_embeds_mask,
"encoder_hidden_states_2": negative_prompt_embeds_2,
"encoder_attention_mask_2": negative_prompt_embeds_mask_2,
"image_embeds": image_embeds,
"return_dict": False,
}
latents = self.scheduler_step_maybe_with_cfg(
noise_pred,
t,
latents,
do_true_cfg=do_cfg and negative_kwargs is not None,
)
noise_pred = self.predict_noise_maybe_with_cfg(
do_true_cfg=do_cfg and negative_kwargs is not None,
true_cfg_scale=guidance_scale,
positive_kwargs=positive_kwargs,
negative_kwargs=negative_kwargs,
cfg_normalize=req.sampling_params.cfg_normalize,
)
latents = self.scheduler_step_maybe_with_cfg(
noise_pred,
t,
latents,
do_true_cfg=do_cfg and negative_kwargs is not None,
)
pbar.update()
self._current_timestep = None
@@ -38,7 +38,9 @@ from vllm_omni.diffusion.models.hunyuan_video.pipeline_hunyuan_video_1_5 import
retrieve_latents,
)
from vllm_omni.diffusion.models.interface import SupportImageInput
from vllm_omni.diffusion.models.progress_bar import ProgressBarMixin
from vllm_omni.diffusion.models.t5_encoder import T5EncoderModel
from vllm_omni.diffusion.profiler.diffusion_pipeline_profiler import DiffusionPipelineProfilerMixin
from vllm_omni.diffusion.request import OmniDiffusionRequest
from vllm_omni.diffusion.utils.tf_utils import get_transformer_config_kwargs
from vllm_omni.platforms import current_omni_platform
@@ -98,7 +100,9 @@ def get_hunyuan_video_15_i2v_pre_process_func(od_config: OmniDiffusionConfig):
return pre_process_func
class HunyuanVideo15I2VPipeline(nn.Module, CFGParallelMixin, SupportImageInput):
class HunyuanVideo15I2VPipeline(
nn.Module, CFGParallelMixin, SupportImageInput, ProgressBarMixin, DiffusionPipelineProfilerMixin
):
support_image_input = True
color_format = "RGB"
@@ -199,6 +203,10 @@ class HunyuanVideo15I2VPipeline(nn.Module, CFGParallelMixin, SupportImageInput):
self._num_timesteps = None
self._current_timestep = None
self.setup_diffusion_pipeline_profiler(
enable_diffusion_pipeline_profiler=self.od_config.enable_diffusion_pipeline_profiler
)
@property
def guidance_scale(self):
return self._guidance_scale
@@ -520,61 +528,64 @@ class HunyuanVideo15I2VPipeline(nn.Module, CFGParallelMixin, SupportImageInput):
timesteps = self.scheduler.timesteps
self._num_timesteps = len(timesteps)
for i, t in enumerate(timesteps):
self._current_timestep = t
with self.progress_bar(total=len(timesteps)) as pbar:
for i, t in enumerate(timesteps):
self._current_timestep = t
latent_model_input = torch.cat([latents, cond_latents, mask], dim=1)
timestep = t.expand(latent_model_input.shape[0]).to(latent_model_input.dtype)
latent_model_input = torch.cat([latents, cond_latents, mask], dim=1)
timestep = t.expand(latent_model_input.shape[0]).to(latent_model_input.dtype)
timestep_r = None
if self.use_meanflow:
if i == len(timesteps) - 1:
timestep_r = torch.tensor([0.0], device=device)
else:
timestep_r = timesteps[i + 1]
timestep_r = timestep_r.expand(latents.shape[0]).to(latents.dtype)
timestep_r = None
if self.use_meanflow:
if i == len(timesteps) - 1:
timestep_r = torch.tensor([0.0], device=device)
else:
timestep_r = timesteps[i + 1]
timestep_r = timestep_r.expand(latents.shape[0]).to(latents.dtype)
positive_kwargs = {
"hidden_states": latent_model_input,
"timestep": timestep,
"timestep_r": timestep_r,
"encoder_hidden_states": prompt_embeds,
"encoder_attention_mask": prompt_embeds_mask,
"encoder_hidden_states_2": prompt_embeds_2,
"encoder_attention_mask_2": prompt_embeds_mask_2,
"image_embeds": image_embeds,
"return_dict": False,
}
negative_kwargs = None
if do_cfg and negative_prompt_embeds is not None:
# For I2V CFG, negative still uses image embeds (only text is unconditional)
negative_kwargs = {
positive_kwargs = {
"hidden_states": latent_model_input,
"timestep": timestep,
"timestep_r": timestep_r,
"encoder_hidden_states": negative_prompt_embeds,
"encoder_attention_mask": negative_prompt_embeds_mask,
"encoder_hidden_states_2": negative_prompt_embeds_2,
"encoder_attention_mask_2": negative_prompt_embeds_mask_2,
"encoder_hidden_states": prompt_embeds,
"encoder_attention_mask": prompt_embeds_mask,
"encoder_hidden_states_2": prompt_embeds_2,
"encoder_attention_mask_2": prompt_embeds_mask_2,
"image_embeds": image_embeds,
"return_dict": False,
}
noise_pred = self.predict_noise_maybe_with_cfg(
do_true_cfg=do_cfg and negative_kwargs is not None,
true_cfg_scale=guidance_scale,
positive_kwargs=positive_kwargs,
negative_kwargs=negative_kwargs,
cfg_normalize=req.sampling_params.cfg_normalize,
)
negative_kwargs = None
if do_cfg and negative_prompt_embeds is not None:
# For I2V CFG, negative still uses image embeds (only text is unconditional)
negative_kwargs = {
"hidden_states": latent_model_input,
"timestep": timestep,
"timestep_r": timestep_r,
"encoder_hidden_states": negative_prompt_embeds,
"encoder_attention_mask": negative_prompt_embeds_mask,
"encoder_hidden_states_2": negative_prompt_embeds_2,
"encoder_attention_mask_2": negative_prompt_embeds_mask_2,
"image_embeds": image_embeds,
"return_dict": False,
}
latents = self.scheduler_step_maybe_with_cfg(
noise_pred,
t,
latents,
do_true_cfg=do_cfg and negative_kwargs is not None,
)
noise_pred = self.predict_noise_maybe_with_cfg(
do_true_cfg=do_cfg and negative_kwargs is not None,
true_cfg_scale=guidance_scale,
positive_kwargs=positive_kwargs,
negative_kwargs=negative_kwargs,
cfg_normalize=req.sampling_params.cfg_normalize,
)
latents = self.scheduler_step_maybe_with_cfg(
noise_pred,
t,
latents,
do_true_cfg=do_cfg and negative_kwargs is not None,
)
pbar.update()
self._current_timestep = None