CoolFace
Apppublic

rafmacalaba/data-use-annotate

sourceHugging Faceupdated 13d agoView on Hugging Face
0likes
rescore_singlepass.py93 linesDownload Raw Back to root
1#!/usr/bin/env python32"""Rescore labeling queues with the singlepass infer head (local MPS).3 4Same weights the H100 fit (probe_head.pt in the singlepass bundle), applied5to fixed queue spans via training/probe_features_infer.encode_split_infer:6one prompt-conditioned forward per passage batch, score =7sigmoid(head([start; end; mean; +-64 window])).8 9Scoring happens only for items without scored_by (or --force). Every queue10item — scored here or carrying authoritative H100 scores from11build_gold_queue.py — is then tagged with the singlepass decision rule12(human_labeling/probe_labels.py):13 14    keep        score >= per-origin best-F1 threshold (thresholds.json)15    drop        score <= 0.0516    confusion   between threshold and the drop floor (was "mid")17    unscored    score missing (out-of-grid span)18 19    uv run python human_labeling/rescore_singlepass.py [--force] [--limit N]20"""21 22import argparse23import json24import sys25from pathlib import Path26 27REPO = Path(__file__).resolve().parent.parent28sys.path.insert(0, str(REPO))29 30MODEL = "rafmacalaba/gliner-datause-catchall-singlepass"31QUEUES = ["human_labeling/queue.json", "human_labeling/queue_human473.json"]32 33 34def main() -> None:35    ap = argparse.ArgumentParser()36    ap.add_argument("--model", default=MODEL)37    ap.add_argument("--force", action="store_true")38    ap.add_argument("--limit", type=int, default=0)39    ap.add_argument("--batch", type=int, default=8)40    a = ap.parse_args()41 42    import torch43    from training.singlepass_infer import default_device, load_bundle44    from training.probe_features_infer import encode_split_infer45    from probe_labels import decide, load_thresholds46 47    device = default_device()48    print(f"device={device} model={a.model}", flush=True)49    model, head, bundle = load_bundle(50        "rafmacalaba/gliner-datause-mentions-catch-all", a.model, device)51    thresholds = bundle.get("thresholds") or load_thresholds()52    args = argparse.Namespace(encode_batch_size=a.batch, context_radius=64)53 54    for qname in QUEUES:55        p = REPO / qname56        if not p.exists():57            continue58        items = [json.loads(l) for l in p.read_text().splitlines() if l.strip()]59        todo = [(i, r) for i, r in enumerate(items) if r.get("ctx")]60        to_score = [(i, r) for i, r in todo if a.force or not r.get("scored_by")]61        if a.limit:62            to_score = to_score[:a.limit]63 64        n_scored = n_skip = skipped = 065        if to_score:66            texts = [r["ctx"] for _, r in to_score]67            spans = [(k, r["start"], r["end"], 0, r["key"])68                     for k, (_, r) in enumerate(to_score)]69            feats, dim, skipped = encode_split_infer(model, texts, spans, args, device)70            F = torch.from_numpy(feats).to(device)71            with torch.no_grad():72                probs = torch.sigmoid(head(F)).cpu().numpy().ravel()73            for (i, r), frow, ps in zip(to_score, feats, probs):74                if not frow.any():  # out-of-grid: zero row, not a real score75                    r["head_score"] = None76                    n_skip += 177                else:78                    r["head_score"] = float(ps)79                    n_scored += 180                r["scored_by"] = a.model81 82        n_tag = 083        for i, r in todo:84            r["band"] = decide(r.get("head_score"), r.get("origin"), thresholds)85            n_tag += 186        if to_score or n_tag:87            p.write_text("\n".join(json.dumps(r) for r in items) + "\n")88        print(f"{qname}: rescored={n_scored} unscored={n_skip} "89              f"tagged={n_tag} skipped_align={skipped}", flush=True)90 91 92if __name__ == "__main__":93    main()