1+ """Generate one Wan video and score it with VBench metrics.
2+
3+ This example mirrors ``examples/inference/eval/basic_ltx2_eval.py`` but uses
4+ Wan as the text-to-video generator.
5+
6+ Wan outputs are video-only by default, so this script evaluates video metrics
7+ rather than audio metrics. Audio metrics should only be used if an audio track
8+ is explicitly available or muxed into the generated mp4.
9+
10+ The first run downloads the VBench-related checkpoints to
11+ ``~/.cache/fastvideo/eval/``.
12+ """
13+
14+ from pathlib import Path
15+
16+ import torch
17+
18+ from fastvideo import VideoGenerator
19+ from fastvideo .eval import Evaluator
20+ from fastvideo .eval .io import build_eval_kwargs
21+
22+ PROMPT = (
23+ "A cinematic shot of a small dog running through a sunny park, "
24+ "with realistic motion, natural lighting, and a shallow depth of field. "
25+ "The camera follows the dog from the side as it runs across the grass."
26+ )
27+
28+ # VBench sub-metrics meaningful for an arbitrary text-to-video sample.
29+ # Structured-prompt metrics such as vbench.color, vbench.multiple_objects,
30+ # and vbench.scene are excluded because they need prompts built to a
31+ # specific schema.
32+ METRICS = [
33+ "vbench.aesthetic_quality" ,
34+ "vbench.subject_consistency" ,
35+ "vbench.background_consistency" ,
36+ "vbench.imaging_quality" ,
37+ "vbench.temporal_flickering" ,
38+ "vbench.motion_smoothness" ,
39+ "vbench.dynamic_degree" ,
40+ "vbench.overall_consistency" ,
41+ ]
42+
43+ MODEL_PATH = "Wan-AI/Wan2.1-T2V-1.3B-Diffusers"
44+ OUTPUT_PATH = Path ("outputs_video/wan_basic/output_wan_t2v_480_832.mp4" )
45+ FPS = 16.0
46+
47+
48+ def _print_results (results ) -> None :
49+ print ("\n === VBench scores ===" )
50+
51+ for name in METRICS :
52+ if name not in results :
53+ print (f" { name } : MISSING" )
54+ continue
55+
56+ r = results [name ]
57+
58+ if r .score is None :
59+ reason = (
60+ r .details .get ("skipped" , "no score" )
61+ if isinstance (r .details , dict )
62+ else "no score"
63+ )
64+ print (f" { name } : SKIPPED ({ reason } )" )
65+ else :
66+ print (f" { name } : { r .score :.4f} " )
67+
68+ if r .details :
69+ for key , value in r .details .items ():
70+ print (f" { key } : { value } " )
71+
72+
73+ def main () -> None :
74+ OUTPUT_PATH .parent .mkdir (parents = True , exist_ok = True )
75+
76+ # ----- generation -----
77+ if OUTPUT_PATH .exists ():
78+ print (f"[eval] using existing video: { OUTPUT_PATH } " )
79+ else :
80+ print ("[eval] generating Wan video..." )
81+
82+ generator = VideoGenerator .from_pretrained (
83+ MODEL_PATH ,
84+ num_gpus = 1 ,
85+ )
86+
87+ generator .generate_video (
88+ prompt = PROMPT ,
89+ output_path = str (OUTPUT_PATH ),
90+ save_video = True ,
91+ num_frames = 81 ,
92+ height = 480 ,
93+ width = 832 ,
94+ )
95+
96+ generator .shutdown ()
97+
98+ # Free residual CUDA memory before building the evaluator.
99+ torch .cuda .empty_cache ()
100+
101+ # ----- scoring -----
102+ print (f"\n [eval] building evaluator: { METRICS } " )
103+ evaluator = Evaluator (metrics = METRICS )
104+
105+ sample = build_eval_kwargs (
106+ {"prompt" : PROMPT },
107+ str (OUTPUT_PATH ),
108+ fps = FPS ,
109+ )
110+
111+ print (f"[eval] running ({ sample ['video' ].shape [1 ]} frames @ { FPS :g} fps)..." )
112+ results = evaluator .evaluate (** sample )
113+
114+ _print_results (results )
115+
116+
117+ if __name__ == "__main__" :
118+ main ()
0 commit comments