---
title: eval
---

<div class="python-reference">
<a id="fastvideo.eval-classes"></a>
<a id="fastvideo.eval-functions"></a>
<a id="fastvideo.eval.BaseMetric-functions"></a>
<a id="fastvideo.eval.Evaluator-functions"></a>
<a id="fastvideo.eval.Evaluator--parameters"></a>
<a id="fastvideo.eval.evaluate--parameters"></a>
<a id="fastvideo.eval.samples_from--parameters"></a>
<a id="fastvideo.eval.samples_from--returns"></a>
<a id="fastvideo.eval.samples_from--cardinality-and-shape"></a>
<a id="fastvideo.eval.samples_from--notes"></a>
<a id="fastvideo.eval.Evaluator.evaluate--parameters"></a>
<a id="fastvideo.eval.Evaluator.evaluate--returns"></a>
<a id="fastvideo.eval"></a>

<h2 id="fastvideo.eval.ensure_checkpoint"><code>fastvideo.eval.ensure_checkpoint</code></h2>
<pre class="doc-signature"><code>ensure_checkpoint(name: str, source: str, filename: str | None = None) -&gt; str</code></pre>
<p>Resolve a model checkpoint path, downloading on miss.</p>
<p>See module docstring for the full source contract. <em>name</em> is used
only as the local cache filename for URL sources; ignored otherwise.</p>
<h2 id="fastvideo.eval.get_cache_dir"><code>fastvideo.eval.get_cache_dir</code></h2>
<pre class="doc-signature"><code>get_cache_dir() -&gt; Path</code></pre>
<p>Eval cache root.</p>
<p>Layout::</p>
<pre><code>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
</code></pre>
<p>Override priority: <code>FASTVIDEO_EVAL_CACHE</code> &gt; <code>$&#123;FASTVIDEO_CACHE_ROOT&#125;/eval</code>.</p>
<p>Metric authors writing new code: when wrapping a third-party loader
that has its own cache convention (CLIP's <code>download_root</code>, pyiqa's
<code>cache_dir</code>, etc.), pass <code>str(get_cache_dir() / "&lt;library&gt;")</code> so
users get a single <code>FASTVIDEO_EVAL_CACHE</code> knob to redirect them all.</p>
<h2 id="fastvideo.eval.EvalResults"><code>fastvideo.eval.EvalResults</code></h2>
<pre class="doc-signature"><code>EvalResults(samples: list&#91;dict&#91;str, MetricResult&#93;&#93; | None = None, corpus: dict&#91;str, MetricResult&#93; | None = None)</code></pre>
<p>Return type for :meth:<code>Evaluator.evaluate</code> with <code>samples=...</code>.</p>
<p>Behaves like a <code>list[dict[str, MetricResult]]</code> — one dict per
input sample, in input order — so existing iteration and indexing
keeps working. The <code>corpus</code> 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.</p>

<h2 id="fastvideo.eval.MetricResult"><code>fastvideo.eval.MetricResult</code></h2>
<pre class="doc-signature"><code>MetricResult(name: str, score: float | None, details: dict&#91;str, Any&#93; = dict())</code></pre>
<p>Standard result container returned by all metrics.</p>
<p><code>score</code> is <code>None</code> when the metric was skipped (e.g. missing
required input).  Check <code>details["skipped"]</code> for the reason.</p>

<h2 id="fastvideo.eval.Video"><code>fastvideo.eval.Video</code></h2>
<pre class="doc-signature"><code>Video(source: Any, fps: float | None = None, frames: Any = None, audio: Any = None, audio_sr: int | None = None)</code></pre>
<p>Path-backed media handle. The :class:<code>VideoPool</code> populates
<code>frames</code> (and optionally <code>audio</code>) before the metric loop sees
the sample.</p>

<h3 id="fastvideo.eval.Video.has_frames"><code>fastvideo.eval.Video.has_frames</code></h3>
<pre class="doc-signature"><code>has_frames() -&gt; bool</code></pre>

<h3 id="fastvideo.eval.Video.has_audio"><code>fastvideo.eval.Video.has_audio</code></h3>
<pre class="doc-signature"><code>has_audio() -&gt; bool</code></pre>

<h2 id="fastvideo.eval.BaseMetric"><code>fastvideo.eval.BaseMetric</code></h2>
<pre class="doc-signature"><code>BaseMetric()</code></pre>
<p>Abstract base class for all eval metrics.</p>
<p>Two execution shapes:</p>
<ul>
<li>
<p><strong>Per-sample</strong> (<code>is_set_metric=False</code>, default) — implement
  :meth:<code>compute</code>. The Evaluator calls it once per input sample and
  returns one :class:<code>MetricResult</code> per sample.</p>
</li>
<li>
<p><strong>Set-vs-set</strong> (<code>is_set_metric=True</code>) — implement
  :meth:<code>accumulate</code> (called once per sample to buffer features)
  and :meth:<code>finalize</code> (called once after all samples to compute
  the corpus-level result). Use :meth:<code>reset</code> to clear buffers and
  :meth:<code>merge_from</code> to fold multi-GPU per-worker state together.</p>
</li>
</ul>
<p>Optionally override :meth:<code>setup</code> to eagerly load models. Metrics
that chunk along the time dim for memory hardcode their own chunk
size in <code>__init__</code> (see <code>optical_flow</code> for the canonical
example). Eval always processes one video per
:meth:<code>Evaluator.evaluate</code> call; <code>compute</code> / <code>accumulate</code>
receive a single sample, not a batch.</p>

<h3 id="fastvideo.eval.BaseMetric.to"><code>fastvideo.eval.BaseMetric.to</code></h3>
<pre class="doc-signature"><code>to(device: str | torch.device) -&gt; BaseMetric</code></pre>
<p>Move metric (and its internal models) to <em>device</em>.</p>
<h3 id="fastvideo.eval.BaseMetric.setup"><code>fastvideo.eval.BaseMetric.setup</code></h3>
<pre class="doc-signature"><code>setup() -&gt; None</code></pre>
<p>Eagerly load models. Called once by :class:<code>EvalWorker</code>.</p>
<p>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.</p>
<h3 id="fastvideo.eval.BaseMetric.compute"><code>fastvideo.eval.BaseMetric.compute</code></h3>
<pre class="doc-signature"><code>compute(sample: dict) -&gt; MetricResult</code></pre>
<p>Per-sample metrics: compute the score for one sample.</p>
<p><code>sample["video"]</code> is <code>(T, C, H, W)</code> float in <code>[0, 1]</code>.
<code>sample["reference"]</code> (if used) has the same shape. Return
<code>self._skip(sample, reason)</code> for missing inputs.</p>
<h3 id="fastvideo.eval.BaseMetric.reset"><code>fastvideo.eval.BaseMetric.reset</code></h3>
<pre class="doc-signature"><code>reset() -&gt; None</code></pre>
<p>Clear accumulator state at the start of each evaluate() call.</p>
<h3 id="fastvideo.eval.BaseMetric.accumulate"><code>fastvideo.eval.BaseMetric.accumulate</code></h3>
<pre class="doc-signature"><code>accumulate(sample: dict) -&gt; None</code></pre>
<p>Buffer per-sample features for a corpus-level metric.</p>
<h3 id="fastvideo.eval.BaseMetric.finalize"><code>fastvideo.eval.BaseMetric.finalize</code></h3>
<pre class="doc-signature"><code>finalize() -&gt; MetricResult</code></pre>
<p>Compute the corpus-level result from buffered state.</p>
<h3 id="fastvideo.eval.BaseMetric.merge_from"><code>fastvideo.eval.BaseMetric.merge_from</code></h3>
<pre class="doc-signature"><code>merge_from(other: BaseMetric) -&gt; None</code></pre>
<p>Multi-GPU: fold another worker's accumulator state into this one.</p>
<h2 id="fastvideo.eval.register"><code>fastvideo.eval.register</code></h2>
<pre class="doc-signature"><code>register(name: str)</code></pre>
<p>Decorator to register a metric class.</p>
<p>Usage::</p>
<pre><code>@register("ssim")
class SSIMMetric(BaseMetric):
    ...
</code></pre>
<h2 id="fastvideo.eval.list_metrics"><code>fastvideo.eval.list_metrics</code></h2>
<pre class="doc-signature"><code>list_metrics() -&gt; list&#91;str&#93;</code></pre>
<p>Return sorted list of all registered metric names.</p>
<h2 id="fastvideo.eval.get_metric"><code>fastvideo.eval.get_metric</code></h2>
<pre class="doc-signature"><code>get_metric(name: str, **kwargs: Any) -&gt; BaseMetric</code></pre>
<p>Instantiate a registered metric by name.</p>
<p>Checks that optional dependencies are installed before instantiation
and gives a clear install hint pointing at the right extra group.</p>
<h2 id="fastvideo.eval.evaluate"><code>fastvideo.eval.evaluate</code></h2>
<pre class="doc-signature"><code>evaluate(generated: torch.Tensor | str | Path, reference: torch.Tensor | str | Path | None = None, metrics: list&#91;str&#93; | str = &#x27;all&#x27;, device: str = &#x27;cuda&#x27;, **kwargs) -&gt; dict&#91;str, MetricResult&#93; | list&#91;dict&#91;str, MetricResult&#93;&#93;</code></pre>
<p>One-shot evaluation. For repeated use, prefer :func:<code>create_evaluator</code>.</p>
<h2>Parameters</h2>
<p>generated : Tensor | str | Path
    Generated video. Either a pre-loaded <code>(T, C, H, W)</code> 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 <em>generated</em>).
metrics : list[str] | str
    Metric names, or <code>"all"</code>.
device : str
    PyTorch device string.</p>
<h2 id="fastvideo.eval.Evaluator"><code>fastvideo.eval.Evaluator</code></h2>
<pre class="doc-signature"><code>Evaluator(metrics: list&#91;str&#93; | str = &#x27;all&#x27;, device: str = &#x27;cuda:0&#x27;, num_gpus: int = 1, compile: bool = False, *, loader_threads: int = 1, prefetch_factor: int = 2, pre_upload: bool = True, skip_missing_deps: bool = False)</code></pre>
<p>Pre-initialized scorer for repeated evaluation.</p>
<h2>Parameters</h2>
<p>metrics : list[str] | str
    Metric names, group prefixes (<code>"vbench"</code>), or <code>"all"</code>.
device : str
    Single-GPU device (e.g. <code>"cuda:0"</code>). Ignored when <em>num_gpus</em> &gt; 1.
num_gpus : int
    Number of GPU replicas. Each gets its own :class:<code>EvalWorker</code>.
compile : bool
    Apply :func:<code>torch.compile</code> to each metric's <code>_model</code>.
loader_threads : int
    Background decode threads in the :class:<code>VideoPool</code>. 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
    <code>pool max_size = prefetch_factor * num_workers</code>. Default 2 —
    one sample being consumed, one prefetched per worker.
pre_upload : bool
    When <code>True</code> (default), the worker performs a single
    host→device upload of <code>video</code> / <code>reference</code> per sample
    before the metric loop, and every metric reads from that
    shared GPU-resident tensor. Without it, each metric pays its
    own <code>.to(self.device)</code> — N transfers of the same clip for N
    metrics, which dominates at high resolution. Set <code>False</code> 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 <code>True</code>, silently drop explicit metric names whose
    optional deps aren't importable (with a one-line warning per
    skipped metric). Default <code>False</code> — an explicit name with a
    missing dep raises :class:<code>ImportError</code> at construction time.
    Group selectors (<code>"vbench"</code>, <code>"all"</code>) always silent-skip
    regardless of this flag.</p>

<h3 id="fastvideo.eval.Evaluator.evaluate"><code>fastvideo.eval.Evaluator.evaluate</code></h3>
<pre class="doc-signature"><code>evaluate(samples: Iterable&#91;dict&#93; | None = None, *, metrics: list&#91;str&#93; | None = None, **kwargs) -&gt; dict&#91;str, MetricResult&#93; | EvalResults</code></pre>
<p>Score one sample (kwargs form) or many samples (list form).</p>
<p>Both forms go through the same :class:<code>VideoPool</code> pipeline;
<code>video</code> / <code>reference</code> paths are decoded asynchronously.</p>
<h2>Parameters</h2>
<p>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.  <code>None</code> (default) runs all registered.
    Lets a single long-lived Evaluator score different (gen,
    ref) corpora with different metric subsets across multiple
    <code>evaluate()</code> 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 <em>metrics</em>, so state for other set
    metrics is preserved across calls.</p>
<p>Single sample::</p>
<pre><code>ev.evaluate(video=tensor, text_prompt="...", fps=24.0)
</code></pre>
<p>Many samples::</p>
<pre><code>ev.evaluate(samples=[&#123;"video": ..., "reference": ...&#125;, ...])
</code></pre>
<p>Many samples with a metric filter::</p>
<pre><code>ev.evaluate(samples=lpips_samples, metrics=["common.lpips"])
ev.evaluate(samples=fvd_samples,   metrics=["common.fvd"])
</code></pre>
<h2>Returns</h2>
<p>dict[str, MetricResult] for the single-sample form;
:class:<code>EvalResults</code> (list-of-dict subclass with <code>.corpus</code>) for
the list form.</p>
<h3 id="fastvideo.eval.Evaluator.release_cuda_memory"><code>fastvideo.eval.Evaluator.release_cuda_memory</code></h3>
<pre class="doc-signature"><code>release_cuda_memory() -&gt; None</code></pre>
<p>Free CUDA caches on every replica without dropping models.</p>
<h3 id="fastvideo.eval.Evaluator.unload"><code>fastvideo.eval.Evaluator.unload</code></h3>
<pre class="doc-signature"><code>unload() -&gt; None</code></pre>
<p>Drop metric refs on every replica. Reverse with :meth:<code>reload</code>.</p>
<h3 id="fastvideo.eval.Evaluator.reload"><code>fastvideo.eval.Evaluator.reload</code></h3>
<pre class="doc-signature"><code>reload() -&gt; None</code></pre>
<p>Rebuild metrics dropped by :meth:<code>unload</code>.</p>
<h3 id="fastvideo.eval.Evaluator.shutdown"><code>fastvideo.eval.Evaluator.shutdown</code></h3>
<pre class="doc-signature"><code>shutdown() -&gt; None</code></pre>
<p>No-op; kept for API compatibility with older callers.</p>
<h2 id="fastvideo.eval.create_evaluator"><code>fastvideo.eval.create_evaluator</code></h2>
<pre class="doc-signature"><code>create_evaluator(metrics: list&#91;str&#93; | str = &#x27;all&#x27;, device: str = &#x27;cuda:0&#x27;, num_gpus: int = 1, compile: bool = False, *, skip_missing_deps: bool = False) -&gt; Evaluator</code></pre>

<h2 id="fastvideo.eval.as_video"><code>fastvideo.eval.as_video</code></h2>
<pre class="doc-signature"><code>as_video(x: str | Path | torch.Tensor | Video) -&gt; Video</code></pre>
<p>Coerce path/tensor/Video → :class:<code>Video</code> for the pool to decode.</p>
<p>Path strings and :class:<code>pathlib.Path</code> become <code>Video(source=str(x))</code>;
the pool then calls :func:<code>load_video</code> on first use.  Tensors become
<code>Video(source=None, frames=x)</code> — the pool sees <code>.frames</code> already
populated and forwards untouched.  :class:<code>Video</code> instances pass through.</p>
<h2 id="fastvideo.eval.samples_from"><code>fastvideo.eval.samples_from</code></h2>
<pre class="doc-signature"><code>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&#91;str&#93; | None = None, fps: float | None = None, auxiliary_info: dict | list&#91;dict&#93; | None = None, extras: dict | list&#91;dict&#93; | None = None, extract_audio: bool | str | Path = False, extract_workers: int = 4) -&gt; list&#91;dict&#93;</code></pre>
<p>Build a samples list from path-style inputs.</p>
<h2>Parameters</h2>
<p>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 <code>sample["video"]</code> /
    <code>sample["reference"]</code> / <code>sample["audio"]</code> /
    <code>sample["reference_audio"]</code> respectively.  Video paths are
    wrapped in :class:<code>Video</code> so :class:<code>VideoPool</code> 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 <code>.jsonl</code> /
    <code>.json</code> file containing per-sample prompts.
fps :
    Scalar fps broadcast onto every sample.
auxiliary_info :
    Single dict (broadcast) or list of dicts (zipped) for
    <code>sample["auxiliary_info"]</code> — vbench structured-prompt
    metrics read this.
extras :
    Catch-all per-sample attachments.  Use for metric-specific keys
    the dedicated kwargs don't cover (<code>scenario</code>, <code>view</code>,
    <code>actions</code>, <code>calibration</code>, <code>reference_take2</code>, ...).  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 <code>video</code> /
    <code>reference</code> source into <code>.wav</code> files via PyAV and attach
    the paths under <code>sample["audio"]</code> / <code>sample["reference_audio"]</code>.
    Pass a path for a persistent cache, <code>True</code> for a tempdir.
    Skipped silently for videos with no audio stream; ignored
    wherever <code>audio</code> / <code>reference_audio</code> is already explicit.
extract_workers :
    Parallel workers for <code>extract_audio</code>.</p>
<h2>Returns</h2>
<p>list[dict]
    Canonical samples shape — hand directly to
    :meth:<code>Evaluator.evaluate</code>.</p>
<h2>Cardinality and shape</h2>
<p>Let <code>N = len(generated inputs)</code> (the agreed length of whichever
of <code>video</code> / <code>audio</code> you passed).  References are attached
1:1 onto the first N samples; any extras (when <code>|ref| &gt; N</code>)
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.</p>
<h2>Notes</h2>
<p>"Missing" keys are simply absent from the sample dict.  Metrics
handle them per their own contract (<code>sample.get(...)</code> for
optional, <code>sample[...]</code> raises for required, or
:meth:<code>BaseMetric._skip</code> for opt-in skip behavior).  One fat samples
list with many keys can serve many metrics — each reads its subset.</p>
<h2 id="fastvideo.eval.samples_from_manifest"><code>fastvideo.eval.samples_from_manifest</code></h2>
<pre class="doc-signature"><code>samples_from_manifest(manifest: str | Path, *, extract_audio: bool | str | Path = False, extract_workers: int = 4) -&gt; list&#91;dict&#93;</code></pre>
<p>Load canonical eval samples from a JSON or JSONL manifest.</p>
<p>Each row may contain <code>video</code>, <code>audio</code>, <code>reference</code>,
<code>reference_audio</code>, <code>reference_audio_source</code>, <code>text_prompt</code> and
arbitrary metric metadata. <code>reference_audio_source</code> is a media file
whose audio track is extracted when <code>extract_audio</code> is enabled. Paths are
resolved relative to the manifest directory. Video paths are wrapped as
:class:<code>Video</code> 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.</p>
</div>

<h2>Submodules</h2>
<ul>
<li><a href="/FastVideo/api/fastvideo/eval/api">api</a></li>
<li><a href="/FastVideo/api/fastvideo/eval/datasets">datasets</a></li>
<li><a href="/FastVideo/api/fastvideo/eval/evaluator">evaluator</a></li>
<li><a href="/FastVideo/api/fastvideo/eval/io">io</a></li>
<li><a href="/FastVideo/api/fastvideo/eval/memory">memory</a></li>
<li><a href="/FastVideo/api/fastvideo/eval/metrics">metrics</a></li>
<li><a href="/FastVideo/api/fastvideo/eval/models">models</a></li>
<li><a href="/FastVideo/api/fastvideo/eval/pool">pool</a></li>
<li><a href="/FastVideo/api/fastvideo/eval/registry">registry</a></li>
<li><a href="/FastVideo/api/fastvideo/eval/types">types</a></li>
<li><a href="/FastVideo/api/fastvideo/eval/v2a">v2a</a></li>
<li><a href="/FastVideo/api/fastvideo/eval/worker">worker</a></li>
</ul>
