Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1cdaddd79b |
No files matched your search
@@ -751,6 +751,7 @@ def test_from_pipeline_config_routes_regional_compile_dynamic(tmp_path):
|
|||||||
" - stage_id: 0",
|
" - stage_id: 0",
|
||||||
" diffusion_compile_granularity: regional",
|
" diffusion_compile_granularity: regional",
|
||||||
" diffusion_compile_dynamic: false",
|
" diffusion_compile_dynamic: false",
|
||||||
|
" diffusion_compile_vae: false",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -762,13 +763,16 @@ def test_from_pipeline_config_routes_regional_compile_dynamic(tmp_path):
|
|||||||
cli_overrides={
|
cli_overrides={
|
||||||
"diffusion_compile_granularity": "full",
|
"diffusion_compile_granularity": "full",
|
||||||
"diffusion_compile_dynamic": True,
|
"diffusion_compile_dynamic": True,
|
||||||
|
"diffusion_compile_vae": True,
|
||||||
},
|
},
|
||||||
).stage_by_id(0)
|
).stage_by_id(0)
|
||||||
|
|
||||||
assert configured_stage.diffusion_config.diffusion_compile_granularity == "regional"
|
assert configured_stage.diffusion_config.diffusion_compile_granularity == "regional"
|
||||||
assert configured_stage.diffusion_config.diffusion_compile_dynamic is False
|
assert configured_stage.diffusion_config.diffusion_compile_dynamic is False
|
||||||
|
assert configured_stage.diffusion_config.diffusion_compile_vae is False
|
||||||
assert overridden_stage.diffusion_config.diffusion_compile_granularity == "full"
|
assert overridden_stage.diffusion_config.diffusion_compile_granularity == "full"
|
||||||
assert overridden_stage.diffusion_config.diffusion_compile_dynamic is True
|
assert overridden_stage.diffusion_config.diffusion_compile_dynamic is True
|
||||||
|
assert overridden_stage.diffusion_config.diffusion_compile_vae is True
|
||||||
|
|
||||||
|
|
||||||
def test_structured_diffusion_config_rejects_non_boolean_compile_dynamic():
|
def test_structured_diffusion_config_rejects_non_boolean_compile_dynamic():
|
||||||
@@ -776,24 +780,9 @@ def test_structured_diffusion_config_rejects_non_boolean_compile_dynamic():
|
|||||||
omni_config_module._DiffusionConfigProjection(diffusion_compile_dynamic="false")
|
omni_config_module._DiffusionConfigProjection(diffusion_compile_dynamic="false")
|
||||||
|
|
||||||
|
|
||||||
def test_from_pipeline_config_routes_ltx2_model_extra(tmp_path):
|
def test_structured_diffusion_config_rejects_non_boolean_compile_vae():
|
||||||
deploy_path = tmp_path / "dreamzero_ltx2_extras.yaml"
|
with pytest.raises(ValidationError, match="diffusion_compile_vae"):
|
||||||
deploy_path.write_text(
|
omni_config_module._DiffusionConfigProjection(diffusion_compile_vae="false")
|
||||||
"\n".join(
|
|
||||||
[
|
|
||||||
"pipeline: dreamzero",
|
|
||||||
"async_chunk: false",
|
|
||||||
"stages:",
|
|
||||||
" - stage_id: 0",
|
|
||||||
" extras:",
|
|
||||||
" ltx2_use_channels_last_3d: true",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
stage = _from_pipeline_key("dreamzero", deploy_config_path=str(deploy_path)).stage_by_id(0)
|
|
||||||
|
|
||||||
assert stage.diffusion_config.extras["ltx2_use_channels_last_3d"] is True
|
|
||||||
|
|
||||||
|
|
||||||
def test_structured_diffusion_config_rejects_invalid_compile_granularity():
|
def test_structured_diffusion_config_rejects_invalid_compile_granularity():
|
||||||
|
|||||||
@@ -11,100 +11,6 @@ import torch
|
|||||||
pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
|
pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
|
||||||
|
|
||||||
|
|
||||||
class TestLTXChannelsLast3D:
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
("extras", "expected"),
|
|
||||||
[({}, False), ({"ltx2_use_channels_last_3d": True}, True)],
|
|
||||||
)
|
|
||||||
def test_channels_last_opt_in_is_ltx2_model_extra(self, extras, expected):
|
|
||||||
from vllm_omni.diffusion.models.ltx2.ltx2_components import _ltx2_use_channels_last_3d
|
|
||||||
|
|
||||||
assert _ltx2_use_channels_last_3d(SimpleNamespace(extras=extras)) is expected
|
|
||||||
|
|
||||||
def test_channels_last_opt_in_rejects_non_boolean_model_extra(self):
|
|
||||||
from vllm_omni.diffusion.models.ltx2.ltx2_components import _ltx2_use_channels_last_3d
|
|
||||||
|
|
||||||
with pytest.raises(TypeError, match="ltx2_use_channels_last_3d"):
|
|
||||||
_ltx2_use_channels_last_3d(SimpleNamespace(extras={"ltx2_use_channels_last_3d": "true"}))
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
("causal", "kernel_size"),
|
|
||||||
[
|
|
||||||
(True, 3),
|
|
||||||
(False, 3),
|
|
||||||
(True, (3, 1, 1)),
|
|
||||||
(True, 1),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def test_layout_preserving_causal_conv_matches_original(self, causal, kernel_size):
|
|
||||||
from diffusers.models.autoencoders.autoencoder_kl_ltx2 import LTX2VideoCausalConv3d
|
|
||||||
|
|
||||||
from vllm_omni.diffusion.distributed.autoencoders.autoencoder_kl_ltx2 import (
|
|
||||||
_enable_channels_last_3d,
|
|
||||||
_weight_is_channels_last_3d,
|
|
||||||
)
|
|
||||||
|
|
||||||
torch.manual_seed(0)
|
|
||||||
conv = LTX2VideoCausalConv3d(4, 5, kernel_size).to(dtype=torch.float32).eval()
|
|
||||||
hidden_states = torch.randn(1, 4, 5, 6, 7, dtype=torch.float32)
|
|
||||||
|
|
||||||
# Pointwise Conv3d storage is valid in both contiguous formats because
|
|
||||||
# all spatial/temporal kernel dimensions are singleton.
|
|
||||||
if kernel_size != 1:
|
|
||||||
assert not _weight_is_channels_last_3d(conv)
|
|
||||||
with torch.no_grad():
|
|
||||||
expected = conv(hidden_states.clone(), causal=causal)
|
|
||||||
|
|
||||||
converted, patched = _enable_channels_last_3d(conv)
|
|
||||||
|
|
||||||
assert (converted, patched) == (1, 1)
|
|
||||||
assert _weight_is_channels_last_3d(conv)
|
|
||||||
with torch.no_grad():
|
|
||||||
actual = conv(hidden_states.clone(), causal=causal)
|
|
||||||
|
|
||||||
torch.testing.assert_close(actual, expected, rtol=1e-4, atol=1e-4)
|
|
||||||
|
|
||||||
def test_temporal_pad_replicates_edges_in_channels_last_3d(self):
|
|
||||||
from vllm_omni.diffusion.distributed.autoencoders.autoencoder_kl_ltx2 import (
|
|
||||||
_temporal_pad_channels_last_3d,
|
|
||||||
)
|
|
||||||
|
|
||||||
torch.manual_seed(0)
|
|
||||||
hidden_states = torch.randn(1, 4, 3, 2, 2, dtype=torch.float32)
|
|
||||||
|
|
||||||
actual = _temporal_pad_channels_last_3d(hidden_states, left=2, right=1)
|
|
||||||
expected = torch.cat(
|
|
||||||
[
|
|
||||||
hidden_states[:, :, :1].repeat(1, 1, 2, 1, 1),
|
|
||||||
hidden_states,
|
|
||||||
hidden_states[:, :, -1:],
|
|
||||||
],
|
|
||||||
dim=2,
|
|
||||||
)
|
|
||||||
|
|
||||||
assert actual.is_contiguous(memory_format=torch.channels_last_3d)
|
|
||||||
torch.testing.assert_close(actual, expected, rtol=0, atol=0)
|
|
||||||
|
|
||||||
def test_contiguous_weight_keeps_original_padding_path(self, monkeypatch):
|
|
||||||
from diffusers.models.autoencoders.autoencoder_kl_ltx2 import LTX2VideoCausalConv3d
|
|
||||||
|
|
||||||
import vllm_omni.diffusion.distributed.autoencoders.autoencoder_kl_ltx2 as ltx2_vae
|
|
||||||
|
|
||||||
conv = LTX2VideoCausalConv3d(4, 5, 3).to(dtype=torch.float32).eval()
|
|
||||||
hidden_states = torch.randn(1, 4, 3, 2, 2, dtype=torch.float32)
|
|
||||||
|
|
||||||
def fail_channels_last_pad(*_args, **_kwargs):
|
|
||||||
raise AssertionError("contiguous weights must retain the original padding path")
|
|
||||||
|
|
||||||
monkeypatch.setattr(ltx2_vae, "_temporal_pad_channels_last_3d", fail_channels_last_pad)
|
|
||||||
|
|
||||||
with torch.no_grad():
|
|
||||||
expected = conv(hidden_states, causal=True)
|
|
||||||
actual = ltx2_vae._layout_preserving_causal_conv_forward(conv, hidden_states, causal=True)
|
|
||||||
|
|
||||||
torch.testing.assert_close(actual, expected, rtol=0, atol=0)
|
|
||||||
|
|
||||||
|
|
||||||
class TestLTXOutputRank:
|
class TestLTXOutputRank:
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("distributed_vae_state", "expected_decode_calls"),
|
("distributed_vae_state", "expected_decode_calls"),
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import pytest
|
|||||||
import torch.nn as nn
|
import torch.nn as nn
|
||||||
|
|
||||||
import vllm_omni.diffusion.compile as compile_module
|
import vllm_omni.diffusion.compile as compile_module
|
||||||
from vllm_omni.diffusion.compile import regionally_compile
|
from vllm_omni.diffusion.compile import compile_callable_with_fallback, regionally_compile
|
||||||
|
|
||||||
pytestmark = [pytest.mark.core_model, pytest.mark.diffusion, pytest.mark.cpu]
|
pytestmark = [pytest.mark.core_model, pytest.mark.diffusion, pytest.mark.cpu]
|
||||||
|
|
||||||
@@ -74,3 +74,50 @@ def test_regionally_compile_does_not_partially_mutate_on_setup_failure(monkeypat
|
|||||||
regionally_compile(model, dynamic=True)
|
regionally_compile(model, dynamic=True)
|
||||||
|
|
||||||
assert [block.forward.__func__ for block in model.transformer_blocks] == original_forwards
|
assert [block.forward.__func__ for block in model.transformer_blocks] == original_forwards
|
||||||
|
|
||||||
|
|
||||||
|
def test_compile_callable_falls_back_once_after_lazy_failure(monkeypatch, caplog):
|
||||||
|
compiled_calls = 0
|
||||||
|
eager_calls = 0
|
||||||
|
|
||||||
|
def eager(value):
|
||||||
|
nonlocal eager_calls
|
||||||
|
eager_calls += 1
|
||||||
|
return value + 1
|
||||||
|
|
||||||
|
def compile_fn(fn, **kwargs):
|
||||||
|
assert fn is eager
|
||||||
|
assert kwargs == {"mode": "default"}
|
||||||
|
|
||||||
|
def compiled(value):
|
||||||
|
nonlocal compiled_calls
|
||||||
|
compiled_calls += 1
|
||||||
|
raise RuntimeError("lazy failure")
|
||||||
|
|
||||||
|
return compiled
|
||||||
|
|
||||||
|
monkeypatch.setattr(compile_module.torch, "compile", compile_fn)
|
||||||
|
callable_fn, activated = compile_callable_with_fallback(eager, label="test callable", mode="default")
|
||||||
|
|
||||||
|
assert activated
|
||||||
|
assert callable_fn(1) == 2
|
||||||
|
assert callable_fn(2) == 3
|
||||||
|
assert compiled_calls == 1
|
||||||
|
assert eager_calls == 2
|
||||||
|
assert "disabling compilation and retrying eagerly" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
def test_compile_callable_keeps_eager_on_setup_failure(monkeypatch, caplog):
|
||||||
|
def eager(value):
|
||||||
|
return value + 1
|
||||||
|
|
||||||
|
def compile_fn(*args, **kwargs):
|
||||||
|
raise RuntimeError("setup failure")
|
||||||
|
|
||||||
|
monkeypatch.setattr(compile_module.torch, "compile", compile_fn)
|
||||||
|
callable_fn, activated = compile_callable_with_fallback(eager, label="test callable")
|
||||||
|
|
||||||
|
assert not activated
|
||||||
|
assert callable_fn is eager
|
||||||
|
assert callable_fn(1) == 2
|
||||||
|
assert "continuing eagerly" in caplog.text
|
||||||
@@ -515,16 +515,19 @@ class TestDiffusionCompileConfig:
|
|||||||
|
|
||||||
assert config.diffusion_compile_granularity == "regional"
|
assert config.diffusion_compile_granularity == "regional"
|
||||||
assert config.diffusion_compile_dynamic is True
|
assert config.diffusion_compile_dynamic is True
|
||||||
|
assert config.diffusion_compile_vae is True
|
||||||
|
|
||||||
def test_from_kwargs_preserves_compile_controls(self) -> None:
|
def test_from_kwargs_preserves_compile_controls(self) -> None:
|
||||||
config = OmniDiffusionConfig.from_kwargs(
|
config = OmniDiffusionConfig.from_kwargs(
|
||||||
model="test",
|
model="test",
|
||||||
diffusion_compile_granularity="full",
|
diffusion_compile_granularity="full",
|
||||||
diffusion_compile_dynamic=False,
|
diffusion_compile_dynamic=False,
|
||||||
|
diffusion_compile_vae=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert config.diffusion_compile_granularity == "full"
|
assert config.diffusion_compile_granularity == "full"
|
||||||
assert config.diffusion_compile_dynamic is False
|
assert config.diffusion_compile_dynamic is False
|
||||||
|
assert config.diffusion_compile_vae is False
|
||||||
|
|
||||||
def test_config_rejects_invalid_compile_granularity(self) -> None:
|
def test_config_rejects_invalid_compile_granularity(self) -> None:
|
||||||
with pytest.raises(ValueError, match="diffusion_compile_granularity"):
|
with pytest.raises(ValueError, match="diffusion_compile_granularity"):
|
||||||
@@ -534,6 +537,10 @@ class TestDiffusionCompileConfig:
|
|||||||
with pytest.raises(TypeError, match="diffusion_compile_dynamic"):
|
with pytest.raises(TypeError, match="diffusion_compile_dynamic"):
|
||||||
OmniDiffusionConfig(model="test", diffusion_compile_dynamic="false")
|
OmniDiffusionConfig(model="test", diffusion_compile_dynamic="false")
|
||||||
|
|
||||||
|
def test_config_rejects_non_boolean_compile_vae(self) -> None:
|
||||||
|
with pytest.raises(TypeError, match="diffusion_compile_vae"):
|
||||||
|
OmniDiffusionConfig(model="test", diffusion_compile_vae="false")
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"kwargs, feature",
|
"kwargs, feature",
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -130,6 +130,23 @@ class _CompileTrackingModel:
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
class _DecodeVAE(torch.nn.Module):
|
||||||
|
def decode(self, value):
|
||||||
|
return value + 1
|
||||||
|
|
||||||
|
|
||||||
|
class _PipelineWithVAE(torch.nn.Module):
|
||||||
|
_dit_modules = []
|
||||||
|
_encoder_modules = []
|
||||||
|
_vae_modules = ["vae", "vae_alias"]
|
||||||
|
_resident_modules = []
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.vae = _DecodeVAE()
|
||||||
|
self.vae_alias = self.vae
|
||||||
|
|
||||||
|
|
||||||
def _make_request():
|
def _make_request():
|
||||||
sampling_params = SimpleNamespace(
|
sampling_params = SimpleNamespace(
|
||||||
generator=None,
|
generator=None,
|
||||||
@@ -320,6 +337,31 @@ def test_compile_transformer_falls_back_after_synchronous_setup_failure(monkeypa
|
|||||||
assert "lazy compilation errors" in caplog.text
|
assert "lazy compilation errors" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.core_model
|
||||||
|
@pytest.mark.cpu
|
||||||
|
def test_compile_vae_decodes_uses_discovery_and_deduplicates_aliases(monkeypatch):
|
||||||
|
runner = object.__new__(DiffusionModelRunner)
|
||||||
|
runner.pipeline = _PipelineWithVAE()
|
||||||
|
compile_calls = []
|
||||||
|
|
||||||
|
def compile_fn(fn, **kwargs):
|
||||||
|
compile_calls.append((fn, kwargs))
|
||||||
|
return lambda *args, **call_kwargs: fn(*args, **call_kwargs) + 10
|
||||||
|
|
||||||
|
monkeypatch.setattr(model_runner_module.torch, "compile", compile_fn)
|
||||||
|
|
||||||
|
DiffusionModelRunner._compile_vae_decodes(runner)
|
||||||
|
|
||||||
|
assert len(compile_calls) == 1
|
||||||
|
assert compile_calls[0][1] == {
|
||||||
|
"mode": "default",
|
||||||
|
"fullgraph": False,
|
||||||
|
"dynamic": None,
|
||||||
|
}
|
||||||
|
assert runner.pipeline.vae.decode(1) == 12
|
||||||
|
assert runner.pipeline.vae_alias.decode is runner.pipeline.vae.decode
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.core_model
|
@pytest.mark.core_model
|
||||||
@pytest.mark.cpu
|
@pytest.mark.cpu
|
||||||
def test_execute_stepwise_streaming_returns_chunks_at_boundaries(monkeypatch):
|
def test_execute_stepwise_streaming_returns_chunks_at_boundaries(monkeypatch):
|
||||||
|
|||||||
@@ -971,6 +971,44 @@ class TestDiffusionEngine:
|
|||||||
admitted_request = engine.add_req_and_wait_for_response.call_args.args[0]
|
admitted_request = engine.add_req_and_wait_for_response.call_args.args[0]
|
||||||
assert admitted_request.request_id == "dummy_req_id"
|
assert admitted_request.request_id == "dummy_req_id"
|
||||||
|
|
||||||
|
def test_compile_warmup_repeats_through_normal_request_path(self, mocker: MockerFixture) -> None:
|
||||||
|
engine = DiffusionEngine.__new__(DiffusionEngine)
|
||||||
|
engine.od_config = SimpleNamespace(
|
||||||
|
model_class_name="mock_model",
|
||||||
|
diffusion_load_format="default",
|
||||||
|
diffusion_compile_vae=True,
|
||||||
|
enforce_eager=False,
|
||||||
|
)
|
||||||
|
engine.add_req_and_wait_for_response = mocker.Mock(
|
||||||
|
side_effect=[DiffusionOutput(output=None), DiffusionOutput(output=None)]
|
||||||
|
)
|
||||||
|
|
||||||
|
engine._dummy_run()
|
||||||
|
|
||||||
|
requests = [call.args[0] for call in engine.add_req_and_wait_for_response.call_args_list]
|
||||||
|
assert len(requests) == 2
|
||||||
|
assert requests[0].is_dummy_run()
|
||||||
|
assert not requests[1].is_dummy_run()
|
||||||
|
assert requests[1].prompt == {"prompt": "A detailed image."}
|
||||||
|
assert requests[1].sampling_params.need_kv_receive is False
|
||||||
|
assert requests[1].sampling_params.num_inference_steps == 1
|
||||||
|
|
||||||
|
def test_compile_real_path_warmup_failure_is_non_fatal(self, mocker: MockerFixture, caplog) -> None:
|
||||||
|
engine = DiffusionEngine.__new__(DiffusionEngine)
|
||||||
|
engine.od_config = SimpleNamespace(
|
||||||
|
model_class_name="mock_model",
|
||||||
|
diffusion_load_format="default",
|
||||||
|
diffusion_compile_vae=True,
|
||||||
|
enforce_eager=False,
|
||||||
|
)
|
||||||
|
engine.add_req_and_wait_for_response = mocker.Mock(
|
||||||
|
side_effect=[DiffusionOutput(output=None), RuntimeError("prewarm failure")]
|
||||||
|
)
|
||||||
|
|
||||||
|
engine._dummy_run()
|
||||||
|
|
||||||
|
assert "serving will continue" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
class TestStepScheduler:
|
class TestStepScheduler:
|
||||||
def setup_method(self) -> None:
|
def setup_method(self) -> None:
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ def test_default_stage_config_includes_cache_backend():
|
|||||||
"cache_backend": "cache_dit",
|
"cache_backend": "cache_dit",
|
||||||
"cache_config": '{"Fn_compute_blocks": 2}',
|
"cache_config": '{"Fn_compute_blocks": 2}',
|
||||||
"vae_use_slicing": True,
|
"vae_use_slicing": True,
|
||||||
"extras": {"ltx2_use_channels_last_3d": True},
|
|
||||||
"ulysses_degree": 2,
|
"ulysses_degree": 2,
|
||||||
}
|
}
|
||||||
)[0]
|
)[0]
|
||||||
@@ -30,7 +29,6 @@ def test_default_stage_config_includes_cache_backend():
|
|||||||
assert engine_args["cache_backend"] == "cache_dit"
|
assert engine_args["cache_backend"] == "cache_dit"
|
||||||
assert engine_args["cache_config"]["Fn_compute_blocks"] == 2
|
assert engine_args["cache_config"]["Fn_compute_blocks"] == 2
|
||||||
assert engine_args["vae_use_slicing"] is True
|
assert engine_args["vae_use_slicing"] is True
|
||||||
assert engine_args["extras"]["ltx2_use_channels_last_3d"] is True
|
|
||||||
assert engine_args["parallel_config"].ulysses_degree == 2
|
assert engine_args["parallel_config"].ulysses_degree == 2
|
||||||
assert engine_args["model_stage"] == "diffusion"
|
assert engine_args["model_stage"] == "diffusion"
|
||||||
|
|
||||||
@@ -89,6 +87,7 @@ def test_default_stage_config_defaults_nullified_parallel_size_kwargs():
|
|||||||
"enforce_eager": None,
|
"enforce_eager": None,
|
||||||
"diffusion_compile_granularity": None,
|
"diffusion_compile_granularity": None,
|
||||||
"diffusion_compile_dynamic": None,
|
"diffusion_compile_dynamic": None,
|
||||||
|
"diffusion_compile_vae": None,
|
||||||
}
|
}
|
||||||
)[0]
|
)[0]
|
||||||
|
|
||||||
@@ -100,6 +99,7 @@ def test_default_stage_config_defaults_nullified_parallel_size_kwargs():
|
|||||||
assert stage_cfg["engine_args"]["enforce_eager"] is False
|
assert stage_cfg["engine_args"]["enforce_eager"] is False
|
||||||
assert stage_cfg["engine_args"]["diffusion_compile_granularity"] == "regional"
|
assert stage_cfg["engine_args"]["diffusion_compile_granularity"] == "regional"
|
||||||
assert stage_cfg["engine_args"]["diffusion_compile_dynamic"] is True
|
assert stage_cfg["engine_args"]["diffusion_compile_dynamic"] is True
|
||||||
|
assert stage_cfg["engine_args"]["diffusion_compile_vae"] is True
|
||||||
|
|
||||||
|
|
||||||
def test_default_stage_config_propagates_ulysses_mode():
|
def test_default_stage_config_propagates_ulysses_mode():
|
||||||
@@ -317,7 +317,7 @@ def test_serve_cli_forwards_distributed_offload_residency():
|
|||||||
|
|
||||||
|
|
||||||
def test_serve_cli_accepts_diffusion_compile_controls():
|
def test_serve_cli_accepts_diffusion_compile_controls():
|
||||||
"""Ensure both compile controls reach the diffusion stage."""
|
"""Ensure all compile controls reach the diffusion stage."""
|
||||||
parser = TrackingArgumentParser()
|
parser = TrackingArgumentParser()
|
||||||
subparsers = parser.add_subparsers(dest="command")
|
subparsers = parser.add_subparsers(dest="command")
|
||||||
OmniServeCommand().subparser_init(subparsers)
|
OmniServeCommand().subparser_init(subparsers)
|
||||||
@@ -330,6 +330,7 @@ def test_serve_cli_accepts_diffusion_compile_controls():
|
|||||||
"--diffusion-compile-granularity",
|
"--diffusion-compile-granularity",
|
||||||
"full",
|
"full",
|
||||||
"--no-diffusion-compile-dynamic",
|
"--no-diffusion-compile-dynamic",
|
||||||
|
"--no-diffusion-compile-vae",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -338,8 +339,10 @@ def test_serve_cli_accepts_diffusion_compile_controls():
|
|||||||
|
|
||||||
assert args.diffusion_compile_granularity == "full"
|
assert args.diffusion_compile_granularity == "full"
|
||||||
assert args.diffusion_compile_dynamic is False
|
assert args.diffusion_compile_dynamic is False
|
||||||
|
assert args.diffusion_compile_vae is False
|
||||||
assert stage_cfg["engine_args"]["diffusion_compile_granularity"] == "full"
|
assert stage_cfg["engine_args"]["diffusion_compile_granularity"] == "full"
|
||||||
assert stage_cfg["engine_args"]["diffusion_compile_dynamic"] is False
|
assert stage_cfg["engine_args"]["diffusion_compile_dynamic"] is False
|
||||||
|
assert stage_cfg["engine_args"]["diffusion_compile_vae"] is False
|
||||||
|
|
||||||
|
|
||||||
def test_serve_cli_accepts_diffusion_attention_backend():
|
def test_serve_cli_accepts_diffusion_attention_backend():
|
||||||
|
|||||||
@@ -570,6 +570,7 @@ class _DiffusionConfigProjection:
|
|||||||
pin_cpu_memory: bool = True
|
pin_cpu_memory: bool = True
|
||||||
diffusion_compile_granularity: Literal["regional", "full"] = "regional"
|
diffusion_compile_granularity: Literal["regional", "full"] = "regional"
|
||||||
diffusion_compile_dynamic: bool = Field(default=True, strict=True)
|
diffusion_compile_dynamic: bool = Field(default=True, strict=True)
|
||||||
|
diffusion_compile_vae: bool = Field(default=True, strict=True)
|
||||||
fa_deterministic: bool = False
|
fa_deterministic: bool = False
|
||||||
vae_use_slicing: bool = False
|
vae_use_slicing: bool = False
|
||||||
vae_use_tiling: bool = False
|
vae_use_tiling: bool = False
|
||||||
|
|||||||
@@ -394,6 +394,7 @@ class StageDeployConfig:
|
|||||||
# Diffusion execution, cache, and VAE behavior.
|
# Diffusion execution, cache, and VAE behavior.
|
||||||
diffusion_compile_granularity: str | None = None
|
diffusion_compile_granularity: str | None = None
|
||||||
diffusion_compile_dynamic: bool | None = None
|
diffusion_compile_dynamic: bool | None = None
|
||||||
|
diffusion_compile_vae: bool | None = None
|
||||||
fa_deterministic: bool | None = None
|
fa_deterministic: bool | None = None
|
||||||
cache_backend: str | None = None
|
cache_backend: str | None = None
|
||||||
cache_config: dict[str, Any] | None = None
|
cache_config: dict[str, Any] | None = None
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||||
|
from collections.abc import Callable
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import torch
|
import torch
|
||||||
@@ -9,6 +10,59 @@ from vllm.logger import init_logger
|
|||||||
logger = init_logger(__name__)
|
logger = init_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class _FallbackCompiledCallable:
|
||||||
|
"""Run a compiled callable until it fails, then permanently use eager."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
eager: Callable[..., Any],
|
||||||
|
compiled: Callable[..., Any],
|
||||||
|
*,
|
||||||
|
label: str,
|
||||||
|
) -> None:
|
||||||
|
self._eager = eager
|
||||||
|
self._compiled: Callable[..., Any] | None = compiled
|
||||||
|
self._label = label
|
||||||
|
|
||||||
|
def __call__(self, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
compiled = self._compiled
|
||||||
|
if compiled is None:
|
||||||
|
return self._eager(*args, **kwargs)
|
||||||
|
try:
|
||||||
|
return compiled(*args, **kwargs)
|
||||||
|
except Exception as exc:
|
||||||
|
self._compiled = None
|
||||||
|
logger.warning(
|
||||||
|
"%s failed during lazy torch.compile execution (%s); disabling compilation and retrying eagerly.",
|
||||||
|
self._label,
|
||||||
|
exc,
|
||||||
|
)
|
||||||
|
return self._eager(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def compile_callable_with_fallback(
|
||||||
|
fn: Callable[..., Any],
|
||||||
|
*,
|
||||||
|
label: str,
|
||||||
|
**compile_kwargs: Any,
|
||||||
|
) -> tuple[Callable[..., Any], bool]:
|
||||||
|
"""Compile ``fn`` with a fail-closed eager fallback.
|
||||||
|
|
||||||
|
The boolean return value reports whether lazy compilation was activated.
|
||||||
|
Synchronous setup failures return the original callable unchanged.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
compiled = torch.compile(fn, **compile_kwargs)
|
||||||
|
except Exception as exc:
|
||||||
|
logger.warning(
|
||||||
|
"%s torch.compile setup failed (%s); continuing eagerly.",
|
||||||
|
label,
|
||||||
|
exc,
|
||||||
|
)
|
||||||
|
return fn, False
|
||||||
|
return _FallbackCompiledCallable(fn, compiled, label=label), True
|
||||||
|
|
||||||
|
|
||||||
def _matches_repeated_block(
|
def _matches_repeated_block(
|
||||||
name: str,
|
name: str,
|
||||||
module: nn.Module,
|
module: nn.Module,
|
||||||
|
|||||||
@@ -726,6 +726,9 @@ class OmniDiffusionConfig:
|
|||||||
# provide its own setup_compile() implementation.
|
# provide its own setup_compile() implementation.
|
||||||
diffusion_compile_granularity: str = "regional"
|
diffusion_compile_granularity: str = "regional"
|
||||||
diffusion_compile_dynamic: bool = True
|
diffusion_compile_dynamic: bool = True
|
||||||
|
# Compile discovered VAE ``decode`` callables whenever generic diffusion
|
||||||
|
# torch.compile is enabled. Runtime failures permanently fall back to eager.
|
||||||
|
diffusion_compile_vae: bool = True
|
||||||
|
|
||||||
# Parallel weight loading (for faster diffusion model startup)
|
# Parallel weight loading (for faster diffusion model startup)
|
||||||
enable_multithread_weight_load: bool = True
|
enable_multithread_weight_load: bool = True
|
||||||
@@ -930,6 +933,8 @@ class OmniDiffusionConfig:
|
|||||||
)
|
)
|
||||||
if not isinstance(self.diffusion_compile_dynamic, bool):
|
if not isinstance(self.diffusion_compile_dynamic, bool):
|
||||||
raise TypeError(f"diffusion_compile_dynamic must be a bool, got {type(self.diffusion_compile_dynamic)!r}")
|
raise TypeError(f"diffusion_compile_dynamic must be a bool, got {type(self.diffusion_compile_dynamic)!r}")
|
||||||
|
if not isinstance(self.diffusion_compile_vae, bool):
|
||||||
|
raise TypeError(f"diffusion_compile_vae must be a bool, got {type(self.diffusion_compile_vae)!r}")
|
||||||
self.diffusion_kv_mode = parse_diffusion_kv_cache_mode(self.diffusion_kv_mode)
|
self.diffusion_kv_mode = parse_diffusion_kv_cache_mode(self.diffusion_kv_mode)
|
||||||
|
|
||||||
if self.omni_kv_config is None:
|
if self.omni_kv_config is None:
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ if TYPE_CHECKING:
|
|||||||
logger = init_logger(__name__)
|
logger = init_logger(__name__)
|
||||||
|
|
||||||
_ASYNC_OUTPUT_TIMEOUT = 30.0 # seconds
|
_ASYNC_OUTPUT_TIMEOUT = 30.0 # seconds
|
||||||
|
_VAE_COMPILE_WARMUP_REQUEST_ID = "vae_compile_warmup_req_id"
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"DiffusionEngine",
|
"DiffusionEngine",
|
||||||
@@ -851,28 +852,26 @@ class DiffusionEngine:
|
|||||||
num_inference_steps = 1
|
num_inference_steps = 1
|
||||||
height = 512
|
height = 512
|
||||||
width = 512
|
width = 512
|
||||||
prompt: OmniTextPrompt = {"prompt": "dummy run"}
|
|
||||||
|
|
||||||
supports_image_input, supports_audio_input = supports_multimodal_input(self.od_config)
|
supports_image_input, supports_audio_input = supports_multimodal_input(self.od_config)
|
||||||
if supports_image_input:
|
|
||||||
# Provide a dummy image input if the model supports it
|
|
||||||
color_format = image_color_format(self.od_config.model_class_name)
|
|
||||||
dummy_image = PIL.Image.new(color_format, (width, height))
|
|
||||||
prompt.setdefault("multi_modal_data", {})["image"] = dummy_image
|
|
||||||
|
|
||||||
if supports_audio_input:
|
|
||||||
audio_sr = 16000
|
|
||||||
dummy_audio = np.random.randn(audio_sr * 2).astype(np.float32)
|
|
||||||
prompt.setdefault("multi_modal_data", {})["audio"] = dummy_audio
|
|
||||||
|
|
||||||
num_frames = get_dummy_run_num_frames(self.od_config.model_class_name, supports_audio_input)
|
num_frames = get_dummy_run_num_frames(self.od_config.model_class_name, supports_audio_input)
|
||||||
if num_frames <= 0:
|
if num_frames <= 0:
|
||||||
logger.info("Skipping dummy warmup run (num_frames=0)")
|
logger.info("Skipping dummy warmup run (num_frames=0)")
|
||||||
return
|
return
|
||||||
req = OmniDiffusionRequest(
|
|
||||||
prompt=prompt,
|
def build_request(request_id: str, prompt_text: str, *, real_path: bool) -> OmniDiffusionRequest:
|
||||||
request_id=DUMMY_DIFFUSION_REQUEST_ID,
|
prompt: OmniTextPrompt = {"prompt": prompt_text}
|
||||||
sampling_params=OmniDiffusionSamplingParams(
|
if supports_image_input:
|
||||||
|
color_format = image_color_format(self.od_config.model_class_name)
|
||||||
|
prompt.setdefault("multi_modal_data", {})["image"] = PIL.Image.new(
|
||||||
|
color_format,
|
||||||
|
(width, height),
|
||||||
|
)
|
||||||
|
if supports_audio_input:
|
||||||
|
audio_sr = 16000
|
||||||
|
prompt.setdefault("multi_modal_data", {})["audio"] = np.random.randn(audio_sr * 2).astype(np.float32)
|
||||||
|
|
||||||
|
sampling_params = OmniDiffusionSamplingParams(
|
||||||
height=height,
|
height=height,
|
||||||
width=width,
|
width=width,
|
||||||
num_inference_steps=num_inference_steps,
|
num_inference_steps=num_inference_steps,
|
||||||
@@ -885,13 +884,47 @@ class DiffusionEngine:
|
|||||||
# Disable CFG for warmup to avoid triggering CFG parallel
|
# Disable CFG for warmup to avoid triggering CFG parallel
|
||||||
# validation when cfg_parallel_size > 1.
|
# validation when cfg_parallel_size > 1.
|
||||||
extra_args={"cfg_text_scale": 1.0, "cfg_img_scale": 1.0},
|
extra_args={"cfg_text_scale": 1.0, "cfg_img_scale": 1.0},
|
||||||
),
|
)
|
||||||
)
|
if real_path:
|
||||||
|
# Internal pretraffic must exercise ordinary pipeline branches
|
||||||
|
# without waiting for KV produced by an upstream stage.
|
||||||
|
sampling_params.need_kv_receive = False
|
||||||
|
return OmniDiffusionRequest(
|
||||||
|
prompt=prompt,
|
||||||
|
request_id=request_id,
|
||||||
|
sampling_params=sampling_params,
|
||||||
|
)
|
||||||
|
|
||||||
|
req = build_request(DUMMY_DIFFUSION_REQUEST_ID, "dummy run", real_path=False)
|
||||||
logger.info("dummy run to warm up the model")
|
logger.info("dummy run to warm up the model")
|
||||||
output = self.add_req_and_wait_for_response(req)
|
output = self.add_req_and_wait_for_response(req)
|
||||||
if output.error:
|
if output.error:
|
||||||
raise RuntimeError(f"Dummy run failed: {output.error}")
|
raise RuntimeError(f"Dummy run failed: {output.error}")
|
||||||
|
|
||||||
|
compile_real_path = bool(
|
||||||
|
getattr(self.od_config, "diffusion_compile_vae", False)
|
||||||
|
and not getattr(self.od_config, "enforce_eager", True)
|
||||||
|
)
|
||||||
|
if not compile_real_path:
|
||||||
|
return
|
||||||
|
|
||||||
|
logger.info("real request-path warmup for compiled VAE decode")
|
||||||
|
real_path_req = build_request(
|
||||||
|
_VAE_COMPILE_WARMUP_REQUEST_ID,
|
||||||
|
"A detailed image.",
|
||||||
|
real_path=True,
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
real_path_output = self.add_req_and_wait_for_response(real_path_req)
|
||||||
|
except Exception as exc:
|
||||||
|
logger.warning("Real request-path compile warmup failed (%s); serving will continue.", exc)
|
||||||
|
return
|
||||||
|
if real_path_output.error:
|
||||||
|
logger.warning(
|
||||||
|
"Real request-path compile warmup returned an error (%s); serving will continue.",
|
||||||
|
real_path_output.error,
|
||||||
|
)
|
||||||
|
|
||||||
def _submit_rpc(
|
def _submit_rpc(
|
||||||
self,
|
self,
|
||||||
method: str,
|
method: str,
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||||
|
|
||||||
from types import MethodType
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import torch
|
import torch
|
||||||
from diffusers import AutoencoderKLLTX2Video
|
from diffusers import AutoencoderKLLTX2Video
|
||||||
from diffusers.models.autoencoders.autoencoder_kl_ltx2 import LTX2VideoCausalConv3d
|
|
||||||
from diffusers.models.autoencoders.vae import DecoderOutput
|
from diffusers.models.autoencoders.vae import DecoderOutput
|
||||||
from torch import nn
|
|
||||||
from vllm.logger import init_logger
|
from vllm.logger import init_logger
|
||||||
|
|
||||||
from vllm_omni.diffusion.distributed.autoencoders.distributed_vae_executor import (
|
from vllm_omni.diffusion.distributed.autoencoders.distributed_vae_executor import (
|
||||||
@@ -22,89 +19,6 @@ from vllm_omni.diffusion.distributed.autoencoders.distributed_vae_executor impor
|
|||||||
logger = init_logger(__name__)
|
logger = init_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
# Adapted from https://github.com/sgl-project/sglang/pull/27431.
|
|
||||||
def _weight_is_channels_last_3d(module: LTX2VideoCausalConv3d) -> bool:
|
|
||||||
weight = module.conv.weight
|
|
||||||
return (
|
|
||||||
weight.dim() == 5
|
|
||||||
and hasattr(torch, "channels_last_3d")
|
|
||||||
and weight.is_contiguous(memory_format=torch.channels_last_3d)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _temporal_pad_channels_last_3d(
|
|
||||||
hidden_states: torch.Tensor,
|
|
||||||
*,
|
|
||||||
left: int,
|
|
||||||
right: int,
|
|
||||||
) -> torch.Tensor:
|
|
||||||
"""Replicate temporal edge frames directly into CL3D storage."""
|
|
||||||
batch, channels, frames, height, width = hidden_states.shape
|
|
||||||
padded = torch.empty(
|
|
||||||
(batch, channels, frames + left + right, height, width),
|
|
||||||
dtype=hidden_states.dtype,
|
|
||||||
device=hidden_states.device,
|
|
||||||
memory_format=torch.channels_last_3d,
|
|
||||||
)
|
|
||||||
padded[:, :, left : left + frames].copy_(hidden_states)
|
|
||||||
if left:
|
|
||||||
padded[:, :, :left].copy_(hidden_states[:, :, :1])
|
|
||||||
if right:
|
|
||||||
padded[:, :, left + frames :].copy_(hidden_states[:, :, -1:])
|
|
||||||
return padded
|
|
||||||
|
|
||||||
|
|
||||||
def _layout_preserving_causal_conv_forward(
|
|
||||||
module: LTX2VideoCausalConv3d,
|
|
||||||
hidden_states: torch.Tensor,
|
|
||||||
causal: bool = True,
|
|
||||||
) -> torch.Tensor:
|
|
||||||
"""Diffusers LTX causal-conv math with a CL3D-preserving pad path."""
|
|
||||||
time_kernel_size = module.kernel_size[0]
|
|
||||||
use_channels_last_pad = hidden_states.dim() == 5 and _weight_is_channels_last_3d(module)
|
|
||||||
|
|
||||||
if use_channels_last_pad:
|
|
||||||
if causal:
|
|
||||||
left, right = time_kernel_size - 1, 0
|
|
||||||
else:
|
|
||||||
left = right = (time_kernel_size - 1) // 2
|
|
||||||
if left == 0 and right == 0:
|
|
||||||
hidden_states = hidden_states.contiguous(memory_format=torch.channels_last_3d)
|
|
||||||
else:
|
|
||||||
hidden_states = _temporal_pad_channels_last_3d(
|
|
||||||
hidden_states,
|
|
||||||
left=left,
|
|
||||||
right=right,
|
|
||||||
)
|
|
||||||
elif causal:
|
|
||||||
pad_left = hidden_states[:, :, :1, :, :].repeat((1, 1, time_kernel_size - 1, 1, 1))
|
|
||||||
hidden_states = torch.concatenate([pad_left, hidden_states], dim=2)
|
|
||||||
else:
|
|
||||||
pad_size = (time_kernel_size - 1) // 2
|
|
||||||
pad_left = hidden_states[:, :, :1, :, :].repeat((1, 1, pad_size, 1, 1))
|
|
||||||
pad_right = hidden_states[:, :, -1:, :, :].repeat((1, 1, pad_size, 1, 1))
|
|
||||||
hidden_states = torch.concatenate([pad_left, hidden_states, pad_right], dim=2)
|
|
||||||
|
|
||||||
return module.conv(hidden_states)
|
|
||||||
|
|
||||||
|
|
||||||
def _enable_channels_last_3d(model: nn.Module) -> tuple[int, int]:
|
|
||||||
"""Convert LTX Conv3d weights and install layout-preserving causal pads."""
|
|
||||||
if not hasattr(torch, "channels_last_3d"):
|
|
||||||
return 0, 0
|
|
||||||
|
|
||||||
converted_convs = 0
|
|
||||||
patched_causal_convs = 0
|
|
||||||
for module in model.modules():
|
|
||||||
if isinstance(module, LTX2VideoCausalConv3d):
|
|
||||||
module.forward = MethodType(_layout_preserving_causal_conv_forward, module)
|
|
||||||
patched_causal_convs += 1
|
|
||||||
if isinstance(module, nn.Conv3d):
|
|
||||||
module.weight.data = module.weight.data.contiguous(memory_format=torch.channels_last_3d)
|
|
||||||
converted_convs += 1
|
|
||||||
return converted_convs, patched_causal_convs
|
|
||||||
|
|
||||||
|
|
||||||
class LTX2VaeExecutor(DistributedVaeExecutor):
|
class LTX2VaeExecutor(DistributedVaeExecutor):
|
||||||
def _pack_local_tiles_without_meta(self, local_results, global_padding_shape, device, dtype):
|
def _pack_local_tiles_without_meta(self, local_results, global_padding_shape, device, dtype):
|
||||||
tile_tensor = torch.zeros(global_padding_shape, device=device, dtype=dtype)
|
tile_tensor = torch.zeros(global_padding_shape, device=device, dtype=dtype)
|
||||||
@@ -166,16 +80,6 @@ class DistributedAutoencoderKLLTX2Video(AutoencoderKLLTX2Video, DistributedVaeMi
|
|||||||
model.init_distributed()
|
model.init_distributed()
|
||||||
return model
|
return model
|
||||||
|
|
||||||
def enable_channels_last_3d(self) -> None:
|
|
||||||
"""Opt into the layout-preserving CL3D path for this video VAE."""
|
|
||||||
converted_convs, patched_causal_convs = _enable_channels_last_3d(self)
|
|
||||||
logger.info(
|
|
||||||
"LTX2 video VAE: converted %d Conv3d weights to channels_last_3d and "
|
|
||||||
"installed %d layout-preserving causal conv paths",
|
|
||||||
converted_convs,
|
|
||||||
patched_causal_convs,
|
|
||||||
)
|
|
||||||
|
|
||||||
def init_distributed(self):
|
def init_distributed(self):
|
||||||
self.distributed_executor = LTX2VaeExecutor()
|
self.distributed_executor = LTX2VaeExecutor()
|
||||||
|
|
||||||
|
|||||||
@@ -57,17 +57,6 @@ _LTX_COMPONENT_SUBFOLDERS = (
|
|||||||
)
|
)
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
_LTX2_CHANNELS_LAST_3D_EXTRA = "ltx2_use_channels_last_3d"
|
|
||||||
|
|
||||||
|
|
||||||
def _ltx2_use_channels_last_3d(od_config: Any) -> bool:
|
|
||||||
"""Read the LTX2-only channels-last opt-in from model extras."""
|
|
||||||
extras = getattr(od_config, "extras", {}) or {}
|
|
||||||
enabled = extras.get(_LTX2_CHANNELS_LAST_3D_EXTRA, False)
|
|
||||||
if not isinstance(enabled, bool):
|
|
||||||
raise TypeError(f"{_LTX2_CHANNELS_LAST_3D_EXTRA} must be a bool, got {type(enabled)!r}")
|
|
||||||
return enabled
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class LTXComponentProfile:
|
class LTXComponentProfile:
|
||||||
@@ -376,8 +365,6 @@ def initialize_pipeline_components(pipeline: Any, od_config: Any) -> None:
|
|||||||
local_files_only=local_files_only,
|
local_files_only=local_files_only,
|
||||||
dtype=dtype,
|
dtype=dtype,
|
||||||
)
|
)
|
||||||
if _ltx2_use_channels_last_3d(od_config):
|
|
||||||
pipeline.vae.enable_channels_last_3d()
|
|
||||||
pipeline.audio_vae = _load_component(
|
pipeline.audio_vae = _load_component(
|
||||||
AutoencoderKLLTX2Audio,
|
AutoencoderKLLTX2Audio,
|
||||||
model,
|
model,
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ from vllm_omni.diffusion.cache.prompt_embed_cache import (
|
|||||||
resolve_prompt_embed_cache_config,
|
resolve_prompt_embed_cache_config,
|
||||||
)
|
)
|
||||||
from vllm_omni.diffusion.cache.selector import get_cache_backend
|
from vllm_omni.diffusion.cache.selector import get_cache_backend
|
||||||
from vllm_omni.diffusion.compile import regionally_compile
|
from vllm_omni.diffusion.compile import compile_callable_with_fallback, regionally_compile
|
||||||
from vllm_omni.diffusion.data import DiffusionOutput, OmniDiffusionConfig
|
from vllm_omni.diffusion.data import DiffusionOutput, OmniDiffusionConfig
|
||||||
from vllm_omni.diffusion.forward_context import set_forward_context
|
from vllm_omni.diffusion.forward_context import set_forward_context
|
||||||
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
|
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
|
||||||
@@ -40,6 +40,7 @@ from vllm_omni.diffusion.models.interface import (
|
|||||||
supports_step_execution,
|
supports_step_execution,
|
||||||
)
|
)
|
||||||
from vllm_omni.diffusion.offloader import get_offload_backend
|
from vllm_omni.diffusion.offloader import get_offload_backend
|
||||||
|
from vllm_omni.diffusion.offloader.module_collector import ModuleDiscovery
|
||||||
from vllm_omni.diffusion.registry import _NO_CACHE_ACCELERATION
|
from vllm_omni.diffusion.registry import _NO_CACHE_ACCELERATION
|
||||||
from vllm_omni.diffusion.request import OmniDiffusionRequest
|
from vllm_omni.diffusion.request import OmniDiffusionRequest
|
||||||
from vllm_omni.diffusion.sched.interface import DiffusionSchedulerOutput, KVPrefetchJob
|
from vllm_omni.diffusion.sched.interface import DiffusionSchedulerOutput, KVPrefetchJob
|
||||||
@@ -188,6 +189,39 @@ class DiffusionModelRunner(OmniConnectorModelRunnerMixin):
|
|||||||
compile_dynamic,
|
compile_dynamic,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _compile_vae_decodes(self) -> None:
|
||||||
|
"""Compile declared VAE decode callables with eager fallback."""
|
||||||
|
assert self.pipeline is not None
|
||||||
|
modules = ModuleDiscovery.discover(self.pipeline)
|
||||||
|
compiled_count = 0
|
||||||
|
for name, vae in zip(modules.vae_names, modules.vaes, strict=True):
|
||||||
|
decode = getattr(vae, "decode", None)
|
||||||
|
if not callable(decode):
|
||||||
|
logger.debug("Model runner: VAE component %s has no decode callable; skipping compile.", name)
|
||||||
|
continue
|
||||||
|
|
||||||
|
label = f"VAE component {name}.decode"
|
||||||
|
compiled_decode, activated = compile_callable_with_fallback(
|
||||||
|
decode,
|
||||||
|
label=label,
|
||||||
|
mode="default",
|
||||||
|
fullgraph=False,
|
||||||
|
dynamic=None,
|
||||||
|
)
|
||||||
|
if not activated:
|
||||||
|
continue
|
||||||
|
setattr(vae, "decode", compiled_decode)
|
||||||
|
compiled_count += 1
|
||||||
|
|
||||||
|
if compiled_count:
|
||||||
|
logger.info(
|
||||||
|
"Model runner: configured lazy torch.compile for %d VAE decode callable(s); "
|
||||||
|
"startup warmup will compile the real request path.",
|
||||||
|
compiled_count,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
logger.info("Model runner: no compile-compatible VAE decode callable was discovered.")
|
||||||
|
|
||||||
def load_model(
|
def load_model(
|
||||||
self,
|
self,
|
||||||
memory_pool_context_fn: Callable[[str], AbstractContextManager[Any]] | None = None,
|
memory_pool_context_fn: Callable[[str], AbstractContextManager[Any]] | None = None,
|
||||||
@@ -277,7 +311,8 @@ class DiffusionModelRunner(OmniConnectorModelRunnerMixin):
|
|||||||
# Apply torch.compile if not in eager mode
|
# Apply torch.compile if not in eager mode
|
||||||
if not self.od_config.enforce_eager:
|
if not self.od_config.enforce_eager:
|
||||||
if current_omni_platform.supports_torch_inductor():
|
if current_omni_platform.supports_torch_inductor():
|
||||||
if hasattr(self.pipeline, "setup_compile"):
|
pipeline_owns_compile = hasattr(self.pipeline, "setup_compile")
|
||||||
|
if pipeline_owns_compile:
|
||||||
try:
|
try:
|
||||||
self.pipeline.setup_compile()
|
self.pipeline.setup_compile()
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
@@ -291,6 +326,9 @@ class DiffusionModelRunner(OmniConnectorModelRunnerMixin):
|
|||||||
transformer_attrs = ("transformer", "transformer_2")
|
transformer_attrs = ("transformer", "transformer_2")
|
||||||
for attr_name in transformer_attrs:
|
for attr_name in transformer_attrs:
|
||||||
self._compile_transformer(attr_name)
|
self._compile_transformer(attr_name)
|
||||||
|
|
||||||
|
if self.od_config.diffusion_compile_vae and not pipeline_owns_compile:
|
||||||
|
self._compile_vae_decodes()
|
||||||
else:
|
else:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Model runner: Platform %s does not support torch inductor, skipping torch.compile.",
|
"Model runner: Platform %s does not support torch inductor, skipping torch.compile.",
|
||||||
|
|||||||
@@ -485,6 +485,7 @@ class OrchestratorArgs:
|
|||||||
diffusion_attention_config: str | None = None
|
diffusion_attention_config: str | None = None
|
||||||
diffusion_compile_granularity: str | None = None
|
diffusion_compile_granularity: str | None = None
|
||||||
diffusion_compile_dynamic: bool | None = None
|
diffusion_compile_dynamic: bool | None = None
|
||||||
|
diffusion_compile_vae: bool | None = None
|
||||||
cache_backend: str = "none"
|
cache_backend: str = "none"
|
||||||
cache_config: str | None = None
|
cache_config: str | None = None
|
||||||
enable_cache_dit_summary: bool = False
|
enable_cache_dit_summary: bool = False
|
||||||
|
|||||||
@@ -1043,6 +1043,9 @@ class AsyncOmniEngine:
|
|||||||
"diffusion_compile_dynamic": (
|
"diffusion_compile_dynamic": (
|
||||||
True if kwargs.get("diffusion_compile_dynamic") is None else kwargs["diffusion_compile_dynamic"]
|
True if kwargs.get("diffusion_compile_dynamic") is None else kwargs["diffusion_compile_dynamic"]
|
||||||
),
|
),
|
||||||
|
"diffusion_compile_vae": (
|
||||||
|
True if kwargs.get("diffusion_compile_vae") is None else kwargs["diffusion_compile_vae"]
|
||||||
|
),
|
||||||
"fa_deterministic": bool(kwargs.get("fa_deterministic", False)),
|
"fa_deterministic": bool(kwargs.get("fa_deterministic", False)),
|
||||||
"boundary_ratio": kwargs.get("boundary_ratio", None),
|
"boundary_ratio": kwargs.get("boundary_ratio", None),
|
||||||
"flow_shift": kwargs.get("flow_shift", None),
|
"flow_shift": kwargs.get("flow_shift", None),
|
||||||
@@ -1069,7 +1072,6 @@ class AsyncOmniEngine:
|
|||||||
"streaming_output": kwargs.get("diffusion_streaming_output", False),
|
"streaming_output": kwargs.get("diffusion_streaming_output", False),
|
||||||
"enable_ar_profiler": kwargs.get("enable_ar_profiler", False),
|
"enable_ar_profiler": kwargs.get("enable_ar_profiler", False),
|
||||||
"extras": {
|
"extras": {
|
||||||
**(kwargs.get("extras") or {}),
|
|
||||||
"auxiliary_text_encoder": kwargs.get("auxiliary_text_encoder", None),
|
"auxiliary_text_encoder": kwargs.get("auxiliary_text_encoder", None),
|
||||||
"default_llama_model_id": kwargs.get("default_llama_model_id", "meta-llama/Meta-Llama-3.1-8B-Instruct"),
|
"default_llama_model_id": kwargs.get("default_llama_model_id", "meta-llama/Meta-Llama-3.1-8B-Instruct"),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -446,6 +446,15 @@ class OmniServeCommand(CLISubcommand):
|
|||||||
"Disable for fixed-shape workloads with --no-diffusion-compile-dynamic."
|
"Disable for fixed-shape workloads with --no-diffusion-compile-dynamic."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
omni_config_group.add_argument(
|
||||||
|
"--diffusion-compile-vae",
|
||||||
|
action=argparse.BooleanOptionalAction,
|
||||||
|
default=None,
|
||||||
|
help=(
|
||||||
|
"Compile discovered VAE decode callables when diffusion torch.compile is enabled. "
|
||||||
|
"Use --no-diffusion-compile-vae to keep VAE decode eager."
|
||||||
|
),
|
||||||
|
)
|
||||||
omni_config_group.add_argument(
|
omni_config_group.add_argument(
|
||||||
"--fa-deterministic",
|
"--fa-deterministic",
|
||||||
dest="fa_deterministic",
|
dest="fa_deterministic",
|
||||||
@@ -629,6 +638,7 @@ class OmniServeCommand(CLISubcommand):
|
|||||||
action="store_true",
|
action="store_true",
|
||||||
help="Enable VAE tiling for memory optimization (useful for mitigating OOM issues).",
|
help="Enable VAE tiling for memory optimization (useful for mitigating OOM issues).",
|
||||||
)
|
)
|
||||||
|
|
||||||
# Parallel weight loading (faster diffusion startup)
|
# Parallel weight loading (faster diffusion startup)
|
||||||
omni_config_group.add_argument(
|
omni_config_group.add_argument(
|
||||||
"--disable-multithread-weight-load",
|
"--disable-multithread-weight-load",
|
||||||
|
|||||||
Reference in new issue
Block a user