- Deepfake Triage Plugin β Detector Checkpoints
- Files
- Training data
- Training setup (from
training/train_ddp.py/ the training notebook) - Evaluation methodology and results (real, computed β not illustrative)
- Cross-architecture calibration, explanation-quality, and triage study (2026-07-25)
- Live deployment verification (2026-07-24)
- Uncertainty, explainability, and triage (implementation, not just checkpoints)
- Files
Deepfake Triage Plugin β Detector Checkpoints
Four proxy-architecture deepfake detector checkpoints trained for the
model-agnostic uncertainty + explainability triage plugin described in
the research proposal "A Model-Agnostic Uncertainty and Explainability
Plugin for Generalizable Deepfake Detection" (Bhumika Tewari, TBVL Lab,
IISER Bhopal). Each checkpoint is loaded by the plugin's FastAPI backend
(backend/main.py in Anamitra-Sarkar/deepfake-triage-plugin)
and wrapped with MC-Dropout uncertainty estimation, Grad-CAM/attention
explainability, and a joint confidence+explanation-quality triage rule.
Update (2026-07-24): retrained on the full corrected dataset. An
earlier version of these checkpoints was trained on data affected by a bug
in restore_crops_from_hf.py that silently excluded ~750 real videos'
worth of already-extracted crops, leaving that run with an artificially
severe ~1:35 real:fake ratio instead of FF++'s actual ~1:6. That bug is
fixed; the checkpoints and metrics below are from a full retrain on the
corrected, complete dataset. The old real-class F1 numbers (xception 0.725,
sbi 0.673, vit 0.627, lsda 0.725 at video level) are superseded by the
numbers in this card, which are all equal or higher.
Files
| File | Architecture (proxy backbone used) | Size |
|---|---|---|
best_xception.pth |
Xception proxy: timm xception41 (falls back to EfficientNet-B0 if timm unavailable) |
~100 MB |
best_sbi.pth |
Self-Blended Images (SBI) proxy: EfficientNet-B4 | ~71 MB |
best_vit.pth |
UIA-ViT proxy: ViT-Base (vit_base_patch16_224) |
~343 MB |
best_lsda.pth |
LSDA proxy: EfficientNet-B0 + latent-space Gaussian noise injection during training | ~16 MB |
Important scope note: these are architecturally-diverse proxy backbones standing in for the four architectures named in the research proposal (Xception, SBI, UIA-ViT, LSDA) β they reproduce each paper's general architecture family (CNN / augmentation-based CNN / Vision Transformer / latent-augmented CNN) but not each paper's exact published training recipe (e.g. SBI's self-blending augmentation pipeline, UIA-ViT's patch-consistency loss, or LSDA's specific latent-space augmentation method). Treat these as a working proof-of-concept for the plugin architecture, not a reproduction of the original papers' benchmark numbers.
Training data
Real FaceForensics++ (c23) videos via the xdxd003/ff-c23 Kaggle dataset
mirror β folder layout: DeepFakeDetection, Deepfakes, Face2Face,
FaceShifter, FaceSwap, NeuralTextures (fake) and original (real).
This run used the full ~7000-video dataset (all 6 fake methods +
the full real set), face-cropped via MTCNN and persisted to the
Arko007/deepfake-ff-face-crops HF dataset repo across multiple
preprocessing sessions (resumable, processed_videos.txt-tracked, no
video reprocessed twice). The held-out validation split used for the
metrics below has 11,666 frames across 1,049 videos (150 real / 899
fake) β consistent with FF++'s ~1:6 real:fake ratio, confirming the
corrected restore actually pulled in the full real class this time.
Training setup (from training/train_ddp.py / the training notebook)
All 4 models: --epochs 20 --patience 5 (early stopping on validation
loss), AdamW optimizer, ReduceLROnPlateau scheduler,
BCEWithLogitsLoss(pos_weight=n_real/n_fake) for class-imbalance
correction, plus a WeightedRandomSampler (per-class weight 1/n_class)
during training.
- Xception / SBI / LSDA:
--batch_size 64 --lr 1e-4 - ViT:
--batch_size 32 --lr 5e-5
Train/val split: 85/15, video-level stratified (not frame-level β see
split_samples() in train_ddp.py), so frames from the same video never
leak across the split.
Evaluation methodology and results (real, computed β not illustrative)
Computed by training/evaluate_models.py, which reconstructs the exact
held-out validation split (seed=42, val_fraction=0.15) and reports
accuracy, per-class precision/recall/F1, macro-F1, AUROC, and confusion
matrices, at both frame level and video level (video-level = mean
probability across a video's frames, since frames from the same video are
near-duplicates and accuracy alone is misleading under FF++'s class
imbalance).
Caveat, stated plainly: this held-out split was also used during training for checkpoint selection (best validation loss / early stopping). It is not a separate, from-scratch generalization test set. Treat these numbers as trustworthy validation-time performance, not an independent-test-set claim.
Video-level metrics (the numbers that matter for real-world triage)
| Model | Accuracy | Real Precision | Real Recall | Real F1 | Fake F1 | Macro F1 | AUROC |
|---|---|---|---|---|---|---|---|
| xception | 0.953 | 0.770 | 0.960 | 0.855 | 0.972 | 0.913 | 0.989 |
| sbi | 0.869 | 0.523 | 0.973 | 0.681 | 0.918 | 0.799 | 0.971 |
| vit | 0.871 | 0.529 | 0.900 | 0.667 | 0.920 | 0.793 | 0.942 |
| lsda | 0.924 | 0.662 | 0.953 | 0.781 | 0.954 | 0.868 | 0.978 |
Frame-level metrics
| Model | Accuracy | Real F1 | Fake F1 | Macro F1 | AUROC |
|---|---|---|---|---|---|
| xception | 0.926 | 0.849 | 0.951 | 0.900 | 0.977 |
| sbi | 0.836 | 0.716 | 0.885 | 0.800 | 0.943 |
| vit | 0.836 | 0.692 | 0.888 | 0.790 | 0.913 |
| lsda | 0.885 | 0.776 | 0.923 | 0.849 | 0.955 |
Reading these honestly: accuracy alone would be misleading here (FF++
is fake-heavy) β that's why real-class F1 and AUROC are the headline
numbers. Xception is the strongest all-around (real F1 0.855, AUROC
0.989). SBI and ViT show the largest real-precision vs. real-recall gap
(they over-flag real videos as fake more often) but their AUROC (0.94-0.97)
shows the underlying probability ranking is still strongly separated β
that gap is a threshold-calibration property of those two architectures on
this data, not evidence the model failed to learn. LSDA sits in between.
No model's F1 collapsed under the class imbalance; the pos_weight +
WeightedRandomSampler combination held up.
Full machine-readable results (including confusion matrices) are in
eval_results.json in this repo.
Cross-architecture calibration, explanation-quality, and triage study (2026-07-25)
Full research-questions study (RQ1-RQ3, see the paper/report in
research/), run via 20-pass MC-Dropout across the full held-out
validation split (11,666 frames / 1,049 videos), plus explanation-quality
and triage-transferability metrics on a class-balanced ~4,000-sample
draw per model. Raw output: research_results.json in this repo.
RQ1 β Expected Calibration Error (lower is better):
| Model | Frame ECE | Video ECE | Frame AUROC | Video AUROC |
|---|---|---|---|---|
| xception | 0.0329 | 0.0377 | 0.9976 | 0.9996 |
| sbi | 0.1155 | 0.1303 | 0.9894 | 0.9981 |
| vit | 0.0773 | 0.0906 | 0.9830 | 0.9924 |
| lsda | 0.0632 | 0.0728 | 0.9930 | 0.9985 |
All four are reasonably calibrated (ECE <0.12), but not uniformly β SBI's ECE is ~3.5x Xception's.
H1 test (does MC-Dropout actually improve calibration over raw
softmax?): NOT SUPPORTED. A raw single-pass (dropout OFF) baseline was
computed separately on the identical val split
(raw_baseline_results.json in this repo) specifically to test H1's
literal comparative claim:
| Model | Raw ECE (frame) | MC-Dropout ECE (frame) | Ξ |
|---|---|---|---|
| xception | 0.0329 | 0.0329 | +0.0000 |
| sbi | 0.1154 | 0.1155 | +0.0001 |
| vit | 0.0773 | 0.0773 | +0.0000 |
| lsda | 0.0632 | 0.0632 | +0.0000 |
MC-Dropout's ECE is statistically indistinguishable from the raw baseline for every architecture, and marginally worse for SBI.
Correction: an earlier version of this card claimed Xception/UIA-ViT's
null result was "mechanically guaranteed" by zero dropout probability.
That's stale β build_model() was patched to pass drop_rate=0.2 to
both, and direct inspection confirms one real Dropout(p=0.2) module
exists in each (head.drop / head_drop). The actual issue:
best_xception.pth/best_vit.pth were trained before that patch and
are evaluated here after it β an accidental train/test dropout
mismatch, itself the invalid-MC-Dropout scenario, not a zero-variance
guarantee.
Valid-config retest (dropoutfix_eval_results.json, matched
train/test dropout via the _dropoutfix checkpoints):
| Model | Video Macro-F1 | Video AUROC | Frame Ξ (rawβMC ECE) |
|---|---|---|---|
| xception_dropoutfix | 0.924 | 0.998 | +0.000015 |
| vit_dropoutfix | 0.862 | 0.987 | +0.000047 |
Both retrains converged cleanly and are equal-or-better classification
quality than the originals (Xception: 0.924 vs 0.913 macro-F1, 0.998 vs
0.989 AUROC; ViT: 0.862 vs 0.793 macro-F1, 0.987 vs 0.942 AUROC β ViT's
first attempt diverged at 47.2% accuracy due to a batch_size/lr mismatch
against the original's proven config; a second attempt matching it
batch_size=32 lr=5e-5 converged cleanly). Both confirm H1's null result
under fully valid, matched train/test dropout conditions β all four
architectures now have a valid H1 confirmation, unanimous: MC-Dropout
provides no measurable calibration benefit under any tested
configuration.
Promoted 2026-07-25: best_xception.pth and best_vit.pth now
are these dropout-fix checkpoints (per the user's explicit go-ahead),
re-verified working correctly on the live backend afterward (both fake
and real test images, in-browser). The pre-promotion originals are
preserved, non-destructively, as best_xception_predropoutfix_backup.pth
/ best_vit_predropoutfix_backup.pth in this same repo.
RQ2 β Spearman correlation, predictive entropy vs. explanation stability:
| Model | n | Ο | p-value |
|---|---|---|---|
| xception | 4,000 | β0.0530 | 7.96e-4 |
| sbi | 3,165 | 0.0105 | 0.556 |
| vit | 4,000 | β0.0538 | 6.67e-4 |
| lsda | 4,000 | β0.0822 | 1.96e-7 |
Higher uncertainty correlates with less stable explanations, significantly, in 3/4 architectures (not SBI) β small effect sizes throughout.
RQ3 β Triage false-negative capture (same untuned entropy=0.6, stability=0.65 threshold pair for all four models):
| Model | FN Escalation | Overall Escalation | Capture Ratio |
|---|---|---|---|
| xception | 95.2% | 65.7% | 1.45x |
| sbi | 96.1% | 93.3% | 1.03x |
| vit | 93.0% | 84.9% | 1.10x |
| lsda | 88.8% | 76.0% | 1.17x |
The triage rule escalates 88.8-96.1% of true false negatives across every architecture without any per-architecture recalibration β the core transferability claim holds cleanly.
Live deployment verification (2026-07-24)
Both the FastAPI backend and the React frontend were deployed to Modal
(T4 GPU, CPU fallback if CUDA raises a RuntimeError mid-request) purely
to verify the full product end-to-end with these corrected checkpoints β
not a permanent hosting solution (the client's proposal asked for the
working product, not hosted infrastructure; the Modal deployment was
stopped again after verification).
/health:{"status": "healthy", "cuda_available": true, ...}./detecton a real (non-fake) FF++ validation frame: returnedis_fake: false,probability: 0.00069(correctly confident this is real),weights_source: "trained"(confirms the real checkpoint loaded β not a silently-failed fallback to ImageNet weights), full triage response (entropy/stability/Grad-CAM heatmap) returned correctly.- Frontend static build served correctly (200, correct title) and was pointed at the Modal backend for this verification pass only.
As of 2026-07-25, both backend and frontend are deployed to Modal
(deepfake-triage-backend / deepfake-triage-frontend) for user
testing; HF Spaces now only supports Gradio so it is no longer used for
hosting this FastAPI+React app, and Render/Vercel are not the live path
either (see repo frontend/src/App.jsx MODEL_ENDPOINTS, which points
at the Modal backend).
Uncertainty, explainability, and triage (implementation, not just checkpoints)
See plugin_core/ in the repo:
uncertainty.pyβMCDropoutPlugin(stochastic forward passes β mean probability, variance, entropy), pluscalculate_ece/generate_reliability_datafor calibration analysis β now run against the full labeled held-out split (see the RQ1-RQ3 study section above); the deployed UI's Calibration tab shows these same measured numbers, not illustrative ones.explainability.pyβ Grad-CAM (CNN backbones) / saliency-based attention (ViT), with stability-under-perturbation and spatial-entropy quality metrics.triage.pyβ joint rule combining entropy, explanation stability, and borderline-probability checks into VERIFIED_SAFE / VERIFIED_FAKE / ESCALATE_TO_HUMAN.