Converted from the official PyTorch weights released by the authors at erprogs/GenConViT.
Model Description
GenConViT is a hybrid architecture for deepfake video detection that combines:
A CNN Encoder-Decoder that learns to reconstruct the input face image
A ConvNeXt-Tiny + Swin Transformer-Tiny backbone (via hybrid patch embedding) that extracts features from both the reconstructed and original images
A classification head that concatenates both feature vectors and outputs a binary REAL/FAKE prediction
The ED variant is one of two independent networks in the full GenConViT framework (the other being a VAE variant). It processes an input face image through two parallel paths using shared backbone weights, producing a 2-class logit output.
Numerical comparison against the original PyTorch model across 100 random inputs:
Metric
Value
Max Absolute Error
1.15e-05
Mean Absolute Error
4.31e-06
Mean Relative Error
0.015%
Classification Agreement
100%
The conversion is numerically equivalent to the original PyTorch model.
Usage
Installation
pip install onnxruntime numpy pillow
Inference on a Single Image
python
1import numpy as np
2import onnxruntime as ort
3from PIL import Image
45# ImageNet normalization constants6MEAN = np.array([0.485,0.456,0.406], dtype=np.float32).reshape(1,3,1,1)7STD = np.array([0.229,0.224,0.225], dtype=np.float32).reshape(1,3,1,1)89defpreprocess(image_path:str)-> np.ndarray:10"""Load and preprocess a face image for GenConViT."""11 img = Image.open(image_path).convert("RGB").resize((224,224))12# HWC uint8 -> CHW float32 [0, 1] -> ImageNet normalized13 arr = np.asarray(img, dtype=np.float32)/255.014 arr = np.transpose(arr,(2,0,1))[np.newaxis]# (1, 3, 224, 224)15return(arr - MEAN)/ STD
1617defpredict(session: ort.InferenceSession, image_path:str)->tuple[str,float]:18"""Run prediction on a single face image. Returns (label, confidence)."""19 input_tensor = preprocess(image_path)20 logits = session.run(None,{"input": input_tensor})[0]# (1, 2)2122 scores =1.0/(1.0+ np.exp(-logits))# sigmoid23 mean_scores = scores.mean(axis=0)2425 pred_class =int(np.argmax(mean_scores))26 label ="FAKE"if pred_class ==0else"REAL"27 confidence =float(mean_scores[pred_class])28return label, confidence
2930# Load model31session = ort.InferenceSession("genconvit_ed_inference.onnx")3233# Predict34label, confidence = predict(session,"face.jpg")35print(f"{label} (confidence: {confidence:.4f})")
Inference on Video Frames
python
1import numpy as np
2import onnxruntime as ort
3from PIL import Image
45MEAN = np.array([0.485,0.456,0.406], dtype=np.float32).reshape(1,3,1,1)6STD = np.array([0.229,0.224,0.225], dtype=np.float32).reshape(1,3,1,1)78defpreprocess_frames(face_images:list[np.ndarray])-> np.ndarray:9"""Preprocess a list of cropped face images (HWC uint8 numpy arrays)."""10 batch = np.stack([11 np.transpose(img.astype(np.float32)/255.0,(2,0,1))12for img in face_images
13])# (N, 3, 224, 224)14return(batch - MEAN)/ STD
1516defpredict_video(session: ort.InferenceSession, face_frames:list[np.ndarray])->tuple[str,float]:17"""
18 Predict on a list of face crops extracted from video frames.
19 Each face_frame should be a 224x224 RGB uint8 numpy array.
20 """21 input_tensor = preprocess_frames(face_frames)2223# Run inference frame by frame (or batched if memory allows)24 all_scores =[]25for i inrange(len(input_tensor)):26 logits = session.run(None,{"input": input_tensor[i:i+1]})[0]27 scores =1.0/(1.0+ np.exp(-logits))# sigmoid28 all_scores.append(scores[0])2930 all_scores = np.stack(all_scores)# (N, 2)31 mean_scores = all_scores.mean(axis=0)3233 pred_class =int(np.argmax(mean_scores))34 label ="FAKE"if pred_class ==0else"REAL"35 confidence =float(mean_scores[pred_class])36return label, confidence
3738# Example usage:39# session = ort.InferenceSession("genconvit_ed_inference.onnx")40# face_crops = [...] # list of 224x224 RGB numpy arrays from face detection41# label, confidence = predict_video(session, face_crops)
Preprocessing Requirements
The model expects cropped face images, not raw frames. You must run face detection before inference:
Extract frames from video
Detect and crop faces (e.g., using face_recognition, dlib, mediapipe, or any face detector)
Resize each face crop to 224x224 RGB
Normalize with ImageNet stats: mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]
Output Interpretation
The model outputs 2 raw logits: [score_0, score_1].
After applying sigmoid and averaging across frames:
argmax == 0 (score_0 > score_1) -> FAKE
argmax == 1 (score_1 > score_0) -> REAL
This follows the original GenConViT convention where class 0 = FAKE and class 1 = REAL (then the label is flipped via prediction ^ 1 in the original code; the logic above already accounts for this).
Training Data and Performance
The original model was trained and evaluated on:
Dataset
Accuracy
AUC
DFDC
-
-
FaceForensics++
-
-
Celeb-DF v2
-
-
DeepfakeTIMIT
-
-
Average across datasets: 95.8% accuracy, 99.3% AUC (as reported in the paper for the full GenConViT ensemble). Individual ED network results may differ.
Citation
bibtex
1@article{wodajo2023genconvit,
2 title={Deepfake Video Detection Using Generative Convolutional Vision Transformer},
3 author={Wodajo, Deressa and Mareen, Hannes and Lambert, Peter and Atnafu, Solomon and Akhtar, Zahid and Van Wallendael, Glenn},
4 journal={Applied Sciences},
5 volume={15},
6 number={12},
7 pages={6622},
8 year={2025},
9 publisher={MDPI},
10 doi={10.3390/app15126622}
11}