Token Classification
Transformers
ONNX
Safetensors
Transformers.js
modernbert
punctuation
punctuation-restoration
truecasing
capitalization
asr
speech-recognition
transcription
mmbert
Instructions to use Horizon-Labs/multilingual-punctuation-truecase-base with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Horizon-Labs/multilingual-punctuation-truecase-base with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("token-classification", model="Horizon-Labs/multilingual-punctuation-truecase-base")# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForTokenClassification tokenizer = AutoTokenizer.from_pretrained("Horizon-Labs/multilingual-punctuation-truecase-base") model = AutoModelForTokenClassification.from_pretrained("Horizon-Labs/multilingual-punctuation-truecase-base", device_map="auto") - Transformers.js
How to use Horizon-Labs/multilingual-punctuation-truecase-base with Transformers.js:
// npm i @huggingface/transformers import { pipeline } from '@huggingface/transformers'; // Allocate pipeline const pipe = await pipeline('token-classification', 'Horizon-Labs/multilingual-punctuation-truecase-base'); - Notebooks
- Google Colab
- Kaggle
Download code/truecase/boundary_check.py from Horizon-Labs/multilingual-punctuation-truecase-base: direct link, hf CLI and curl.
- Browser
- Download file 5.3 kB
-
https://huggingface.co/Horizon-Labs/multilingual-punctuation-truecase-base/resolve/main/code/truecase/boundary_check.py
- Command line
-
hf download hf://Horizon-Labs/multilingual-punctuation-truecase-base/code/truecase/boundary_check.py
-
curl -L -o boundary_check.py https://huggingface.co/Horizon-Labs/multilingual-punctuation-truecase-base/resolve/main/code/truecase/boundary_check.py
5.3 kB
| """Comma -> capital boundary errors of a joint truecase model, and a boundary-consistent decoding. | |
| The mark of word i and the case of word i+1 are separate labels, so the model can write "hello, How are you". Where the argmax gives | |
| (',' after word i, Cap on word i+1), compare three options with the marginal probabilities: keep (',' , Cap) * beta, ('.'/'?' , Cap), | |
| (',' , lower). beta = 1 is the plain argmax. beta is chosen on held-out VALIDATION windows (val.parquet rows after the 6,000 used for | |
| checkpoint selection), then the test sets are scored with every beta for the record. | |
| python truecase/boundary_check.py OUT.json DATA_DIR EVAL_DIR MODEL [MODEL ...]""" | |
| import json, os, sys | |
| import numpy as np, pandas as pd, torch | |
| sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))); sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "punct")) | |
| from common import LABELS as PL, NOSPACE, lower_keep_len | |
| from common_tc import unit_cases | |
| from tc_metrics import chunks, score | |
| from transformers import AutoModelForTokenClassification, AutoTokenizer | |
| out_f, data, ev = sys.argv[1:4]; models = sys.argv[4:] | |
| BETAS = [1.0, 0.8, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0] | |
| COMMA, PER, Q = PL.index(","), PL.index("."), PL.index("?") | |
| va = pd.read_parquet(f"{data}/val.parquet").sample(frac=1.0, random_state=0).iloc[6000:] | |
| val_items = [dict(set="val", lang=l, text=t, ends=e.tolist(), gp=[PL[x] for x in lb], gc=unit_cases(t, e.tolist(), l in NOSPACE), nos=l in NOSPACE) | |
| for t, e, lb, l in zip(va.text, va.ends, va.labs, va.lang)] | |
| test_items = [it for it in chunks(ev) if it["set"] in ("europarl", "ted", "flores")] | |
| print("val", len(val_items), "test", len(test_items), flush=True) | |
| def probs(tok, model, items): | |
| texts = [lower_keep_len(it["text"]) for it in items]; order = np.argsort([len(t) for t in texts]); res = [None] * len(items) | |
| for s in range(0, len(order), 64): | |
| idx = order[s:s + 64] | |
| enc = tok([texts[i] for i in idx], truncation=True, max_length=512, padding=True, return_offsets_mapping=True, return_tensors="pt") | |
| offs = enc.pop("offset_mapping").tolist() | |
| with torch.no_grad(): | |
| p = torch.softmax(model(**{k: v.cuda() for k, v in enc.items()}).logits.float(), -1).cpu().numpy() | |
| for j, i in enumerate(idx): | |
| at = {e: k for k, (b, e) in enumerate(offs[j]) if e > b} | |
| P = np.zeros((len(items[i]["ends"]), 18), np.float32); P[:, 0] = 1.0 | |
| for u, e in enumerate(items[i]["ends"]): | |
| if e in at: | |
| P[u] = p[j, at[e]] | |
| res[i] = P | |
| return res | |
| def decode(P, beta): | |
| j = P.argmax(1); pm, pc = (j // 3).tolist(), (j % 3).tolist() | |
| if beta < 1: | |
| M, C = P.reshape(-1, 6, 3).sum(2), P.reshape(-1, 6, 3).sum(1) | |
| for i in range(len(pm) - 1): | |
| if pm[i] == COMMA and pc[i + 1] == 1: | |
| b = PER if M[i, PER] >= M[i, Q] else Q | |
| z, x, y = M[i, COMMA] * C[i + 1, 1] * beta, M[i, b] * C[i + 1, 1], M[i, COMMA] * C[i + 1, 0] | |
| if x >= z and x >= y: | |
| pm[i] = b | |
| elif y > z: | |
| pc[i + 1] = 0 | |
| return [PL[m] for m in pm], pc | |
| def events(items, PP): | |
| """raw argmax (',' , Cap) boundaries by gold: sentence boundary, comma + capital (name/I), comma/none + lower (wrong capital).""" | |
| n = dict(total=0, gold_sentence_break=0, gold_comma_cap=0, gold_lower=0, other=0, words=0) | |
| for it, P in zip(items, PP): | |
| pm, pc = decode(P, 1.0); n["words"] += len(pm) | |
| for i in range(len(pm) - 1): | |
| if pm[i] == "," and pc[i + 1] == 1: | |
| n["total"] += 1; g, gc = it["gp"][i], it["gc"][i + 1] | |
| k = "gold_sentence_break" if g in (".", "?") and gc == 1 else "gold_comma_cap" if gc == 1 else "gold_lower" if gc == 0 else "other" | |
| n[k] += 1 | |
| return n | |
| res = json.load(open(out_f)) if os.path.exists(out_f) else {} | |
| for m in models: | |
| tok = AutoTokenizer.from_pretrained(m); model = AutoModelForTokenClassification.from_pretrained(m, dtype=torch.bfloat16).cuda().eval() | |
| PV, PT = probs(tok, model, val_items), probs(tok, model, test_items) | |
| r = dict(events_val=events(val_items, PV), events_test={s: events([it for it in test_items if it["set"] == s], [P for it, P in zip(test_items, PT) if it["set"] == s]) | |
| for s in ("europarl", "ted", "flores")}, val={}, test={}) | |
| for b in BETAS: | |
| dv = [decode(P, b) for P in PV]; dt = [decode(P, b) for P in PT] | |
| r["val"][b] = score(val_items, [d[0] for d in dv], [d[1] for d in dv])["summary"] | |
| r["test"][b] = score(test_items, [d[0] for d in dt], [d[1] for d in dt])["summary"] | |
| v = r["val"][b]["val"]; print(m[-50:], "beta", b, "val", round(v["punct_f1"], 4), round(v["case_f1"], 4), | |
| {s: (round(x["punct_f1"], 4), round(x["case_f1"], 4)) for s, x in r["test"][b].items()}, flush=True) | |
| best = max(BETAS, key=lambda b: (r["val"][b]["val"]["punct_f1"] + r["val"][b]["val"]["case_f1"]) / 2); r["best_beta_val"] = best | |
| print(m[-50:], "events", r["events_val"], r["events_test"], "best beta (val)", best, flush=True) | |
| res[m] = r; json.dump(res, open(out_f, "w"), indent=1) | |