Implement explicit Base FL2VA and Ref2VA profiles, sigma node and native workflow contracts; add Diffusers and ComfyUI-native parity runners, golden evidence, CI jobs, compatibility contracts, and package/release updates. Progress: tracked index and reviewed .secrets.baseline reconciled across 56 public paths; performance matrix regenerated; local Diffusers and native ComfyUI H3 parity PASS; wheel audit PASS (102 files, zero mandatory runtime dependencies). Linux full gate passed pre-pytest stages and reached 2603 passed, 3 skipped, 2 failed. Blockers: the remaining pytest failures are stale native-Windows receipt/matrix fingerprints; this WSL environment cannot execute powershell.exe, cmd.exe, wsl.exe, or PE32+ Windows Python. Hosted Actions evidence is unavailable because GH_TOKEN is invalid. Canonical pinned H1/H2 was not launched because reference/ComfyUI requires comfy-aimdo==0.4.11 while the selected executable environment has 0.4.10. Handoff: regenerate tests/compatibility/fixtures/windows_py313_v1.json natively, regenerate/check the derived compatibility matrix, rerun the Linux full gate, publish the candidate through authenticated hosted CI, then run scripts/run_comfyui_e2e.py --minimax-h3-only against ComfyUI 14b05228 with comfy-aimdo==0.4.11. Keep M6-05 IN_PROGRESS until all gates pass. Detailed local-only records remain in ignored .planning/ and reference/; no weights or credentials are included.
155 lines
5.9 KiB
Python
155 lines
5.9 KiB
Python
"""Run isolated MiniMax H3 Diffusers parity against the pinned unreleased branch."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import importlib
|
|
import importlib.metadata
|
|
import json
|
|
import sys
|
|
from collections.abc import Sequence
|
|
from pathlib import Path
|
|
from typing import Any, cast
|
|
|
|
from scripts.parity.minimax_h3_diffusers_report import (
|
|
NUMPY_VERSION,
|
|
REQUIRED_GRID_POINTS,
|
|
TORCH_VERSION,
|
|
build_parity_report,
|
|
canonical_json,
|
|
)
|
|
from scripts.parity.minimax_h3_official import DIFFUSERS_REVISION
|
|
|
|
|
|
def _require_distribution_version(distribution: str, expected: str) -> str:
|
|
try:
|
|
actual = importlib.metadata.version(distribution)
|
|
except importlib.metadata.PackageNotFoundError as error:
|
|
raise RuntimeError(
|
|
f"missing parity dependency {distribution}=={expected}; "
|
|
"install requirements/parity-minimax-h3-diffusers.txt in an isolated environment"
|
|
) from error
|
|
cpu_build = distribution == "torch" and actual == f"{expected}+cpu"
|
|
if actual != expected and not cpu_build:
|
|
raise RuntimeError(f"parity dependency {distribution} must be {expected}, found {actual}")
|
|
return expected
|
|
|
|
|
|
def _require_diffusers_revision() -> str:
|
|
"""Require a VCS-installed Diffusers distribution at the frozen H3 commit."""
|
|
|
|
try:
|
|
distribution = importlib.metadata.distribution("diffusers")
|
|
except importlib.metadata.PackageNotFoundError as error:
|
|
raise RuntimeError(
|
|
"Diffusers is not installed in the isolated parity environment"
|
|
) from error
|
|
raw_direct_url = distribution.read_text("direct_url.json")
|
|
if not raw_direct_url:
|
|
raise RuntimeError("Diffusers direct_url.json is missing; a VCS commit cannot be proven")
|
|
try:
|
|
direct_url = json.loads(raw_direct_url)
|
|
except json.JSONDecodeError as error:
|
|
raise RuntimeError("Diffusers direct_url.json is malformed") from error
|
|
vcs_info = direct_url.get("vcs_info")
|
|
if not isinstance(vcs_info, dict) or vcs_info.get("commit_id") != DIFFUSERS_REVISION:
|
|
raise RuntimeError("Diffusers is not installed from the pinned MiniMax H3 commit")
|
|
return DIFFUSERS_REVISION
|
|
|
|
|
|
def _tensor_values(tensor: object) -> tuple[float, ...]:
|
|
try:
|
|
detached = tensor.detach() # type: ignore[attr-defined]
|
|
cpu = detached.cpu()
|
|
values = cpu.tolist()
|
|
except (AttributeError, TypeError, ValueError, RuntimeError) as error:
|
|
raise RuntimeError("Diffusers parity tensor cannot be read as CPU values") from error
|
|
if not isinstance(values, list):
|
|
raise RuntimeError("Diffusers parity tensor must flatten to a list")
|
|
return tuple(float(value) for value in values)
|
|
|
|
|
|
def _load_diffusers_cases() -> tuple[dict[int, dict[str, tuple[float, ...]]], dict[str, str]]:
|
|
diffusers_revision = _require_diffusers_revision()
|
|
versions = {
|
|
"device": "cpu",
|
|
"diffusers": importlib.metadata.version("diffusers"),
|
|
"diffusers_revision": diffusers_revision,
|
|
"numpy": _require_distribution_version("numpy", NUMPY_VERSION),
|
|
"python": f"{sys.version_info.major}.{sys.version_info.minor}",
|
|
"torch": _require_distribution_version("torch", TORCH_VERSION),
|
|
}
|
|
torch = importlib.import_module("torch")
|
|
scheduler_module = importlib.import_module("diffusers.schedulers.scheduling_minimax_h3")
|
|
scheduler_type = cast(Any, scheduler_module.MiniMaxH3Scheduler)
|
|
cases: dict[int, dict[str, tuple[float, ...]]] = {}
|
|
with torch.no_grad():
|
|
for points in REQUIRED_GRID_POINTS:
|
|
video_scheduler = scheduler_type(shift=12.0)
|
|
video_scheduler.set_timesteps(num_inference_steps=points, device="cpu")
|
|
audio_scheduler = scheduler_type(shift=3.0)
|
|
audio_scheduler.set_timesteps(num_inference_steps=points, device="cpu")
|
|
cases[points] = {
|
|
"audio": _tensor_values(audio_scheduler.sigmas),
|
|
"video": _tensor_values(video_scheduler.sigmas),
|
|
}
|
|
return cases, versions
|
|
|
|
|
|
def _load_velocity_probe() -> dict[str, object]:
|
|
torch = importlib.import_module("torch")
|
|
scheduler_module = importlib.import_module("diffusers.schedulers.scheduling_minimax_h3")
|
|
scheduler_type = cast(Any, scheduler_module.MiniMaxH3Scheduler)
|
|
scheduler = scheduler_type(shift=12.0)
|
|
scheduler.set_timesteps(num_inference_steps=4, device="cpu")
|
|
sample = torch.tensor((0.25, -0.5), dtype=torch.float32, device="cpu")
|
|
velocity = torch.tensor((0.125, -0.25), dtype=torch.float32, device="cpu")
|
|
timestep = scheduler.timesteps[0]
|
|
with torch.no_grad():
|
|
result = scheduler.step(velocity, timestep, sample)
|
|
return {
|
|
"reference": _tensor_values(result.prev_sample),
|
|
"sample": _tensor_values(sample),
|
|
"sigma": float(scheduler.sigmas[0].item()),
|
|
"sigma_next": float(scheduler.sigmas[1].item()),
|
|
"timestep": float(timestep.item()),
|
|
"velocity": _tensor_values(velocity),
|
|
}
|
|
|
|
|
|
def main(arguments: Sequence[str] | None = None) -> int:
|
|
"""Generate a complete report or fail without creating partial evidence."""
|
|
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--output", type=Path, required=True)
|
|
parsed = parser.parse_args(arguments)
|
|
|
|
try:
|
|
cases, environment = _load_diffusers_cases()
|
|
report = build_parity_report(
|
|
cases,
|
|
velocity_reference=_load_velocity_probe(),
|
|
environment=environment,
|
|
)
|
|
encoded = canonical_json(report)
|
|
except (
|
|
AttributeError,
|
|
ImportError,
|
|
KeyError,
|
|
ModuleNotFoundError,
|
|
RuntimeError,
|
|
TypeError,
|
|
ValueError,
|
|
) as error:
|
|
print(f"PARITY=FAIL\n{error}", file=sys.stderr)
|
|
return 2
|
|
|
|
parsed.output.parent.mkdir(parents=True, exist_ok=True)
|
|
parsed.output.write_text(encoded, encoding="utf-8", newline="\n")
|
|
print(f"PARITY=PASS\nREPORT={parsed.output}")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|