Instructions to use kesha-humonen/runic-reader-2 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use kesha-humonen/runic-reader-2 with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
Download code/matched_noise.py from kesha-humonen/runic-reader-2: direct link, hf CLI and curl.
- Browser
- Download file 5.62 kB
-
https://huggingface.co/kesha-humonen/runic-reader-2/resolve/main/code/matched_noise.py
- Command line
-
hf download hf://kesha-humonen/runic-reader-2/code/matched_noise.py
-
curl -L -o matched_noise.py https://huggingface.co/kesha-humonen/runic-reader-2/resolve/main/code/matched_noise.py
5.62 kB
| """Real recognition errors vs synthetic corruption on the same transliterations (reviewer 3, point 4). | |
| For every leak-free test photograph, the recognizer output (crop recognizer, loop-cut) and the synthetic corruptions of | |
| the same reference transliteration (noise levels of E4) are translated by the same translator. Two comparisons: | |
| bins photographs grouped by recognizer CER; chrF++ retention (output / reference input) for the real output | |
| and for each synthetic level on the same photographs, with the synthetic CER measured on those items | |
| matched for each photograph the synthetic level whose CER on that item is closest to the recognizer's CER | |
| (only photographs with a level within 10 CER points); corpus chrF++ real vs matched synthetic, cluster | |
| paired bootstrap | |
| Writes results/matched_noise.json. | |
| """ | |
| import json | |
| import os | |
| import random | |
| import sys | |
| sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) | |
| import metrics # noqa: E402 | |
| import sacrebleu # noqa: E402 | |
| ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | |
| P = f"{ROOT}/preds" | |
| KEEP = set(json.load(open(f"{ROOT}/data/leakfree.json"))["keep_test"]) | |
| OCR_TAG = os.environ.get("OCR_TAG", "ocr4b_cropcut") | |
| CHRF = sacrebleu.CHRF(word_order=2) | |
| def load(name): | |
| return [r for r in metrics.read(f"{P}/{name}.jsonl") if (r.get("row_id") or r.get("base_id") or r["id"]) in KEEP] | |
| def cer(ref, hyp): | |
| d, n = metrics.cer_parts(ref, hyp) | |
| return 100 * d / n | |
| def chrf(hyps, refs): | |
| return CHRF.corpus_score(hyps, [refs]).score | |
| ocr = {r["id"]: r for r in load(f"ocr_test_{OCR_TAG}")} | |
| res = {} | |
| for tr in ("mt4b", "mt4b_noise"): | |
| real = {r["id"]: r for r in load(f"e2e_{OCR_TAG}_{tr}_fromocr")} | |
| gold = {r["id"]: r for r in load(f"e2e_ocr4b_mixcut_{tr}_fromgold")} | |
| noise = {} | |
| for r in load(f"noise_{tr}"): | |
| noise[(r["base_id"], r["level"])] = r | |
| levels = sorted({lv for _, lv in noise}) | |
| photos = [i for i in ocr if i in real and i in gold and (ocr[i]["row_id"], 0.0) in noise] | |
| out = {"n_photos": len(photos), "bins": {}, "matched": {}} | |
| def retention(ids, hyp_of): | |
| g = chrf([gold[i]["pred"] for i in ids], [gold[i]["tgt"] for i in ids]) | |
| h = chrf([hyp_of(i) for i in ids], [gold[i]["tgt"] for i in ids]) | |
| return h, g, 100 * h / g | |
| for lo, hi in ((0, 25), (25, 50), (50, 75), (75, 1e9)): | |
| ids = [i for i in photos if lo <= cer(ocr[i]["target"], ocr[i]["pred"]) < hi] | |
| if not ids: | |
| continue | |
| rc = sum(metrics.cer_parts(ocr[i]["target"], ocr[i]["pred"])[0] for i in ids) / \ | |
| sum(metrics.cer_parts(ocr[i]["target"], ocr[i]["pred"])[1] for i in ids) * 100 | |
| h, g, ret = retention(ids, lambda i: real[i]["pred"]) | |
| b = {"n": len(ids), "real": {"cer": rc, "chrfpp": h, "chrfpp_gold": g, "retention": ret}} | |
| for lv in levels: | |
| if lv == 0.0: | |
| continue | |
| rows = [noise[(ocr[i]["row_id"], lv)] for i in ids] | |
| sc = sum(metrics.cer_parts(r["src_clean"], r["src"])[0] for r in rows) / \ | |
| sum(metrics.cer_parts(r["src_clean"], r["src"])[1] for r in rows) * 100 | |
| hs, gs, rs = retention(ids, lambda i, lv=lv: noise[(ocr[i]["row_id"], lv)]["pred"]) | |
| b[f"synthetic_{lv}"] = {"cer": sc, "chrfpp": hs, "retention": rs} | |
| out["bins"][f"{lo}-{hi if hi < 1e9 else 'inf'}"] = b | |
| # per-photo CER matching | |
| pairs = [] | |
| for i in photos: | |
| rc = cer(ocr[i]["target"], ocr[i]["pred"]) | |
| best = min((abs(cer(noise[(ocr[i]["row_id"], lv)]["src_clean"], noise[(ocr[i]["row_id"], lv)]["src"]) - rc), lv) | |
| for lv in levels if lv > 0) | |
| if best[0] <= 10: | |
| pairs.append((i, best[1])) | |
| ids = [i for i, _ in pairs] | |
| lv_of = dict(pairs) | |
| syn = {i: noise[(ocr[i]["row_id"], lv_of[i])] for i in ids} | |
| real_cer = 100 * sum(metrics.cer_parts(ocr[i]["target"], ocr[i]["pred"])[0] for i in ids) / \ | |
| sum(metrics.cer_parts(ocr[i]["target"], ocr[i]["pred"])[1] for i in ids) | |
| syn_cer = 100 * sum(metrics.cer_parts(syn[i]["src_clean"], syn[i]["src"])[0] for i in ids) / \ | |
| sum(metrics.cer_parts(syn[i]["src_clean"], syn[i]["src"])[1] for i in ids) | |
| a = [dict(real[i], id=i) for i in ids] | |
| s = [dict(syn[i], id=i, tgt=real[i]["tgt"], cluster=real[i]["cluster"]) for i in ids] | |
| h_real, g, ret_real = retention(ids, lambda i: real[i]["pred"]) | |
| h_syn, _, ret_syn = retention(ids, lambda i: syn[i]["pred"]) | |
| out["matched"] = {"n": len(ids), "real_cer": real_cer, "synthetic_cer": syn_cer, "chrfpp_gold": g, | |
| "real_chrfpp": h_real, "synthetic_chrfpp": h_syn, "real_retention": ret_real, | |
| "synthetic_retention": ret_syn, "paired_real_gt_synthetic": metrics.paired_bootstrap_chrf(a, s)} | |
| res[tr] = out | |
| json.dump(res, open(f"{ROOT}/results/matched_noise.json", "w"), indent=1) | |
| for tr, out in res.items(): | |
| print(f"=== {tr}: {out['n_photos']} photos") | |
| for k, b in out["bins"].items(): | |
| print(f" CER {k:7s} n={b['n']:3d} real CER {b['real']['cer']:.1f} ret {b['real']['retention']:.0f}% | " + | |
| " ".join(f"{lv[10:]}: CER {v['cer']:.1f} ret {v['retention']:.0f}%" for lv, v in b.items() if lv.startswith("synthetic"))) | |
| m = out["matched"] | |
| print(f" matched n={m['n']} CER real {m['real_cer']:.1f} syn {m['synthetic_cer']:.1f} | chrF gold {m['chrfpp_gold']:.1f} " | |
| f"real {m['real_chrfpp']:.1f} ({m['real_retention']:.0f}%) syn {m['synthetic_chrfpp']:.1f} ({m['synthetic_retention']:.0f}%) " | |
| f"p={m['paired_real_gt_synthetic']['p']:.3f}") | |