Skip to content
Open
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
26a4e8d
add time cost log for different stages
SamitHuang Mar 6, 2026
b3b70a8
reduce hop3 overhead
SamitHuang Mar 6, 2026
104d71c
perf: reduce IPC overhead for single-stage diffusion serving
SamitHuang Mar 6, 2026
bf2ddb0
perf: reduce IPC overhead for single-stage diffusion serving (~6.5s, …
SamitHuang Mar 6, 2026
735b2ca
Merge branch 'main' into main
SamitHuang Mar 6, 2026
dd4468c
fix conflicts
SamitHuang Mar 6, 2026
ff62a1e
rm redundancy
SamitHuang Mar 9, 2026
870963e
Merge branch 'main' into main
SamitHuang Mar 9, 2026
5414a42
rm logs
SamitHuang Mar 9, 2026
e3dec54
fix inline
SamitHuang Mar 9, 2026
2cd9f9f
fix ci
SamitHuang Mar 9, 2026
172040a
fix ci
SamitHuang Mar 9, 2026
0a86fc5
fix log
SamitHuang Mar 9, 2026
9b9c597
fix
SamitHuang Mar 9, 2026
bda0f2d
fix log
SamitHuang Mar 9, 2026
3452ad3
Merge branch 'main' of https://github.com/samithuang/vllm-omni
SamitHuang Mar 9, 2026
9ab7c55
Merge remote-tracking branch 'upstream/main'
SamitHuang Mar 12, 2026
c32a78a
Merge remote-tracking branch 'upstream/main'
SamitHuang Mar 12, 2026
5fcf302
[Enhancement] Upgrade cache-dit from 1.2.0 to 1.3.0
SamitHuang Mar 12, 2026
a05183c
[Enhancement] Add cache-dit force_refresh support for Helios and GLM-…
SamitHuang Mar 12, 2026
2ba9814
[Enhancement] Add cache-dit CLI support to GLM-Image end2end.py
SamitHuang Mar 12, 2026
c36e4b4
[Enhancement] Remove cache-dit support for Helios, keep GLM-Image only
SamitHuang Mar 12, 2026
c9e7f43
Merge branch 'main' into feat/cache-dit-helios-glm-image
SamitHuang Mar 12, 2026
833ce12
Merge branch 'main' into feat/cache-dit-helios-glm-image
wtomin Mar 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion requirements/common.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ diffusers>=0.36.0
accelerate==1.12.0
gradio==5.50
soundfile>=0.13.1
cache-dit==1.2.0
cache-dit==1.3.0
tqdm>=4.66.0
torchsde>=0.2.6
openai-whisper>=20250625
Expand Down
124 changes: 124 additions & 0 deletions vllm_omni/diffusion/cache/cache_dit_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ def _build_db_cache_config(cache_config: Any) -> DBCacheConfig:
max_cached_steps=cache_config.max_cached_steps,
max_continuous_cached_steps=cache_config.max_continuous_cached_steps,
residual_diff_threshold=cache_config.residual_diff_threshold,
force_refresh_step_hint=cache_config.force_refresh_step_hint,
force_refresh_step_policy=cache_config.force_refresh_step_policy,
)


Expand Down Expand Up @@ -984,6 +986,125 @@ def refresh_cache_context(pipeline: Any, num_inference_steps: int, verbose: bool
return refresh_cache_context


def enable_cache_for_helios(pipeline: Any, cache_config: Any) -> Callable[[int], None]:
"""Enable cache-dit for Helios pipeline (multi-chunk denoise loop).

Helios splits num_frames into multiple chunks and runs multiple passes of the
transformer denoise loop. The cache context must be refreshed at the end of each
loop to prevent stale cache from the previous chunk leaking into the next one.
This is achieved by setting force_refresh_step_hint = num_inference_steps with
force_refresh_step_policy = "repeat".
"""
db_cache_config = _build_db_cache_config(cache_config)

calibrator_config = None
if cache_config.enable_taylorseer:
calibrator_config = TaylorSeerCalibratorConfig(taylorseer_order=cache_config.taylorseer_order)
logger.info(f"TaylorSeer enabled with order={cache_config.taylorseer_order}")

logger.info(
f"Enabling cache-dit on Helios transformer: "
f"Fn={db_cache_config.Fn_compute_blocks}, "
f"Bn={db_cache_config.Bn_compute_blocks}, "
f"W={db_cache_config.max_warmup_steps}, "
f"force_refresh_step_policy={db_cache_config.force_refresh_step_policy}, "
)

cache_dit.enable_cache(
pipeline.transformer,
cache_config=db_cache_config,
calibrator_config=calibrator_config,
)

def refresh_cache_context(pipeline: Any, num_inference_steps: int, verbose: bool = True) -> None:
hint = cache_config.force_refresh_step_hint
if hint is None:
hint = num_inference_steps
policy = cache_config.force_refresh_step_policy
if policy == "once":
policy = "repeat"
if cache_config.scm_steps_mask_policy is None:
cache_dit.refresh_context(
pipeline.transformer,
cache_config=DBCacheConfig().reset(
num_inference_steps=num_inference_steps,
force_refresh_step_hint=hint,
force_refresh_step_policy=policy,
),
verbose=verbose,
)
else:
cache_dit.refresh_context(
pipeline.transformer,
cache_config=DBCacheConfig().reset(
num_inference_steps=num_inference_steps,
force_refresh_step_hint=hint,
force_refresh_step_policy=policy,
steps_computation_mask=cache_dit.steps_mask(
mask_policy=cache_config.scm_steps_mask_policy,
total_steps=num_inference_steps,
),
steps_computation_policy=cache_config.scm_steps_policy,
),
verbose=verbose,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

There's a critical issue in refresh_cache_context. Using DBCacheConfig().reset(...) creates a new configuration from defaults, which causes all the original cache settings (like Fn_compute_blocks, max_warmup_steps, etc.) from db_cache_config to be lost. This will lead to incorrect and inefficient caching behavior.

The fix is to use db_cache_config.reset(...) to ensure the refreshed configuration is based on the original settings. I've also refactored the logic slightly to remove duplication within the function.

        hint = cache_config.force_refresh_step_hint
        if hint is None:
            hint = num_inference_steps
        policy = cache_config.force_refresh_step_policy
        if policy == "once":
            policy = "repeat"

        reset_kwargs = {
            "num_inference_steps": num_inference_steps,
            "force_refresh_step_hint": hint,
            "force_refresh_step_policy": policy,
        }

        if cache_config.scm_steps_mask_policy is not None:
            reset_kwargs["steps_computation_mask"] = cache_dit.steps_mask(
                mask_policy=cache_config.scm_steps_mask_policy,
                total_steps=num_inference_steps,
            )
            reset_kwargs["steps_computation_policy"] = cache_config.scm_steps_policy

        # Use db_cache_config.reset to preserve the original cache settings
        # when creating the refreshed configuration.
        refreshed_config = db_cache_config.reset(**reset_kwargs)

        cache_dit.refresh_context(
            pipeline.transformer,
            cache_config=refreshed_config,
            verbose=verbose,
        )

return refresh_cache_context


def enable_cache_for_glm_image(pipeline: Any, cache_config: Any) -> Callable[[int], None]:
"""Enable cache-dit for GLM-Image pipeline.

GLM-Image processes prompt and image by calling the transformer before the
denoising loop. When an input image is provided (editing mode), the cache must
be force-refreshed after the preprocessing step so stale hidden states are
discarded. Set force_refresh_step_hint = 1 for editing, None for text-to-image.
"""
db_cache_config = _build_db_cache_config(cache_config)

calibrator_config = None
if cache_config.enable_taylorseer:
calibrator_config = TaylorSeerCalibratorConfig(taylorseer_order=cache_config.taylorseer_order)
logger.info(f"TaylorSeer enabled with order={cache_config.taylorseer_order}")

logger.info(
f"Enabling cache-dit on GLM-Image transformer: "
f"Fn={db_cache_config.Fn_compute_blocks}, "
f"Bn={db_cache_config.Bn_compute_blocks}, "
f"W={db_cache_config.max_warmup_steps}, "
f"force_refresh_step_hint={db_cache_config.force_refresh_step_hint}, "
)

cache_dit.enable_cache(
pipeline.transformer,
cache_config=db_cache_config,
calibrator_config=calibrator_config,
)

def refresh_cache_context(pipeline: Any, num_inference_steps: int, verbose: bool = True) -> None:
if cache_config.scm_steps_mask_policy is None:
cache_dit.refresh_context(
pipeline.transformer,
num_inference_steps=num_inference_steps,
verbose=verbose,
)
else:
cache_dit.refresh_context(
pipeline.transformer,
cache_config=DBCacheConfig().reset(
num_inference_steps=num_inference_steps,
steps_computation_mask=cache_dit.steps_mask(
mask_policy=cache_config.scm_steps_mask_policy,
total_steps=num_inference_steps,
),
steps_computation_policy=cache_config.scm_steps_policy,
),
verbose=verbose,
)
Comment on lines +1184 to +1195

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Similar to the issue in the Helios enabler, this else block has a critical bug. By using DBCacheConfig().reset(...), you are creating a new cache configuration from defaults whenever SCM is enabled. This discards all the original settings from db_cache_config, including Fn_compute_blocks, max_warmup_steps, and the force_refresh_step_hint that is crucial for GLM-Image.

The fix is to base the refreshed configuration on the existing db_cache_config by using db_cache_config.reset(...).

        else:
            # Use db_cache_config.reset to preserve original settings
            refreshed_config = db_cache_config.reset(
                num_inference_steps=num_inference_steps,
                steps_computation_mask=cache_dit.steps_mask(
                    mask_policy=cache_config.scm_steps_mask_policy,
                    total_steps=num_inference_steps,
                ),
                steps_computation_policy=cache_config.scm_steps_policy,
            )
            cache_dit.refresh_context(
                pipeline.transformer,
                cache_config=refreshed_config,
                verbose=verbose,
            )


return refresh_cache_context

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There is significant code duplication between enable_cache_for_helios and enable_cache_for_glm_image. The logic for building db_cache_config, setting up calibrator_config, logging, and calling cache_dit.enable_cache is nearly identical.

To improve maintainability and reduce redundancy, consider extracting this common setup logic into a shared helper function. This would make the code easier to manage and prevent potential inconsistencies in the future.


# Register custom cache-dit enablers after function definitions
CUSTOM_DIT_ENABLERS.update(
{
Expand All @@ -998,6 +1119,9 @@ def refresh_cache_context(pipeline: Any, num_inference_steps: int, verbose: bool
"LTX2Pipeline": enable_cache_for_ltx2,
"LTX2ImageToVideoPipeline": enable_cache_for_ltx2,
"BagelPipeline": enable_cache_for_bagel,
"HeliosPipeline": enable_cache_for_helios,
"HeliosPyramidPipeline": enable_cache_for_helios,
"GlmImagePipeline": enable_cache_for_glm_image,
}
)

Expand Down
6 changes: 6 additions & 0 deletions vllm_omni/diffusion/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,12 @@ class DiffusionCacheConfig:
# Used by cache-dit for scm mask generation. If this value changes during inference,
# we will re-generate the scm mask and refresh the cache context.
num_inference_steps: int | None = None
# Force refresh the cache at a specific step index hint, useful for models like
# Helios (multi-chunk denoise loop) and GLM-Image (image preprocessing step).
force_refresh_step_hint: int | None = None
# Policy for force refresh: "once" refreshes only at the hint step,
# "repeat" refreshes every force_refresh_step_hint steps.
force_refresh_step_policy: str = "once"

# Additional parameters that may be passed but not explicitly defined
_extra_params: dict[str, Any] = field(default_factory=dict, repr=False)
Expand Down
Loading