Coverage for wrapper/wan/run_wan_benchmark.py: 57%
65 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-09 04:47 +0000
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-09 04:47 +0000
1import os
2import time
3import logging
4import torch
6from PIL import Image
8from torch.profiler import profile
9from torch.profiler import ProfilerActivity
11from wrapper_wan21 import Wan21VideoGeneration
13from wan.utils.utils import cache_video
16def main() -> None:
17 NUM_GPUS = 8
18 WORLD_SIZE = int(os.environ.get("WORLD_SIZE", 1))
19 RANK = int(os.environ.get("RANK", 1))
20 GPU = torch.cuda.get_device_name(0)
22 TIMING_LOG_FILE = "timing.csv"
24 # Load the Wan model
25 activities = [ProfilerActivity.CPU, ProfilerActivity.CUDA, ProfilerActivity.XPU]
26 with profile(activities=activities, profile_memory=True, record_shapes=True) as prof:
27 t0 = time.time()
29 parallel_mode = "mixed"
30 # Multiserver setup: ulysses in server and ring across
31 ulysses_size = NUM_GPUS if WORLD_SIZE > NUM_GPUS else WORLD_SIZE
32 ring_size = WORLD_SIZE // NUM_GPUS if WORLD_SIZE > NUM_GPUS else 1
34 if parallel_mode == "ulysses":
35 # Ulysses all GPUs in the cluster
36 ulysses_size = WORLD_SIZE
37 ring_size = 1
38 elif parallel_mode == "ring":
39 # Ring all GPUs in the cluster
40 ulysses_size = 1
41 ring_size = WORLD_SIZE
43 print(f"[{RANK:03d}] Parallel setup: {WORLD_SIZE} GPUs, {ulysses_size} Ulysses, {ring_size} Ring")
44 video_gen = Wan21VideoGeneration(
45 # ulysses_size=ulysses_size,
46 # ring_size=ring_size,
47 param_dtype=torch.bfloat16,
48 # param_dtype=torch.float32,
49 )
50 print(f"[{video_gen.rank}] Loaded model in {time.time() - t0:.3f} seconds {video_gen.load_timer}")
52 # Show profiling data
53 if video_gen.rank == 0:
54 print(prof.key_averages().table(sort_by="cpu_time_total", row_limit=10))
55 print(prof.key_averages().table(sort_by="self_cpu_memory_usage", row_limit=10))
57 # Translated from "wan/configs/shared_config.py"
58 input_neg_prompt = "Gorgeous colors, overexposed, static, blurred details, subtitles, style, artwork, "
59 input_neg_prompt += "painting, picture, still, overall gray, worst quality, low quality, "
60 input_neg_prompt += "JPEG compression residue, ugly, incomplete, extra fingers, poorly drawn hands, "
61 input_neg_prompt += "poorly drawn faces, deformed, disfigured, deformed limbs, fused fingers, "
62 input_neg_prompt += "still picture, cluttered background, three legs, many people in the background, "
63 input_neg_prompt += "walking backwards"
65 # Query 1
66 input_image = Image.open("generated_image.png").convert("RGB") # 640x480
67 input_prompt = "The woman on the right speaks while the man on the left listens."
68 input_neg_prompt = "No camera movement."
70 # Query 2
71 # input_image = Image.open("generated_image_man.png").convert("RGB")
72 # input_image = Image.open("generated_image_man_highres.png").convert("RGB")
73 # input_prompt = "The man is explaining something to another person in the podcast studio."
74 # input_neg_prompt = "No camera movement."
76 # Warm-up run (loading models fully, etc)
77 video = video_gen.generate(
78 img=Image.open("warmup_image.png").convert("RGB"),
79 prompt="Warmup prompt",
80 neg_prompt="Warmup prompt",
81 num_frames=4 + 1,
82 sampling_steps=1,
83 )
85 if video_gen.rank == 0:
86 with open(TIMING_LOG_FILE, "a") as file_timing:
87 file_timing.write(
88 "#run_id,hw,world_size,ulysses_size,ring_size,batch_size,num_frames,sampling_steps,colors,"
89 "frames,height,width,txt_enc,img_enc,vae_enc,sched_setup,dit,sched,vae_dec,total\n")
90 video_size_str = ",".join(map(str, video.size()))
91 file_timing.write(
92 f"w,{GPU},{WORLD_SIZE},{ulysses_size},{ring_size},1,5,1,{video_size_str},{video_gen.gen_timer[-1]}\n")
94 # Timing multiple configurations
95 for run_id in range(1):
96 # for num_frames in [80+1, 4+1, 8+1, 20+1, 40+1, 60+1, 80+1]: # 4n+1
97 for num_frames in [80 + 1]: # 4n+1
98 # for sampling_steps in [10, 1, 2, 4, 5, 6, 8, 10, 20, 50]:
99 for sampling_steps in [10, 50]:
100 t0 = time.time()
101 video = video_gen.generate(
102 img=input_image,
103 prompt=input_prompt,
104 neg_prompt=input_neg_prompt,
105 num_frames=num_frames,
106 sampling_steps=sampling_steps,
107 )
108 total_time_seconds = time.time() - t0
109 logging.info(
110 f"Video generated in {total_time_seconds:.3f} seconds with {num_frames} frames "
111 f"and {sampling_steps} steps.")
113 if video_gen.rank == 0:
114 with open(TIMING_LOG_FILE, "a") as file_timing:
115 video_size_str = ",".join(map(str, video.size()))
116 file_timing.write(
117 f"{run_id},{GPU},{WORLD_SIZE},{ulysses_size},{ring_size},1,{num_frames},"
118 f"{sampling_steps},{video_size_str},{video_gen.gen_timer[-1]}\n")
120 if video_gen.rank == 0:
121 video_file_name = f"gen_video_world{WORLD_SIZE}_u{ulysses_size}_r{ring_size}_" + \
122 f"frames{num_frames}_steps{sampling_steps}_run{run_id}.mp4"
123 cache_video(
124 tensor=video[None],
125 save_file=video_file_name,
126 fps=video_gen.FPS,
127 nrow=1,
128 normalize=True,
129 value_range=(-1, 1))
131 del video_gen
134if __name__ == "__main__":
135 main()