[Cache Refactor 1/N] Simplify CacheDiT Integration (#2527)
Signed-off-by: Alex Brooks <albrooks@redhat.com>
This commit is contained in:
1 parent
951ae28eb0
commit
6ff246bf3c
21 files changed
+508
-1332
No files matched your search
+79
-36
@@ -13,10 +13,12 @@ This module tests the cache backend implementations:
|
||||
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
import cache_dit
|
||||
import pytest
|
||||
from cache_dit import ForwardPattern
|
||||
|
||||
from vllm_omni.diffusion.cache.cache_dit_backend import (
|
||||
CUSTOM_DIT_ENABLERS,
|
||||
CacheDiTAdapterConfig,
|
||||
CacheDiTBackend,
|
||||
)
|
||||
from vllm_omni.diffusion.cache.magcache.backend import MagCacheBackend
|
||||
@@ -45,13 +47,20 @@ class TestCacheDiTBackend:
|
||||
assert backend.config.Fn_compute_blocks == 4
|
||||
assert backend.enabled is False
|
||||
|
||||
@patch("vllm_omni.diffusion.cache.cache_dit_backend.BlockAdapter")
|
||||
@patch("vllm_omni.diffusion.cache.cache_dit_backend.cache_dit")
|
||||
def test_enable_single_transformer(self, mock_cache_dit):
|
||||
def test_enable_single_transformer(self, mock_cache_dit, mock_block_adapter):
|
||||
"""Test enabling cache-dit on single-transformer pipeline."""
|
||||
# Mock pipeline
|
||||
mock_pipeline = Mock()
|
||||
mock_pipeline.__class__.__name__ = "DiTPipeline"
|
||||
mock_transformer = Mock()
|
||||
mock_transformer._cache_dit_adapter_config = CacheDiTAdapterConfig(
|
||||
block_forward_patterns={
|
||||
"layers": ForwardPattern.Pattern_0,
|
||||
},
|
||||
)
|
||||
|
||||
mock_pipeline.transformer = mock_transformer
|
||||
|
||||
# Mock cache_dit functions
|
||||
@@ -66,14 +75,20 @@ class TestCacheDiTBackend:
|
||||
assert backend._refresh_func is not None
|
||||
mock_cache_dit.enable_cache.assert_called_once()
|
||||
|
||||
@patch("vllm_omni.diffusion.cache.cache_dit_backend.BlockAdapter")
|
||||
@patch("vllm_omni.diffusion.cache.cache_dit_backend.cache_dit")
|
||||
def test_refresh(self, mock_cache_dit):
|
||||
def test_refresh(self, mock_cache_dit, mock_block_adapter):
|
||||
"""Test refreshing cache context with SCM mask policy updates when num_inference_steps changes."""
|
||||
# Mock pipeline
|
||||
mock_pipeline = Mock()
|
||||
mock_pipeline.__class__.__name__ = "DiTPipeline"
|
||||
mock_transformer = Mock()
|
||||
mock_pipeline.transformer = mock_transformer
|
||||
mock_transformer._cache_dit_adapter_config = CacheDiTAdapterConfig(
|
||||
block_forward_patterns={
|
||||
"layers": ForwardPattern.Pattern_0,
|
||||
},
|
||||
)
|
||||
|
||||
# Mock cache_dit functions
|
||||
mock_cache_dit.enable_cache = Mock()
|
||||
@@ -124,23 +139,24 @@ class TestCacheDiTBackend:
|
||||
assert "cache_config" in call_args[1]
|
||||
assert backend._last_num_inference_steps == 100
|
||||
|
||||
def test_hunyuan_custom_enabler_registered(self):
|
||||
"""Test HunyuanImage3 custom cache-dit enabler is registered."""
|
||||
assert "HunyuanImage3Pipeline" in CUSTOM_DIT_ENABLERS
|
||||
|
||||
def test_dreamid_custom_enabler_registered(self):
|
||||
"""Test DreamIDOmni custom cache-dit enabler is registered."""
|
||||
assert "DreamIDOmniPipeline" in CUSTOM_DIT_ENABLERS
|
||||
|
||||
@patch("vllm_omni.diffusion.cache.cache_dit_backend.BlockAdapter")
|
||||
@patch("vllm_omni.diffusion.cache.cache_dit_backend.cache_dit")
|
||||
def test_enable_hunyuan_pipeline_uses_model_transformer(self, mock_cache_dit, mock_block_adapter):
|
||||
"""Test HunyuanImage3 custom enabler uses pipeline.model for cache enable/refresh."""
|
||||
"""Test HunyuanImage3 uses pipeline.transformer for cache enable/refresh.
|
||||
|
||||
NOTE: HunyuanImage3 no longer has a custom enabler, so this tests against the generic path.
|
||||
"""
|
||||
mock_pipeline = Mock()
|
||||
mock_pipeline.__class__.__name__ = "HunyuanImage3Pipeline"
|
||||
mock_pipeline.model = Mock()
|
||||
mock_pipeline.model.layers = Mock()
|
||||
|
||||
mock_pipeline.model._cache_dit_adapter_config = CacheDiTAdapterConfig(
|
||||
block_forward_patterns={
|
||||
"layers": ForwardPattern.Pattern_4,
|
||||
},
|
||||
)
|
||||
# NOTE: pipe.transformer is pipe.model in HunyuanImage3Pipelines
|
||||
mock_pipeline.transformer = mock_pipeline.model
|
||||
mock_cache_dit.enable_cache = Mock()
|
||||
mock_cache_dit.refresh_context = Mock()
|
||||
|
||||
@@ -152,9 +168,9 @@ class TestCacheDiTBackend:
|
||||
mock_block_adapter.assert_called_once()
|
||||
adapter_kwargs = mock_block_adapter.call_args.kwargs
|
||||
assert adapter_kwargs["transformer"] is mock_pipeline.model
|
||||
assert adapter_kwargs["blocks"] is mock_pipeline.model.layers
|
||||
assert adapter_kwargs["forward_pattern"] == adapter_kwargs["forward_pattern"].__class__.Pattern_4
|
||||
assert len(adapter_kwargs["params_modifiers"]) == 1
|
||||
assert len(adapter_kwargs["blocks"]) == 1
|
||||
assert adapter_kwargs["blocks"][0] == mock_pipeline.model.layers
|
||||
assert adapter_kwargs["forward_pattern"][0] == ForwardPattern.Pattern_4
|
||||
mock_cache_dit.enable_cache.assert_called_once()
|
||||
|
||||
backend.refresh(mock_pipeline, num_inference_steps=12)
|
||||
@@ -163,24 +179,23 @@ class TestCacheDiTBackend:
|
||||
assert call_args[0][0] is mock_pipeline.model
|
||||
assert call_args[1]["num_inference_steps"] == 12
|
||||
|
||||
def test_enable_hunyuan_pipeline_requires_model_layers(self):
|
||||
"""Test HunyuanImage3 enabler fails with a formatted pipeline class name."""
|
||||
mock_pipeline = Mock()
|
||||
mock_pipeline.__class__.__name__ = "HunyuanImage3Pipeline"
|
||||
mock_pipeline.model = Mock(spec=[])
|
||||
|
||||
backend = CacheDiTBackend({"Fn_compute_blocks": 2})
|
||||
|
||||
with pytest.raises(ValueError, match="HunyuanImage3Pipeline"):
|
||||
backend.enable(mock_pipeline)
|
||||
|
||||
@patch("vllm_omni.diffusion.cache.cache_dit_backend.BlockAdapter")
|
||||
@patch("vllm_omni.diffusion.cache.cache_dit_backend.cache_dit")
|
||||
def test_enable_dreamid_pipeline_uses_fused_blocks(self, mock_cache_dit, mock_block_adapter):
|
||||
"""Test DreamID uses pipeline.transformer for cache enable/refresh.
|
||||
|
||||
NOTE: DreamID no longer has a custom enabler, so this tests against the generic path.
|
||||
"""
|
||||
mock_pipeline = Mock()
|
||||
mock_pipeline.__class__.__name__ = "DreamIDOmniPipeline"
|
||||
mock_pipeline.transformer = Mock()
|
||||
mock_pipeline.transformer.fused_blocks = Mock()
|
||||
mock_pipeline.transformer._cache_dit_adapter_config = CacheDiTAdapterConfig(
|
||||
block_forward_patterns={
|
||||
"fused_blocks": ForwardPattern.Pattern_0,
|
||||
},
|
||||
has_separate_cfg=True,
|
||||
)
|
||||
|
||||
mock_cache_dit.enable_cache = Mock()
|
||||
mock_cache_dit.refresh_context = Mock()
|
||||
@@ -193,10 +208,10 @@ class TestCacheDiTBackend:
|
||||
mock_block_adapter.assert_called_once()
|
||||
adapter_kwargs = mock_block_adapter.call_args.kwargs
|
||||
assert adapter_kwargs["transformer"] is mock_pipeline.transformer
|
||||
assert adapter_kwargs["blocks"] is mock_pipeline.transformer.fused_blocks
|
||||
assert adapter_kwargs["forward_pattern"] == adapter_kwargs["forward_pattern"].__class__.Pattern_0
|
||||
assert len(adapter_kwargs["blocks"]) == 1
|
||||
assert adapter_kwargs["blocks"][0] == mock_pipeline.transformer.fused_blocks
|
||||
assert adapter_kwargs["forward_pattern"][0] == ForwardPattern.Pattern_0
|
||||
assert adapter_kwargs["has_separate_cfg"] is True
|
||||
assert len(adapter_kwargs["params_modifiers"]) == 1
|
||||
mock_cache_dit.enable_cache.assert_called_once()
|
||||
|
||||
backend.refresh(mock_pipeline, num_inference_steps=12)
|
||||
@@ -205,15 +220,43 @@ class TestCacheDiTBackend:
|
||||
assert call_args[0][0] is mock_pipeline.transformer
|
||||
assert call_args[1]["num_inference_steps"] == 12
|
||||
|
||||
def test_enable_dreamid_pipeline_requires_fused_blocks(self):
|
||||
@pytest.mark.parametrize("num_inference_steps", [1, 7])
|
||||
@patch("vllm_omni.diffusion.cache.cache_dit_backend.BlockAdapter")
|
||||
@patch("vllm_omni.diffusion.cache.cache_dit_backend.cache_dit")
|
||||
def test_refresh_scm_bypassed_for_unsupported_step_counts(
|
||||
self, mock_cache_dit, mock_block_adapter, num_inference_steps
|
||||
):
|
||||
"""Ensure SCM is bypassed when num_inference_steps < 8 and not in (4, 6),
|
||||
because cache_dit.steps_mask() raises for unsupported step count.
|
||||
For these cases, we fall back to the non-SCM path to avoid crashing.
|
||||
"""
|
||||
mock_pipeline = Mock()
|
||||
mock_pipeline.__class__.__name__ = "DreamIDOmniPipeline"
|
||||
mock_pipeline.transformer = Mock(spec=[])
|
||||
mock_pipeline.__class__.__name__ = "DiTPipeline"
|
||||
mock_transformer = Mock()
|
||||
mock_pipeline.transformer = mock_transformer
|
||||
mock_transformer._cache_dit_adapter_config = CacheDiTAdapterConfig(
|
||||
block_forward_patterns={
|
||||
"layers": ForwardPattern.Pattern_0,
|
||||
},
|
||||
)
|
||||
|
||||
backend = CacheDiTBackend({"Fn_compute_blocks": 2})
|
||||
mock_cache_dit.enable_cache = Mock()
|
||||
mock_cache_dit.refresh_context = Mock()
|
||||
mock_cache_dit.steps_mask = cache_dit.steps_mask
|
||||
|
||||
with pytest.raises(ValueError, match="DreamIDOmniPipeline"):
|
||||
backend.enable(mock_pipeline)
|
||||
# Create a cache config with an scm policy & enable it
|
||||
config = DiffusionCacheConfig(scm_steps_mask_policy="fast")
|
||||
backend = CacheDiTBackend(config)
|
||||
backend.enable(mock_pipeline)
|
||||
|
||||
backend.refresh(mock_pipeline, num_inference_steps=num_inference_steps)
|
||||
|
||||
mock_cache_dit.refresh_context.assert_called_once()
|
||||
call_args = mock_cache_dit.refresh_context.call_args
|
||||
# Ensure that we properly guard, i.e., cache config is filtered
|
||||
assert call_args[0][0] == mock_transformer
|
||||
assert call_args[1]["num_inference_steps"] == num_inference_steps
|
||||
assert "cache_config" not in call_args[1]
|
||||
|
||||
|
||||
class TestTeaCacheBackend:
|
||||
|
||||
Reference in new issue
Block a user