INC4AI's picture
Upload folder using huggingface_hub
368274e verified
Raw History Blame Contribute Delete
4.99 kB
#!/usr/bin/env python
"""Run the official Wan2.2-Animate-14B example against this quantized repo.
Usage (from the repository root):
python examples/run_example.py --backend native
python examples/run_example.py --backend sage_v2 --steps 20
"""
from __future__ import annotations
import argparse
from pathlib import Path
import imageio.v3 as iio
import numpy as np
import torch
from diffusers import AutoencoderKLWan, WanAnimatePipeline
from diffusers.models.attention_dispatch import (
AttentionBackendName,
_AttentionBackendRegistry,
_check_device_cuda_atleast_smXY,
_check_shape,
)
from diffusers.utils import load_image, load_video
MODEL_DIR = Path(__file__).resolve().parents[1]
EXAMPLE_DIR = Path(__file__).resolve().parent / "animate"
PROMPT = "People in the video are doing actions."
def register_sage_backends() -> None:
from sageattention import sageattn, sageattn_qk_int8_pv_fp16_triton
from sageattn3 import sageattn3_blackwell
def sage_v1(query, key, value, attn_mask=None, is_causal=False, scale=None, **kw):
if attn_mask is not None:
raise ValueError("SAGE_ATTN_1 does not support attn_mask")
return sageattn_qk_int8_pv_fp16_triton(
query, key, value, tensor_layout="NHD", is_causal=is_causal, sm_scale=scale, smooth_k=True
)
def sage_v2(query, key, value, attn_mask=None, is_causal=False, scale=None, **kw):
if attn_mask is not None:
raise ValueError("SAGE_ATTN does not support attn_mask")
return sageattn(query, key, value, tensor_layout="NHD", is_causal=is_causal, sm_scale=scale, smooth_k=True)
def sage_v3(query, key, value, attn_mask=None, is_causal=False, **kw):
if attn_mask is not None:
raise ValueError("SAGE_ATTN_3 does not support attn_mask")
return sageattn3_blackwell(
query.transpose(1, 2).contiguous(),
key.transpose(1, 2).contiguous(),
value.transpose(1, 2).contiguous(),
is_causal=is_causal,
).transpose(1, 2).contiguous()
_AttentionBackendRegistry.register(
AttentionBackendName._SAGE_QK_INT8_PV_FP16_TRITON,
constraints=[_check_device_cuda_atleast_smXY(8, 0), _check_shape],
)(sage_v1)
_AttentionBackendRegistry.register(
AttentionBackendName._SAGE_QK_INT8_PV_FP8_CUDA,
constraints=[_check_device_cuda_atleast_smXY(8, 0), _check_shape],
)(sage_v2)
_AttentionBackendRegistry.register(
AttentionBackendName._SAGE_QK_INT8_PV_FP8_CUDA_SM90,
constraints=[_check_device_cuda_atleast_smXY(10, 0), _check_shape],
)(sage_v3)
BACKENDS = {
"native": "native",
"sage_v1": "_sage_qk_int8_pv_fp16_triton",
"sage_v2": "_sage_qk_int8_pv_fp8_cuda",
"sage_v3": "_sage_qk_int8_pv_fp8_cuda_sm90",
}
def parse_args() -> argparse.Namespace:
p = argparse.ArgumentParser()
p.add_argument("--backend", default="native", choices=sorted(BACKENDS))
p.add_argument("--steps", type=int, default=20)
p.add_argument("--segment-frame-length", type=int, default=77)
p.add_argument("--limit-frames", type=int, default=0)
p.add_argument("--output", default="")
p.add_argument("--no-offload", action="store_true", help="Keep all components on GPU (needs ~68 GB).")
return p.parse_args()
def main() -> None:
args = parse_args()
backend = BACKENDS[args.backend]
if args.backend.startswith("sage"):
register_sage_backends()
vae = AutoencoderKLWan.from_pretrained(MODEL_DIR, subfolder="vae", torch_dtype=torch.float32)
pipe = WanAnimatePipeline.from_pretrained(
MODEL_DIR,
torch_dtype=torch.bfloat16,
vae=vae,
device_map="balanced",
)
if args.no_offload:
pipe.to("cuda")
else:
pipe.reset_device_map()
pipe.enable_model_cpu_offload(device="cuda")
pipe.transformer.set_attention_backend(backend)
image = load_image(str(EXAMPLE_DIR / "src_ref.png"))
pose = load_video(str(EXAMPLE_DIR / "src_pose.mp4"))
face = load_video(str(EXAMPLE_DIR / "src_face.mp4"))
if args.limit_frames:
pose = pose[: args.limit_frames]
face = face[: args.limit_frames]
result = pipe(
image=image,
pose_video=pose,
face_video=face,
prompt=PROMPT,
height=720,
width=1280,
segment_frame_length=args.segment_frame_length,
prev_segment_conditioning_frames=1,
num_inference_steps=args.steps,
mode="animate",
guidance_scale=1.0,
generator=torch.Generator(device="cuda").manual_seed(42),
output_type="np",
)
frames = np.stack([np.asarray(f) for f in result.frames[0]], axis=0)
output = Path(args.output or f"example_{args.backend}.mp4")
iio.imwrite(output, frames, fps=30, codec="libx264", quality=8)
print(f"saved {output} ({frames.shape[0]} frames, {frames.shape[2]}x{frames.shape[1]})")
if __name__ == "__main__":
main()