Spaces:
Sleeping
Sleeping
File size: 10,984 Bytes
cd24b4a b91ce50 cd24b4a 463a482 b91ce50 cd24b4a 26a7256 cd24b4a 26a7256 cd24b4a 26a7256 cd24b4a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 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 | # SynthScope capabilities (orientation for an agent building a new detector)
SynthScope is a **reproduction + benchmarking library for AI-generated *image and video* detection**. It
hosts many published detectors behind one interface, reproduces each on its own benchmark, and
serves a web UI + a Python/CLI API. Read this before adding a method, then follow
[`docs/ADD_DETECTOR.md`](ADD_DETECTOR.md) for the exact checklist.
> Environment: everything runs in the **`SynthScope` conda env** β
> `/home/ssalehi/miniconda3/bin/conda run -n SynthScope <cmd>`. Config is **Hydra** (`conf/`).
---
## 1. What's already integrated (17 detectors)
`synthscope.list_models()` / `from synthscope.api import list_specs`. Each is an `SynthScope<Name>Model` with a
matching `conf/model/<modality>/<key>.yaml`, a `trainer.py._build_model` branch, an
`interface/backend/registry.py` `ModelSpec`, a per-model `README.md`, and a `tests/test_<k>_smoke.py`.
| key | modality | predict_kind | weights | interp map | method |
|---|---|---|---|---|---|
| `clip` | image | ce | synthscope | β | UnivFD / CLIP linear probe |
| `cnn` | image | ce | synthscope | β | CNNDetection (ResNet-50) |
| `dinov2`,`dinov3`,`adapted_dino` | image | ce | synthscope | β | DINO probes / adapter-tuned |
| `npr` | image | bce_npr | official | npr_residual | Neighboring-Pixel Relationships |
| `safe` | image | ce | synthscope | safe_hf | High-freq DWT artifacts |
| `aide` | image | ce | official | aide_dct | ConvNeXt-XXL + DCT/SRM (native-res 5-view) |
| `fat_former` | image | ce | official | β | Forgery-aware adaptive transformer (CLIP) |
| `spai` | image | bce | synthscope* | spai_patch | Spectral, any-resolution (MFM ViT-B/16) |
| `co_spy` | image | bce | synthscope* | β | Semantic + artifact fusion (SigLIP + SD-VAE) |
| `pgc` | image | bce | official | pgc_peak | LoRA-DINOv2 + YCbCr residual, peak-guided |
| `cure` | image | ce | official | β | Frozen PE-Core L/14 + Q/V LoRA + source-response subspace (mixing-ratio regression) |
| `vib_net` | image | vib | synthscope | β | Variational information bottleneck (FLAVA) |
| `d3` | video | video | training-free | β | Disentangled detail dynamics (X-CLIP) |
| `restrav` | video | video | synthscope | β | Representation-trajectory geometry (DINOv2) |
| `stall` | video | video | training-free | β | Spatio-temporal whitened log-likelihoods (DINOv3) |
`*` served via official weights remapped into the SynthScope class. **`predict_kind`** sets the score
convention the engine applies to `forward()` logits: `ce`β`softmax[:,1]`, `bce`β`sigmoid`,
`bce_npr` (NPR residual transform then sigmoid), `vib` (tuple out), `video` (clip in).
---
## 2. The detector contract (what a new method must implement)
`models/<modality>/<key>/<key>.py`:
```python
class SynthScope<Name>Model(nn.Module):
def __init__(self, config: DictConfig): ... # build arch from config.ModelConfig
def forward(self, images) -> logits: ... # RAW logits, not probs; model-specific
# preprocessing (residual/DWT/DCT) goes INSIDE forward
def compute_loss(self, batch) -> {"loss", "outputs"} # outputs = [N,2] real/fake logits, used by training
```
Repo rule: **all imports + helper classes at module top level** (no nested defs/imports). Vendor the
official arch pieces verbatim where possible and document deviations in the per-model README.
To wire it in: `conf/model/<modality>/<key>.yaml` (`model_type: <key>`), a branch in
`trainer.py._build_model` (dispatches on `model_type`), and a `ModelSpec` in the interface registry
(see `ADD_DETECTOR.md`). The web engine (`interface/backend/engine.py`) lazy-imports by `model_type`.
---
## 3. Training infrastructure
- **`trainer.py`** (`SynthScopeModelTrainer`) + **`main.py`** entrypoint; Hydra config in `conf/config.yaml`
with groups `model/`, `dataset/`, `trainer/`. Multi-GPU via π€ `accelerate` (`accelerate_config.yaml`).
- **`dataset.py`** β image/video dataset loaders; `_decode_rgb` feeds uint8 `[3,H,W]` tensors;
`sample_video_frames(..., edge_crop=)` for video.
- **`transformations.py`** β composable named transforms / augmentations: `resize_224`,
`resize_short_{256,384,448}`, `center_crop_{224,256,384,448}`, `random_crop_*`, `pad_random_crop_224`
(PGC), `gaussian_blur`, `jpeg_compression`, `random_horizontal/vertical_flip`, `random_rotation_180`,
`color_jitter_safe`, `to_tensor`/`to_dtype`. **Eval-transform fidelity is critical** β artifact/
low-level detectors (SAFE/AIDE/SPAI/PGC/NPR) are wrecked by a wrong resize; match the official eval
exactly (see `repro/investigate/pgc_gap_investigation.md` and the SAFE crop-not-resize lesson).
- **`metrics.py`** β torchmetrics binary `Accuracy` (real/fake), `AveragePrecision` (AP),
`AUROC`. Threshold-free AP/AUROC are the headline metrics (esp. video, where per-gen real:fake
ratios make mAP degenerate β prefer AUROC there).
---
## 4. Evaluation / benchmarking
- **Image**: `benchmark/bench_eval.py --model <k> --benchmark {forensynths|ufd|pergen|pool} --data <root> [--ckpt <pth>] [--native-res] --tag <t>`. Auto-discovers `<gen>/{0_real,1_fake}` (or `{ai,nature}`, shared-reals) layouts; prints per-generator acc/AP/AUROC + mean; writes `repro/bench_results/<tag>.json`.
- **Video**: `benchmark/bench_eval_video.py --model {d3|restrav|stall} --dataset NAME` (auto-download) or `--benchmark {genvideo|fakeonly|pergen} --data DIR`.
- `--ckpt` overrides the registry checkpoint (for official-vs-SynthScope side-by-side).
- `benchmark/aggregate_results.py`, `leaderboard.py`, `evaluate.py`, `schema.json` aggregate runs.
- Results live in `repro/`: `RESULTS_SUMMARY.md` (read first), `AGGREGATED_BENCHMARK.md`,
`BENCHMARK_COVERAGE_MATRIX.md`, `REPRODUCED_MODELS_BENCHMARKS.md`, `repro/bench_results/*.json`,
and per-method deep-dives in `repro/investigate/`.
---
## 5. Datasets (explorer registry: `interface/backend/datasets.py`, `DATASET_DEFS`)
Known image sets: `cnndetection` (ForenSynths/ProGAN), `genimage`, `genimage_full` (8-gen),
`universialfakedetection` (Ojha UFD), `aigibench`, `synthbuster`, `ditfake`, `diffusionforensics`,
`diffusion1kstep`, `aigcdetect`, `commgen15`, `realchain`, `evalgen`, `synthwildx`, `wildrf`, `bfree_online`, `rrdataset`, `cospy`/`cospy_subset`, `spai_ldm`, `freqnetdetection`.
Video: `genvideo_val`, `genvideo`, `videophy`, `vidprom`, `restrav_data`, `evalcrafter`, `genvidbench`, `videofeedback`, `comgenvid`.
Each `DatasetDef` lists candidate roots; **`_resolve_root` is node-portable** β it remaps the configured
`/hddstore` path onto whatever scratch mount exists (`/hddstore`β`/ssdstore`β`/nvmestore`), overridable
with `SYNTHSCOPE_DATA_PREFIXES`. Labels are inferred from path tokens (`0_real`/`nature`βreal,
`1_fake`/`ai`βfake). **Not every dataset is physically present on every node** β data is node-local
scratch; check what's staged (e.g. CNNDetection, GenImage, GenImage_full are on cn029 `/ssdstore`).
---
## 6. The `synthscope` package (Python + CLI)
```python
import synthscope
det = synthscope.load("pgc") # or load(key, checkpoint=PATH, device=...)
det.predict("img.png") # -> {fake_probability, verdict, confidence, interpret_map, ...}
synthscope.list_models(); synthscope.available_models() # registered / weights-present
```
CLI: `synthscope list`, `synthscope detect <file> --model <k>`, `synthscope pull <k>` (fetch weights from the HF model
zoo), `synthscope push` (maintainer). Weights resolve under **`$SYNTHSCOPE_CKPT_DIR`** (default
`/hddstore/ssalehi/SynthScope/checkpoints`; override per node) or are auto-downloaded.
---
## 7. Web interface (`interface/`, FastAPI + uvicorn)
`bash interface/run_backend.sh` (`SYNTHSCOPE_PORT`, `SYNTHSCOPE_HOST`). Serves `frontend/dist` if built, else the
no-build `static/index.html`. Endpoints (`interface/backend/app.py`): `/api/models`, `/api/predict`
(image/video, lazy model load + LRU), `/api/datasets[.../sample]`, `/api/predict_dataset`,
`/api/score_batch`, `/api/leaderboard`, `/api/generator_benchmarks`, and a **SOTA-vs-detector** demo
(`/api/sota/{generators,real_image,compare}`) that generates an image from a prompt (`generators.py`,
API-keyed SOTA generators incl. local Ideogram) and scores real vs generated across detectors.
On-cluster launch scripts: `repro/webui_cn029_serve.sbatch` (GPU on free cees node, checkpoints staged
to `/ssdstore`), `repro/webui_cn023_cpu.sbatch`. Reach it via SSH tunnel through the `ivi-h1` login host.
### Interpretability maps
The engine returns a per-detector artifact map for the 5 native-signal detectors (`spec.interpret`):
`safe_hf` (DWT high-freq band), `npr_residual` (pixel residual), `pgc_peak` (peak-guided residual
score), `aide_dct` (native-res DCT patch energy), `spai_patch` (per-patch spectral fake-evidence). Each
yields **`interpret_map`** (bare jet heatmap) **+ `interpret_overlay`** (heatmap blended on the input,
transform-aligned). A new method exposes one by setting `interpret="<kind>"` on its `ModelSpec` and
adding a branch in `engine._interpret_map` that produces a 2-D saliency tensor.
---
## 8. New detectors & repo hygiene
New detectors are integrated **on a `detector/<key>` branch and pushed for review β never auto-merged to `main`**
(see [ADD_DETECTOR.md](ADD_DETECTOR.md)). Never commit weights (`*.pth`), `.env`, or caches.
---
## 9. Cluster cheat-sheet (IvI SLURM)
- **cn023** (`quva`/`quvausers`, A6000) holds all detector checkpoints + most datasets on node-local
**`/hddstore`**; GPUs are often booked for days. `SYNTHSCOPE_CKPT_DIR=/hddstore/ssalehi/SynthScope/checkpoints`.
- **cees** (`ceesusers`: cn029 etc., a5000, free) and **cees6000** (cn030/31, rtx6000) use node-local
`/ssdstore` / `/nvmestore`. To run there, stage checkpoints/data from cn023 (`rsync -aL`, dereference
the symlinks) β note `pam_slurm_adopt` only allows ssh to a node where you hold an active job.
- `/ivi/zfs/...` is the shared home (24 GiB user quota β don't park big checkpoints there);
HF cache is shared at `/ivi/.../SynthScope/.cache_shared/hf` (`HF_HOME`). DINOv3 weights gated, under
`dinov3_checkpoints/` (`DINO_V3_WEIGHTS`); SPAI MFM backbone via `SYNTHSCOPE_MFM_CKPT`.
---
## 10. Starting a new method β TL;DR
1. Confirm it passes both rules (public repo + strong results). Read `ADD_DETECTOR.md`.
2. `git checkout -b detector/<key>`; add the 5 files (model, conf, trainer dispatch, registry ModelSpec, README) + smoke test.
3. **Match the official eval transform exactly** in the `ModelSpec` (resize vs crop, norm) β this is the #1 silent-failure source.
4. Reproduce on the paper's benchmark with official weights via `bench_eval.py --ckpt`; fix `remap_<k>` for key mismatches; record per-gen AP/AUROC in the Paper/SynthScope_official/SynthScope_train schema.
5. (Optional) add an interpretability map. Push the branch; do **not** merge to `main`.
|