CharlesCNorton
Image-level person classification on EUPE-ViT-B features with a single free parameter
f5498f9
Raw
History Blame Contribute Delete
2.49 kB
"""Score a classifier config over a named pool and write its eval artifact.
python verify.py # baseline on VAL5000
python verify.py --classifier classifier_tight_fpr.json
python verify.py --pool CALIB1000
Writes eval.json for the baseline config and eval_tight_fpr.json for the
tight-FPR one, unless --out says otherwise.
"""
import argparse
import json
import sys
from pathlib import Path
import torch
sys.path.insert(0, str(Path(__file__).resolve().parent)) # repo root, for `common`
from common import BACKBONE, device, f1_at, load_pool, score_pool, write_artifact # noqa: E402
from common.models import load_backbone # noqa: E402
from common.pools import VAL5000, by_name # noqa: E402
HERE = Path(__file__).resolve().parent
def out_path_for(classifier: Path) -> Path:
"""classifier.json -> eval.json; classifier_tight_fpr.json -> eval_tight_fpr.json."""
suffix = classifier.stem[len('classifier'):]
return classifier.parent / f'eval{suffix}.json'
def main():
ap = argparse.ArgumentParser(description=__doc__)
ap.add_argument('--classifier', type=Path, default=HERE / 'classifier.json')
ap.add_argument('--backbone', default=BACKBONE)
ap.add_argument('--pool', default=VAL5000.name)
ap.add_argument('--out', type=Path, default=None)
args = ap.parse_args()
dev = device()
pool = by_name(args.pool)
c = json.loads(args.classifier.read_text())
print(f'[init] loading {args.backbone}', flush=True)
backbone = load_backbone(args.backbone).to(dev)
print(f'[pool] {pool.name}', flush=True)
loaded = load_pool(pool, dev)
pos = torch.tensor(c['pos_dims'], dtype=torch.long, device=dev)
neg = torch.tensor(c['neg_dims'], dtype=torch.long, device=dev)
scores, _ = score_pool(backbone, loaded, pos, neg)
m = f1_at(scores, loaded.labels, c['threshold'])
print(f'[verify] F1={m.f1:.4f} P={m.precision:.4f} R={m.recall:.4f}', flush=True)
path = args.out or out_path_for(args.classifier)
write_artifact(
path, {'metrics': {k: round(v, 4) if k != 'threshold' else v
for k, v in m.asdict().items()}},
generator='verify.py', classifier=args.classifier,
pool_info=loaded.provenance(),
task='image-level person presence (binary)',
protocol='live backbone forward at 768 px, no feature caching')
print(f'[done] wrote {path}', flush=True)
if __name__ == '__main__':
main()