All projects
MSc dissertation · Royal Holloway, University of London

Hybrid visual–forensic deepfake detection

2026MSc dissertationPythonPyTorchEfficientNet-B4timmOpenCVscikit-learnGradio

A two-stream deepfake image detector that fuses an EfficientNet-B4 network with 406 hand-crafted forensic features through a learned attention gate, evaluated for robustness to JPEG re-compression and on an unseen dataset. On the identity-disjoint FaceForensics++ test set the hybrid reached 0.981 AUC, ahead of either stream on its own.

The question

Most deepfake detectors look only at pixels with a deep CNN. They score very well on the data they were trained on, but the assumption I set out to test is that they break down when an image is re-compressed (as happens on every social platform) or when the fake comes from a dataset they have never seen. My dissertation asks whether adding a second stream of hand-crafted forensic evidence, and letting the model learn how much to trust it, makes detection more reliable in exactly those conditions.

0.981
Hybrid AUC on the identity-disjoint FaceForensics++ test set
49,996
Aligned face crops from FaceForensics++ (c23)
406
Hand-crafted forensic features per image
0.726 → 0.783
Hybrid AUC on unseen Celeb-DF-v2, v1 → v2

Source: results/*.jsonl in the project repository

How it works

The detector takes a single face image and outputs the probability that it is fake.

  • Visual stream: a pretrained EfficientNet-B4 (Noisy Student weights, via timm) producing a 1,792-dimensional embedding.
  • Forensic stream: a fixed 406-dimensional feature vector computed from the pixels: error level analysis (262), DCT coefficient histograms (48), noise residual statistics (7), JPEG blockiness (4), an FFT radial spectrum (64), facial landmark symmetry (6) and colour statistics (15), passed through a small MLP.
  • Attention-gated fusion: both embeddings are projected to 128 dimensions and a gate network outputs a softmax weight for each stream, per image, so the model can lean on forensic evidence when the pixels are unreliable. Concatenation and bilinear fusion are implemented as ablations.

Detector pipeline

  1. 01
    Face extraction
    MTCNN detects and aligns the face; 224 × 224 crop
  2. 02
    Two parallel streams
    Visual: EfficientNet-B4 (1,792-d). Forensic: 406 features → MLP (64-d)
  3. 03
    Attention-gated fusion
    Both projected to 128-d; a gate learns a weight for each stream
  4. 04
    Prediction
    Joint head outputs the probability the face is fake
The two streams run in parallel on the same face crop; the gate decides, per image, how much each one contributes.

Training runs in three phases (fusion only, then the forensic stream with the fusion, then full fine-tuning with a much lower learning rate for the backbone) using AdamW, a cosine schedule, mixed precision and early stopping on validation AUC. The project started as an earlier prototype that packed these signals into a padded 128-dimensional "metadata" vector; the final version replaced that with the fixed 406-feature layout, added identity-leakage checks and brought in new test sets.

Data and evaluation

I trained on FaceForensics++ (c23): 500 videos in each of five categories (original, Deepfakes, Face2Face, FaceSwap and NeuralTextures), giving 49,996 aligned 224-pixel face crops. Splits follow the official identity-disjoint lists, and the pipeline asserts that no identity crosses train, validation and test. Celeb-DF-v2 (5,177 test crops) was held out as an unseen dataset. Models are compared on AUC, equal error rate and partial AUC.

FaceForensics++ test set (v1 models)

  • Visual (CNN)
  • Forensic features
  • Hybrid (gated)
AUC
0.972
0.795
0.981
Partial AUC (FPR ≤ 0.1)
0.905
0.654
0.936
Higher is better. n = 6,800 identity-disjoint test crops. Partial AUC is measured up to a 10% false-positive rate.

Source: results/20260602_103250_train_visual.jsonl, 20260602_133754_train_forensic.jsonl, 20260602_140851_train_hybrid.jsonl

Findings

On the in-distribution test set the hybrid was the strongest model (AUC 0.981, equal error rate 7.1%), but its margin over the visual CNN alone was small. The compression sweep is where the results became interesting, and not in the direction I expected.

AUC under JPEG re-compression (v1, FaceForensics++ test)

  • Visual (CNN)
  • Forensic features
  • Hybrid (gated)
0.40.550.70.8511009575503015JPEG quality factor
Lower quality factor means heavier compression. The axis starts at 0.4; an AUC of 0.5 is chance.

Source: results/20260602_151646_compression_sweep.jsonl

  • The visual CNN proved fairly robust: its AUC fell gradually from 0.972 on clean images to 0.864 at JPEG quality 15.
  • The forensic stream, trained on clean images, collapsed to near chance from quality 75 downwards, because compression destroys the very traces it measures.
  • The attention gate responded sensibly: the weight it gave the forensic stream rose from 5% on clean images to 21% at quality 15.

Two of my starting premises were therefore not supported as stated. I treated that as a result rather than a failure, and used it to drive a second iteration.

Iteration two: training for robustness

For v2 I retrained with heavier compression and degradation augmentation (re-encoding, downscaling, blur, gamma and affine changes) and added StyleGAN-generated faces to the training data. Measured on the same FaceForensics++ test crops, the forensic stream held up far better under compression, at a small cost on clean images.

Forensic-stream AUC under compression: v1 vs v2

  • v1 (clean training)
  • v2 (robustness training)
0.40.550.70.8511009575503015JPEG quality factor
v2 gives up a little clean-image accuracy (0.795 → 0.767) for much better behaviour under compression. The axis starts at 0.4.

Source: results/20260608_154115_compare_v1_v2.jsonl

On Celeb-DF-v2 the hybrid's cross-dataset AUC improved from 0.726 to 0.783. The visual stream alone (0.791) edged it out, though, which is an honest limit of the fusion approach as it stands.

Unseen dataset: Celeb-DF-v2 (AUC)

  • v1
  • v2
Visual (CNN)
0.704
0.791
Forensic features
0.552
0.552
Hybrid (gated)
0.726
0.783
Models trained without any Celeb-DF data. 5,177 test crops (1,777 real, 3,400 fake).

Source: results/20260608_154115_compare_v1_v2.jsonl

I also built a Gradio interface that detects and aligns the face in an uploaded image and shows the fake probability, each stream's vote, the gate weights and an ELA heatmap.

What I would do next

  • Benchmark the concatenation and bilinear fusion ablations, which are implemented but were not yet evaluated.
  • Test on a further held-out dataset such as DFDC: StyleGAN faces became in-distribution in v2, so they can no longer serve as an unseen-generator test.
  • Look for forensic signals that survive heavy compression, rather than ones that compression erases.
← Back to all projects