runic-reader-2 / code /backbones.py
kesha-humonen's picture
Add files using upload-large-folder tool
ed46c5d verified
Raw History Blame Contribute Delete
5.12 kB
"""Other backbones trained with our recipes (Reviewer 1, comment 3): translators (Qwen3-4B-Instruct-2507,
Ministral-8B-Instruct-2410, Olmo-3-7B-Instruct) against the Qwen3.5-4B translator, and recognizers (Qwen2.5-VL-7B,
Qwen3-VL-8B, crop recipe) against the Qwen3.5-4B crop recognizer; plus the thesis-B adapters run on our test images.
Missing prediction files are skipped. Writes results/backbones.json."""
import json
import os
import statistics
import sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import metrics # noqa: E402
from analyze import load, domain, rare_word_recall, name_recall # noqa: E402
from loopcut import cut_loops # noqa: E402
ROOT = os.path.expanduser("~/runic_access")
out = {"mt": {}, "ocr": {}, "perfilev": {}}
# ---------------- translators ----------------
MT = [("mt4b", "Qwen/Qwen3.5-4B"), ("q3i4b", "Qwen/Qwen3-4B-Instruct-2507"),
("ministral8b", "mistralai/Ministral-8B-Instruct-2410"), ("olmo3_7b", "allenai/Olmo-3-7B-Instruct")]
base = {"ref": load("mt_test_mt4b"), "ocr": load("e2e_ocr4b_cropcut_mt4b_fromocr")}
for tag, hf in MT:
ref = load(f"mt_test_{tag}")
ocr = load(f"e2e_ocr4b_cropcut_{tag}_fromocr")
if not ref:
continue
d = dict(hf=hf, ref=metrics.mt_scores(ref), en=metrics.mt_scores([r for r in ref if r["lang"] == "en"], boot=False),
sv=metrics.mt_scores([r for r in ref if r["lang"] == "sv"], boot=False), names=name_recall(ref))
zs = load(f"mt_test_{tag}_zs")
if zs:
d["zero_shot"] = metrics.mt_scores(zs, boot=False)
if ocr:
d["ocr"] = metrics.mt_scores(ocr)
d["ocr_names"] = name_recall(ocr)
if tag != "mt4b":
d["paired_mt4b_minus_this_ref"] = metrics.paired_bootstrap_chrf(base["ref"], ref)
d["paired_this_minus_mt4b_ref"] = metrics.paired_bootstrap_chrf(ref, base["ref"])
if ocr:
d["paired_mt4b_minus_this_ocr"] = metrics.paired_bootstrap_chrf(base["ocr"], ocr)
d["paired_this_minus_mt4b_ocr"] = metrics.paired_bootstrap_chrf(ocr, base["ocr"])
out["mt"][tag] = d
print(f"MT {tag:12s} ref {d['ref']['chrfpp']:.1f} [{d['ref']['chrfpp_ci'][0]:.1f},{d['ref']['chrfpp_ci'][1]:.1f}] "
f"en {d['en']['chrfpp']:.1f} sv {d['sv']['chrfpp']:.1f} names {d['names']:.1f}"
+ (f" zs {d['zero_shot']['chrfpp']:.1f}" if "zero_shot" in d else "")
+ (f" | photo {d['ocr']['chrfpp']:.1f} names {d['ocr_names']:.1f}" if "ocr" in d else "")
+ (f" | p(mt4b>this) ref {d['paired_mt4b_minus_this_ref']['p']:.3f} p(this>mt4b) ref {d['paired_this_minus_mt4b_ref']['p']:.3f}" if tag != "mt4b" else ""))
# ---------------- recognizers ----------------
def ocr_block(rows, e2e=None):
rows = [dict(r, pred=cut_loops(r.get("pred_raw", r["pred"]) or "")) for r in rows]
cers = [metrics.cer_parts(r["target"], r["pred"]) for r in rows]
d = dict(all=metrics.ocr_scores(rows), median_cer=statistics.median(100 * e / max(n, 1) for e, n in cers),
rare_recall=rare_word_recall(rows), by_domain={})
for dom in ("gr", "rdb_photo", "card"):
sub = [r for r in rows if domain(r) == dom]
if sub:
d["by_domain"][dom] = metrics.ocr_scores(sub)["cer"]
if e2e:
d["e2e"] = metrics.mt_scores(e2e)
return d
OCR = [("ocr4b", "Qwen/Qwen3.5-4B"), ("q25vl7b", "Qwen/Qwen2.5-VL-7B-Instruct"), ("q3vl8b", "Qwen/Qwen3-VL-8B-Instruct")]
for tag, hf in OCR:
test = load(f"ocr_test_{tag}_crop") if tag != "ocr4b" else load("ocr_test_ocr4b_crop")
if not test:
continue
d = dict(hf=hf, test=ocr_block(test, load(f"e2e_{tag}_cropcut_mt4b_fromocr")))
val = load(f"ocr_val_{tag}_crop")
if val:
d["val"] = ocr_block(val, load(f"e2eval_{tag}_cropcut_mt4b_fromocr"))
syn = load(f"ocr_synval_{tag}_crop")
if syn:
d["synval_cer"] = metrics.ocr_scores([dict(r, pred=cut_loops(r["pred"])) for r in syn])["cer"]
if tag != "ocr4b" and "e2e" in d["test"]:
d["paired_ocr4b_minus_this"] = metrics.paired_bootstrap_chrf(load("e2e_ocr4b_cropcut_mt4b_fromocr"), load(f"e2e_{tag}_cropcut_mt4b_fromocr"))
d["paired_this_minus_ocr4b"] = metrics.paired_bootstrap_chrf(load(f"e2e_{tag}_cropcut_mt4b_fromocr"), load("e2e_ocr4b_cropcut_mt4b_fromocr"))
out["ocr"][tag] = d
t = d["test"]
print(f"OCR {tag:8s} CER {t['all']['cer']:.1f} med {t['median_cer']:.1f} rare {t['rare_recall']:.1f} "
+ " ".join(f"{k}:{v:.1f}" for k, v in t["by_domain"].items())
+ (f" e2e {t['e2e']['chrfpp']:.1f}" if "e2e" in t else ""))
# ---------------- thesis-B adapters on our test images ----------------
for t in ("qwen25vl7b", "qwen3vl8b"):
for split in ("test", "testcrop", "valcrop", "testcrop320"):
rows = load(f"ocr_{split}_perf_{t}")
if rows:
out["perfilev"][f"{t}_{split}"] = ocr_block(rows)
b = out["perfilev"][f"{t}_{split}"]
print(f"PERF {t} {split:12s} n={b['all']['n']} CER {b['all']['cer']:.1f} med {b['median_cer']:.1f} rare {b['rare_recall']:.1f}")
json.dump(out, open(f"{ROOT}/results/backbones.json", "w"), indent=1)