Files
hao-ai-lab-FastVideo/fastvideo/eval/README.md
T

215 lines
7.7 KiB
Markdown

# `fastvideo.eval`
In-process evaluation suite for video generations. Includes pixel
metrics (SSIM, PSNR, LPIPS), optical-flow comparisons, the full VBench
suite, Physics-IQ, and a VLM scorer (VideoScore-2) behind a single
registry-driven API.
## Install
| Use case | Install |
|---|---|
| Default (common, optical_flow, vbench-light, physics_iq, videoscore2) | `uv pip install -e .[eval]` |
| Just VBench (12 of 16 sub-metrics) | `uv pip install -e .[eval-vbench]` |
| Just Physics-IQ (covered by `[eval]`) | `uv pip install -e .[eval-physics-iq]` |
| Plus `vbench.scene` (AVoCaDO) | `uv pip install -e .[eval-full]` |
| Plus `vbench.{color, multiple_objects, object_class, spatial_relationship}` (GRiT) | `uv pip install -e .[eval-vbench]` then `uv pip install --no-build-isolation 'git+https://github.com/facebookresearch/detectron2.git'` |
To use VBench, also pull the upstream submodule:
```bash
git submodule update --init --recursive # fetches vbench + kernel deps
```
The submodule is a clean upstream pin. Compat with current
transformers/numpy/timm versions is applied at import time in
`fastvideo/eval/metrics/vbench/__init__.py` via attribute-level
monkey-patches; the submodule files are unchanged.
## Public API
```python
from fastvideo.eval import (
create_evaluator, # build a reusable Evaluator
evaluate, # one-shot helper
Evaluator, # the class itself
BaseMetric, MetricResult,
register, list_metrics, get_metric,
ensure_checkpoint, get_cache_dir,
)
ev = create_evaluator(metrics=["common.ssim", "vbench.aesthetic_quality"],
device="cuda")
scores = ev.evaluate(video=tensor, reference=ref, fps=8.0)
```
`evaluate` accepts either a pre-loaded `(T, C, H, W)` tensor or a path
string for `video` and `reference`. Paths are decoded inside the worker
that picks up the sample, so peak memory stays bounded by `num_gpus`
when scoring large batches.
### CLI
```bash
fastvideo eval list # list registered metrics
fastvideo eval list --group vbench # filter by group
fastvideo eval run --videos clip.mp4 \
--metrics vbench.aesthetic_quality \
--output scores.json
fastvideo eval run --videos generated/*.mp4 \
--reference reference/ \
--metrics common.ssim,common.lpips
```
### Generate-then-score example
`examples/inference/eval/eval_ltx2_vbench.py` runs an LTX2 prompt
through `VideoGenerator` and scores the resulting mp4 with
`vbench.aesthetic_quality` and `vbench.subject_consistency`. Use it as
a template for end-to-end "generate then score" pipelines.
## Layout
```
fastvideo/
├── eval/
│ ├── api.py, evaluator.py, registry.py, models.py, ...
│ ├── io/ # video loading helpers
│ ├── datasets/ # prompt corpora (vbench, physics_iq)
│ └── metrics/
│ ├── base.py # BaseMetric + @register contract
│ ├── common/ # SSIM, PSNR, LPIPS
│ ├── optical_flow/ # gt_optical_flow, synthetic_optical_flow
│ ├── videoscore2/ # VideoScore-2 (Qwen2.5-VL)
│ ├── physics_iq/ # PhysicsIQ + sub-metrics
│ └── vbench/ # adapter: sys.path bootstrap + shims
│ ├── __init__.py
│ └── <16 sub-metric pkgs>
└── third_party/
└── eval/
└── vbench/ # git submodule (Vchitect/VBench)
```
### Prompt datasets
```python
from fastvideo.eval.datasets import get_dataset, list_datasets
list_datasets() # ['physics_iq', 'vbench']
ds = get_dataset("physics_iq", limit=4) # auto-fetches assets on first miss
for row in ds:
# row contains 'prompt', 'reference', 'reference_take2', and
# metric-specific aux fields. Drop straight into Evaluator.evaluate(**row).
...
```
The Physics-IQ manifest CSV is vendored at
`fastvideo/eval/metrics/physics_iq/_vendored/descriptions.csv`.
Per-scenario videos, masks, and switch-frames auto-fetch on first use
into `${FASTVIDEO_EVAL_CACHE}/datasets/physics_iq/`. For air-gapped
runs, pass `auto_download=False` or `dataset_root=` a pre-downloaded
copy. Set `FASTVIDEO_PHYSICS_IQ_BUCKET_URL` to redirect the fetch to
an internal mirror.
## Adding a new metric
The full porting guide is at
[`docs/contributing/eval-metrics.md`](../../docs/contributing/eval-metrics.md).
Summary below.
### Native metric (no submodule)
```python
# fastvideo/eval/metrics/common/<your_metric>/metric.py
from fastvideo.eval.metrics.base import BaseMetric
from fastvideo.eval.registry import register
from fastvideo.eval.types import MetricResult
@register("common.your_metric")
class YourMetric(BaseMetric):
name = "common.your_metric"
requires_reference = True
needs_gpu = False
dependencies: list[str] = [] # e.g. ["pyiqa"] if relevant
def compute(self, sample) -> list[MetricResult]:
...
```
The metric is auto-discovered by `fastvideo/eval/metrics/__init__.py`,
which walks all non-underscore subdirectories and imports their
`metric` module.
### Wrapping upstream code via a submodule
See `fastvideo/eval/metrics/vbench/` for a worked example. The
contract is:
1. Upstream lives as a git submodule under
`fastvideo/third_party/eval/<bench>/`, pinned to a SHA in repo-root
`.gitmodules`.
2. The metric package's `__init__.py`
(`fastvideo/eval/metrics/<bench>/__init__.py`) inserts that
submodule path on `sys.path` and installs any compat shims for
modern torch/transformers/numpy. Do not modify upstream files on
disk.
3. Per-sub-metric `metric.py` files use `@register("<bench>.<name>")`.
Patches live as Python in the metric's `__init__.py` so they are
grep-able and reviewable.
## Caches
Eval cache root: `${FASTVIDEO_CACHE_ROOT}/eval/`, default
`~/.cache/fastvideo/eval/`. Override with `FASTVIDEO_EVAL_CACHE`.
```
${FASTVIDEO_CACHE_ROOT}/eval/
├── models/ # URL-fetched checkpoints (LAION head, AMT, GRiT)
├── torch/ # redirected TORCH_HOME (DINO via torch.hub, lpips)
├── clip/ # passed as download_root= to clip.load callsites
└── datasets/ # auto-fetched dataset assets, one subdir per benchmark
# (e.g. datasets/physics_iq/{split-videos,switch-frames,...})
```
HF-hosted models stay in HF's default cache
(`~/.cache/huggingface/hub/`) so they dedupe with other ML projects on
the same host.
### Convention for new metrics
If your metric wraps a third-party loader that has its own cache
directory, route it through `get_cache_dir()` so users get one knob
to redirect everything.
```python
# CLIP: pass download_root explicitly
import clip
from fastvideo.eval.models import get_cache_dir
model, _ = clip.load("ViT-B/32", device=device,
download_root=str(get_cache_dir() / "clip"))
# torch.hub is already redirected by fastvideo.eval.__init__ via
# TORCH_HOME; no per-callsite work needed.
# transformers / huggingface_hub: leave alone. HF's default cache is
# shared with other tools.
```
For libraries that do not honour any env var or kwarg (pyiqa, funasr),
their cache lands in the library's own dir. Document the exception in
the metric's docstring if it matters.
## Out of scope (follow-up PRs)
- **MIND** metrics. Depend on a separate `vipe` upstream submodule.
- **VBench-2.0**. Sibling vbench2 package; needs its own port.
- **FVD as a registered metric**. Currently still at `benchmarks/fvd/`.
FVD is a set-vs-set distribution distance and does not fit the
per-sample `BaseMetric.compute` API without a stateful accumulator;
conversion is a designed follow-up.
- **Training-time eval callback** (`EvalCallback`) and the
`RolloutEvaluator` helper.