[feat] add MXFP8 support on H3 (#1796)
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
"""Generate 5-second FastH3 videos with a supported Preview adapter."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import statistics
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
from huggingface_hub import hf_hub_download
|
||||
|
||||
FASTVIDEO_ROOT = Path(__file__).resolve().parents[3]
|
||||
sys.path.insert(0, str(FASTVIDEO_ROOT))
|
||||
|
||||
from fastvideo import VideoGenerator # noqa: E402
|
||||
from fastvideo.api import ( # noqa: E402
|
||||
CompileConfig,
|
||||
ComponentConfig,
|
||||
EngineConfig,
|
||||
GenerationRequest,
|
||||
GeneratorConfig,
|
||||
OffloadConfig,
|
||||
OutputConfig,
|
||||
ParallelismConfig,
|
||||
PipelineSelection,
|
||||
SamplingConfig,
|
||||
)
|
||||
|
||||
# FastVideo exposes these three backend switches only through environment variables.
|
||||
os.environ.update({
|
||||
"FASTVIDEO_FA4": "1",
|
||||
"FASTVIDEO_MINIMAX_H3_FUSIONS": "all",
|
||||
"FASTVIDEO_VSA_SM100A": "0",
|
||||
})
|
||||
os.environ.pop("FASTVIDEO_INFERENCE_TORCH_COMPILE", None)
|
||||
|
||||
VARIANT_BACKENDS = {
|
||||
"dense-datafree": "FLASH_ATTN",
|
||||
"vsa-datafree": "VIDEO_SPARSE_ATTN_H3",
|
||||
"vsa-synthetic-step1300": "VIDEO_SPARSE_ATTN_H3",
|
||||
"vsa-synthetic-step1900": "VIDEO_SPARSE_ATTN_H3",
|
||||
}
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("variant", choices=VARIANT_BACKENDS)
|
||||
parser.add_argument("--prompt", required=True)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Run one compile warmup and three measured generations with one fixed recipe."""
|
||||
args = parse_args()
|
||||
|
||||
attention_backend = VARIANT_BACKENDS[args.variant]
|
||||
experimental = {
|
||||
"attention_backend": attention_backend,
|
||||
"inference_torch_compile": attention_backend == "FLASH_ATTN",
|
||||
"vae_parallel_decode": True,
|
||||
"vae_parallel_decode_strategy": "gather",
|
||||
}
|
||||
if attention_backend == "VIDEO_SPARSE_ATTN_H3":
|
||||
experimental.update({
|
||||
"VSA_sparsity": 0.9,
|
||||
"VSA_tile_size": 64,
|
||||
})
|
||||
|
||||
adapter_path = hf_hub_download(
|
||||
repo_id="FastVideo/FastVideo-FastH3-4-step-Preview-v1-LoRA",
|
||||
filename=f"{args.variant}/adapter_model.safetensors",
|
||||
)
|
||||
output_dir = FASTVIDEO_ROOT / "outputs/fasth3_lora_preview" / args.variant
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
generator = VideoGenerator.from_config(
|
||||
GeneratorConfig(
|
||||
model_path="MiniMaxAI/MiniMax-H3",
|
||||
pipeline=PipelineSelection(
|
||||
components=ComponentConfig(lora_path=adapter_path, lora_strength=1.0),
|
||||
experimental=experimental,
|
||||
),
|
||||
engine=EngineConfig(
|
||||
num_gpus=4,
|
||||
parallelism=ParallelismConfig(tp_size=1, sp_size=4),
|
||||
offload=OffloadConfig(dit=False, dit_layerwise=False),
|
||||
compile=CompileConfig(vae_enabled=True),
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
generation_count = 4
|
||||
warmup_count = 1
|
||||
measured_count = generation_count - warmup_count
|
||||
measured_seconds: list[float] = []
|
||||
|
||||
print(f"Variant: {args.variant} ({attention_backend})")
|
||||
print(f"Output directory: {output_dir}")
|
||||
try:
|
||||
for generation_index in range(generation_count):
|
||||
measured = generation_index >= warmup_count
|
||||
if measured:
|
||||
measured_index = generation_index - warmup_count + 1
|
||||
label = f"measured {measured_index}/{measured_count}"
|
||||
output_path = output_dir / f"fasth3_all_run_{measured_index:02d}.mp4"
|
||||
else:
|
||||
warmup_index = generation_index + 1
|
||||
label = f"warmup {warmup_index}/{warmup_count}"
|
||||
output_path = output_dir / f"_fasth3_warmup_{warmup_index:02d}.mp4"
|
||||
|
||||
request = GenerationRequest(
|
||||
prompt=args.prompt,
|
||||
negative_prompt="",
|
||||
sampling=SamplingConfig(
|
||||
height=768,
|
||||
width=1344,
|
||||
num_frames=345, # <-- Change video length: 5sec: 124; 10sec: 243; 15sec: 345.
|
||||
fps=24,
|
||||
num_inference_steps=5,
|
||||
guidance_scale=1.0,
|
||||
batch_cfg=False,
|
||||
seed=1000,
|
||||
),
|
||||
output=OutputConfig(
|
||||
output_path=str(output_path),
|
||||
save_video=True,
|
||||
return_frames=False,
|
||||
),
|
||||
)
|
||||
started = time.perf_counter()
|
||||
result = generator.generate(request)
|
||||
elapsed = time.perf_counter() - started
|
||||
if measured:
|
||||
measured_seconds.append(elapsed)
|
||||
suffix = "" if measured else " (excluded from median)"
|
||||
print(f"[{label}] {result.video_path or output_path}: {elapsed:.3f}s{suffix}")
|
||||
finally:
|
||||
generator.shutdown()
|
||||
|
||||
print(f"Median E2E wall time: {statistics.median(measured_seconds):.3f}s")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
PROMPT="integrated_multimodal_description: A red fox runs through fresh snow at dawn. overall_soundscape: Fast pawsteps in snow, winter wind, and distant birds."
|
||||
|
||||
# Options: dense-datafree, vsa-datafree, vsa-synthetic-step1300, vsa-synthetic-step1900
|
||||
VARIANT="vsa-datafree"
|
||||
|
||||
exec python "$(dirname "$0")/basic_fasth3_simplified.py" \
|
||||
"$VARIANT" \
|
||||
--prompt "$PROMPT"
|
||||
@@ -0,0 +1,126 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
"""Profile one FastH3 Preview generation with NVTX after warmup."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
import torch
|
||||
from huggingface_hub import hf_hub_download
|
||||
|
||||
from fastvideo import VideoGenerator
|
||||
from fastvideo.api import (
|
||||
CompileConfig,
|
||||
ComponentConfig,
|
||||
EngineConfig,
|
||||
GenerationRequest,
|
||||
GeneratorConfig,
|
||||
OffloadConfig,
|
||||
OutputConfig,
|
||||
ParallelismConfig,
|
||||
PipelineSelection,
|
||||
QuantizationConfig,
|
||||
SamplingConfig,
|
||||
)
|
||||
from fastvideo.profiler import nvtx_range
|
||||
|
||||
VARIANT_BACKENDS = {
|
||||
"dense-datafree": "FLASH_ATTN",
|
||||
"vsa-datafree": "VIDEO_SPARSE_ATTN_H3",
|
||||
"vsa-synthetic-step1300": "VIDEO_SPARSE_ATTN_H3",
|
||||
"vsa-synthetic-step1900": "VIDEO_SPARSE_ATTN_H3",
|
||||
}
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("variant", choices=VARIANT_BACKENDS)
|
||||
parser.add_argument("--prompt", required=True)
|
||||
parser.add_argument("--output", required=True)
|
||||
parser.add_argument("--num-frames", type=int, default=345)
|
||||
parser.add_argument("--warmup-runs", type=int, default=3)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Warm the selected FastH3 recipe, then profile one identical generation."""
|
||||
args = parse_args()
|
||||
output_dir = Path(args.output)
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
attention_backend = VARIANT_BACKENDS[args.variant]
|
||||
experimental = {
|
||||
"attention_backend": attention_backend,
|
||||
"inference_torch_compile": attention_backend == "FLASH_ATTN",
|
||||
"vae_parallel_decode": True,
|
||||
"vae_parallel_decode_strategy": "gather",
|
||||
}
|
||||
if attention_backend == "VIDEO_SPARSE_ATTN_H3":
|
||||
experimental.update({
|
||||
"VSA_sparsity": 0.9,
|
||||
"VSA_tile_size": 64,
|
||||
})
|
||||
|
||||
adapter_path = hf_hub_download(
|
||||
repo_id="FastVideo/FastVideo-FastH3-4-step-Preview-v1-LoRA",
|
||||
filename=f"{args.variant}/adapter_model.safetensors",
|
||||
)
|
||||
generator = VideoGenerator.from_config(
|
||||
GeneratorConfig(
|
||||
model_path="MiniMaxAI/MiniMax-H3",
|
||||
pipeline=PipelineSelection(
|
||||
components=ComponentConfig(lora_path=adapter_path, lora_strength=1.0),
|
||||
experimental=experimental,
|
||||
),
|
||||
engine=EngineConfig(
|
||||
num_gpus=4,
|
||||
parallelism=ParallelismConfig(tp_size=1, sp_size=4),
|
||||
offload=OffloadConfig(dit=False, dit_layerwise=False),
|
||||
compile=CompileConfig(vae_enabled=True),
|
||||
quantization=QuantizationConfig(transformer_quant="MXFP8"),
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
request = GenerationRequest(
|
||||
prompt=args.prompt,
|
||||
negative_prompt="",
|
||||
sampling=SamplingConfig(
|
||||
height=768,
|
||||
width=1344,
|
||||
num_frames=args.num_frames,
|
||||
fps=24,
|
||||
num_inference_steps=5,
|
||||
guidance_scale=1.0,
|
||||
batch_cfg=False,
|
||||
seed=1000,
|
||||
),
|
||||
output=OutputConfig(
|
||||
output_path=str(output_dir / "fasth3_profile.mp4"),
|
||||
save_video=True,
|
||||
return_frames=False,
|
||||
),
|
||||
)
|
||||
|
||||
try:
|
||||
for warmup_index in range(args.warmup_runs):
|
||||
warmup_result = generator.generate(request)
|
||||
print(f"Warmup {warmup_index + 1}/{args.warmup_runs}: {warmup_result.video_path}")
|
||||
|
||||
torch.cuda.profiler.start()
|
||||
try:
|
||||
with nvtx_range("fasth3.profiled_generation"):
|
||||
measured_result = generator.generate(request)
|
||||
finally:
|
||||
torch.cuda.profiler.stop()
|
||||
|
||||
print(f"Profiled output: {measured_result.video_path}")
|
||||
if measured_result.generation_time is not None:
|
||||
print(f"Generation time: {measured_result.generation_time:.2f}s")
|
||||
finally:
|
||||
generator.shutdown()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env bash
|
||||
# Capture one FastH3 Preview generation with CUDA and FastVideo NVTX ranges.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||
WORKTREE_ROOT="$(cd -- "${SCRIPT_DIR}/../../.." && pwd)"
|
||||
WORKSPACE_ROOT="$(cd -- "${WORKTREE_ROOT}/.." && pwd)"
|
||||
PYTHON_BIN="${WORKSPACE_ROOT}/.venv-fv/bin/python"
|
||||
NSYS_BIN=/usr/local/cuda/bin/nsys
|
||||
PROFILE_SCRIPT="${SCRIPT_DIR}/basic_fasth3_simplified_profile.py"
|
||||
|
||||
export CUDA_VISIBLE_DEVICES=0,1,2,3
|
||||
export FASTVIDEO_FA4=1
|
||||
export FASTVIDEO_INFERENCE_TORCH_COMPILE=0
|
||||
export FASTVIDEO_MINIMAX_H3_FUSIONS=all
|
||||
export FASTVIDEO_NVTX_PROFILE=1
|
||||
export FASTVIDEO_VSA_SM100A=0
|
||||
export PYTHONUNBUFFERED=1
|
||||
export PYTHONPATH="${WORKTREE_ROOT}${PYTHONPATH:+:${PYTHONPATH}}"
|
||||
|
||||
PROMPT="integrated_multimodal_description: A red fox runs through fresh snow at dawn. overall_soundscape: Fast pawsteps in snow, winter wind, and distant birds."
|
||||
|
||||
# Options: dense-datafree, vsa-datafree, vsa-synthetic-step1300, vsa-synthetic-step1900
|
||||
VARIANT="vsa-datafree"
|
||||
NUM_FRAMES=345
|
||||
WARMUP_RUNS=3
|
||||
|
||||
PROFILE_ID="${VARIANT}_4gpu_sp4_${NUM_FRAMES}frames"
|
||||
RUN_ID="$(date -u +%Y%m%dT%H%M%SZ)-$$"
|
||||
RESULT_DIR="${WORKTREE_ROOT}/runs/fasth3_lora_preview_profile/${PROFILE_ID}/${RUN_ID}"
|
||||
MEDIA_DIR="${RESULT_DIR}/media"
|
||||
RUN_LOG="${RESULT_DIR}/run.log"
|
||||
mkdir -p "${MEDIA_DIR}"
|
||||
|
||||
"${NSYS_BIN}" profile \
|
||||
--trace=cuda,nvtx \
|
||||
--sample=none \
|
||||
--cpuctxsw=none \
|
||||
--capture-range=cudaProfilerApi \
|
||||
--capture-range-end=stop \
|
||||
--output="${RESULT_DIR}/${PROFILE_ID}" \
|
||||
"${PYTHON_BIN}" "${PROFILE_SCRIPT}" \
|
||||
"${VARIANT}" \
|
||||
--num-frames "${NUM_FRAMES}" \
|
||||
--warmup-runs "${WARMUP_RUNS}" \
|
||||
--prompt "${PROMPT}" \
|
||||
--output "${MEDIA_DIR}" \
|
||||
2>&1 | tee "${RUN_LOG}"
|
||||
|
||||
printf 'RESULT_DIR=%s\n' "${RESULT_DIR}"
|
||||
printf 'NSYS_REPORT=%s\n' "${RESULT_DIR}/${PROFILE_ID}.nsys-rep"
|
||||
printf 'MEDIA_DIR=%s\n' "${MEDIA_DIR}"
|
||||
Reference in New Issue
Block a user