perf(video): accuracy-first round 2 for HunyuanVideo-1.5: compile parity, cache quality presets, dual-GPU CFG
Cuts the shipped default's LPIPS vs the bit-exact reference from 0.224 to 0.139 while going faster (24.9 s to 21.2 s at 720p/33f/30 steps, 22.7x vs reference), and makes the remaining speed/accuracy trade a user knob. - inductor precision parity: set emulate_precision_casts=True for the regional compile (fused pointwise kernels kept fp32 intermediates where eager rounds to bf16 between ops); full-clip LPIPS vs bit-exact 0.221 to 0.052 at zero speed cost. Snapshot/restored with the other process-wide backend flags. - cache x compile composition fix: diffusers cache hooks are torch.compiler.disable'd, so every COMPUTED step ran eager (1.69 vs 1.09 s/step) under MagCache/FBCache in both enable orders. Re-point each hook's fn_ref.original_forward at a torch.compile'd wrapper of the same bound method (armed only where the speed layer compiled the block; restored before every disable_cache so the uncached path stays pristine). Balanced MagCache at 50 steps: 1.48x to 2.17x, identical skip counts, bit-identical uncached rerun after enable/disable cycles. - transformer_cache_quality knob (quality|balanced|fast; API + UI + bench) mapping to (threshold, max_skip_steps, retention_ratio). Auto resolves to the near-lossless quality preset (0.06, 2, 0.3; 1.63-1.64x at pairwise LPIPS 0.05-0.09) for the HunyuanVideo-1.5 families and to balanced (the pre-knob values, byte-identical behaviour) everywhere else. - TE auto-quant resolves dense for HunyuanVideo-1.5: TE fp8_dynamic alone moves the clip to LPIPS 0.236 vs bit-exact for zero speed win (the quantised encoder perturbs the conditioning and the trajectory amplifies it chaotically); VAE fp8 stays in auto (0.053, at the compile floor). Explicit schemes honored. - dual-GPU CFG branch parallelism (new diffusion_cfg_parallel.py): transformer proxy + DiT replica on the most-free second CUDA device + worker thread, branch-routed off the pipeline's own cache_context names. Auto engages only where measured bit-identical (eager tier: max abs diff 0.0, 1.66x); the compiled stack is explicit cfg_parallel=on (1.52x over the sequential default; per-device compiled artifacts differ by 1 bf16 ulp/step, documented in the resolved record). Fail-soft gates: family allowlist, guider CFG, pipeline kind, dense DiT, no offload, free-VRAM check; single-GPU loads are untouched and the memory plan stays single-device. - video API: the transformer_cache literal now accepts auto/magcache (an explicit magcache request was rejected at the pydantic layer); the mxfp8 family deny records the round-2 measurement (block-32 MX scaling fixes the zero-row collapse, no black frames, but is latency-neutral at LPIPS 0.37: fails both ship bars). Measured on B200 via the production lever path (video_speedmem_bench.py, which gained a --cache-quality lever and companion-quant isolation configs). Tests: 441 passing across the video inference suite (32 new for cfg-parallel, 20 for presets/arming, 3 for the inductor flag, 2 for TE auto-dense); ruff clean.
This commit is contained in:
parent
f7824b9db1
commit
7dbdd28161
15 changed files with 1929 additions and 22 deletions
|
|
@ -250,6 +250,16 @@ _CONFIGS: dict[str, dict[str, Any]] = {
|
|||
"te_fbcache": dict(
|
||||
te = "auto", vae = "none", dit = "none", speed = "default", attn = "auto", cache = "auto"
|
||||
),
|
||||
# Companion-quant accuracy isolation vs the bit-exact reference (uncached, so the cache
|
||||
# cannot mask it): TE-only and VAE-only on top of the trim+cudnn+compile stack. With the
|
||||
# compile rounding fixed (emulate_precision_casts), the companions are the next-largest
|
||||
# divergence source, and only one of them should pay for it.
|
||||
"diag_te_nocache": dict(
|
||||
te = "auto", vae = "none", dit = "none", speed = "default", attn = "auto", cache = "off"
|
||||
),
|
||||
"diag_vae_nocache": dict(
|
||||
te = "none", vae = "auto", dit = "none", speed = "default", attn = "auto", cache = "off"
|
||||
),
|
||||
"ditfp8_fbcache": dict(
|
||||
te = "none", vae = "none", dit = "auto", speed = "default", attn = "auto", cache = "auto"
|
||||
),
|
||||
|
|
@ -362,6 +372,7 @@ def _apply_levers(
|
|||
force_fp32_vae: bool,
|
||||
default_steps: int,
|
||||
cache_threshold: Optional[float] = None,
|
||||
cache_quality: Optional[str] = None,
|
||||
logger = None,
|
||||
) -> dict:
|
||||
"""Apply the configured levers with the loader's own argument values, in the loader's order:
|
||||
|
|
@ -383,6 +394,8 @@ def _apply_levers(
|
|||
from core.inference.diffusion_cache import (
|
||||
apply_step_cache,
|
||||
auto_cache_mode,
|
||||
auto_cache_quality,
|
||||
normalize_cache_quality,
|
||||
FBCACHE_MIN_STEPS,
|
||||
)
|
||||
|
||||
|
|
@ -467,6 +480,9 @@ def _apply_levers(
|
|||
# HunyuanVideo-1.5 families, FBCache elsewhere.
|
||||
cache_request = auto_cache_mode(fam_name) if default_steps >= FBCACHE_MIN_STEPS else None
|
||||
if cache_request is not None:
|
||||
# Quality preset resolution, exactly like the loader (video.py): an unset
|
||||
# request takes the family's measured auto default.
|
||||
quality = normalize_cache_quality(cache_quality) or auto_cache_quality(fam_name)
|
||||
for v in views:
|
||||
engaged["cache"] = apply_step_cache(
|
||||
v,
|
||||
|
|
@ -475,6 +491,7 @@ def _apply_levers(
|
|||
quant_active = dit_quant_active,
|
||||
family = fam_name,
|
||||
steps = default_steps,
|
||||
quality = quality,
|
||||
logger = logger,
|
||||
)
|
||||
cache_active = engaged["cache"] not in (None, "off")
|
||||
|
|
@ -525,6 +542,7 @@ def _timed_video(
|
|||
default_steps,
|
||||
guidance_via_guider = False,
|
||||
cache_threshold = None,
|
||||
cache_quality = None,
|
||||
family = None,
|
||||
logger = None,
|
||||
):
|
||||
|
|
@ -532,7 +550,12 @@ def _timed_video(
|
|||
exactly like the loader, then times total + per-step. Returns (output, total_s, [per_step_ms])."""
|
||||
import torch
|
||||
|
||||
from core.inference.diffusion_cache import auto_cache_mode, maybe_toggle_step_cache
|
||||
from core.inference.diffusion_cache import (
|
||||
auto_cache_mode,
|
||||
auto_cache_quality,
|
||||
maybe_toggle_step_cache,
|
||||
normalize_cache_quality,
|
||||
)
|
||||
|
||||
if cache_mode == "auto":
|
||||
# Toggle on EVERY expert view, exactly like the loader's per-view recheck
|
||||
|
|
@ -551,6 +574,8 @@ def _timed_video(
|
|||
threshold = cache_threshold,
|
||||
mode = auto_cache_mode(family),
|
||||
family = family,
|
||||
quality = normalize_cache_quality(cache_quality)
|
||||
or auto_cache_quality(family),
|
||||
logger = logger,
|
||||
)
|
||||
except Exception:
|
||||
|
|
@ -632,6 +657,7 @@ def _run_config(
|
|||
iters: int,
|
||||
out: Path,
|
||||
cache_threshold: Optional[float] = None,
|
||||
cache_quality: Optional[str] = None,
|
||||
logger = None,
|
||||
):
|
||||
import numpy as np
|
||||
|
|
@ -668,6 +694,7 @@ def _run_config(
|
|||
force_fp32_vae = force_fp32,
|
||||
default_steps = default_steps,
|
||||
cache_threshold = cache_threshold,
|
||||
cache_quality = cache_quality,
|
||||
logger = logger,
|
||||
)
|
||||
pipe = pipe.to("cuda")
|
||||
|
|
@ -693,6 +720,7 @@ def _run_config(
|
|||
default_steps = default_steps,
|
||||
guidance_via_guider = gvg,
|
||||
cache_threshold = cache_threshold,
|
||||
cache_quality = cache_quality,
|
||||
family = family,
|
||||
logger = logger,
|
||||
)
|
||||
|
|
@ -714,6 +742,7 @@ def _run_config(
|
|||
default_steps = default_steps,
|
||||
guidance_via_guider = gvg,
|
||||
cache_threshold = cache_threshold,
|
||||
cache_quality = cache_quality,
|
||||
family = family,
|
||||
logger = logger,
|
||||
)
|
||||
|
|
@ -770,6 +799,7 @@ def _run_config(
|
|||
"speed_optims": engaged["speed_optims"],
|
||||
"attn_trim": engaged.get("attn_trim", False),
|
||||
"cache_threshold": cache_threshold,
|
||||
"cache_quality": cache_quality,
|
||||
"cache_marker": getattr(getattr(pipe, "transformer", None), "_unsloth_step_cache", None),
|
||||
"load_peak_gb": round(load_peak, 2),
|
||||
"weights_gb": round(weights_gb, 2),
|
||||
|
|
@ -804,6 +834,12 @@ def main(argv = None) -> int:
|
|||
default = None,
|
||||
help = "FBCache residual-diff threshold override (None -> the production default)",
|
||||
)
|
||||
ap.add_argument(
|
||||
"--cache-quality",
|
||||
default = None,
|
||||
choices = ("quality", "balanced", "fast"),
|
||||
help = "Step-cache quality preset (None -> the family's production auto default)",
|
||||
)
|
||||
args = ap.parse_args(argv)
|
||||
|
||||
import logging
|
||||
|
|
@ -859,6 +895,7 @@ def main(argv = None) -> int:
|
|||
iters = args.iters,
|
||||
out = out,
|
||||
cache_threshold = args.cache_threshold,
|
||||
cache_quality = args.cache_quality,
|
||||
logger = logger,
|
||||
)
|
||||
if n == "reference":
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue