Image Classification
Transformers
Safetensors
PyTorch
English
Chinese
beit
ai-detection
ai-image-detection
deepfake-detection
fake-image-detection
ai-art-detection
stable-diffusion-detection
midjourney-detection
dall-e-detection
image-forensics
digital-art-verification
vit
computer-vision
Eval Results (legacy)
Remove binary classification, v1 returns source labels only
Browse files
README.md
CHANGED
|
@@ -54,7 +54,7 @@ model-index:
|
|
| 54 |
|
| 55 |
> **Detect AI-generated images | Identify the AI generator | Verify human-made artwork**
|
| 56 |
|
| 57 |
-
A
|
| 58 |
|
| 59 |
**Website**: [https://itsnotai.org](https://itsnotai.org)
|
| 60 |
|
|
@@ -62,12 +62,12 @@ A state-of-the-art Vision Transformer model that detects AI-generated images wit
|
|
| 62 |
|
| 63 |
## Newer Version Available
|
| 64 |
|
| 65 |
-
| Version |
|
| 66 |
-
|---------|----------
|
| 67 |
-
| **v2 (Latest)** |
|
| 68 |
-
| v1 (This) |
|
| 69 |
|
| 70 |
-
> **Recommendation**: Use [v2](https://huggingface.co/boluobobo/ItsNotAI-ai-detector-v2) for better binary (Real/AI) classification
|
| 71 |
|
| 72 |
---
|
| 73 |
|
|
@@ -156,9 +156,6 @@ model_id = "boluobobo/ItsNotAI-ai-detector-v1"
|
|
| 156 |
model = AutoModelForImageClassification.from_pretrained(model_id)
|
| 157 |
processor = AutoImageProcessor.from_pretrained(model_id)
|
| 158 |
|
| 159 |
-
# Real source labels
|
| 160 |
-
REAL_LABELS = {"afhq", "celebahq", "coco", "ffhq", "imagenet", "landscape", "lsun", "metfaces"}
|
| 161 |
-
|
| 162 |
def detect_image(image_path):
|
| 163 |
image = Image.open(image_path).convert("RGB")
|
| 164 |
inputs = processor(image, return_tensors="pt")
|
|
@@ -167,56 +164,43 @@ def detect_image(image_path):
|
|
| 167 |
outputs = model(**inputs)
|
| 168 |
probs = torch.softmax(outputs.logits, dim=-1)[0]
|
| 169 |
|
| 170 |
-
#
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
human_prob = top_confidence
|
| 178 |
-
ai_prob = 1.0 - human_prob
|
| 179 |
-
else:
|
| 180 |
-
ai_prob = top_confidence
|
| 181 |
-
human_prob = 1.0 - ai_prob
|
| 182 |
-
|
| 183 |
-
# Get top 3 AI sources
|
| 184 |
-
ai_sources = []
|
| 185 |
-
for i, prob in enumerate(probs.tolist()):
|
| 186 |
-
label = model.config.id2label[str(i)]
|
| 187 |
-
if label not in REAL_LABELS:
|
| 188 |
-
ai_sources.append({"label": label, "score": round(prob, 3)})
|
| 189 |
-
ai_sources.sort(key=lambda x: x["score"], reverse=True)
|
| 190 |
-
top3_sources = ai_sources[:3]
|
| 191 |
|
| 192 |
return {
|
| 193 |
-
"
|
| 194 |
-
"
|
| 195 |
-
"
|
| 196 |
-
"top3_sources": top3_sources
|
| 197 |
}
|
| 198 |
|
| 199 |
# Example
|
| 200 |
result = detect_image("test.jpg")
|
| 201 |
-
print(f"AI Probability: {result['ai_probability']:.1%}")
|
| 202 |
-
print(f"Human Probability: {result['human_probability']:.1%}")
|
| 203 |
print(f"Predicted Source: {result['predicted_source']}")
|
|
|
|
| 204 |
```
|
| 205 |
|
| 206 |
**Example Output:**
|
| 207 |
```json
|
| 208 |
{
|
| 209 |
-
"ai_probability": 0.452,
|
| 210 |
-
"human_probability": 0.548,
|
| 211 |
"predicted_source": "stable_diffusion",
|
| 212 |
-
"
|
|
|
|
| 213 |
{"label": "stable_diffusion", "score": 0.452},
|
| 214 |
{"label": "latent_diffusion", "score": 0.213},
|
| 215 |
-
{"label": "glide", "score": 0.089}
|
|
|
|
|
|
|
| 216 |
]
|
| 217 |
}
|
| 218 |
```
|
| 219 |
|
|
|
|
|
|
|
| 220 |
## Performance
|
| 221 |
|
| 222 |
| Metric | Value |
|
|
@@ -276,42 +260,11 @@ with open(meta_path) as f:
|
|
| 276 |
meta = json.load(f)
|
| 277 |
|
| 278 |
source_names = meta["source_names"]
|
| 279 |
-
source_is_real = meta["source_is_real"]
|
| 280 |
-
|
| 281 |
-
# Check if prediction is real or AI
|
| 282 |
-
predicted_source = source_names[pred_idx]
|
| 283 |
-
is_real = source_is_real.get(predicted_source, False)
|
| 284 |
-
|
| 285 |
-
print(f"Source: {predicted_source}")
|
| 286 |
-
print(f"Is Real: {'Yes' if is_real else 'No (AI Generated)'}")
|
| 287 |
|
| 288 |
# Get all probabilities
|
| 289 |
for i, (name, prob) in enumerate(zip(source_names, probs[0].tolist())):
|
| 290 |
if prob > 0.01: # Show only >1%
|
| 291 |
-
|
| 292 |
-
print(f" [{marker}] {name}: {prob:.2%}")
|
| 293 |
-
```
|
| 294 |
-
|
| 295 |
-
### Calculate Real vs Fake Probability
|
| 296 |
-
|
| 297 |
-
```python
|
| 298 |
-
# Top-1 决定 + 置信度
|
| 299 |
-
top_idx = probs[0].argmax().item()
|
| 300 |
-
top_source = source_names[top_idx]
|
| 301 |
-
top_confidence = probs[0][top_idx].item()
|
| 302 |
-
is_real = source_is_real.get(top_source, False)
|
| 303 |
-
|
| 304 |
-
if is_real:
|
| 305 |
-
real_prob = top_confidence
|
| 306 |
-
fake_prob = 1.0 - real_prob
|
| 307 |
-
else:
|
| 308 |
-
fake_prob = top_confidence
|
| 309 |
-
real_prob = 1.0 - fake_prob
|
| 310 |
-
|
| 311 |
-
print(f"Predicted Source: {top_source}")
|
| 312 |
-
print(f"Is Real: {'Yes' if is_real else 'No (AI Generated)'}")
|
| 313 |
-
print(f"Real: {real_prob:.2%}")
|
| 314 |
-
print(f"AI Generated: {fake_prob:.2%}")
|
| 315 |
```
|
| 316 |
|
| 317 |
## Training Details
|
|
|
|
| 54 |
|
| 55 |
> **Detect AI-generated images | Identify the AI generator | Verify human-made artwork**
|
| 56 |
|
| 57 |
+
A Vision Transformer model that detects AI-generated images and identifies the specific AI generator used (33 classes).
|
| 58 |
|
| 59 |
**Website**: [https://itsnotai.org](https://itsnotai.org)
|
| 60 |
|
|
|
|
| 62 |
|
| 63 |
## Newer Version Available
|
| 64 |
|
| 65 |
+
| Version | Features | Link |
|
| 66 |
+
|---------|----------|------|
|
| 67 |
+
| **v2 (Latest)** | Dual-head, FLUX detection, improved Midjourney | [ItsNotAI-ai-detector-v2](https://huggingface.co/boluobobo/ItsNotAI-ai-detector-v2) |
|
| 68 |
+
| v1 (This) | Single-head, 33-class classification | Current page |
|
| 69 |
|
| 70 |
+
> **Recommendation**: Use [v2](https://huggingface.co/boluobobo/ItsNotAI-ai-detector-v2) for better binary (Real/AI) classification. Use v1 if you only need source identification without the binary head.
|
| 71 |
|
| 72 |
---
|
| 73 |
|
|
|
|
| 156 |
model = AutoModelForImageClassification.from_pretrained(model_id)
|
| 157 |
processor = AutoImageProcessor.from_pretrained(model_id)
|
| 158 |
|
|
|
|
|
|
|
|
|
|
| 159 |
def detect_image(image_path):
|
| 160 |
image = Image.open(image_path).convert("RGB")
|
| 161 |
inputs = processor(image, return_tensors="pt")
|
|
|
|
| 164 |
outputs = model(**inputs)
|
| 165 |
probs = torch.softmax(outputs.logits, dim=-1)[0]
|
| 166 |
|
| 167 |
+
# Get top predictions
|
| 168 |
+
top_indices = probs.argsort(descending=True)[:5]
|
| 169 |
+
predictions = []
|
| 170 |
+
for idx in top_indices:
|
| 171 |
+
label = model.config.id2label[str(idx.item())]
|
| 172 |
+
score = probs[idx].item()
|
| 173 |
+
predictions.append({"label": label, "score": round(score, 3)})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 174 |
|
| 175 |
return {
|
| 176 |
+
"predicted_source": predictions[0]["label"],
|
| 177 |
+
"confidence": predictions[0]["score"],
|
| 178 |
+
"top5_predictions": predictions
|
|
|
|
| 179 |
}
|
| 180 |
|
| 181 |
# Example
|
| 182 |
result = detect_image("test.jpg")
|
|
|
|
|
|
|
| 183 |
print(f"Predicted Source: {result['predicted_source']}")
|
| 184 |
+
print(f"Confidence: {result['confidence']:.1%}")
|
| 185 |
```
|
| 186 |
|
| 187 |
**Example Output:**
|
| 188 |
```json
|
| 189 |
{
|
|
|
|
|
|
|
| 190 |
"predicted_source": "stable_diffusion",
|
| 191 |
+
"confidence": 0.452,
|
| 192 |
+
"top5_predictions": [
|
| 193 |
{"label": "stable_diffusion", "score": 0.452},
|
| 194 |
{"label": "latent_diffusion", "score": 0.213},
|
| 195 |
+
{"label": "glide", "score": 0.089},
|
| 196 |
+
{"label": "ddpm", "score": 0.056},
|
| 197 |
+
{"label": "imagenet", "score": 0.042}
|
| 198 |
]
|
| 199 |
}
|
| 200 |
```
|
| 201 |
|
| 202 |
+
> **Note**: v1 returns source classification only. For binary Real/AI detection, use [v2](https://huggingface.co/boluobobo/ItsNotAI-ai-detector-v2) with its dedicated binary head.
|
| 203 |
+
|
| 204 |
## Performance
|
| 205 |
|
| 206 |
| Metric | Value |
|
|
|
|
| 260 |
meta = json.load(f)
|
| 261 |
|
| 262 |
source_names = meta["source_names"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 263 |
|
| 264 |
# Get all probabilities
|
| 265 |
for i, (name, prob) in enumerate(zip(source_names, probs[0].tolist())):
|
| 266 |
if prob > 0.01: # Show only >1%
|
| 267 |
+
print(f" {name}: {prob:.2%}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 268 |
```
|
| 269 |
|
| 270 |
## Training Details
|