aigc-detector / src /config.py
saminv81's picture
Upload folder using huggingface_hub
384e467 verified
Raw History Blame Contribute Delete
6.72 kB
# src/config.py
from dataclasses import dataclass
@dataclass
class Config:
resolution: int = 518
patch_grid: int = 37
n_patch: int = 1369
embed_dim: int = 768
backbone: str = "stub" # "stub" (local CI) | "dinov2_vitb14_reg" (GPU host)
# REJECTED (kept for reference): RINE-style last-N fusion never beat single-layer readout.
# n_intermediate_layers: int = 1
extract_layer: int = 8 # SHIP DEFAULT (train.py trains 8 and 10 for the ensemble) β€” >0 = read patch tokens after DINOv2 block L (1-indexed) and TRUNCATE the stack to L blocks (real FLOP saving); tests whether localized signal survives earlier. 0 = full depth. Mutually exclusive with n_intermediate_layers>1.
# REJECTED: MIL top-k image logits (k=16/64 and DC-centered) gave no transfer gain β€” the
# head's self-attention broadcasts the verdict into every patch, so top-k of a broadcast
# is the broadcast. Left commented for the record.
# mil_top_k: int = 0
# mil_centered: bool = False
label_smooth: float = 0.05 # BCE target smoothing eps: targets eps/1βˆ’eps instead of 0/1 (bounds optimal logits, calibrates probs). 0 = hard labels.
# REJECTED: warp minimal-pair augmentation taught the warp artifact, not anatomy
# (unseen-GAN AUC βˆ’0.027). Implementation retained in data/aug/warp.py for reference.
# warp_strength: float = 1.0
# p_global_warp: float = 0.0
corruption_scale: float = 1.0 # train-only: >1 stretches corruption severity ranges toward their harsh end (clamped). Ship default 1.0 β€” scaling alone measured negative; keep at 1.0 unless re-validated together with lambda_feat.
lambda_feat: float = 1.5 # feature-consistency weight: cosine drift of the pooled trainable representation across the clean/corrupted pair (label-blind, both classes) β€” forces the decision path onto corruption-stable semantic/geometric directions.
fusion_project: bool = True # fusion projection: True=dense DxD (~590K); False=scalar layer-mix (K params, preferred at low data)
train_impls: dict | None = None # {family:[impl,...]} operator subset for TRAINING β€” set BEFORE training so held-out impls stay genuinely unseen (the impl-holdout gap is only valid when training is restricted to this subset)
data_parallel: bool = False # DataParallel across all visible GPUs (e.g. dual T4): splits the heavy frozen-backbone forward for ~2x + halves per-GPU batch memory. No idle GPU regardless of arm count.
head_hidden: int = 0 # 0 = linear-probe head; >0 = MLP head (Linear-GELU-Linear)
head_pool: str = "attn" # "attn" (baseline MIL) | "dist" (+mean/std/top-k patch-logit stats) | "nbr" (dist + zero-init 3x3 depthwise conv over the patch grid = local adjacency; density-gate redirect, orthogonal to global-realism signal) | "enc" (dist + zero-init self-attention encoder w/ 2D pos-embed = configural "sequence-not-bag" test)
# NULLED (never shipped): opt-in spectral branch β€” JPEG/blur corruption destroys the
# frequency signal it reads; only viable as a fusion member, which we did not ship.
# use_freq_branch: bool = False
enc_layers: int = 2 # EncoderPoolHead: transformer-encoder depth (head_pool="enc")
enc_heads: int = 8 # EncoderPoolHead: self-attention heads (head_pool="enc")
use_pos_embed: bool = True # EncoderPoolHead: add fixed 2D sin/cos positional embedding before the encoder
# SUPERSEDED by deshortcut=True (the full pipeline); kept for ablation only.
# defeat_resolution: bool = False
deshortcut: bool = False # train: thumbnail-degrade+contrast+sharpness+codec aug (stronger shortcut defeat)
p_codec: float = 0.5 # deshortcut: P(random JPEG/PNG re-encode) β€” kills the codec-history shortcut
random_resolution: bool = False # train: per-batch random resolution (varied token grid, no res anchor)
res_lo: int = 392 # random_resolution range lo (mult of 14)
res_hi: int = 644 # random_resolution range hi (mult of 14)
fair_eval: bool = False # eval: normalize real+fake to common size+format (no res/format tell)
feature_mode: str = "jit" # Phase-2: "jit"|"cache" β€” cache path not yet implemented (no consumer in Phase 1)
compile: bool = False # torch.compile toggle (GPU-host only)
amp: bool = False # fp16 autocast on the FROZEN backbone only (T4 tensor cores ~2x); head stays fp32
gpu_preprocess: bool = False # workers emit uint8 (resize only); float/normalize/res-resize happen ON GPU (halves worker CPU, 4x smaller host transfers). Bilinear resize commutes with per-channel normalize, so numerics match the CPU path.
lambda_aug: float = 0.8
lambda_cons_max: float = 0.3
# NULLED (never shipped): teacher distillation from a pretrained forensics model was cut
# early on licensing + complexity grounds; the frozen-backbone head needs no teacher.
# lambda_kd: float = 0.0
pos_weight: float = 0.0 # 0 = unweighted BCE; >0 scales the fake(1) term (calibration)
entropy_gate: float = 0.5
stack_prob: float = 0.1
seed: int = 0
epochs: int = 10
epoch_frac: float = 1.0 # train on this fraction of the loader per epoch (0.5 = half an epoch); shuffle=True makes the half-pass a random subsample
batch_size: int = 32
eval_batch_size: int = 32 # eval forward-pass chunk (predict_fn); bounds VRAM on large val sets
eval_pool_max: int = 64 # max decoded val images resident at once (bounds HOST RAM in streaming eval)
eval_workers: int = 0 # >0 = thread-pool the eval corruption prep (PIL releases the GIL); 0 = serial (legacy)
holdout_eval_cap: int = 0 # 0=eval whole holdout; >0=stratified subsample cap (speed)
val_eval_cap: int = 0 # 0=eval whole val EVERY epoch; >0=stratified per-epoch subsample (a 7.5k val x 19 conds = hours of CPU-bound corruption PER EPOCH on the 47k corpus)
lr: float = 1e-3
lr_schedule: str = "none" # "none" | "onecycle" (per-step mid-epoch warmup+cosine)
num_workers: int = 2
pin_memory: bool = True
max_images: int = 0 # 0 = all
data_root: str = "data"
cache_dir: str = "cache"
# Weights & Biases logging (OFF by default; training hosts flip use_wandb=True)
use_wandb: bool = False
wandb_project: str = "track5-aigc"
wandb_run_name: str = "" # empty -> wandb autogenerates
log_every: int = 10 # log train metrics every N steps
@classmethod
def smoke(cls) -> "Config":
return cls(max_images=200, epochs=1, compile=False, batch_size=8)