Reju983 commited on
Commit
f53f978
·
verified ·
1 Parent(s): 8540127

Add inference script for detecting AI-generated images

Browse files
Files changed (1) hide show
  1. inference.py +156 -0
inference.py ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ AI-Generated Image Detector - Inference Script
3
+ Detects whether an image is real or AI-generated using frequency analysis + deep learning.
4
+
5
+ Usage:
6
+ python inference.py --image path/to/image.jpg
7
+ python inference.py --image https://example.com/image.png
8
+ python inference.py --image_dir path/to/folder/
9
+ """
10
+ import os
11
+ import io
12
+ import math
13
+ import argparse
14
+ import json
15
+ import numpy as np
16
+ import torch
17
+ import torch.nn as nn
18
+ import torch.nn.functional as F
19
+ from PIL import Image
20
+ from torchvision.transforms import Compose, Resize, CenterCrop, ToTensor, Normalize
21
+ from pathlib import Path
22
+
23
+
24
+ # Import model architecture from train.py
25
+ from train import FrequencyAwareDetector
26
+
27
+
28
+ def load_model(model_dir=".", device="cuda" if torch.cuda.is_available() else "cpu"):
29
+ """Load trained FrequencyAwareDetector model."""
30
+ config_path = os.path.join(model_dir, "detector_config.json")
31
+ weights_path = os.path.join(model_dir, "model_state_dict.pt")
32
+
33
+ if os.path.exists(config_path):
34
+ with open(config_path) as f:
35
+ config = json.load(f)
36
+ else:
37
+ config = {
38
+ "backbone_name": "microsoft/swinv2-tiny-patch4-window8-256",
39
+ "num_labels": 2, "dct_patch_size": 32,
40
+ "num_freq_bands": 8, "fft_bins": 32,
41
+ }
42
+
43
+ model = FrequencyAwareDetector(
44
+ backbone_name=config["backbone_name"],
45
+ num_labels=config["num_labels"],
46
+ dct_patch_size=config["dct_patch_size"],
47
+ num_freq_bands=config["num_freq_bands"],
48
+ fft_bins=config["fft_bins"],
49
+ )
50
+
51
+ if os.path.exists(weights_path):
52
+ state_dict = torch.load(weights_path, map_location=device)
53
+ model.load_state_dict(state_dict)
54
+ print(f"✓ Loaded weights from {weights_path}")
55
+ else:
56
+ print("⚠ No weights found, using random initialization")
57
+
58
+ model.to(device)
59
+ model.eval()
60
+ return model, config
61
+
62
+
63
+ def get_transform(image_size=256):
64
+ """Standard evaluation transform."""
65
+ return Compose([
66
+ Resize((image_size + 32, image_size + 32)),
67
+ CenterCrop((image_size, image_size)),
68
+ ToTensor(),
69
+ Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
70
+ ])
71
+
72
+
73
+ def predict_single(model, image_path, transform, device="cpu"):
74
+ """Predict whether a single image is real or AI-generated."""
75
+ if image_path.startswith("http"):
76
+ import requests
77
+ response = requests.get(image_path)
78
+ img = Image.open(io.BytesIO(response.content)).convert("RGB")
79
+ else:
80
+ img = Image.open(image_path).convert("RGB")
81
+
82
+ pixel_values = transform(img).unsqueeze(0).to(device)
83
+
84
+ with torch.no_grad():
85
+ output = model(pixel_values=pixel_values)
86
+ logits = output["logits"]
87
+ probs = torch.softmax(logits, dim=1)
88
+ pred = probs.argmax(dim=1).item()
89
+ confidence = probs[0][pred].item()
90
+
91
+ labels = {0: "Real", 1: "AI-Generated"}
92
+ return {
93
+ "prediction": labels[pred],
94
+ "confidence": confidence,
95
+ "real_probability": probs[0][0].item(),
96
+ "ai_generated_probability": probs[0][1].item(),
97
+ }
98
+
99
+
100
+ def main():
101
+ parser = argparse.ArgumentParser(description="Detect AI-generated images")
102
+ parser.add_argument("--image", type=str, help="Path or URL to single image")
103
+ parser.add_argument("--image_dir", type=str, help="Directory of images to analyze")
104
+ parser.add_argument("--model_dir", type=str, default=".", help="Directory containing model weights")
105
+ parser.add_argument("--image_size", type=int, default=256)
106
+ parser.add_argument("--device", type=str, default="auto")
107
+ args = parser.parse_args()
108
+
109
+ if args.device == "auto":
110
+ device = "cuda" if torch.cuda.is_available() else "cpu"
111
+ else:
112
+ device = args.device
113
+
114
+ print(f"Device: {device}")
115
+ model, config = load_model(args.model_dir, device)
116
+ transform = get_transform(args.image_size)
117
+
118
+ if args.image:
119
+ result = predict_single(model, args.image, transform, device)
120
+ print(f"\n{'='*50}")
121
+ print(f"Image: {args.image}")
122
+ print(f"Prediction: {result['prediction']}")
123
+ print(f"Confidence: {result['confidence']:.2%}")
124
+ print(f" Real probability: {result['real_probability']:.4f}")
125
+ print(f" AI-generated probability: {result['ai_generated_probability']:.4f}")
126
+ print(f"{'='*50}")
127
+
128
+ elif args.image_dir:
129
+ extensions = {'.jpg', '.jpeg', '.png', '.webp', '.bmp', '.tiff'}
130
+ image_files = [
131
+ f for f in Path(args.image_dir).iterdir()
132
+ if f.suffix.lower() in extensions
133
+ ]
134
+
135
+ print(f"\nAnalyzing {len(image_files)} images from {args.image_dir}...\n")
136
+
137
+ results = []
138
+ for img_path in sorted(image_files):
139
+ try:
140
+ result = predict_single(model, str(img_path), transform, device)
141
+ results.append(result)
142
+ status = "🤖" if result["prediction"] == "AI-Generated" else "📷"
143
+ print(f" {status} {img_path.name}: {result['prediction']} ({result['confidence']:.1%})")
144
+ except Exception as e:
145
+ print(f" ❌ {img_path.name}: Error - {e}")
146
+
147
+ real_count = sum(1 for r in results if r["prediction"] == "Real")
148
+ ai_count = sum(1 for r in results if r["prediction"] == "AI-Generated")
149
+ print(f"\nSummary: {real_count} Real, {ai_count} AI-Generated out of {len(results)} images")
150
+
151
+ else:
152
+ parser.print_help()
153
+
154
+
155
+ if __name__ == "__main__":
156
+ main()