SQuaDE ViT-g
冻结 DINOv2 ViT-g + 两组各三个专家头。干净图在第 27 个 block 提前退出, 省约 18% 前向深度。为 NTIRE 2026 Robust AIGI Detection 训练。
骨干不在本仓库内,运行时从 facebook/dinov2-giant 加载。本仓库只有专家头与门。
当前推荐 v3/。
快速推理
git clone https://github.com/kelvinchua1099-alt/SQuaDE && cd SQuaDE
pip install -r requirements.txt
huggingface-cli download kelvinchua/squade-vitg --local-dir ckpt
python Inference.py --dir /path/to/images \
--shallow ckpt/v3/mix2_shallow \
--deep ckpt/v3/mix2_deep \
--gate ckpt/v3/mix2_gate.pt \
--out preds.csv
单张图把 --dir 换成 --image a.jpg。
输出
image score label route experts votes ms_per_img
002d7df53e3ae55af5.jpg 1.000000 1 deep L26/L33/L37 1.000|1.000|0.955 684
0053097bfa680600.jpg 0.000000 0 shallow L14/L21/L27 1.000|0.000|0.000 684
| 列 | 含义 |
|---|---|
score |
0~1,越大越可能是 AI 生成 |
label |
score > 0.5 时为 1(假) |
route |
走了哪一组专家 |
experts |
该组的三个抽头层 |
votes |
组内三个专家各自的概率 |
vote_spread |
三票最大差。大 = 这张图在决策边界上,最值得人工复核 |
depth_used |
实际跑了多少个 block(27 或 37) |
gate_logit |
门的输出,≤0 判「干净」走浅组 |
ms_per_img |
每张图耗时 |
常用参数
--batch-size 8 # 24 GB 显存下可到 16
--no-early-exit # 两组都算完再按门选。精度相同,用来核对提前退出没改变结果
--device cpu # 慢很多,应急用
成绩
只报 held-out。官方 val 的 70% 与 val_hard 的 70% 参与了训练,划分文件
(val_split_70_30.json / valhard_split_70_30.json)随权重一起发布,可自行核验。
v3(当前)
| 数据 | 方案 | 全量 | clean | robust |
|---|---|---|---|---|
| 官方 val held-out (3,000) | shallow-only | 0.9922 | 0.9978 | 0.9833 |
| ±SE 0.23 | gated route | 0.9911 | 0.9977 | 0.9809 |
| 官方 val_hard held-out (750) | shallow-only | 0.9430 | 0.9904 | 0.8674 |
| ±SE 1.8 | gated route | 0.9423 | 0.9857 | 0.8781 |
三个版本
| 口径 | v1 | v2 | v3 |
|---|---|---|---|
| val_hard held-out robust | — | 0.8068 | 0.8674 |
| val_hard held-out 全量 | — | 0.9111 | 0.9430 |
| val held-out robust | 0.9629 | 0.9830 | 0.9833 |
| 门 AUC(val_hard) | 0.7684 | 0.9072 | 0.9464 |
v1 训练时 val_hard 尚未划分,无对应的 held-out 数。
改动
- v1 → v2:训练集配比(NTIRE 从 11.4% 提到 37.9%)、退化强度(我们的档位掺入一半
官方
distortion_range)、并入官方 val 的 70%。三者贡献未拆分。 - v2 → v3:并入官方 val_hard 的 70%(1,750 行),从 v2 权重热启动 8 轮 @ lr 1e-4。 val_hard held-out 上 robust +6.06,同时 val held-out 未退化(+0.03)。
robust = 只在退化图上算,是竞赛主指标。gated route 相对全深度省约 18% 前向深度。
输入尺寸怎么处理
推理与训练用同一套规则。不一致等于给测试集加一层没记录在案的域偏移,且不会报错。
短边 >= 512 中心裁 512x512,一次重采样都不做
短边 < 512 先裁成正方,再用随机挑的一个内核上采样到 512
内核池 [BILINEAR, BICUBIC, BOX, LANCZOS],按图名确定性挑
之后送进骨干时中心裁到 504(patch=14 的整数倍),同样不 resize。
Inference.py 自动完成。
已知局限
- 两份官方评测集都已被部分用于训练。 只剩 3,000 + 750 张 held-out, 而 750 张的 SE 是 ±1.8 点 —— 小于 3~4 点的差异读不出来。唯一完全干净的是官方 test。
- 抽头层是在官方 val / val_hard 上选的。 从 41 层里选 3 层,信息量小但不是零。
- 门在原生低分辨率来源上会失效。 它学到的偏向「图糊不糊」而非「有没有施加过 退化算子」;实测 200×200 上采样的图里 82% 被判成退化,省下的算力掉到 5.8%。
- 训练集的真图缺少「手机随手拍 + 多次转发重压缩」这一类。 真图来自图库与 OpenImages,偏专业摄影;对低画质真实照片的表现未经检验。
- 一部分训练数据的「干净档」并不真干净 —— 源图本身是 JPEG,自带未记录的压缩。
被本项目否定的假设
原始主张是「不同退化杀死不同深度的取证线索,所以最优读取深度是退化状态的函数」。 经 13 项独立测量全部不成立。最干净的一次(val_hard 内部折外交叉拟合、完整桶尺寸、 无分布偏移)净增益 +0.117 点,置换检验 p = 0.323。
站得住的是多深度均匀融合(集成方差缩减:在官方数据上比最强单专家高 1.67~5.89 点) 与干净/退化二元门控提前退出(省约 18% 算力)。
退化与标签在训练集里严格独立(交叉表核验:干净/退化两侧的假图占比均为 50.07%, 只用「是否退化」这一位去猜真假的 AUC = 0.5000),不存在「退化痕迹 → 假」的构造性泄漏。
文件
v3/mix2_shallow/stage1.pt 浅组 L14/L21/L27 + 标准化统计量 ← 推荐
v3/mix2_deep/stage1.pt 深组 L26/L33/L37 + 标准化统计量
v3/mix2_gate.pt 二元门,读浅组特征
v3/val_split_70_30.json 官方 val 的固定划分(held 永不参与训练)
v3/valhard_split_70_30.json 官方 val_hard 的固定划分
v2/, v1/ 更早两版,保留对照
MIT。DINOv2 权重另有其许可条款。