[NPU][Model] Add distilled 4-step sigma schedule support for MiniMax H3 t2va (#5991)
Signed-off-by: Zijun Huang <zijunhua@usc.edu> Co-authored-by: WeiQing Chen <40507679+david6666666@users.noreply.github.com>
This commit is contained in:
1 parent
1f65814fab
commit
1a56953d7a
6 files changed
+377
-3
No files matched your search
@@ -484,6 +484,182 @@ def test_shifted_sigma_schedule_matches_reference_values():
|
||||
)
|
||||
|
||||
|
||||
def test_base_schedule_overrides_the_uniform_sigma_positions():
|
||||
from vllm_omni.diffusion.models.minimax_h3.time_request import (
|
||||
minimax_h3_time_shift_sigmas,
|
||||
)
|
||||
|
||||
base_schedule = [1.0, 0.7, 0.4, 0.15, 0.0]
|
||||
|
||||
video = minimax_h3_time_shift_sigmas(
|
||||
num_steps=len(base_schedule),
|
||||
shift_scale=12.0,
|
||||
base_schedule=base_schedule,
|
||||
)
|
||||
audio = minimax_h3_time_shift_sigmas(
|
||||
num_steps=len(base_schedule),
|
||||
shift_scale=3.0,
|
||||
base_schedule=base_schedule,
|
||||
)
|
||||
|
||||
assert video == pytest.approx([1.0, 0.9655172, 0.8888889, 0.6792453, 0.0], abs=1e-6)
|
||||
assert audio == pytest.approx([1.0, 0.875, 0.6666667, 0.3461539, 0.0], abs=1e-6)
|
||||
assert video != pytest.approx(
|
||||
minimax_h3_time_shift_sigmas(num_steps=len(base_schedule), shift_scale=12.0),
|
||||
abs=1e-6,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"base_schedule",
|
||||
[
|
||||
[0.9, 0.5, 0.0],
|
||||
[1.0, 0.5, 0.1],
|
||||
[1.0, 0.5, 0.5, 0.0],
|
||||
[1.0],
|
||||
[],
|
||||
[1.0, float("nan"), 0.4, 0.0],
|
||||
[1.0, float("inf"), 0.4, 0.0],
|
||||
],
|
||||
)
|
||||
def test_base_schedule_rejects_malformed_positions(base_schedule):
|
||||
from vllm_omni.diffusion.models.minimax_h3.time_request import (
|
||||
minimax_h3_time_shift_sigmas,
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
minimax_h3_time_shift_sigmas(
|
||||
num_steps=max(len(base_schedule), 1),
|
||||
shift_scale=12.0,
|
||||
base_schedule=base_schedule,
|
||||
)
|
||||
|
||||
|
||||
def _distilled_pipeline(diffuse_calls, base_schedule_by_partition):
|
||||
from vllm_omni.diffusion.models.minimax_h3 import MiniMaxH3Pipeline
|
||||
from vllm_omni.diffusion.sched import DMD2SigmaSchedule
|
||||
|
||||
schedules = {
|
||||
partition: None if positions is None else DMD2SigmaSchedule.from_positions(positions)
|
||||
for partition, positions in base_schedule_by_partition.items()
|
||||
}
|
||||
pipeline = object.__new__(MiniMaxH3Pipeline)
|
||||
torch.nn.Module.__init__(pipeline)
|
||||
pipeline.partition = "combined"
|
||||
pipeline.supported_tasks = frozenset({"t2va", "fl2va", "ref2va"})
|
||||
pipeline.default_video_shift = 12.0
|
||||
pipeline.default_audio_shift = 3.0
|
||||
pipeline.device = torch.device("cpu")
|
||||
pipeline.od_config = SimpleNamespace()
|
||||
pipeline._base_schedule_by_partition = schedules
|
||||
pipeline._quality_policy = Mock()
|
||||
pipeline._quality_policy.resolve.return_value = SimpleNamespace(cache_dit=None)
|
||||
pipeline._cache_dit_runtime = SimpleNamespace(prepare=lambda spec: None)
|
||||
pipeline.encode_prompt = Mock(
|
||||
return_value=(
|
||||
torch.ones(1, 2),
|
||||
torch.ones(1, dtype=torch.long),
|
||||
)
|
||||
)
|
||||
|
||||
def diffuse(**kwargs):
|
||||
diffuse_calls.append(kwargs)
|
||||
return torch.zeros(1), torch.zeros(1)
|
||||
|
||||
pipeline.diffuse = diffuse
|
||||
pipeline.decode = Mock(return_value=(torch.zeros(1), torch.zeros(1)))
|
||||
return pipeline
|
||||
|
||||
|
||||
def _t2va_batch(num_inference_steps=None):
|
||||
from vllm_omni.diffusion.request import OmniDiffusionRequest
|
||||
from vllm_omni.diffusion.worker.request_batch import DiffusionRequestBatch
|
||||
from vllm_omni.inputs.data import OmniDiffusionSamplingParams
|
||||
|
||||
sampling = OmniDiffusionSamplingParams(
|
||||
quality="lossless",
|
||||
width=1344,
|
||||
height=768,
|
||||
fps=24,
|
||||
num_frames=124,
|
||||
num_inference_steps=num_inference_steps,
|
||||
extra_args={"task": "t2va", "aspect_ratio": "16:9"},
|
||||
)
|
||||
return DiffusionRequestBatch(
|
||||
[
|
||||
OmniDiffusionRequest(
|
||||
prompt="distilled schedule",
|
||||
sampling_params=sampling,
|
||||
request_id="distilled",
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def test_base_schedule_is_scoped_to_the_serving_partition():
|
||||
"""A distilled FL2VA must not drag a regular Ref2VA onto its step count."""
|
||||
distilled = [1.0, 0.7, 0.4, 0.15, 0.0]
|
||||
pipeline = _distilled_pipeline([], {"fl2va": distilled, "ref2va": None})
|
||||
|
||||
assert pipeline._base_schedule_for_task("t2va").base_schedule == tuple(distilled)
|
||||
assert pipeline._base_schedule_for_task("fl2va").base_schedule == tuple(distilled)
|
||||
assert pipeline._base_schedule_for_task("ref2va") is None
|
||||
|
||||
|
||||
def test_partially_constructed_pipeline_falls_back_to_the_uniform_schedule():
|
||||
from vllm_omni.diffusion.models.minimax_h3 import MiniMaxH3Pipeline
|
||||
|
||||
pipeline = object.__new__(MiniMaxH3Pipeline)
|
||||
|
||||
assert pipeline._base_schedule_for_task("t2va") is None
|
||||
|
||||
|
||||
def test_distilled_forward_reports_denoising_steps_not_sigma_boundaries():
|
||||
diffuse_calls = []
|
||||
base_schedule = [1.0, 0.7, 0.4, 0.15, 0.0]
|
||||
pipeline = _distilled_pipeline(diffuse_calls, {"fl2va": base_schedule, "ref2va": None})
|
||||
|
||||
pipeline.forward(_t2va_batch())
|
||||
|
||||
assert diffuse_calls[0]["base_schedule"] == tuple(base_schedule)
|
||||
# Five boundaries describe four denoising steps.
|
||||
assert diffuse_calls[0]["num_steps"] == 4
|
||||
pipeline._quality_policy.resolve.assert_called_once_with(
|
||||
quality="lossless",
|
||||
num_inference_steps=4,
|
||||
extra_args={"task": "t2va", "aspect_ratio": "16:9"},
|
||||
)
|
||||
|
||||
|
||||
def test_distilled_forward_accepts_the_matching_explicit_step_count():
|
||||
diffuse_calls = []
|
||||
pipeline = _distilled_pipeline(diffuse_calls, {"fl2va": [1.0, 0.7, 0.4, 0.15, 0.0], "ref2va": None})
|
||||
|
||||
pipeline.forward(_t2va_batch(num_inference_steps=4))
|
||||
|
||||
assert diffuse_calls[0]["num_steps"] == 4
|
||||
|
||||
|
||||
def test_distilled_forward_rejects_a_mismatched_explicit_step_count():
|
||||
from vllm_omni.errors import OmniClientError
|
||||
|
||||
pipeline = _distilled_pipeline([], {"fl2va": [1.0, 0.7, 0.4, 0.15, 0.0], "ref2va": None})
|
||||
|
||||
with pytest.raises(OmniClientError, match="must be 4 or omitted"):
|
||||
pipeline.forward(_t2va_batch(num_inference_steps=50))
|
||||
|
||||
|
||||
def test_absent_base_schedule_key_differs_from_an_empty_list():
|
||||
from vllm_omni.diffusion.models.minimax_h3.pipeline_minimax_h3 import (
|
||||
_read_base_schedule,
|
||||
)
|
||||
|
||||
assert _read_base_schedule({}) is None
|
||||
assert _read_base_schedule({"base_schedule": [1.0, 0.5, 0.0]}).base_schedule == (1.0, 0.5, 0.0)
|
||||
with pytest.raises(ValueError):
|
||||
_read_base_schedule({"base_schedule": []})
|
||||
|
||||
|
||||
def test_cudnn_packed_attention_uses_python_length_without_padding_mask():
|
||||
from vllm_omni.diffusion.models.minimax_h3.minimax_h3_transformer import (
|
||||
MiniMaxH3Attention,
|
||||
|
||||
Reference in new issue
Block a user