[perf] FastH3 OmniRef: lossless speed-ups behind default-off switches (#1930)

These speed-ups for the MiniMax-H3 pipelines keep the output bit-identical. Each
one has a switch that is off by default:

- FASTVIDEO_MINIMAX_H3_EXACT_KERNELS: Triton RoPE, AdaLN modulation, gated
  residual and SwiGLU kernels that round to bf16 at the same points as the
  eager ops.
- FASTVIDEO_H3_VSA_HEADS_FIRST_TILE: VSA-H3 tiles are written directly in the
  heads-first layout of the kernel.
- FASTVIDEO_H3_VAE_TILE_PARALLEL: VAE spatial tiles are split across the
  sequence-parallel ranks.
- FASTVIDEO_H3_REF2VA_MEMO_ENTRIES: repeat reference encodes are reused.

The example basic_fasth3_omniref_pdd.py --lossless-accel turns them all on.

On GB200 with 4 GPUs, MiniMax-H3 text to video with audio (124 frames,
1344x768) gives bit-identical frames and audio with the first three switches
on and off.
This commit is contained in:
Davide Locatelli
2026-10-07 15:35:37 -07:00
committed by GitHub
parent 8d2e1cf328
commit e1e2559359
20 changed files with 1744 additions and 158 deletions
@@ -21,12 +21,19 @@ sequence is split across them (sequence parallelism).
References are ordered. Pass them in order with --image / --video / --audio,
for example ``--video dance.mp4 --image outfit.png --audio voice.wav``.
``--lossless-accel`` turns on every bit-identical speed-up the pipeline has
(LOSSLESS_ACCEL_ENV below, plus resident encoders, pinned host memory and the
sequence-parallel VAE); the output is bitwise the same as without it. It keeps
the 63 GB Qwen3-VL text encoder resident on every GPU, so it needs about
125 GB per GPU at four GPUs (B200/B300 class).
"""
from __future__ import annotations
import argparse
import json
import os
from collections.abc import Sequence
from pathlib import Path
from typing import Any
@@ -54,6 +61,21 @@ BASE_COMPONENTS = ("text_encoder", "tokenizer", "processor", "vae", "audio_vae")
MANIFESTS = ("modular_model_index.json", "model_index.json")
# Components the composed directory's manifest must declare, besides its transformer_ref.
MANIFEST_COMPONENTS = ("scheduler", "audio_scheduler", *BASE_COMPONENTS)
# Bit-identical speed-ups that FastVideo reads from the environment. Workers
# inherit it, so these must be set before the generator starts.
LOSSLESS_ACCEL_ENV = {
# Fused NVLink Ulysses all-to-all instead of NCCL plus permute copies.
"FASTVIDEO_ULYSSES_A2A": "auto",
# RoPE, AdaLN modulation / gated residual and SwiGLU kernels that round to
# bf16 exactly where the eager ops do (not the FP32 round-once fusions).
"FASTVIDEO_MINIMAX_H3_EXACT_KERNELS": "all",
# VSA tiles scattered straight into the kernels' heads-first layout.
"FASTVIDEO_H3_VSA_HEADS_FIRST_TILE": "1",
# VAE spatial tiles split across the sequence-parallel ranks.
"FASTVIDEO_H3_VAE_TILE_PARALLEL": "1",
# Content-keyed reuse of repeat reference encodes.
"FASTVIDEO_H3_REF2VA_MEMO_ENTRIES": "16",
}
class _AppendReference(argparse.Action):
@@ -97,6 +119,9 @@ def build_parser() -> argparse.ArgumentParser:
parser.add_argument("--num-frames", type=int, default=124)
parser.add_argument("--seed", type=int, default=0)
parser.add_argument("--num-gpus", type=int, default=1, help="sequence-parallel GPUs (must divide 56 heads)")
parser.add_argument("--lossless-accel",
action="store_true",
help="enable every bit-identical speed-up (output unchanged; about 125 GB per GPU)")
return parser
@@ -201,7 +226,23 @@ def resolve_model(args: argparse.Namespace) -> tuple[Path, dict[str, Any]]:
return compose_model_dir(export_dir, base_dir, composed_dir), contract
def build_generator_config(model_dir: Path, num_gpus: int) -> GeneratorConfig:
def apply_lossless_accel_env() -> None:
"""Set LOSSLESS_ACCEL_ENV, keeping any value already in the environment."""
for name, value in LOSSLESS_ACCEL_ENV.items():
os.environ.setdefault(name, value)
def build_generator_config(model_dir: Path, num_gpus: int, lossless_accel: bool = False) -> GeneratorConfig:
if lossless_accel:
# Resident encoders skip streaming the 63 GB text encoder (and the
# VAEs) from host memory on every clip; pinned buffers copy the
# decoded clip at full PCIe speed; the parallel VAE paths reassemble
# the serial result exactly.
offload = OffloadConfig(dit=False, dit_layerwise=False, text_encoder=False, vae=False, pin_cpu_memory=True)
experimental = {"vae_parallel_decode": num_gpus > 1, "vae_parallel_encode": num_gpus > 1}
else:
offload = OffloadConfig(dit=False, dit_layerwise=False, text_encoder=True, vae=True, pin_cpu_memory=False)
experimental = {}
return GeneratorConfig(
model_path=str(model_dir),
engine=EngineConfig(
@@ -209,13 +250,14 @@ def build_generator_config(model_dir: Path, num_gpus: int) -> GeneratorConfig:
# Shard the DiT across the GPUs rather than holding a full copy on each.
use_fsdp_inference=num_gpus > 1,
parallelism=ParallelismConfig(tp_size=1, sp_size=num_gpus),
offload=OffloadConfig(dit=False, dit_layerwise=False, text_encoder=True, vae=True, pin_cpu_memory=False),
offload=offload,
),
pipeline=PipelineSelection(
workload_type="i2v",
# FastVideo reads the trained fused-block partition and attention
# settings from the composed directory's fastvideo_inference.json.
components=ComponentConfig(override_pipeline_cls_name="MiniMaxH3Ref2VAModularPipeline"),
experimental=experimental,
),
)
@@ -231,7 +273,9 @@ def main() -> None:
f"{contract['vsa_tile_size']}-token tiles, reference keep rate {contract['vsa_ref_keep_rate']}")
references = [MiniMaxH3Reference(source=path, media_type=kind) for kind, path in args.references]
generator = VideoGenerator.from_config(build_generator_config(model_dir, args.num_gpus))
if args.lossless_accel:
apply_lossless_accel_env()
generator = VideoGenerator.from_config(build_generator_config(model_dir, args.num_gpus, args.lossless_accel))
try:
result = generator.generate(
GenerationRequest(