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/make_tables.py from kesha-humonen/runic-reader-2: direct link, hf CLI and curl.
- Browser
- Download file 11.7 kB
-
https://huggingface.co/kesha-humonen/runic-reader-2/resolve/main/code/make_tables.py
- Command line
-
hf download hf://kesha-humonen/runic-reader-2/code/make_tables.py
-
curl -L -o make_tables.py https://huggingface.co/kesha-humonen/runic-reader-2/resolve/main/code/make_tables.py
11.7 kB
| """Write LaTeX tables for the results section from results/results.json (no hand-copied numbers).""" | |
| import json | |
| import os | |
| ROOT = os.path.expanduser("~/runic_access") | |
| R = json.load(open(f"{ROOT}/results/" + os.environ.get("RESULTS", "results.json"))) | |
| OUT = f"{ROOT}/paper/tables" | |
| os.makedirs(OUT, exist_ok=True) | |
| def ci(v, c, d=1): | |
| return f"{v:.{d}f} {{\\scriptsize[{c[0]:.{d}f}, {c[1]:.{d}f}]}}" | |
| # ---------------- E1 ---------------- | |
| e1 = R.get("E1", {}) | |
| rows = [("Constant string", "--", "ocr_test_constant"), ("Zero-shot", "0.8B", "ocr_test_zs08"), ("Zero-shot", "4B", "ocr_test_zs4b"), | |
| ("Procedural", "4B", "ocr_test_ocr4b_syn"), ("Diffusion", "4B", "ocr_test_ocr4b_diff"), | |
| ("Real", "4B", "ocr_test_ocr4b_real"), ("Real + procedural", "4B", "ocr_test_ocr4b_mix"), | |
| ("Real + diffusion", "4B", "ocr_test_ocr4b_diffmix"), ("Real + proc., 1\\,MP", "4B", "ocr_test_ocr4b_mix_hr"), | |
| ("Real crops + proc.", "4B", "ocr_test_ocr4b_crop"), ("Real + proc., on crops", "4B", "ocr_test_ocr4b_mix_oncrop"), | |
| ("Real + procedural", "0.8B", "ocr_test_ocr08_mix")] | |
| def cell(v, key): | |
| return f"{v[key]['cer']:.1f}" if key in v else "--" | |
| n = {k: e1.get("ocr_test_ocr4b_mix", {}).get(k, {}).get("n", 0) for k in ("all", "gr", "rdb_photo", "card")} | |
| lines = [r"\begin{table*}[t]", r"\centering", r"\color{blue}", | |
| r"\caption{Recognition across image domains: CER (\%%, lower is better) on held-out synthetic images of each style and on the real test images by domain (GR: Gamla runor field photographs; RuneS: photographs of objects; Cards: scanned archive cards). \emph{All}: the %d real test images with a 95\%% bootstrap interval. Rare: recall of words outside the 150 most frequent training words.}" % n["all"], | |
| r"\label{tab:ocr}", r"\small", r"\begin{tabular}{llrrrrrrr}", r"\toprule", | |
| r" & & \multicolumn{2}{c}{Synthetic} & \multicolumn{3}{c}{Real test} & & \\", | |
| r"\cmidrule(lr){3-4}\cmidrule(lr){5-7}", | |
| r"Training data & Model & Proc. & Diff. & GR (%d) & RuneS (%d) & Cards (%d) & All & Rare \\" % (n["gr"], n["rdb_photo"], n["card"]), | |
| r"\midrule"] | |
| for name, size, tag in rows: | |
| if tag not in e1: | |
| continue | |
| v = e1[tag] | |
| a = v["all"] | |
| rare = f"{v['rare_recall']:.1f}" if "rare_recall" in v else "--" | |
| lines.append(f"{name} & {size} & {cell(v, 'proc_syn')} & {cell(v, 'diff_syn')} & {cell(v, 'gr')} & {cell(v, 'rdb_photo')} & {cell(v, 'card')} & {ci(a['cer'], a['cer_ci'])} & {rare} \\\\") | |
| lines += [r"\bottomrule", r"\end{tabular}", r"\end{table*}"] | |
| open(f"{OUT}/ocr.tex", "w").write("\n".join(lines) + "\n") | |
| # ---------------- E2 ---------------- | |
| e2 = R.get("E2", {}) | |
| rows = [("Zero-shot", "0.8B", "mt_test_zs08"), ("Zero-shot", "4B", "mt_test_zs4b"), ("Retrieval", "--", "mt_test_retrieval"), | |
| ("LoRA", "0.8B", "mt_test_mt08"), ("LoRA", "4B", "mt_test_mt4b"), ("LoRA + noise", "4B", "mt_test_mt4b_noise")] | |
| lines = [r"\begin{table*}[t]", r"\centering", r"\color{blue}", | |
| r"\caption{Translation of reference transliterations on the held-out test set (chrF++ and BLEU, higher is better; 95\% bootstrap intervals for chrF++). \emph{Strict}: test pairs whose closest training transliteration is below 80\% similarity.}", | |
| r"\label{tab:mt}", r"\begin{tabular}{llrrrrrr}", r"\toprule", | |
| r" & & \multicolumn{2}{c}{English ($n{=}%d$)} & \multicolumn{2}{c}{Swedish ($n{=}%d$)} & \multicolumn{2}{c}{Strict ($n{=}%d$)} \\" % ( | |
| e2.get("mt_test_retrieval", {}).get("en", {}).get("n", 0), e2.get("mt_test_retrieval", {}).get("sv", {}).get("n", 0), | |
| e2.get("mt_test_retrieval", {}).get("strict", {}).get("n", 0)), | |
| r"\cmidrule(lr){3-4}\cmidrule(lr){5-6}\cmidrule(lr){7-8}", | |
| r"System & Model & chrF++ & BLEU & chrF++ & BLEU & chrF++ & BLEU \\", r"\midrule"] | |
| for name, size, tag in rows: | |
| if tag not in e2: | |
| continue | |
| v = e2[tag] | |
| cells = [] | |
| for k in ("en", "sv", "strict"): | |
| cells += [ci(v[k]["chrfpp"], v[k]["chrfpp_ci"]), f"{v[k]['bleu']:.1f}"] | |
| lines.append(f"{name} & {size} & " + " & ".join(cells) + r" \\") | |
| lines += [r"\bottomrule", r"\end{tabular}", r"\end{table*}"] | |
| open(f"{OUT}/mt.tex", "w").write("\n".join(lines) + "\n") | |
| # ---------------- E3 ---------------- | |
| e3 = R.get("E3", {}) | |
| if e3.get("subsets"): | |
| tag = next(k[4:].rsplit("_mt4b", 1)[0] for k in e3 if k.startswith("e2e_") and "_mt4b" in k) | |
| sub = e3["subsets"] | |
| lines = [r"\begin{table}[t]", r"\centering", r"\color{blue}", | |
| r"\caption{End-to-end translation of the test photographs (chrF++). \emph{Reference}: the 4B translator applied to the reference transliterations; the other columns translate the recognizer output. Rows group the photographs by the recognizer's CER on each image and by image domain.}", | |
| r"\label{tab:e2e}", r"\small", r"\setlength{\tabcolsep}{3pt}", r"\begin{tabular}{lrrrrrrr}", r"\toprule", | |
| r" & & & & \multicolumn{4}{c}{From photograph} \\", r"\cmidrule(lr){5-8}", | |
| r"Photographs & $n$ & CER & Ref. & Const. & Retr. & LoRA & +noise \\", r"\midrule"] | |
| a = e3["ocr_cer"]["all"] | |
| lines.append(f"All & {a['n']} & {a['cer']:.1f} & {e3[f'e2e_{tag}_mt4b_fromgold']['all']['chrfpp']:.1f} & " | |
| f"{e3[f'e2e_{tag}_constant']['all']['chrfpp']:.1f} & {e3[f'e2e_{tag}_retrieval_fromocr']['all']['chrfpp']:.1f} & " | |
| f"{e3[f'e2e_{tag}_mt4b_fromocr']['all']['chrfpp']:.1f} & {e3[f'e2e_{tag}_mt4b_noise_fromocr']['all']['chrfpp']:.1f} \\\\") | |
| names = (("cer<25", r"CER $<$25\%"), ("cer25-50", r"CER 25--50\%"), ("cer50-75", r"CER 50--75\%"), ("cer>=75", r"CER $\geq$75\%"), | |
| ("gr", "Gamla runor"), ("rdb_photo", "RuneS photos"), ("card", "RuneS cards")) | |
| for i, (k, name) in enumerate(names): | |
| if i in (0, 4): | |
| lines.append(r"\midrule") | |
| if k not in sub: | |
| continue | |
| v = sub[k] | |
| lines.append(f"{name} & {v['n']} & {v['ocr']['cer']:.1f} & {v['mt4b_fromgold']['chrfpp']:.1f} & {v['constant']['chrfpp']:.1f} & " | |
| f"{v['retrieval_fromocr']['chrfpp']:.1f} & {v['mt4b_fromocr']['chrfpp']:.1f} & {v['mt4b_noise_fromocr']['chrfpp']:.1f} \\\\") | |
| lines += [r"\bottomrule", r"\end{tabular}", r"\end{table}"] | |
| open(f"{OUT}/e2e.tex", "w").write("\n".join(lines) + "\n") | |
| # ---------------- appendix: raw recognition and output length ---------------- | |
| lines = [r"\begin{table}[h]", r"\centering", r"\color{blue}", | |
| r"\caption{Recognition on the real test images: corpus-level CER (\%) without and with repetition truncation, median CER of individual images, ratio of output to reference length, and share of outputs more than twice as long as the reference (after truncation).}", | |
| r"\label{tab:ocr-raw}", r"\footnotesize", r"\setlength{\tabcolsep}{2.5pt}", | |
| r"\begin{tabular}{llrrrrr}", r"\toprule", r"Training data & Model & Raw & Cut & Median & Length & $>$2$\times$ \\", r"\midrule"] | |
| for name, size, tag in [("Zero-shot", "0.8B", "ocr_test_zs08"), ("Zero-shot", "4B", "ocr_test_zs4b"), | |
| ("Procedural", "4B", "ocr_test_ocr4b_syn"), ("Diffusion", "4B", "ocr_test_ocr4b_diff"), | |
| ("Real", "4B", "ocr_test_ocr4b_real"), ("Real + procedural", "4B", "ocr_test_ocr4b_mix"), | |
| ("Real + diffusion", "4B", "ocr_test_ocr4b_diffmix"), ("Real + proc., 1\\,MP", "4B", "ocr_test_ocr4b_mix_hr"), | |
| ("Real crops + proc.", "4B", "ocr_test_ocr4b_crop"), ("Real + proc., on crops", "4B", "ocr_test_ocr4b_mix_oncrop"), | |
| ("Real + procedural", "0.8B", "ocr_test_ocr08_mix")]: | |
| if tag in e1 and "raw" in e1[tag]: | |
| v = e1[tag] | |
| lines.append(f"{name} & {size} & {v['raw']['cer']:.1f} & {v['all']['cer']:.1f} & {v['median_cer']:.1f} & " | |
| f"{v['len_ratio']:.2f} & {v['over2x']:.1f} \\\\") | |
| lines += [r"\bottomrule", r"\end{tabular}", r"\end{table}"] | |
| open(f"{OUT}/ocr_raw.tex", "w").write("\n".join(lines) + "\n") | |
| # ---------------- appendix: reference-free selection of photographs ---------------- | |
| sel = R.get("E3", {}).get("selection", {}) | |
| names = [(k, n) for k, n in (("nll", "NLL"), ("agree_hr", "Agree-2"), ("agree4", "Agree-5"), ("oracle_cer", "Oracle")) if k in sel] | |
| if names: | |
| e3a = R["E3"] | |
| tag = next(k[4:].rsplit("_mt4b", 1)[0] for k in e3a if k.startswith("e2e_") and "_mt4b" in k) | |
| lines = [r"\begin{table}[!ht]", r"\centering", r"\color{blue}", | |
| r"\caption{End-to-end translation of the most confidently read test photographs. Photographs are ranked by a confidence signal and the top fraction is kept; each cell gives the recognizer's CER (\%) and chrF++ of the translation from the photograph. NLL: mean per-token negative log-likelihood that the pipeline recognizer assigns to its own output; empty outputs and decodes stopped by the generation limit are ranked last. Agree-2: normalized edit distance between the outputs of the pipeline recognizer and of a recognizer trained on whole images at 1.05\,MP. Agree-5: mean distance to four other adapted recognizers (real only, real + diffusion, 1.05\,MP and the 0.8B model, all on whole images). Oracle: ranking by the true CER.}", | |
| r"\label{tab:selection}", r"\footnotesize", r"\setlength{\tabcolsep}{2.5pt}", | |
| r"\begin{tabular}{l" + "rr" * len(names) + "}", r"\toprule", | |
| " & " + " & ".join(r"\multicolumn{2}{c}{%s}" % n for _, n in names) + r" \\", | |
| "".join(r"\cmidrule(lr){%d-%d}" % (2 + 2 * j, 3 + 2 * j) for j in range(len(names))), | |
| "Kept & " + " & ".join("CER & chrF++" for _ in names) + r" \\", r"\midrule"] | |
| for frac in ("0.1", "0.2", "0.3", "0.5"): | |
| n = sel[names[0][0]][frac]["n"] | |
| lines.append(f"{round(100 * float(frac))}\\% ({n}) & " + " & ".join( | |
| f"{sel[k][frac]['cer']:.1f} & {sel[k][frac]['chrfpp_ocr']:.1f}" for k, _ in names) + r" \\") | |
| a_ = e3a["ocr_cer"]["all"]["cer"] | |
| c_ = e3a[f"e2e_{tag}_mt4b_fromocr"]["all"]["chrfpp"] | |
| lines.append(f"100\\% ({e3a['ocr_cer']['all']['n']}) & " + " & ".join(f"{a_:.1f} & {c_:.1f}" for _ in names) + r" \\") | |
| lines += [r"\bottomrule", r"\end{tabular}", r"\end{table}"] | |
| open(f"{OUT}/selection.tex", "w").write("\n".join(lines) + "\n") | |
| # ---------------- appendix: archive cards by what the crop shows ---------------- | |
| cards = R.get("E3", {}).get("cards", {}) | |
| if cards: | |
| lines = [r"\begin{table}[!ht]", r"\centering", r"\color{blue}", | |
| r"\caption{Archive cards of the test set by what the located crop shows. Whole: the recognizer trained on whole images reads the whole card; Crop: the pipeline recognizer reads the crop, or the whole card when no box was found. CER (\%) of recognition, chrF++ of translation from the recognizer output and from the reference transliterations (Ref.).}", | |
| r"\label{tab:cards}", r"\small", r"\setlength{\tabcolsep}{3pt}", r"\begin{tabular}{lrrrrrr}", r"\toprule", | |
| r" & & \multicolumn{2}{c}{CER} & \multicolumn{3}{c}{chrF++} \\", r"\cmidrule(lr){3-4}\cmidrule(lr){5-7}", | |
| r"Crop shows & $n$ & Whole & Crop & Whole & Crop & Ref. \\", r"\midrule"] | |
| for k, name in (("photo", "Photograph"), ("drawing", "Drawing"), ("whole", "No box"), (None, None), ("any", "All cards")): | |
| if k is None: | |
| lines.append(r"\midrule") | |
| elif k in cards: | |
| v = cards[k] | |
| lines.append(f"{name} & {v['n']} & {v['cer_whole']:.1f} & {v['cer']:.1f} & {v['chrfpp_whole']:.1f} & " | |
| f"{v['chrfpp']:.1f} & {v['chrfpp_gold']:.1f} \\\\") | |
| lines += [r"\bottomrule", r"\end{tabular}", r"\end{table}"] | |
| open(f"{OUT}/cards.tex", "w").write("\n".join(lines) + "\n") | |
| print("tables written to", OUT) | |