| --- |
| license: apache-2.0 |
| language: |
| - en |
| library_name: pytorch |
| pipeline_tag: image-classification |
| base_model: laion/CLIP-ViT-B-32-laion2B-s34B-b79K |
| datasets: |
| - yangsangtai/tiny-genimage |
| metrics: |
| - accuracy |
| - precision |
| - recall |
| - f1 |
| - roc_auc |
| tags: |
| - image-classification |
| - ai-generated-image-detection |
| - deepfake-detection |
| - clip |
| - computer-vision |
| - binary-classification |
| --- |
| |
| # CLIP-Based AI-Generated Image Detector |
|
|
| ## Model Description |
|
|
| This model is a binary image classifier that distinguishes real (natural) photographs from AI-generated images. It uses a frozen CLIP ViT-B/32 vision encoder (pretrained on LAION-2B) as a fixed feature extractor, with a lightweight multilayer perceptron classification head trained on top of the extracted image embeddings. |
|
|
| The model was developed and trained in a Kaggle notebook titled `complete_Fakeddit_image`. Despite the notebook name, the training data used is the `tiny-genimage` dataset rather than the Fakeddit dataset; this README describes the model as actually implemented and trained. |
|
|
| ## Model Details |
|
|
| - **Base encoder:** CLIP ViT-B-32, pretrained weights `laion2b_s34b_b79k` (loaded via `open_clip`) |
| - **Encoder state:** Frozen; no gradient updates applied to CLIP parameters during training |
| - **Classification head:** Fully connected network operating on 512-dimensional, L2-normalized CLIP image embeddings |
|
|
| | Layer | Output Size | Normalization | Activation | Dropout | |
| |---|---|---|---|---| |
| | Linear | 512 | BatchNorm1d | GELU | 0.4 | |
| | Linear | 256 | BatchNorm1d | GELU | 0.3 | |
| | Linear | 128 | BatchNorm1d | GELU | 0.2 | |
| | Linear | 2 | - | - | - | |
|
|
| - **Output:** Two logits corresponding to the classes `real` (label 0) and `ai-generated` (label 1) |
| - **Framework:** PyTorch, with `open_clip` for the CLIP backbone |
| - **Input resolution:** 224 x 224 pixels, RGB |
|
|
| ## Intended Use |
|
|
| The model is intended for research and experimentation in AI-generated image detection, such as: |
|
|
| - Screening images for likely synthetic origin |
| - Research on generalization of detectors across different generative model families |
| - Educational use in understanding CLIP-based transfer learning for detection tasks |
|
|
| ### Out of Scope Use |
|
|
| This model is not intended for: |
|
|
| - Legal, forensic, or high-stakes determinations of image authenticity without human review |
| - Detection of generative models or techniques not represented in the training distribution |
| - Use as a sole determinant of content moderation decisions |
|
|
| ## Training Data |
|
|
| The model was trained on the `tiny-genimage` dataset (source: `yangsangtai/tiny-genimage`), which pairs natural images with images produced by seven different generative model families. |
|
|
| - **Total images:** 35,000 |
| - **Class balance:** 17,500 real images (label 0), 17,500 AI-generated images (label 1) |
| - **Train / validation split:** 28,000 / 7,000 images |
|
|
| Generators represented in the dataset, each contributing 5,000 images: |
|
|
| - imagenet_ai_0424_wukong |
| - imagenet_glide |
| - imagenet_ai_0419_biggan |
| - imagenet_ai_0419_vqdm |
| - imagenet_midjourney |
| - imagenet_ai_0424_sdv5 |
| - imagenet_ai_0508_adm |
| |
| ## Training Procedure |
| |
| ### Preprocessing and Augmentation |
| |
| Implemented using the `albumentations` library. |
| |
| **Training transforms:** |
| - Resize to 224 x 224 |
| - Horizontal flip (probability 0.5) |
| - Random brightness/contrast (probability 0.3) |
| - Normalization |
| - Conversion to tensor |
| |
| **Validation transforms:** |
| - Resize to 224 x 224 |
| - Normalization |
| - Conversion to tensor |
| |
| ### Optimization |
| |
| - **Loss function:** Cross-entropy loss |
| - **Optimizer:** AdamW, applied only to the classification head parameters |
| - **Learning rate:** 1e-4 (initial training phase), reduced to 1e-5 for a subsequent fine-tuning phase |
| - **Learning rate schedule:** Cosine annealing |
| - **Batch size:** 32 |
| - **Maximum epochs:** 20, with early stopping (patience of 5 epochs, monitored on validation F1 score) |
| - **Checkpointing:** Best model saved whenever validation F1 improved; full training state (model, optimizer, scheduler, epoch, best F1) checkpointed for resumption |
| - **Hardware:** Single NVIDIA Tesla T4 GPU |
| |
| Training was conducted in two stages within the notebook: an initial run to 18 epochs before early stopping triggered a checkpoint save, followed by a resumed run at a lower learning rate for 2 additional epochs. |
| |
| ## Evaluation |
| |
| Evaluation was performed on the held-out validation split (7,000 images) using the checkpoint with the best validation F1 score. |
| |
| ### Final Reported Metrics |
| |
| | Metric | Score | |
| |---|---| |
| | Accuracy | 0.9500 | |
| | Precision | 0.9474 | |
| | Recall | 0.9529 | |
| | F1 Score | 0.9501 | |
| | ROC AUC | 0.9894 | |
| |
| A confusion matrix was also generated on the validation set to inspect class-wise performance; see the original notebook for the corresponding plot. |
| |
| ## Usage |
| |
| ```python |
| import torch |
| import torch.nn as nn |
| import torch.nn.functional as F |
| import open_clip |
| from PIL import Image |
| import albumentations as A |
| from albumentations.pytorch import ToTensorV2 |
| import numpy as np |
|
|
| DEVICE = "cuda" if torch.cuda.is_available() else "cpu" |
| |
| # Load CLIP backbone |
| clip_model, _, _ = open_clip.create_model_and_transforms( |
| "ViT-B-32", |
| pretrained="laion2b_s34b_b79k" |
| ) |
| clip_model = clip_model.to(DEVICE) |
| for param in clip_model.parameters(): |
| param.requires_grad = False |
| |
| # Define classifier head |
| class CLIPBinaryClassifier(nn.Module): |
| def __init__(self): |
| super().__init__() |
| self.clip = clip_model |
| self.classifier = nn.Sequential( |
| nn.Linear(512, 512), nn.BatchNorm1d(512), nn.GELU(), nn.Dropout(0.4), |
| nn.Linear(512, 256), nn.BatchNorm1d(256), nn.GELU(), nn.Dropout(0.3), |
| nn.Linear(256, 128), nn.BatchNorm1d(128), nn.GELU(), nn.Dropout(0.2), |
| nn.Linear(128, 2) |
| ) |
| |
| def forward(self, images): |
| with torch.no_grad(): |
| features = self.clip.encode_image(images) |
| features = F.normalize(features, dim=-1) |
| return self.classifier(features) |
| |
| # Load trained weights |
| model = CLIPBinaryClassifier().to(DEVICE) |
| model.load_state_dict(torch.load("best_clip_detector.pth", map_location=DEVICE)) |
| model.eval() |
| |
| # Preprocess an image |
| transform = A.Compose([ |
| A.Resize(224, 224), |
| A.Normalize(), |
| ToTensorV2() |
| ]) |
| |
| image = np.array(Image.open("example.jpg").convert("RGB")) |
| image_tensor = transform(image=image)["image"].unsqueeze(0).to(DEVICE) |
|
|
| # Run inference |
| with torch.no_grad(): |
| logits = model(image_tensor) |
| probs = torch.softmax(logits, dim=1) |
| prediction = logits.argmax(1).item() |
| |
| label_map = {0: "real", 1: "ai-generated"} |
| print(label_map[prediction], probs.cpu().numpy()) |
| ``` |
| |
| ## Limitations |
| |
| - The training data is derived from ImageNet-based real images paired with a fixed set of seven generative model families; performance on generators, domains, or image types outside this distribution is not established. |
| - The dataset is referred to as "tiny-genimage," implying it is a reduced-scale subset of a larger dataset; results may not generalize to the full-scale version. |
| - The classification head was trained on frozen CLIP embeddings only; the underlying CLIP encoder was not fine-tuned, which may limit adaptation to subtle generation artifacts not captured by general-purpose CLIP features. |
| - No adversarial robustness testing was performed against images specifically crafted to evade detection. |
| |
| ## Citation |
| |
| If you use this model, please cite the underlying CLIP and dataset resources: |
| |
| ``` |
| CLIP backbone: laion2b_s34b_b79k (OpenCLIP, LAION) |
| Dataset: tiny-genimage (yangsangtai/tiny-genimage) |
| ``` |