diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..2436d10 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,24 @@ +name: Tests + +on: + push: + pull_request: + +jobs: + model-shape: + runs-on: ubuntu-latest + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install test dependencies + run: pip install -r requirements-dev.txt + + - name: Run tests + run: python -m unittest discover tests diff --git a/.gitignore b/.gitignore index 9527d99..a5e79ab 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,23 @@ +__pycache__/ +*.pyc +.venv/ +venv/ +.env +.DS_Store +.ipynb_checkpoints/ +*.pth +*.pt +*.ckpt +*.mp4 +*.mov +*.avi +*.mkv +outputs/ +temp/ +*.log + +# Local scratch files from earlier experiments todo im.py MODEL_VISUALIZATION_README.md -run_model_viz.py \ No newline at end of file +run_model_viz.py diff --git a/README.md b/README.md index 82d4903..9080f6b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,250 @@ -# Deepfake Detection +# DeepGuard: Video Deepfake Detection System +DeepGuard is a deepfake detection prototype that analyzes uploaded videos and +predicts whether the video is likely real or fake. The app uses a hybrid deep +learning architecture: EfficientNet-B0 extracts spatial features from detected +face frames, and a GRU models temporal patterns across the video sequence. -[GHP 62 Deepfake detection Paper.pdf](https://github.com/user-attachments/files/21153386/GHP.62.Deepfake.detection.Paper.pdf) +Live demo: https://b-a-r-a-p-deepguard.hf.space/ + +## Overview + +DeepGuard combines a Gradio web interface with a PyTorch video classification +model. A user uploads a video, chooses a processing mode, and receives a +REAL/FAKE confidence score. The project also includes preprocessing and training +scripts that document the broader research workflow used to explore spatial, +frequency, and gradient artifacts in deepfake videos. + +This is a research and portfolio project, not a production-grade verification +system. + +## Live Demo + +Try the hosted Gradio app here: https://b-a-r-a-p-deepguard.hf.space/ + +The hosted demo is the easiest way to test the app quickly because local setup +requires PyTorch, OpenCV, dlib, and a trained model checkpoint. + +## Why I Built This + +Deepfake generation tools are becoming more accessible and realistic, which +makes media authenticity harder to evaluate. This project explores how a video +detector can combine frame-level spatial features with temporal sequence +modeling to identify visual inconsistencies that may indicate manipulation. + +The goal is to demonstrate an end-to-end AI/security research prototype: dataset +preprocessing, model architecture, evaluation, and a usable Gradio inference +interface. + +## Features + +- Gradio web app for video upload and prediction +- PyTorch model using EfficientNet-B0 and GRU +- Face detection with dlib and a faster OpenCV Haar cascade option +- Video frame sampling and face crop preprocessing +- Multiple inference modes: Super Fast, Normal, and Deep Think +- Optional visualization of detected face regions and processed face crops +- Example videos included in the app UI +- Hugging Face Space demo for quick testing + +## How It Works + +Inference pipeline: + +```text +Video upload +-> frame sampling +-> face detection +-> face crop preprocessing +-> EfficientNet-B0 feature extraction +-> GRU temporal modeling +-> binary classifier +-> REAL/FAKE score +``` + +`app.py` reads the uploaded video with OpenCV, samples frames from one or more +chunks, detects faces, crops and normalizes the face regions, stacks them into a +sequence tensor, and sends the tensor through the model. The final score is the +average prediction across the processed chunks and optional test-time +augmentation passes. + +## Model Architecture + +The model combines: + +- `EfficientNet-B0`: extracts per-frame spatial features from face crops +- `GRU`: models temporal patterns across the video frame sequence +- `MLP classifier`: converts the final temporal representation into one binary + logit + +The reusable model definition is in `model.py`. The Gradio app currently keeps a +matching model definition inside `app.py` for deployment compatibility. + +## Research Methodology + +The project paper describes a broader research and training pipeline: + +```text +video dataset +-> dlib face tracking +-> facial bounding boxes +-> 32 extracted frames per video +-> RGB/spatial stream +-> DCT frequency stream +-> Sobel gradient stream +-> model training and evaluation +``` + +The research explored three feature families: + +- spatial RGB face crops +- frequency features using Discrete Cosine Transform +- gradient features using the Sobel operator + +Training used AdamW, a cosine annealing learning rate scheduler, automatic +mixed precision, gradient accumulation, and an NVIDIA RTX 3060 12GB GPU. + +## Reported Results + +The project paper reports evaluation on the challenging Celeb-DF-v2 dataset: + +- 87% test accuracy +- 0.907 ROC AUC + +These are reported evaluation results from the project paper and should not be +interpreted as production performance across all deepfake generation methods. +The paper also discusses a generalization gap between validation and test +performance, which is an important limitation for deepfake detection systems. + +## Processing Modes + +- `Super Fast`: uses fewer frames, a smaller image size, one video chunk, and + the faster OpenCV face detector. +- `Normal`: uses the default frame count and image size with dlib face + detection. +- `Deep Think`: uses more chunks and horizontal flip test-time augmentation for + a slower but more thorough pass. + +## Visualization Mode + +The app can run a prediction with visualization. This mode shows: + +- detected face regions +- processed face crops +- frame and chunk analysis +- per-chunk prediction scores +- final REAL/FAKE confidence score + +Screenshots can be added here: + +- `assets/demo-ui.png` +- `assets/prediction-output.png` +- `assets/visualization-output.png` + +## Local Setup + +Python 3.10+ or 3.11 is recommended. + +```bash +git clone https://github.com/Barap1/Deepfake-Detection.git +cd Deepfake-Detection +python -m venv .venv +.venv\Scripts\activate +pip install -r requirements.txt +``` + +On macOS/Linux, activate the virtual environment with: + +```bash +source .venv/bin/activate +``` + +dlib can be difficult to install because it may require CMake and native build +tools. If local installation fails, use the hosted Hugging Face demo for quick +testing. + +Model weights may need to be provided separately depending on how you run the +project. Do not commit new model weights or uploaded videos to GitHub. + +## Usage + +Run the Gradio app with a trained model checkpoint: + +```bash +python app.py --model_path path/to/model.pth +``` + +Then open the local Gradio URL printed in the terminal and upload a video. + +## Testing + +Run the lightweight model-shape test suite: + +```bash +python -m unittest discover tests +``` + +The tests do not require a trained model checkpoint, video file, dlib detector, +or Gradio launch. + +## Project Structure + +```text +. +|-- app.py # Main Gradio app entrypoint +|-- model.py # Reusable EfficientNet-B0 + GRU model +|-- dataset.py # PyTorch dataset and transforms +|-- train.py # Training/evaluation script +|-- sampleDFDC.py # DFDC sampling utility +|-- SpatialFeaturePreprocessing.py # dlib face tracking and bbox extraction +|-- AdvancedFeatureExtraction.py # RGB/DCT/Sobel feature extraction +|-- Example1.mp4 # Example app video +|-- Example2.mp4 # Example app video +|-- Example3.mp4 # Example app video +|-- Example4.mp4 # Example app video +|-- best_model.pth # Tracked model checkpoint +|-- GHP 62 Deepfake detection Paper.pdf +|-- tests/test_model_shape.py # Lightweight model forward-pass test +|-- .github/workflows/tests.yml # CI test workflow +|-- requirements.txt +|-- requirements-dev.txt +|-- README.md +``` + +## Limitations + +- This is a prototype/research project. +- It is not production-grade. +- It is not suitable for high-stakes decisions. +- Predictions depend on video quality, compression, lighting, and face + visibility. +- The model can fail if no face is detected. +- No complete portable training pipeline is currently included in the repo. +- Reported results are dataset-dependent. +- Deepfake detection models can become outdated as generation methods improve. + +## Ethical Use + +This project is for educational and research purposes. It should not be used to +harass, accuse, or make high-stakes judgments about people. Deepfake detection +outputs should be treated as probabilistic signals, not proof. + +## Future Improvements + +- document the full training pipeline +- add dataset and evaluation scripts +- add Grad-CAM or saliency visualizations +- add batch inference +- split preprocessing, inference, and visualization into modules +- add a Dockerfile +- add screenshots or a demo GIF +- add tests for preprocessing utilities +- consolidate the duplicate model definitions in `app.py` and `model.py` after + deployment compatibility is verified + +## Related Writeup / Paper + +- [Improving Deep Fake Detection: Integrating Spatial, Frequency, and Gradient Analyses](https://github.com/user-attachments/files/21153386/GHP.62.Deepfake.detection.Paper.pdf) +- Local tracked copy: `GHP 62 Deepfake detection Paper.pdf` diff --git a/__pycache__/model.cpython-312.pyc b/__pycache__/model.cpython-312.pyc deleted file mode 100644 index 9ce0edb..0000000 Binary files a/__pycache__/model.cpython-312.pyc and /dev/null differ diff --git a/app.py b/app.py index c40d600..5747c31 100644 --- a/app.py +++ b/app.py @@ -1,4 +1,6 @@ -import os +"""Gradio inference app for the DeepGuard video deepfake detector.""" + +import os import argparse import numpy as np import torch @@ -17,13 +19,17 @@ warnings.filterwarnings("ignore") -class Config: - SEQ_LENGTH = 20 - IMG_SIZE = 224 - DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu") - -class DeepfakeDetector(nn.Module): - def __init__(self, pretrained=True, rnn_hidden_size=128, rnn_num_layers=1, dropout_prob=0.5): +class Config: + """Shared inference defaults for the Gradio app.""" + + SEQ_LENGTH = 20 + IMG_SIZE = 224 + DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu") + +class DeepfakeDetector(nn.Module): + """EfficientNet-B0 frame encoder followed by GRU temporal classification.""" + + def __init__(self, pretrained=True, rnn_hidden_size=128, rnn_num_layers=1, dropout_prob=0.5): super(DeepfakeDetector, self).__init__() if pretrained: weights = EfficientNet_B0_Weights.IMAGENET1K_V1 @@ -48,8 +54,10 @@ def __init__(self, pretrained=True, rnn_hidden_size=128, rnn_num_layers=1, dropo nn.Linear(64, 1) ) - def forward(self, x): - batch_size, seq_length, c, h, w = x.shape + def forward(self, x): + """Run a batch of video frame sequences through the detector.""" + + batch_size, seq_length, c, h, w = x.shape x_reshaped = x.view(batch_size * seq_length, c, h, w) cnn_features = self.cnn(x_reshaped) rnn_input = cnn_features.view(batch_size, seq_length, -1) @@ -59,15 +67,19 @@ def forward(self, x): output = self.classifier(last_time_step_output) return output -def get_inference_transforms(image_size): - return A.Compose([ +def get_inference_transforms(image_size): + """Build the standard resize, normalize, and tensor conversion pipeline.""" + + return A.Compose([ A.Resize(height=image_size, width=image_size), A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ToTensorV2(), ]) -def get_inference_transforms_tta(image_size): - # For "Deep Think" mode, adds a horizontal flip +def get_inference_transforms_tta(image_size): + """Build the horizontal-flip test-time augmentation transform.""" + + # For "Deep Think" mode, adds a horizontal flip return A.Compose([ A.Resize(height=image_size, width=image_size), A.HorizontalFlip(p=1.0), # Always flip for TTA @@ -75,9 +87,10 @@ def get_inference_transforms_tta(image_size): ToTensorV2(), ]) -def preprocess_video(video_path, face_detector, fast_face_detector, seq_length, img_size, num_chunks=1, use_fast_detector=False, tta_flip=False): - - cap = cv2.VideoCapture(video_path) +def preprocess_video(video_path, face_detector, fast_face_detector, seq_length, img_size, num_chunks=1, use_fast_detector=False, tta_flip=False): + """Sample video chunks, crop detected faces, and return tensor sequences.""" + + cap = cv2.VideoCapture(video_path) total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) if total_frames == 0: @@ -137,9 +150,10 @@ def preprocess_video(video_path, face_detector, fast_face_detector, seq_length, cap.release() return all_chunks if all_chunks else None -def visualize_detection_process(video_path, face_detector, fast_face_detector, seq_length, img_size, num_chunks=1, use_fast_detector=False, tta_flip=False): - - if video_path is None: +def visualize_detection_process(video_path, face_detector, fast_face_detector, seq_length, img_size, num_chunks=1, use_fast_detector=False, tta_flip=False): + """Create plots and text explaining face detection and preprocessing.""" + + if video_path is None: return None, "No video uploaded" cap = cv2.VideoCapture(video_path) @@ -301,8 +315,10 @@ def visualize_detection_process(video_path, face_detector, fast_face_detector, s return face_detection_plot, processed_faces_plot, analysis_text -def main(args): - print(f"Using device: {Config.DEVICE}") +def main(args): + """Load detectors and model weights, then launch the Gradio interface.""" + + print(f"Using device: {Config.DEVICE}") face_detector = dlib.get_frontal_face_detector() haar_cascade_path = cv2.data.haarcascades + 'haarcascade_frontalface_default.xml' @@ -322,8 +338,10 @@ def main(args): print(f"An error occurred while loading the model: {e}") return - def predict_with_visualization(video_path, mode): - if video_path is None: + def predict_with_visualization(video_path, mode): + """Run prediction and return visual diagnostics for the Gradio UI.""" + + if video_path is None: return {"No video uploaded": 1.0}, None, None, "No video uploaded" print(f"\nProcessing in '{mode}' mode with visualization...") @@ -369,8 +387,10 @@ def predict_with_visualization(video_path, mode): print(f"Prediction complete. REAL: {real_prob:.2%}, FAKE: {fake_prob:.2%}") return {"FAKE": fake_prob, "REAL": real_prob}, face_plot, processed_plot, analysis_text - def predict(video_path, mode): - if video_path is None: return {"No video uploaded": 1.0} + def predict(video_path, mode): + """Run a prediction and return REAL/FAKE label confidences.""" + + if video_path is None: return {"No video uploaded": 1.0} print(f"\nProcessing in '{mode}' mode...") diff --git a/docs/app-architecture.md b/docs/app-architecture.md new file mode 100644 index 0000000..6f0b43f --- /dev/null +++ b/docs/app-architecture.md @@ -0,0 +1,148 @@ +# App Architecture + +## Entrypoint + +`app.py` remains the main Gradio entrypoint for local usage and Hugging Face +Space compatibility. + +Run it with: + +```bash +python app.py --model_path path/to/model.pth +``` + +The app requires a model checkpoint path at startup. It loads the checkpoint, +builds the Gradio interface, and launches the app from the same file. + +## Config Class + +`Config` stores the core inference defaults: + +- `SEQ_LENGTH = 20` +- `IMG_SIZE = 224` +- `DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")` + +The processing modes override some of these values at prediction time. + +## Model Loading + +Inside `main(args)`, the app: + +1. creates `DeepfakeDetector(pretrained=False)` +2. loads weights from `args.model_path` +3. moves the model to `Config.DEVICE` +4. sets the model to evaluation mode + +If the model file is missing or cannot be loaded, the app prints an error and +returns before launching Gradio. + +## Face Detectors + +The app initializes two face detectors: + +- dlib frontal face detector: used by Normal and Deep Think modes +- OpenCV Haar cascade detector: used by Super Fast mode + +The dlib detector is slower but generally more robust for the default path. The +OpenCV detector is used when the app needs a faster pass with fewer frames. + +## Preprocessing Flow + +### `preprocess_video()` + +`preprocess_video()` reads the uploaded video with OpenCV, seeks to one or more +chunk start positions, detects a face in sampled frames, crops the detected face, +pads the sequence when needed, applies transforms, and returns tensor chunks for +model inference. + +Important parameters: + +- `seq_length`: number of face frames to collect per chunk +- `img_size`: resize target for face crops +- `num_chunks`: number of video chunks to sample +- `use_fast_detector`: switches between OpenCV and dlib detection +- `tta_flip`: adds a horizontally flipped test-time augmentation pass + +### `get_inference_transforms()` + +Builds the standard Albumentations inference transform: + +- resize to the configured image size +- ImageNet normalization +- tensor conversion + +### `get_inference_transforms_tta()` + +Builds the Deep Think test-time augmentation transform: + +- resize to the configured image size +- horizontal flip +- ImageNet normalization +- tensor conversion + +## Visualization Flow + +### `visualize_detection_process()` + +This function runs a readable analysis pass over the video and returns: + +- a face detection plot +- a processed face crop plot +- detailed analysis text + +The visualization includes video metadata, face detection counts by chunk, +detected face bounding boxes, processed face crops, feature extraction context, +and test-time augmentation status. + +## Prediction Flow + +### `predict()` + +`predict()` is the fast prediction callback for the Predict Only button. It: + +1. maps the selected processing mode to preprocessing parameters +2. calls `preprocess_video()` +3. runs each tensor chunk through the loaded model +4. averages chunk predictions +5. returns a Gradio label dictionary with FAKE and REAL probabilities + +### `predict_with_visualization()` + +`predict_with_visualization()` follows the same prediction path but first calls +`visualize_detection_process()`. It returns the prediction label, face detection +plot, processed face plot, and detailed analysis text. + +## Processing Modes + +- `Super Fast`: sequence length 8, image size 160, one chunk, OpenCV face + detector, no test-time augmentation +- `Normal`: sequence length 20, image size 224, one chunk, dlib detector, no + test-time augmentation +- `Deep Think`: sequence length 20, image size 224, three chunks, dlib detector, + horizontal flip test-time augmentation + +## Gradio UI Components + +The Gradio app uses: + +- video input +- processing mode radio +- Predict Only button +- Predict with Visualization button +- label output +- face detection plot +- processed faces plot +- detailed analysis textbox +- example videos + +The visualization row is hidden by default and shown after the visualization +callback runs. + +## Duplicate Model Definitions + +The repo currently has a model architecture in both `app.py` and `model.py`. +Future cleanup should consolidate this into one shared definition, but that +should not be changed casually. `app.py` likely supports the current +Gradio/Hugging Face deployment, so the duplicate definition is intentionally +left in place until deployment compatibility can be fully verified. + diff --git a/docs/final-polish-summary.md b/docs/final-polish-summary.md new file mode 100644 index 0000000..177dd6c --- /dev/null +++ b/docs/final-polish-summary.md @@ -0,0 +1,100 @@ +# Final Polish Summary + +## Changes Made + +- Added a project audit and improvement plan. +- Rewrote the README as a polished portfolio presentation for DeepGuard. +- Preserved the Hugging Face demo link and original paper link. +- Added a research summary based on the tracked project paper. +- Added setup notes for Python, dlib, model weights, GPU usage, and files that + should not be committed. +- Updated requirements files for runtime and lightweight CI testing. +- Expanded `.gitignore` to prevent new model weights, videos, logs, outputs, + virtual environments, notebooks checkpoints, and cache files from being + committed. +- Removed the already-tracked Python bytecode file from version control. +- Added a lightweight model-shape unittest that does not require model weights, + videos, dlib, or Gradio. +- Added a GitHub Actions workflow that installs only `requirements-dev.txt` and + runs the lightweight unittest suite. +- Added Gradio app architecture documentation. +- Added low-risk inline docstrings to `app.py` and `model.py` without changing + callback signatures, model behavior, or app launch behavior. + +## Commits Created + +1. `142d05e` - Add project audit and improvement plan +2. `cd119de` - Rewrite README for DeepGuard portfolio presentation +3. `38e34e0` - Add research summary from project paper +4. `67b40ff` - Add requirements, gitignore, and setup notes +5. `42e9468` - Add lightweight model tests and CI workflow +6. `9f02c6b` - Document Gradio app architecture +7. `11b4a52` - Add inline documentation for inference pipeline + +This file is added in the final summary commit. + +## Validation Commands + +### Passed + +```bash +git status --short --branch +``` + +Output before this summary file was created: + +```text +## codex/deepguard-portfolio-polish +``` + +### Could Not Run Successfully + +```bash +python -m unittest discover tests +``` + +Result: + +```text +ModuleNotFoundError: No module named 'torch' +``` + +The active local interpreter is Python 3.13 and does not have PyTorch installed. +The test itself is intentionally lightweight and the GitHub Actions workflow uses +Python 3.11 with `pip install -r requirements-dev.txt`. + +```bash +python app.py --help +``` + +Result: + +```text +ModuleNotFoundError: No module named 'torch' +``` + +`app.py` imports PyTorch at module import time, so `--help` cannot run until the +runtime dependencies are installed. + +## Remaining Recommended Next Steps + +- Add real screenshots for `assets/demo-ui.png`, + `assets/prediction-output.png`, and `assets/visualization-output.png`. +- Verify the Hugging Face Space still launches after dependency updates. +- Document the model weight download path if weights are moved outside Git. +- Eventually consolidate the duplicate model definitions in `app.py` and + `model.py`. +- Eventually add portable training and evaluation scripts if the full dataset + workflow is available. +- Update the GitHub repository description to: + "Gradio deepfake detection app using EfficientNet-B0 + GRU video sequence + modeling." + +## Entrypoint Status + +`app.py` was left as the main Gradio entrypoint. The expected command remains: + +```bash +python app.py --model_path path/to/model.pth +``` + diff --git a/docs/project-audit.md b/docs/project-audit.md new file mode 100644 index 0000000..119e9c9 --- /dev/null +++ b/docs/project-audit.md @@ -0,0 +1,198 @@ +# Project Audit and Improvement Plan + +## Current Repository Snapshot + +The repository currently contains a Gradio deepfake detection app, model code, +dataset and preprocessing scripts, a sparse README, a tracked paper PDF, example +videos, and a tracked model checkpoint. + +Tracked files at the start of this audit: + +- `.gitignore` +- `AdvancedFeatureExtraction.py` +- `SpatialFeaturePreprocessing.py` +- `app.py` +- `best_model.pth` +- `dataset.py` +- `Example1.mp4` +- `Example2.mp4` +- `Example3.mp4` +- `Example4.mp4` +- `GHP 62 Deepfake detection Paper.pdf` +- `model.py` +- `README.md` +- `requirements.txt` +- `sampleDFDC.py` +- `train.py` +- `__pycache__/model.cpython-312.pyc` + +The tracked model checkpoint, example videos, paper PDF, and Python cache file +were already present before this polish pass. This audit does not add duplicate +large binaries. + +## What `app.py` Does + +`app.py` is the main runnable Gradio entrypoint. It accepts a required model +path: + +```bash +python app.py --model_path path/to/model.pth +``` + +At launch, it: + +- selects CUDA if available, otherwise CPU +- initializes a dlib frontal face detector +- initializes an OpenCV Haar cascade detector for faster face detection +- defines and loads a local `DeepfakeDetector` model class +- loads model weights from `--model_path` +- builds a Gradio UI with video upload, processing mode selection, prediction + output, example videos, and optional visualization plots + +The app exposes three processing modes: + +- `Super Fast`: shorter sequence length, smaller image size, one chunk, and the + OpenCV Haar detector +- `Normal`: default sequence length and image size, one chunk, and dlib face + detection +- `Deep Think`: multiple chunks with dlib detection and horizontal flip + test-time augmentation + +The inference path is: + +1. read uploaded video with OpenCV +2. sample frames from one or more chunks +3. detect a face in each sampled frame +4. crop the detected face +5. resize and normalize crops with Albumentations +6. stack face crops into a tensor sequence +7. run EfficientNet-B0 feature extraction +8. run GRU temporal modeling +9. classify the sequence as real or fake + +The visualization path shows detected face boxes, processed face crops, per-chunk +predictions, and a final confidence summary. + +## What `model.py` Does + +`model.py` defines a reusable `DeepfakeDetector` class. It combines: + +- EfficientNet-B0 as the per-frame CNN feature extractor +- a GRU for temporal sequence modeling +- a small MLP classifier with two linear layers, ReLU, dropout, and one output + logit + +The model expects an input tensor shaped like: + +```text +[batch_size, sequence_length, channels, height, width] +``` + +It returns one logit per video sequence with shape: + +```text +[batch_size, 1] +``` + +## Supporting Scripts + +- `sampleDFDC.py` samples real and fake videos from a local DFDC-style dataset + into a smaller training set. +- `SpatialFeaturePreprocessing.py` uses dlib to detect and track faces, then + writes frame-level bounding boxes to JSON files. +- `AdvancedFeatureExtraction.py` reads bounding-box JSON files and source + videos, then extracts RGB, DCT frequency, and Sobel gradient streams into + compressed `.npz` files. +- `dataset.py` defines a PyTorch dataset for `.npz` feature files plus training + and validation transforms. +- `train.py` trains the model with PyTorch, AdamW, gradient accumulation, AMP, + and validation/test metrics. It contains local absolute dataset paths and is + not currently a portable end-to-end training pipeline. + +## Dependencies Detected from Imports + +Runtime and app dependencies: + +- `torch` +- `torchvision` +- `opencv-python` or an OpenCV package with `cv2` +- `dlib` +- `albumentations` +- `gradio` +- `tqdm` +- `pillow` +- `matplotlib` +- `numpy` + +Training and feature extraction dependencies: + +- `scipy` +- `scikit-learn` + +The app currently depends on dlib, which can be difficult to install on some +systems because it may require CMake and native build tools. + +## Current Gradio Entrypoint Behavior + +`app.py` remains the compatibility-critical Gradio entrypoint. The command-line +contract is: + +```bash +python app.py --model_path path/to/model.pth +``` + +The Hugging Face Space deployment likely depends on this file staying runnable +as-is. Refactoring the UI, model loading, or callback signatures would carry +risk unless tested directly in the deployment environment. + +## What the Research Paper Contributes + +The tracked paper, "Improving Deep Fake Detection: Integrating Spatial, +Frequency, and Gradient Analyses," provides important project context that is +not represented in the original README: + +- the work targets the generalization problem in deepfake detection +- the architecture uses EfficientNet-B0 plus GRU sequence modeling +- evaluation was performed on the challenging Celeb-DF-v2 dataset +- reported test accuracy is 87% +- reported ROC AUC is 0.907 +- training used 20,000 real and fake videos +- dlib face tracking saved facial bounding boxes +- 32 frames per video were extracted +- RGB/spatial, DCT frequency, and Sobel gradient feature streams were explored +- training used AdamW, a cosine annealing scheduler, AMP, gradient accumulation, + and an NVIDIA RTX 3060 12GB +- the discussion notes a validation-to-test generalization gap + +These results should be described as reported project evaluation results, not +as universal production performance. + +## Safe Improvements + +The safest high-impact improvements are documentation and lightweight checks: + +- rewrite the README as an honest portfolio-quality project page +- preserve the Hugging Face demo link +- preserve the existing paper link +- add a research summary based on the tracked paper +- add setup notes for local usage and dlib installation friction +- add a `.gitignore` that prevents new model weights, videos, logs, outputs, and + virtual environments from being committed +- add lightweight model-shape tests that import only `model.py` +- add CI that does not install dlib, launch Gradio, require videos, or require + model weights +- document the Gradio app architecture without refactoring `app.py` + +## Deferred Work + +The following changes should be deferred until they can be verified more deeply: + +- consolidating the duplicate model definitions in `app.py` and `model.py` +- moving preprocessing, inference, and visualization out of `app.py` +- changing Gradio callback signatures or app launch behavior +- making `train.py` a fully portable training pipeline +- adding complete dataset download, preprocessing, and evaluation scripts +- removing or replacing tracked large files unless the repository owner confirms + that history and hosting constraints should be addressed +- adding production claims or broad real-world accuracy statements + diff --git a/docs/research-summary.md b/docs/research-summary.md new file mode 100644 index 0000000..589abd5 --- /dev/null +++ b/docs/research-summary.md @@ -0,0 +1,122 @@ +# Research Summary + +## Title + +Improving Deep Fake Detection: Integrating Spatial, Frequency, and Gradient +Analyses + +## Motivation + +Deepfake generation has become easier to access and increasingly realistic. The +paper frames this as a risk to information integrity and public trust because +synthetic videos can be used for disinformation and impersonation. + +The central technical motivation is generalization. Many deepfake detectors +perform well on the datasets they were trained on but degrade when evaluated on +unseen or in-the-wild videos. The paper argues that effective detection should +focus on features that are more fundamental to the synthesis process rather than +artifacts tied only to one training dataset or generation method. + +## Problem + +Deepfake detectors often fail to generalize to new forgery techniques or unseen +video distributions. A model can learn dataset-specific artifacts instead of +robust manipulation signals, which creates a gap between validation performance +and real test performance. + +## Dataset and Preprocessing + +The paper reports a training dataset of 20,000 real and fake videos. + +Preprocessing used a two-stage approach: + +1. dlib face tracking detected faces and saved facial bounding boxes for each + video. +2. 32 frames per video were extracted and processed into feature streams. + +The repository reflects this workflow through: + +- `SpatialFeaturePreprocessing.py`, which detects/tracks faces and writes + bounding boxes to JSON files +- `AdvancedFeatureExtraction.py`, which uses those boxes to extract per-video + feature arrays + +## Feature Streams Explored + +The research explored three feature streams: + +- Spatial/RGB: resized face crops from selected video frames +- Frequency/DCT: frequency-domain features generated with Discrete Cosine + Transform +- Gradient/Sobel: edge and gradient information generated with the Sobel + operator + +These streams were saved as compressed `.npz` files for training and +evaluation. + +## Model Architecture + +The reported architecture is a hybrid spatio-temporal model: + +- EfficientNet-B0 extracts discriminative spatial features from individual video + frames. +- A Gated Recurrent Unit (GRU) models temporal coherence across the frame + sequence. +- A small MLP classifier produces the final binary output. + +This architecture is implemented in `model.py` and mirrored in `app.py` for the +Gradio inference workflow. + +## Training Procedure + +The paper reports the following training setup: + +- 10 epochs +- NVIDIA RTX 3060 12GB GPU +- AdamW optimizer +- cosine annealing learning rate scheduler +- automatic mixed precision +- gradient accumulation to work within hardware constraints + +The repository includes `train.py`, which demonstrates a PyTorch training loop +with AdamW, mixed precision, gradient accumulation, validation metrics, and +checkpoint saving. It currently contains local dataset paths and should be +treated as research code rather than a fully portable training pipeline. + +## Evaluation + +The paper reports evaluation on Celeb-DF-v2, a challenging deepfake forensics +dataset. + +Reported results: + +- 87% test accuracy +- 0.907 ROC AUC + +These results should be understood as reported project evaluation results on +that dataset. They should not be treated as guaranteed real-world or +production-grade performance across all video sources and deepfake generation +methods. + +## Discussion + +The reported accuracy and ROC AUC indicate that the EfficientNet-B0 plus GRU +approach learned useful spatial and temporal signals. At the same time, the +paper explicitly notes a generalization gap between validation and test +performance. + +That gap matters because deepfake generation methods evolve quickly. Future work +should focus on more fundamental manipulation artifacts, broader evaluation +coverage, and stronger generalization to unseen datasets and wild videos. + +## Relationship to the Current App + +The current Gradio app demonstrates the deployed inference side of the project. +It lets a user upload a video, runs face detection and face-crop preprocessing, +passes sampled frame sequences through the EfficientNet-B0 plus GRU model, and +returns a REAL/FAKE score. + +This research summary documents the broader training and evaluation approach +behind the project: dataset construction, dlib face tracking, multi-stream +feature extraction, training setup, and reported Celeb-DF-v2 results. + diff --git a/docs/setup-notes.md b/docs/setup-notes.md new file mode 100644 index 0000000..b98c893 --- /dev/null +++ b/docs/setup-notes.md @@ -0,0 +1,77 @@ +# Setup Notes + +## Recommended Python Version + +Use Python 3.10+ or 3.11 for local development. + +## Fastest Way to Try the Project + +The hosted Hugging Face demo is the easiest path for quick testing: + +https://b-a-r-a-p-deepguard.hf.space/ + +Local setup requires PyTorch, OpenCV, dlib, Gradio, and access to a trained model +checkpoint. + +## Local Installation + +```bash +python -m venv .venv +.venv\Scripts\activate +pip install -r requirements.txt +``` + +On macOS/Linux: + +```bash +source .venv/bin/activate +pip install -r requirements.txt +``` + +## dlib Installation Notes + +dlib may require native build tools and CMake. If `pip install dlib` fails, +install the platform build prerequisites first, then rerun the requirements +installation. + +On Windows, this may require Visual Studio Build Tools and CMake. On Linux, this +may require compiler and Python development headers. On macOS, this may require +Xcode Command Line Tools and CMake. + +## Running the Gradio App + +Run the app with a trained model checkpoint: + +```bash +python app.py --model_path path/to/model.pth +``` + +`app.py` remains the main entrypoint for local Gradio usage and Hugging Face +Space compatibility. + +## Hardware Notes + +GPU is optional for inference, but CUDA can improve speed when a compatible GPU +and PyTorch CUDA build are available. CPU inference should still work, although +larger videos and Deep Think mode may be slower. + +## Model Weights + +Model weights may need to be provided separately depending on the deployment or +local environment. Do not commit new model weights to GitHub. + +The repository already contained a tracked checkpoint before this documentation +pass. Future checkpoints should be shared through release assets, external model +hosting, or another documented download path rather than committed directly. + +## Files That Should Not Be Committed + +Do not commit: + +- new `.pth`, `.pt`, or `.ckpt` model files +- uploaded or generated videos +- temporary output folders +- logs +- virtual environments +- Python cache files + diff --git a/model.py b/model.py index 25eba98..108a213 100644 --- a/model.py +++ b/model.py @@ -1,4 +1,6 @@ -import torch +"""Reusable EfficientNet-B0 plus GRU model for video deepfake detection.""" + +import torch import torch.nn as nn from torchvision.models import efficientnet_b0, EfficientNet_B0_Weights @@ -35,9 +37,10 @@ def __init__(self, pretrained=True, rnn_hidden_size=128, rnn_num_layers=1, dropo nn.Linear(64, 1) ) - def forward(self, x): - - batch_size, seq_length, c, h, w = x.shape + def forward(self, x): + """Return one binary logit for each video sequence in the batch.""" + + batch_size, seq_length, c, h, w = x.shape x_reshaped = x.view(batch_size * seq_length, c, h, w) @@ -53,4 +56,4 @@ def forward(self, x): # Pass through the final classifier output = self.classifier(last_time_step_output) - return output \ No newline at end of file + return output diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..b5b86d4 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,3 @@ +torch +torchvision +numpy diff --git a/requirements.txt b/requirements.txt index 15661bc..e25e664 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,12 @@ -torch==2.0.0 -torchvision==0.15.1 -gradio -dlib-bin -opencv-python-headless -albumentations -scipy -tqdm \ No newline at end of file +torch +torchvision +opencv-python +dlib +albumentations +gradio +tqdm +pillow +matplotlib +numpy +scipy +scikit-learn diff --git a/tests/test_model_shape.py b/tests/test_model_shape.py new file mode 100644 index 0000000..dea9a62 --- /dev/null +++ b/tests/test_model_shape.py @@ -0,0 +1,22 @@ +import unittest + +import torch + +from model import DeepfakeDetector + + +class DeepfakeDetectorShapeTest(unittest.TestCase): + def test_forward_output_shape(self): + model = DeepfakeDetector(pretrained=False) + model.eval() + + inputs = torch.randn(1, 2, 3, 224, 224) + + with torch.no_grad(): + output = model(inputs) + + self.assertEqual(tuple(output.shape), (1, 1)) + + +if __name__ == "__main__": + unittest.main()