Fastfill-test / code /fastfill /v2 /ops /make_test300.py
XXXpilar's picture
FastFill v4 base (step 6552): LoRA adapter, geometry heads, tokenizer, training code, predict.py
e6f80f3 verified
Raw History Blame Contribute Delete
3.18 kB
"""A fixed test subset for the LLM comparisons: N rooms of test.jsonl, stratified by source in proportion to the test
set (largest remainder; a source too small for one room gets none), each source's rooms drawn with one seeded RNG.
Rooms over the model capacity (more than --max-objects objects) are left out before drawing, so every method can
answer every room. Writes rows.jsonl (test order) and MANIFEST.json (seed, counts, sha256, scene ids).
python fastfill/v2/ops/make_test300.py --test data/v4fixed/test.jsonl --output data/test300 [--rows 300 --seed 0]
"""
from __future__ import annotations
import argparse
from collections import defaultdict
import hashlib
import json
from pathlib import Path
import random
def allocate(sizes: dict, total: int) -> dict:
"""Largest-remainder apportionment of ``total`` over ``sizes`` (ties broken by name)."""
whole = sum(sizes.values())
quota = {k: total * v / whole for k, v in sizes.items()}
share = {k: int(q) for k, q in quota.items()}
for k in sorted(quota, key=lambda k: (-(quota[k] - share[k]), k))[:total - sum(share.values())]:
share[k] += 1
return share
def main(argv=None):
p = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
p.add_argument("--test", type=Path, required=True)
p.add_argument("--output", type=Path, required=True)
p.add_argument("--rows", type=int, default=300)
p.add_argument("--seed", type=int, default=0)
p.add_argument("--max-objects", type=int, default=256)
a = p.parse_args(argv)
lines = [l for l in a.test.read_text().splitlines() if l.strip()]
by_source, over = defaultdict(list), 0
for index, line in enumerate(lines):
row = json.loads(line)
if len(row["condition"]["objects"]) > a.max_objects:
over += 1
continue
by_source[row["provenance"]["source"]].append(index)
share, rng, chosen = allocate({k: len(v) for k, v in by_source.items()}, a.rows), random.Random(a.seed), []
for source in sorted(by_source):
chosen += rng.sample(by_source[source], share[source])
chosen.sort()
a.output.mkdir(parents=True, exist_ok=True)
rows = "".join(lines[i] + "\n" for i in chosen)
(a.output / "rows.jsonl").write_text(rows)
manifest = {"rows": len(chosen), "seed": a.seed, "max_objects": a.max_objects, "over_capacity_excluded": over,
"test_file": a.test.name, "test_rows": len(lines), "test_sha256": hashlib.sha256(a.test.read_bytes()).hexdigest(),
"rows_sha256": hashlib.sha256(rows.encode()).hexdigest(),
"per_source": {k: {"test": len(by_source[k]), "chosen": share[k]} for k in sorted(by_source)},
"test_line_indices": chosen,
"scene_ids": [json.loads(lines[i])["provenance"].get("scene_id") for i in chosen]}
(a.output / "MANIFEST.json").write_text(json.dumps(manifest, indent=1) + "\n")
print(json.dumps({k: manifest[k] for k in ("rows", "over_capacity_excluded", "rows_sha256")}),
{k: v["chosen"] for k, v in manifest["per_source"].items()})
if __name__ == "__main__":
main()