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, ...}.
  • /detect on a real (non-fake) FF++ validation frame: returned is_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), plus calculate_ece / generate_reliability_data for 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.
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support