eval ¶
Classes¶
fastvideo.eval.BaseMetric ¶
Abstract base class for all eval metrics.
Two execution shapes:
- Per-sample (
is_set_metric=False, default) — implement :meth:compute. The Evaluator calls it once per input sample and returns one :class:MetricResultper sample.
- Set-vs-set (
is_set_metric=True) — implement :meth:accumulate(called once per sample to buffer features) and :meth:finalize(called once after all samples to compute the corpus-level result). Use :meth:resetto clear buffers and :meth:merge_fromto fold multi-GPU per-worker state together.
Optionally override :meth:setup to eagerly load models. Metrics that chunk along the time dim for memory hardcode their own chunk size in __init__ (see optical_flow for the canonical example). Eval always processes one video per :meth:Evaluator.evaluate call; compute / accumulate receive a single sample, not a batch.
Source code in fastvideo/eval/metrics/base.py
Methods:¶
fastvideo.eval.BaseMetric.compute ¶
compute(sample: dict) -> MetricResult
Per-sample metrics: compute the score for one sample.
sample["video"] is (T, C, H, W) float in [0, 1]. sample["reference"] (if used) has the same shape. Return self._skip(sample, reason) for missing inputs.
Source code in fastvideo/eval/metrics/base.py
fastvideo.eval.BaseMetric.finalize ¶
finalize() -> MetricResult
fastvideo.eval.BaseMetric.merge_from ¶
merge_from(other: BaseMetric) -> None
fastvideo.eval.BaseMetric.reset ¶
fastvideo.eval.BaseMetric.setup ¶
Eagerly load models. Called once by :class:EvalWorker.
Default is a no-op; metrics with no eager state (pixel math, closed-form ops) inherit this. Override only if your metric needs to load weights.
Source code in fastvideo/eval/metrics/base.py
fastvideo.eval.BaseMetric.to ¶
to(device: str | device) -> BaseMetric
fastvideo.eval.EvalResults ¶
EvalResults(samples: list[dict[str, MetricResult]] | None = None, corpus: dict[str, MetricResult] | None = None)
Bases: list
Return type for :meth:Evaluator.evaluate with samples=....
Behaves like a list[dict[str, MetricResult]] — one dict per input sample, in input order — so existing iteration and indexing keeps working. The corpus attribute carries set-metric results (FAD, IS, …) that are properties of the whole input set, not of any individual sample. Empty dict when no set metric ran.
Source code in fastvideo/eval/types.py
fastvideo.eval.Evaluator ¶
Evaluator(metrics: list[str] | str = 'all', device: str = 'cuda:0', num_gpus: int = 1, compile: bool = False, *, loader_threads: int = 1, prefetch_factor: int = 2, pre_upload: bool = True, skip_missing_deps: bool = False)
Pre-initialized scorer for repeated evaluation.
Parameters¶
metrics : list[str] | str Metric names, group prefixes ("vbench"), or "all". device : str Single-GPU device (e.g. "cuda:0"). Ignored when num_gpus > 1. num_gpus : int Number of GPU replicas. Each gets its own :class:EvalWorker. compile : bool Apply :func:torch.compile to each metric's _model. loader_threads : int Background decode threads in the :class:VideoPool. Default 1 (hide decode behind compute). Bump for I/O-heavy benchmark sets where one loader can't keep up with the workers. prefetch_factor : int pool max_size = prefetch_factor * num_workers. Default 2 — one sample being consumed, one prefetched per worker. pre_upload : bool When True (default), the worker performs a single host→device upload of video / reference per sample before the metric loop, and every metric reads from that shared GPU-resident tensor. Without it, each metric pays its own .to(self.device) — N transfers of the same clip for N metrics, which dominates at high resolution. Set False for training-time eval, where keeping a clip resident on GPU across the metric loop would fight the training step for VRAM. skip_missing_deps : bool When True, silently drop explicit metric names whose optional deps aren't importable (with a one-line warning per skipped metric). Default False — an explicit name with a missing dep raises :class:ImportError at construction time. Group selectors ("vbench", "all") always silent-skip regardless of this flag.
Source code in fastvideo/eval/evaluator.py
Methods:¶
fastvideo.eval.Evaluator.evaluate ¶
evaluate(samples: Iterable[dict] | None = None, *, metrics: list[str] | None = None, **kwargs) -> dict[str, MetricResult] | EvalResults
Score one sample (kwargs form) or many samples (list form).
Both forms go through the same :class:VideoPool pipeline; video / reference paths are decoded asynchronously.
Parameters¶
samples : Iterable of sample dicts. Omit and pass kwargs for a single-sample call. metrics : Subset of this Evaluator's registered metrics to actually run on this batch. None (default) runs all registered. Lets a single long-lived Evaluator score different (gen, ref) corpora with different metric subsets across multiple evaluate() calls — e.g. LPIPS on a paired corpus, FVD on an unequal-cardinality corpus — without burning model loads. Set-metric accumulators are reset only for the metrics included in metrics, so state for other set metrics is preserved across calls.
Single sample::
ev.evaluate(video=tensor, text_prompt="...", fps=24.0)
Many samples::
ev.evaluate(samples=[{"video": ..., "reference": ...}, ...])
Many samples with a metric filter::
ev.evaluate(samples=lpips_samples, metrics=["common.lpips"])
ev.evaluate(samples=fvd_samples, metrics=["common.fvd"])
Returns¶
dict[str, MetricResult] for the single-sample form; :class:EvalResults (list-of-dict subclass with .corpus) for the list form.
Source code in fastvideo/eval/evaluator.py
fastvideo.eval.Evaluator.release_cuda_memory ¶
fastvideo.eval.Evaluator.reload ¶
fastvideo.eval.Evaluator.shutdown ¶
fastvideo.eval.Evaluator.unload ¶
fastvideo.eval.MetricResult dataclass ¶
Standard result container returned by all metrics.
score is None when the metric was skipped (e.g. missing required input). Check details["skipped"] for the reason.
fastvideo.eval.Video dataclass ¶
Video(source: Any, fps: float | None = None, frames: Any = None, audio: Any = None, audio_sr: int | None = None)
Path-backed media handle. The :class:VideoPool populates frames (and optionally audio) before the metric loop sees the sample.
Functions:¶
fastvideo.eval.as_video ¶
Coerce path/tensor/Video → :class:Video for the pool to decode.
Path strings and :class:pathlib.Path become Video(source=str(x)); the pool then calls :func:load_video on first use. Tensors become Video(source=None, frames=x) — the pool sees .frames already populated and forwards untouched. :class:Video instances pass through.
Source code in fastvideo/eval/io/inputs.py
fastvideo.eval.ensure_checkpoint ¶
Resolve a model checkpoint path, downloading on miss.
See module docstring for the full source contract. name is used only as the local cache filename for URL sources; ignored otherwise.
Source code in fastvideo/eval/models.py
fastvideo.eval.evaluate ¶
evaluate(generated: Tensor | str | Path, reference: Tensor | str | Path | None = None, metrics: list[str] | str = 'all', device: str = 'cuda', **kwargs) -> dict[str, MetricResult] | list[dict[str, MetricResult]]
One-shot evaluation. For repeated use, prefer :func:create_evaluator.
Parameters¶
generated : Tensor | str | Path Generated video. Either a pre-loaded (T, C, H, W) tensor or a path to an mp4/avi/etc. — paths are decoded by the worker. reference : Tensor | str | Path | None Reference video (same accepted shapes as generated). metrics : list[str] | str Metric names, or "all". device : str PyTorch device string.
Source code in fastvideo/eval/api.py
fastvideo.eval.get_cache_dir ¶
get_cache_dir() -> Path
Eval cache root.
Layout::
get_cache_dir() / models / ← URL-fetched checkpoints (LAION head,
AMT, GRiT, …)
get_cache_dir() / torch / ← redirected ``TORCH_HOME`` (DINO etc.)
get_cache_dir() / clip / ← passed as ``download_root`` to
``clip.load(...)`` callsites
~/.cache/huggingface/hub / ← left at HF's default; widely shared
with other ML projects
Override priority: FASTVIDEO_EVAL_CACHE > ${FASTVIDEO_CACHE_ROOT}/eval.
Metric authors writing new code: when wrapping a third-party loader that has its own cache convention (CLIP's download_root, pyiqa's cache_dir, etc.), pass str(get_cache_dir() / "<library>") so users get a single FASTVIDEO_EVAL_CACHE knob to redirect them all.
Source code in fastvideo/eval/models.py
fastvideo.eval.get_metric ¶
get_metric(name: str, **kwargs: Any) -> BaseMetric
Instantiate a registered metric by name.
Checks that optional dependencies are installed before instantiation and gives a clear install hint pointing at the right extra group.
Source code in fastvideo/eval/registry.py
fastvideo.eval.list_metrics ¶
fastvideo.eval.register ¶
register(name: str)
Decorator to register a metric class.
Usage::
@register("ssim")
class SSIMMetric(BaseMetric):
...
fastvideo.eval.samples_from ¶
samples_from(*, video: PathSpec | None = None, reference: PathSpec | None = None, audio: PathSpec | None = None, reference_audio: PathSpec | None = None, text_prompt: str | None = None, text_prompts: str | Path | list[str] | None = None, fps: float | None = None, auxiliary_info: dict | list[dict] | None = None, extras: dict | list[dict] | None = None, extract_audio: bool | str | Path = False, extract_workers: int = 4) -> list[dict]
Build a samples list from path-style inputs.
Parameters¶
video, reference, audio, reference_audio : File path, directory of files (sorted by name), or any iterable of paths. Pass whichever modalities apply to the metrics you plan to run — they attach to sample["video"] / sample["reference"] / sample["audio"] / sample["reference_audio"] respectively. Video paths are wrapped in :class:Video so :class:VideoPool decodes them lazily in parallel; audio paths stay as strings (audio metrics each load with their own resample / preprocess). text_prompt : A single prompt string broadcast onto every sample. text_prompts : A list of strings (one per sample), or a path to a .jsonl / .json file containing per-sample prompts. fps : Scalar fps broadcast onto every sample. auxiliary_info : Single dict (broadcast) or list of dicts (zipped) for sample["auxiliary_info"] — vbench structured-prompt metrics read this. extras : Catch-all per-sample attachments. Use for metric-specific keys the dedicated kwargs don't cover (scenario, view, actions, calibration, reference_take2, ...). Pass a single dict to broadcast or a list-of-dicts to zip; the keys merge into each sample dict. extract_audio : If truthy, auto-extract audio from each video / reference source into .wav files via PyAV and attach the paths under sample["audio"] / sample["reference_audio"]. Pass a path for a persistent cache, True for a tempdir. Skipped silently for videos with no audio stream; ignored wherever audio / reference_audio is already explicit. extract_workers : Parallel workers for extract_audio.
Returns¶
list[dict] Canonical samples shape — hand directly to :meth:Evaluator.evaluate.
Cardinality and shape¶
Let N = len(generated inputs) (the agreed length of whichever of video / audio you passed). References are attached 1:1 onto the first N samples; any extras (when |ref| > N) become standalone role-tagged samples at the end of the list, so set metrics like FVD see the full reference corpus while per-sample paired metrics like LPIPS only run on the first N pairs.
Notes¶
"Missing" keys are simply absent from the sample dict. Metrics handle them per their own contract (sample.get(...) for optional, sample[...] raises for required, or :meth:BaseMetric._skip for opt-in skip behavior). One fat samples list with many keys can serve many metrics — each reads its subset.
Source code in fastvideo/eval/io/inputs.py
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | |