Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ed153947b | ||
|
|
2c1f2e32f7 |
No files matched your search
@@ -0,0 +1,76 @@
|
|||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import torch
|
||||||
|
|
||||||
|
pytestmark = [pytest.mark.core_model, pytest.mark.cpu, pytest.mark.diffusion]
|
||||||
|
|
||||||
|
|
||||||
|
def test_scheduler_default_skips_large_finite_scans_and_preserves_results(monkeypatch):
|
||||||
|
from vllm_omni.diffusion.models.minimax_h3 import (
|
||||||
|
scheduling_minimax_h3_euler_ancestral as scheduler,
|
||||||
|
)
|
||||||
|
|
||||||
|
monkeypatch.delenv("VLLM_OMNI_H3_VALIDATE_FINITE_TENSORS", raising=False)
|
||||||
|
original_isfinite = torch.isfinite
|
||||||
|
scanned_numels = []
|
||||||
|
|
||||||
|
def record_isfinite(tensor):
|
||||||
|
scanned_numels.append(tensor.numel())
|
||||||
|
return original_isfinite(tensor)
|
||||||
|
|
||||||
|
monkeypatch.setattr(torch, "isfinite", record_isfinite)
|
||||||
|
state = torch.linspace(-1.0, 1.0, 8)
|
||||||
|
velocity = torch.linspace(0.25, -0.25, 8)
|
||||||
|
timestep = torch.tensor(0.5)
|
||||||
|
default_x0 = scheduler.minimax_h3_rf_v_to_x0(state, velocity, timestep)
|
||||||
|
default = scheduler.minimax_h3_euler_eta0_step(
|
||||||
|
state,
|
||||||
|
default_x0,
|
||||||
|
sigma_curr=0.5,
|
||||||
|
sigma_next=0.25,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert scanned_numels == [1]
|
||||||
|
|
||||||
|
checked_x0 = scheduler.minimax_h3_rf_v_to_x0(
|
||||||
|
state,
|
||||||
|
velocity,
|
||||||
|
timestep,
|
||||||
|
validate_finite_tensors=True,
|
||||||
|
)
|
||||||
|
checked = scheduler.minimax_h3_euler_eta0_step(
|
||||||
|
state,
|
||||||
|
checked_x0,
|
||||||
|
sigma_curr=0.5,
|
||||||
|
sigma_next=0.25,
|
||||||
|
validate_finite_tensors=True,
|
||||||
|
)
|
||||||
|
torch.testing.assert_close(default_x0, checked_x0, rtol=0, atol=0)
|
||||||
|
torch.testing.assert_close(default, checked, rtol=0, atol=0)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("invalid_value", [float("nan"), float("inf")])
|
||||||
|
def test_scheduler_finite_gate_rejects_nonfinite_inputs(monkeypatch, invalid_value):
|
||||||
|
from vllm_omni.diffusion.models.minimax_h3 import (
|
||||||
|
scheduling_minimax_h3_euler_ancestral as scheduler,
|
||||||
|
)
|
||||||
|
|
||||||
|
monkeypatch.setenv("VLLM_OMNI_H3_VALIDATE_FINITE_TENSORS", "1")
|
||||||
|
invalid = torch.ones(8)
|
||||||
|
invalid[0] = invalid_value
|
||||||
|
|
||||||
|
with pytest.raises(ValueError, match="must be finite"):
|
||||||
|
scheduler.minimax_h3_rf_v_to_x0(
|
||||||
|
invalid,
|
||||||
|
torch.ones_like(invalid),
|
||||||
|
torch.tensor(0.5),
|
||||||
|
)
|
||||||
|
with pytest.raises(ValueError, match="must be finite"):
|
||||||
|
scheduler.minimax_h3_euler_eta0_step(
|
||||||
|
invalid,
|
||||||
|
torch.ones_like(invalid),
|
||||||
|
sigma_curr=0.5,
|
||||||
|
sigma_next=0.25,
|
||||||
|
)
|
||||||
@@ -20,6 +20,7 @@ from vllm_omni.diffusion.forward_context import set_forward_context_denoise_step
|
|||||||
from .scheduling_minimax_h3_euler_ancestral import (
|
from .scheduling_minimax_h3_euler_ancestral import (
|
||||||
minimax_h3_euler_eta0_step,
|
minimax_h3_euler_eta0_step,
|
||||||
minimax_h3_rf_v_to_x0,
|
minimax_h3_rf_v_to_x0,
|
||||||
|
minimax_h3_validate_finite_tensors_enabled,
|
||||||
)
|
)
|
||||||
|
|
||||||
MINIMAX_H3_IMGVID_COND_TIMESTEP = 0.999
|
MINIMAX_H3_IMGVID_COND_TIMESTEP = 0.999
|
||||||
@@ -198,6 +199,7 @@ def minimax_h3_denoise_loop(
|
|||||||
if audio_anchor is not None:
|
if audio_anchor is not None:
|
||||||
audio_rows[~audio_update] = audio_anchor
|
audio_rows[~audio_update] = audio_anchor
|
||||||
|
|
||||||
|
validate_finite_tensors = minimax_h3_validate_finite_tensors_enabled()
|
||||||
num_steps = len(sigmas_video) - 1
|
num_steps = len(sigmas_video) - 1
|
||||||
for step in range(num_steps):
|
for step in range(num_steps):
|
||||||
step_cm = step_profiler(step) if step_profiler is not None else nullcontext()
|
step_cm = step_profiler(step) if step_profiler is not None else nullcontext()
|
||||||
@@ -231,8 +233,15 @@ def minimax_h3_denoise_loop(
|
|||||||
video_rows[update],
|
video_rows[update],
|
||||||
mv_video_t,
|
mv_video_t,
|
||||||
torch.tensor(t_v, dtype=torch.float32, device=device),
|
torch.tensor(t_v, dtype=torch.float32, device=device),
|
||||||
|
validate_finite_tensors=validate_finite_tensors,
|
||||||
|
)
|
||||||
|
new_target = minimax_h3_euler_eta0_step(
|
||||||
|
video_rows[update],
|
||||||
|
x0_video,
|
||||||
|
sigma_curr=s_v,
|
||||||
|
sigma_next=s_v_next,
|
||||||
|
validate_finite_tensors=validate_finite_tensors,
|
||||||
)
|
)
|
||||||
new_target = minimax_h3_euler_eta0_step(video_rows[update], x0_video, sigma_curr=s_v, sigma_next=s_v_next)
|
|
||||||
video_rows = video_rows.clone()
|
video_rows = video_rows.clone()
|
||||||
video_rows[update] = new_target
|
video_rows[update] = new_target
|
||||||
if cond_anchor is not None:
|
if cond_anchor is not None:
|
||||||
@@ -242,9 +251,14 @@ def minimax_h3_denoise_loop(
|
|||||||
audio_rows[audio_update],
|
audio_rows[audio_update],
|
||||||
mv_audio_t,
|
mv_audio_t,
|
||||||
torch.tensor(t_a, dtype=torch.float32, device=device),
|
torch.tensor(t_a, dtype=torch.float32, device=device),
|
||||||
|
validate_finite_tensors=validate_finite_tensors,
|
||||||
)
|
)
|
||||||
new_audio = minimax_h3_euler_eta0_step(
|
new_audio = minimax_h3_euler_eta0_step(
|
||||||
audio_rows[audio_update], x0_audio, sigma_curr=s_a, sigma_next=s_a_next
|
audio_rows[audio_update],
|
||||||
|
x0_audio,
|
||||||
|
sigma_curr=s_a,
|
||||||
|
sigma_next=s_a_next,
|
||||||
|
validate_finite_tensors=validate_finite_tensors,
|
||||||
)
|
)
|
||||||
audio_rows = audio_rows.clone()
|
audio_rows = audio_rows.clone()
|
||||||
audio_rows[audio_update] = new_audio
|
audio_rows[audio_update] = new_audio
|
||||||
|
|||||||
@@ -2,10 +2,24 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import math
|
import math
|
||||||
|
import os
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import torch
|
import torch
|
||||||
|
|
||||||
|
MINIMAX_H3_VALIDATE_FINITE_TENSORS_ENV = "VLLM_OMNI_H3_VALIDATE_FINITE_TENSORS"
|
||||||
|
|
||||||
|
|
||||||
|
def minimax_h3_validate_finite_tensors_enabled() -> bool:
|
||||||
|
value = os.getenv(MINIMAX_H3_VALIDATE_FINITE_TENSORS_ENV, "")
|
||||||
|
return value.strip().lower() in {"1", "true", "yes", "on"}
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_validate_finite_tensors(value: bool | None) -> bool:
|
||||||
|
if value is None:
|
||||||
|
return minimax_h3_validate_finite_tensors_enabled()
|
||||||
|
return bool(value)
|
||||||
|
|
||||||
|
|
||||||
def _require_finite_tensor(tensor: torch.Tensor, name: str) -> None:
|
def _require_finite_tensor(tensor: torch.Tensor, name: str) -> None:
|
||||||
if not bool(torch.isfinite(tensor).all().item()):
|
if not bool(torch.isfinite(tensor).all().item()):
|
||||||
@@ -50,6 +64,8 @@ def minimax_h3_rf_v_to_x0(
|
|||||||
xt: torch.Tensor,
|
xt: torch.Tensor,
|
||||||
v: torch.Tensor,
|
v: torch.Tensor,
|
||||||
timestep: torch.Tensor,
|
timestep: torch.Tensor,
|
||||||
|
*,
|
||||||
|
validate_finite_tensors: bool | None = None,
|
||||||
) -> torch.Tensor:
|
) -> torch.Tensor:
|
||||||
if xt.shape != v.shape:
|
if xt.shape != v.shape:
|
||||||
raise ValueError(f"xt and v shapes must match, got {xt.shape} vs {v.shape}")
|
raise ValueError(f"xt and v shapes must match, got {xt.shape} vs {v.shape}")
|
||||||
@@ -57,15 +73,18 @@ def minimax_h3_rf_v_to_x0(
|
|||||||
raise ValueError("xt must be a floating point tensor")
|
raise ValueError("xt must be a floating point tensor")
|
||||||
if not torch.is_floating_point(v):
|
if not torch.is_floating_point(v):
|
||||||
raise ValueError("v must be a floating point tensor")
|
raise ValueError("v must be a floating point tensor")
|
||||||
_require_finite_tensor(xt, "xt")
|
validate_finite_tensors = _resolve_validate_finite_tensors(validate_finite_tensors)
|
||||||
_require_finite_tensor(v, "v")
|
if validate_finite_tensors:
|
||||||
|
_require_finite_tensor(xt, "xt")
|
||||||
|
_require_finite_tensor(v, "v")
|
||||||
_validate_unit_timestep(timestep, "timestep")
|
_validate_unit_timestep(timestep, "timestep")
|
||||||
cond_t = timestep.to(device=xt.device, dtype=xt.dtype)
|
cond_t = timestep.to(device=xt.device, dtype=xt.dtype)
|
||||||
while cond_t.ndim < xt.ndim:
|
while cond_t.ndim < xt.ndim:
|
||||||
cond_t = cond_t.unsqueeze(-1)
|
cond_t = cond_t.unsqueeze(-1)
|
||||||
sigma_t = 1 - cond_t
|
sigma_t = 1 - cond_t
|
||||||
x0 = xt + sigma_t * v
|
x0 = xt + sigma_t * v
|
||||||
_require_finite_tensor(x0, "x0")
|
if validate_finite_tensors:
|
||||||
|
_require_finite_tensor(x0, "x0")
|
||||||
return x0
|
return x0
|
||||||
|
|
||||||
|
|
||||||
@@ -75,6 +94,7 @@ def minimax_h3_euler_eta0_step(
|
|||||||
*,
|
*,
|
||||||
sigma_curr: float,
|
sigma_curr: float,
|
||||||
sigma_next: float,
|
sigma_next: float,
|
||||||
|
validate_finite_tensors: bool | None = None,
|
||||||
) -> torch.Tensor:
|
) -> torch.Tensor:
|
||||||
if state.shape != denoised.shape:
|
if state.shape != denoised.shape:
|
||||||
raise ValueError(f"state and denoised shapes must match, got {state.shape} vs {denoised.shape}")
|
raise ValueError(f"state and denoised shapes must match, got {state.shape} vs {denoised.shape}")
|
||||||
@@ -82,8 +102,10 @@ def minimax_h3_euler_eta0_step(
|
|||||||
raise ValueError("state must be a floating point tensor")
|
raise ValueError("state must be a floating point tensor")
|
||||||
if not torch.is_floating_point(denoised):
|
if not torch.is_floating_point(denoised):
|
||||||
raise ValueError("denoised must be a floating point tensor")
|
raise ValueError("denoised must be a floating point tensor")
|
||||||
_require_finite_tensor(state, "state")
|
validate_finite_tensors = _resolve_validate_finite_tensors(validate_finite_tensors)
|
||||||
_require_finite_tensor(denoised, "denoised")
|
if validate_finite_tensors:
|
||||||
|
_require_finite_tensor(state, "state")
|
||||||
|
_require_finite_tensor(denoised, "denoised")
|
||||||
sigma_curr = _validate_sigma(sigma_curr, "sigma_curr")
|
sigma_curr = _validate_sigma(sigma_curr, "sigma_curr")
|
||||||
sigma_next = _validate_sigma(sigma_next, "sigma_next")
|
sigma_next = _validate_sigma(sigma_next, "sigma_next")
|
||||||
if sigma_curr == 0.0:
|
if sigma_curr == 0.0:
|
||||||
@@ -98,7 +120,8 @@ def minimax_h3_euler_eta0_step(
|
|||||||
sigma_ratio = sigma_next_t / sigma_curr_t
|
sigma_ratio = sigma_next_t / sigma_curr_t
|
||||||
out = sigma_ratio * state.to(dtype=compute_dtype) + (1.0 - sigma_ratio) * denoised.to(dtype=compute_dtype)
|
out = sigma_ratio * state.to(dtype=compute_dtype) + (1.0 - sigma_ratio) * denoised.to(dtype=compute_dtype)
|
||||||
out = out.to(dtype=state.dtype)
|
out = out.to(dtype=state.dtype)
|
||||||
_require_finite_tensor(out, "euler_eta0_step output")
|
if validate_finite_tensors:
|
||||||
|
_require_finite_tensor(out, "euler_eta0_step output")
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
@@ -127,6 +150,7 @@ class MiniMaxH3EulerAncestralEta0SchedulerAdapter:
|
|||||||
audio_sigma_curr: float | None = None,
|
audio_sigma_curr: float | None = None,
|
||||||
audio_sigma_next: float | None = None,
|
audio_sigma_next: float | None = None,
|
||||||
) -> dict[str, torch.Tensor]:
|
) -> dict[str, torch.Tensor]:
|
||||||
|
validate_finite_tensors = minimax_h3_validate_finite_tensors_enabled()
|
||||||
visual_timestep = timestep if video_timestep is None else video_timestep
|
visual_timestep = timestep if video_timestep is None else video_timestep
|
||||||
audio_timestep = timestep if audio_timestep is None else audio_timestep
|
audio_timestep = timestep if audio_timestep is None else audio_timestep
|
||||||
visual_sigma_curr = sigma_curr if video_sigma_curr is None else video_sigma_curr
|
visual_sigma_curr = sigma_curr if video_sigma_curr is None else video_sigma_curr
|
||||||
@@ -148,11 +172,13 @@ class MiniMaxH3EulerAncestralEta0SchedulerAdapter:
|
|||||||
input_visual_latent,
|
input_visual_latent,
|
||||||
noise_pred_visual,
|
noise_pred_visual,
|
||||||
visual_timestep,
|
visual_timestep,
|
||||||
|
validate_finite_tensors=validate_finite_tensors,
|
||||||
)
|
)
|
||||||
denoised_audio = minimax_h3_rf_v_to_x0(
|
denoised_audio = minimax_h3_rf_v_to_x0(
|
||||||
input_audio_latent,
|
input_audio_latent,
|
||||||
noise_pred_audio,
|
noise_pred_audio,
|
||||||
audio_timestep,
|
audio_timestep,
|
||||||
|
validate_finite_tensors=validate_finite_tensors,
|
||||||
)
|
)
|
||||||
return {
|
return {
|
||||||
"output_visual_latent": minimax_h3_euler_eta0_step(
|
"output_visual_latent": minimax_h3_euler_eta0_step(
|
||||||
@@ -160,12 +186,14 @@ class MiniMaxH3EulerAncestralEta0SchedulerAdapter:
|
|||||||
denoised_visual,
|
denoised_visual,
|
||||||
sigma_curr=visual_sigma_curr,
|
sigma_curr=visual_sigma_curr,
|
||||||
sigma_next=visual_sigma_next,
|
sigma_next=visual_sigma_next,
|
||||||
|
validate_finite_tensors=validate_finite_tensors,
|
||||||
),
|
),
|
||||||
"output_audio_latent": minimax_h3_euler_eta0_step(
|
"output_audio_latent": minimax_h3_euler_eta0_step(
|
||||||
input_audio_latent,
|
input_audio_latent,
|
||||||
denoised_audio,
|
denoised_audio,
|
||||||
sigma_curr=audio_sigma_curr,
|
sigma_curr=audio_sigma_curr,
|
||||||
sigma_next=audio_sigma_next,
|
sigma_next=audio_sigma_next,
|
||||||
|
validate_finite_tensors=validate_finite_tensors,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,7 +201,9 @@ class MiniMaxH3EulerAncestralEta0SchedulerAdapter:
|
|||||||
EntryClass = MiniMaxH3EulerAncestralEta0SchedulerAdapter
|
EntryClass = MiniMaxH3EulerAncestralEta0SchedulerAdapter
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
"MINIMAX_H3_VALIDATE_FINITE_TENSORS_ENV",
|
||||||
"MiniMaxH3EulerAncestralEta0SchedulerAdapter",
|
"MiniMaxH3EulerAncestralEta0SchedulerAdapter",
|
||||||
"minimax_h3_euler_eta0_step",
|
"minimax_h3_euler_eta0_step",
|
||||||
"minimax_h3_rf_v_to_x0",
|
"minimax_h3_rf_v_to_x0",
|
||||||
|
"minimax_h3_validate_finite_tensors_enabled",
|
||||||
]
|
]
|
||||||
Reference in new issue
Block a user