| |
| """ |
| predict_nexar_test.py |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ |
| Generate a Kaggle-style submission CSV from a Nexar head checkpoint and the |
| test belief cache. |
| |
| Inputs: |
| --head_ckpt checkpoints/Nexar/qwen3vl4b_head/best.pt |
| --test_cache data/belief_cache_nexar_qwen3vl4b/test.pt |
| |
| Output CSV columns: id,score |
| |
| Usage |
| βββββ |
| python -m training.Policy.predict_nexar_test \ |
| --head_ckpt checkpoints/Nexar/qwen3vl4b_head/best.pt \ |
| --test_cache data/belief_cache_nexar_qwen3vl4b/test.pt \ |
| --out submissions/nexar_qwen3vl4b.csv |
| """ |
| from __future__ import annotations |
|
|
| import argparse |
| import csv |
| import logging |
| from pathlib import Path |
|
|
| import numpy as np |
| import torch |
|
|
| from training.Policy.train_nexar_head import NexarHead |
|
|
| logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s") |
| logger = logging.getLogger("Policy.predict_nexar_test") |
|
|
|
|
| def main(): |
| ap = argparse.ArgumentParser("predict_nexar_test") |
| ap.add_argument("--head_ckpt", required=True) |
| ap.add_argument("--test_cache", required=True) |
| ap.add_argument("--out", required=True) |
| ap.add_argument("--batch_size", type=int, default=128) |
| args = ap.parse_args() |
|
|
| logger.info(f"loading head {args.head_ckpt}") |
| ck = torch.load(args.head_ckpt, map_location="cpu", weights_only=False) |
| meta = ck["meta"] |
| model = NexarHead(hidden_dim=meta["hidden_dim"], |
| proj_dim=meta["proj_dim"], |
| n_layers=meta["n_layers"], |
| n_heads=meta["n_heads"], |
| dropout=meta["dropout"]) |
| model.load_state_dict(ck["state_dict"]) |
| model.eval().to("cuda") |
|
|
| logger.info(f"loading test cache {args.test_cache}") |
| te = torch.load(args.test_cache, map_location="cpu", weights_only=False) |
| x = te["beliefs_frame"].float() |
| v = te["valid_frames"].bool() |
| ids = te["meta"]["video_ids"] |
| assert x.shape[0] == len(ids), f"cache/ids mismatch: {x.shape[0]} vs {len(ids)}" |
|
|
| probs = [] |
| with torch.no_grad(): |
| for i in range(0, x.size(0), args.batch_size): |
| xb = x[i:i + args.batch_size].to("cuda") |
| vb = v[i:i + args.batch_size].to("cuda") |
| logits = model(xb, vb).cpu().numpy() |
| probs.append(1 / (1 + np.exp(-logits))) |
| probs = np.concatenate(probs) |
| assert len(probs) == len(ids) |
|
|
| out = Path(args.out) |
| out.parent.mkdir(parents=True, exist_ok=True) |
| with open(out, "w", newline="") as f: |
| w = csv.writer(f) |
| w.writerow(["id", "score"]) |
| for vid, p in zip(ids, probs): |
| w.writerow([vid, f"{float(p):.6f}"]) |
| logger.info(f"wrote {len(ids)} rows -> {out}") |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|