Signed-off-by: hanzheli <hanzheli@kuaishou.com> Signed-off-by: princepride <wangzhipeng628@gmail.com> Signed-off-by: 汪志鹏 <wangzhipeng628@gmail.com> Co-authored-by: princepride <wangzhipeng628@gmail.com>
215 lines
8.4 KiB
Python
215 lines
8.4 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
|
|
|
"""
|
|
TeaCache backend implementation.
|
|
|
|
This module provides the TeaCache backend that implements the CacheBackend
|
|
interface using the hooks-based TeaCache system.
|
|
"""
|
|
|
|
from typing import Any
|
|
|
|
from vllm.logger import init_logger
|
|
|
|
from vllm_omni.diffusion.cache.base import CacheBackend
|
|
from vllm_omni.diffusion.cache.teacache.config import TeaCacheConfig
|
|
from vllm_omni.diffusion.cache.teacache.hook import TeaCacheHook, apply_teacache_hook
|
|
from vllm_omni.diffusion.data import DiffusionCacheConfig
|
|
|
|
logger = init_logger(__name__)
|
|
|
|
|
|
def enable_hunyuan_image3_teacache(pipeline: Any, config: DiffusionCacheConfig) -> None:
|
|
"""
|
|
Enable TeaCache for HunyuanImage3 model.
|
|
|
|
HunyuanImage3 uses a GPT-based architecture with KV cache, which is incompatible
|
|
with the standard hook-based TeaCache approach. Instead, we store the TeaCacheConfig
|
|
on the pipeline so the denoising loop can implement caching directly.
|
|
"""
|
|
teacache_config = TeaCacheConfig(
|
|
transformer_type="HunyuanImage3Pipeline",
|
|
rel_l1_thresh=config.rel_l1_thresh,
|
|
coefficients=config.coefficients,
|
|
)
|
|
pipeline._tea_cache_config = teacache_config
|
|
|
|
logger.info(f"TeaCache enabled for HunyuanImage3 with rel_l1_thresh={teacache_config.rel_l1_thresh}")
|
|
|
|
|
|
def enable_bagel_teacache(pipeline: Any, config: DiffusionCacheConfig) -> None:
|
|
"""
|
|
Enable TeaCache for Bagel model.
|
|
"""
|
|
teacache_config = TeaCacheConfig(
|
|
transformer_type="Bagel",
|
|
rel_l1_thresh=config.rel_l1_thresh,
|
|
coefficients=config.coefficients,
|
|
)
|
|
transformer = pipeline.bagel
|
|
apply_teacache_hook(transformer, teacache_config)
|
|
pipeline.transformer = transformer
|
|
|
|
logger.info(
|
|
f"TeaCache applied with rel_l1_thresh={teacache_config.rel_l1_thresh}, "
|
|
f"transformer_class={teacache_config.transformer_type}"
|
|
)
|
|
|
|
|
|
def enable_sensenova_u1_teacache(pipeline: Any, config: DiffusionCacheConfig) -> None:
|
|
"""Enable TeaCache for SenseNova-U1 denoising forwards."""
|
|
teacache_config = TeaCacheConfig(
|
|
transformer_type="SenseNovaU1ForCausalLM",
|
|
rel_l1_thresh=config.rel_l1_thresh,
|
|
coefficients=config.coefficients,
|
|
)
|
|
transformer = pipeline.denoising_transformer
|
|
apply_teacache_hook(transformer, teacache_config)
|
|
|
|
logger.info(
|
|
f"TeaCache applied with rel_l1_thresh={teacache_config.rel_l1_thresh}, "
|
|
f"transformer_class={teacache_config.transformer_type}"
|
|
)
|
|
|
|
|
|
def enable_flux2_klein_teacache(pipeline: Any, config: DiffusionCacheConfig) -> None:
|
|
"""
|
|
Enable TeaCache for Flux2 Klein model.
|
|
"""
|
|
teacache_config = TeaCacheConfig(
|
|
transformer_type="Flux2Klein",
|
|
rel_l1_thresh=config.rel_l1_thresh,
|
|
coefficients=config.coefficients,
|
|
)
|
|
transformer = pipeline.transformer
|
|
|
|
apply_teacache_hook(transformer, teacache_config)
|
|
|
|
logger.info(
|
|
f"TeaCache applied with rel_l1_thresh={teacache_config.rel_l1_thresh}, "
|
|
f"transformer_class={teacache_config.transformer_type}"
|
|
)
|
|
|
|
|
|
CUSTOM_TEACACHE_ENABLERS = {
|
|
"BagelPipeline": enable_bagel_teacache,
|
|
"Flux2KleinPipeline": enable_flux2_klein_teacache,
|
|
"HunyuanImage3Pipeline": enable_hunyuan_image3_teacache,
|
|
"SenseNovaU1Pipeline": enable_sensenova_u1_teacache,
|
|
}
|
|
|
|
|
|
class TeaCacheBackend(CacheBackend):
|
|
"""
|
|
TeaCache implementation using hooks.
|
|
|
|
TeaCache (Timestep Embedding Aware Cache) is an adaptive caching technique
|
|
that speeds up diffusion inference by reusing transformer block computations
|
|
when consecutive timestep embeddings are similar.
|
|
|
|
The backend applies TeaCache hooks to the transformer which intercept the
|
|
forward pass and implement the caching logic transparently.
|
|
|
|
Example:
|
|
>>> from vllm_omni.diffusion.data import DiffusionCacheConfig
|
|
>>> backend = TeaCacheBackend(DiffusionCacheConfig(rel_l1_thresh=0.2))
|
|
>>> backend.enable(pipeline)
|
|
>>> # Generate with cache enabled
|
|
>>> backend.refresh(pipeline, num_inference_steps=50) # Refresh before each generation
|
|
>>> # Access config attributes: backend.config.rel_l1_thresh
|
|
"""
|
|
|
|
def enable(self, pipeline: Any) -> None:
|
|
"""
|
|
Enable TeaCache on transformer using hooks.
|
|
|
|
This creates a TeaCacheConfig from the backend's DiffusionCacheConfig
|
|
and applies the TeaCache hook to the transformer.
|
|
|
|
Args:
|
|
pipeline: Diffusion pipeline instance. Extracts transformer and transformer_type:
|
|
- transformer: pipeline.transformer
|
|
- transformer_type: pipeline.transformer.__class__.__name__
|
|
"""
|
|
# Helper to get pipeline class name
|
|
pipeline_type = pipeline.__class__.__name__
|
|
|
|
# Check for pipeline-level custom enablers
|
|
if pipeline_type in CUSTOM_TEACACHE_ENABLERS:
|
|
logger.info(f"Using custom TeaCache enabler for model: {pipeline_type}")
|
|
CUSTOM_TEACACHE_ENABLERS[pipeline_type](pipeline, self.config)
|
|
else:
|
|
transformer = pipeline.transformer
|
|
transformer_type = transformer.__class__.__name__
|
|
|
|
# Create TeaCacheConfig from DiffusionCacheConfig with transformer_type
|
|
# Access parameters via attribute access: config.rel_l1_thresh
|
|
# rel_l1_thresh already has a default value of 0.2 in DiffusionCacheConfig
|
|
try:
|
|
teacache_config = TeaCacheConfig(
|
|
transformer_type=transformer_type,
|
|
rel_l1_thresh=self.config.rel_l1_thresh,
|
|
coefficients=self.config.coefficients,
|
|
)
|
|
except Exception as e:
|
|
logger.error(f"Failed to create TeaCacheConfig: {e}")
|
|
raise ValueError(
|
|
f"Invalid TeaCache configuration: {e}. "
|
|
f"Expected keys: rel_l1_thresh, coefficients (optional). "
|
|
f"transformer_type is automatically extracted from pipeline.transformer.__class__.__name__."
|
|
)
|
|
|
|
# Apply hook to transformer
|
|
apply_teacache_hook(transformer, teacache_config)
|
|
|
|
logger.info(
|
|
f"TeaCache applied with rel_l1_thresh={teacache_config.rel_l1_thresh}, "
|
|
f"transformer_class={teacache_config.transformer_type}"
|
|
)
|
|
|
|
# Mark as enabled
|
|
self.enabled = True
|
|
|
|
def refresh(self, pipeline: Any, num_inference_steps: int, verbose: bool = True) -> None:
|
|
"""
|
|
Refresh TeaCache state for new generation.
|
|
|
|
Clears all cached residuals and resets counters/accumulators.
|
|
Should be called before each generation to ensure clean state.
|
|
|
|
Args:
|
|
pipeline: Diffusion pipeline instance. Extracts transformer via pipeline.transformer.
|
|
num_inference_steps: Number of inference steps for the current generation.
|
|
Currently not used by TeaCache but accepted for interface consistency.
|
|
verbose: Whether to log refresh operations (default: True)
|
|
"""
|
|
# HunyuanImage3: tea cache state is managed inside the denoising loop,
|
|
# so refresh is a no-op (state is re-initialized every __call__).
|
|
if (
|
|
hasattr(pipeline, "_tea_cache_config")
|
|
and isinstance(pipeline._tea_cache_config, TeaCacheConfig)
|
|
and pipeline.__class__.__name__ == "HunyuanImage3Pipeline"
|
|
):
|
|
if verbose:
|
|
logger.debug(f"TeaCache state refreshed for HunyuanImage3 (num_inference_steps={num_inference_steps})")
|
|
return
|
|
|
|
# Extract transformer from pipeline
|
|
transformer = pipeline.transformer
|
|
if not hasattr(transformer, "_hook_registry") and hasattr(pipeline, "denoising_transformer"):
|
|
transformer = pipeline.denoising_transformer
|
|
|
|
if hasattr(transformer, "_hook_registry"):
|
|
hook = transformer._hook_registry.get_hook(TeaCacheHook._HOOK_NAME)
|
|
if hook is not None:
|
|
transformer._hook_registry.reset_hook(TeaCacheHook._HOOK_NAME)
|
|
if verbose:
|
|
logger.debug(f"TeaCache state refreshed (num_inference_steps={num_inference_steps})")
|
|
else:
|
|
if verbose:
|
|
logger.warning("TeaCache hook not found, nothing to refresh")
|
|
else:
|
|
if verbose:
|
|
logger.warning("Transformer has no hook registry, TeaCache may not be applied")
|