eval
fastvideo.eval.ensure_checkpoint
ensure_checkpoint(name: str, source: str, filename: str | None = None) -> str
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.
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.
fastvideo.eval.EvalResults
EvalResults(samples: list[dict[str, MetricResult]] | None = None, corpus: dict[str, MetricResult] | None = None)
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.
fastvideo.eval.MetricResult
MetricResult(name: str, score: float | None, details: dict[str, Any] = dict())
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
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.
fastvideo.eval.Video.has_frames
has_frames() -> bool
fastvideo.eval.Video.has_audio
has_audio() -> bool
fastvideo.eval.BaseMetric
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.
fastvideo.eval.BaseMetric.to
to(device: str | torch.device) -> BaseMetric
Move metric (and its internal models) to device.
fastvideo.eval.BaseMetric.setup
setup() -> None
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.
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.
fastvideo.eval.BaseMetric.reset
reset() -> None
Clear accumulator state at the start of each evaluate() call.
fastvideo.eval.BaseMetric.accumulate
accumulate(sample: dict) -> None
Buffer per-sample features for a corpus-level metric.
fastvideo.eval.BaseMetric.finalize
finalize() -> MetricResult
Compute the corpus-level result from buffered state.
fastvideo.eval.BaseMetric.merge_from
merge_from(other: BaseMetric) -> None
Multi-GPU: fold another worker's accumulator state into this one.
fastvideo.eval.register
register(name: str)
Decorator to register a metric class.
Usage::
@register("ssim")
class SSIMMetric(BaseMetric):
...
fastvideo.eval.list_metrics
list_metrics() -> list[str]
Return sorted list of all registered metric names.
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.
fastvideo.eval.evaluate
evaluate(generated: torch.Tensor | str | Path, reference: torch.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.
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.
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.
fastvideo.eval.Evaluator.release_cuda_memory
release_cuda_memory() -> None
Free CUDA caches on every replica without dropping models.
fastvideo.eval.Evaluator.unload
unload() -> None
Drop metric refs on every replica. Reverse with :meth:reload.
fastvideo.eval.Evaluator.reload
reload() -> None
Rebuild metrics dropped by :meth:unload.
fastvideo.eval.Evaluator.shutdown
shutdown() -> None
No-op; kept for API compatibility with older callers.
fastvideo.eval.create_evaluator
create_evaluator(metrics: list[str] | str = 'all', device: str = 'cuda:0', num_gpus: int = 1, compile: bool = False, *, skip_missing_deps: bool = False) -> Evaluator
fastvideo.eval.as_video
as_video(x: str | Path | torch.Tensor | Video) -> 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.
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.
fastvideo.eval.samples_from_manifest
samples_from_manifest(manifest: str | Path, *, extract_audio: bool | str | Path = False, extract_workers: int = 4) -> list[dict]
Load canonical eval samples from a JSON or JSONL manifest.
Each row may contain video, audio, reference,
reference_audio, reference_audio_source, text_prompt and
arbitrary metric metadata. reference_audio_source is a media file
whose audio track is extracted when extract_audio is enabled. Paths are
resolved relative to the manifest directory. Video paths are wrapped as
:class:Video handles for lazy decoding; all other keys are preserved.
This is the recommended interface for benchmark generation, where matching
by sample id is safer than independently sorting folders.