fev — AI image detector (ONNX, browser-local)
The model shipped by fev, a Manifest V3 Chrome extension that detects AI-generated images entirely inside the browser — WebGPU where available, WebAssembly everywhere else. No cloud inference, no API, no localhost helper. Nothing about an image ever leaves the device.
fev is short for firmes e verdadeiros — firm and true.
What this is
A fine-tune (v13) of Community Forensics ViT-Small/16@384, exported to ONNX fp32.
| architecture | ViT-Small/patch16, 384px, single logit |
| output | P(AI) = sigmoid(logit) |
| decision rule | AI when P(AI) >= 0.65 |
| preprocessing | resize shortest edge → 440 (PIL bicubic), center-crop 384, CLIP mean/std, RGB |
| file | commfor384_web_v13_fp32.onnx (88,369,565 B) |
| sha256 | 6ca91ded511f0cfbf3ded2a7b76e37f62273c42cb42c303b1faf4933c53beeef |
| license | MIT (base weights MIT; this fine-tune is a derivative) |
The SHA-256 above is pinned in the extension's models.lock.json. Its build
verifies these exact bytes and fails if they do not match, so a build either
reproduces what was measured or stops.
Measured performance
All figures at the fixed decision rule P(AI) >= 0.65. Balanced accuracy is
0.5 × (AI recall + real recall).
| set | n | balanced acc | AI recall | real recall |
|---|---|---|---|---|
| frozen proxy (DiffusionDB + COCO) | 1,200 | 0.9950 | 1.0000 | 0.9900 |
| OpenFake test — temporal holdout of newest generators | 800 | 0.8704 | 0.7611 | 0.9797 |
| lexica thumbnails (AI only) | 203 | — | 0.9606 | — |
| web-transformed COCO reals (real only) | 2,400 | — | — | 0.9904 |
The first row was also measured through the built extension in headless Chrome — 1200/1200 images scored at 0.16 s/image on WebGPU, reproducing the PyTorch figure exactly. The numbers are the extension's, not a notebook's.
Read this before trusting the numbers above
Both sets above draw their real class from COCO / ImageNet, which is also the kind of data the model trained on. The splits are byte- and pHash-disjoint, so this is not leakage — but it is an easy question, and balanced accuracy weights the real class equally with the AI class.
So the real class was re-measured against images from the open web the model has never seen a relative of: 768 Wikimedia Commons files across 7 strata, fetched through Commons' own thumbnailer so they arrive resized and re-encoded the way a CMS delivers them. Its own labels were audited twice (embedded provenance, and Commons category membership); 2 of 770 turned out to be AI and were removed before freezing.
| real population | v11 | v13 (this model) |
|---|---|---|
| COCO val2017 | 0.982 | 0.990 |
| diverse web holdout | 0.816 | 0.898 |
| excl. an over-represented fractal series | 0.863 | 0.934 |
| └ screenshots | 0.945 | 0.991 |
| └ random web images | 0.891 | 0.964 |
| └ paintings | 0.835 | 0.945 |
| └ scans / historical photos | 0.955 | 0.927 |
| └ illustrations | 0.909 | 0.918 |
| └ CGI / 3D renders | 0.725 | 0.908 |
| └ human-made digital art | 0.455 | 0.636 |
v13 exists because of that table: v11's real class was entirely clean photography, so it had never been penalised for flagging human-made non-photographic content, and it flagged a lot of it. v13 adds 816 Wikimedia hard negatives — art, CGI, paintings, engravings, scans, screenshots.
This is a trade, not a free win. Frontier AI recall fell 0.820 → 0.761 and lexica 0.985 → 0.961; adding negatives moves the model toward "real" everywhere. Net on realistic web content (frontier AI recall + diverse-holdout real recall) it is 0.830 vs v11's 0.818. A v11+v13 ensemble was measured and rejected — mean/max/min fusion all scored below v13 alone, so a second model would cost 2× latency for nothing.
Digital art at 0.636 remains the weakest stratum, and algorithmic fractal renders (Mandelbulb and similar) are near-worst-case for this model.
Usage
The intended consumer is the extension, which handles preprocessing:
git clone https://github.com/angelhd1999/ullExtension && cd ullExtension
cd extension && npm ci && cd ..
node scripts/vendor-ort.mjs
node scripts/fetch-model.mjs # downloads this file, verifies the SHA-256
node scripts/build-extension.mjs
Then load extension/ unpacked at chrome://extensions.
Direct use with onnxruntime:
import numpy as np, onnxruntime as ort
from PIL import Image
MEAN = np.array([0.48145466, 0.4578275, 0.40821073], np.float32)
STD = np.array([0.26862954, 0.26130258, 0.27577711], np.float32)
img = Image.open("image.jpg").convert("RGB")
w, h = img.size
s = 440 / min(w, h)
img = img.resize((round(w * s), round(h * s)), Image.BICUBIC)
w, h = img.size
img = img.crop(((w - 384) // 2, (h - 384) // 2, (w - 384) // 2 + 384, (h - 384) // 2 + 384))
x = ((np.asarray(img, np.float32) / 255.0 - MEAN) / STD).transpose(2, 0, 1)[None]
sess = ort.InferenceSession("commfor384_web_v13_fp32.onnx")
logit = sess.run(None, {sess.get_inputs()[0].name: x})[0][0, 0]
p_ai = 1 / (1 + np.exp(-logit))
print(f"P(AI) = {p_ai:.4f} -> {'AI' if p_ai >= 0.65 else 'real'}")
Preprocessing must match exactly. The extension reimplements PIL's fixed-point
bicubic resize in JavaScript rather than delegating to drawImage, whose
filter is undocumented and varies across Chrome releases — and resampling is
part of what this classifier reads.
Limitations
- Real recall drops on non-photographic human-made content (see above); human-made digital art is the weakest stratum at 0.636.
- Frontier AI recall is 0.761 — the cost of the hard-negative training that fixed the real class. v11 is better there (0.820) and worse everywhere else.
- Trained partly on the OpenFake validation split, which is CC BY-NC 4.0. The base weights and this export are MIT; whether a CC BY-NC dataset encumbers the resulting weights is unsettled, and an OpenFake-free variant is tracked in the repository.
- fp16 is not published: in Chrome it falls back to WASM (Dawn does not expose
shader-f16) and runs slower than fp32 on WebGPU.
Citation
The base model:
@article{park2024community,
title={Community Forensics: Using Thousands of Generators to Train Fake Image Detectors},
author={Park, Jeongsoo and Owens, Andrew},
journal={arXiv preprint arXiv:2411.04125},
year={2024}
}