Views
No views yet
undetermined class for out-of-distribution input.google/muril-base-cased on a banking-flavoured mix that includes Bhasha-Abhijnaanam, Aksharantar, SST-2, Dakshina, Hinglish corpora, MASSIVE, OffensEval-Dravidian, Bitext retail-banking, plus synthetic banking sentences, banking noun phrases, greeting-led English sentences, conversational shorts, and OOD calibration sources (FLORES-200, Aksharantar non-target Indic, banking-style European, gibberish).0 as 1 bn 2 en 3 gu 4 hi 5 kn 6 ks 7 ml 8 mr
9 ne 10 or 11 pa 12 sa 13 sd 14 ta 15 te 16 ur
17 undetermined (OOD / non-target / gibberish)undetermined is a learned class, trained directly on non-target Indic, FLORES non-target, banking-style European, and synthetic gibberish. An energy-based gate (-logsumexp(logits) > -6.2) is a backup safety net for inputs that the learned class doesn't catch.| Split | Accuracy | F1 (weighted) | F1 (macro) |
|---|---|---|---|
| test | 0.9735 | 0.9735 | 0.9684 |
1import torch
2from transformers import AutoModelForSequenceClassification, AutoTokenizer
3
4LABELS = [
5 "as","bn","en","gu","hi","kn","ks","ml","mr",
6 "ne","or","pa","sa","sd","ta","te","ur","undetermined",
7]
8ENERGY_THRESHOLD = -6.2 # per-checkpoint calibration; see below
9
10tok = AutoTokenizer.from_pretrained("dnivra26/muril-lang-id-v15")
11model = AutoModelForSequenceClassification.from_pretrained("dnivra26/muril-lang-id-v15").eval()
12
13@torch.inference_mode()
14def classify(text: str) -> tuple[str, float]:
15 inputs = tok(text, return_tensors="pt", truncation=True, max_length=128, padding=True)
16 logits = model(**inputs).logits.squeeze(0)
17 energy = -torch.logsumexp(logits, dim=0).item()
18 label = LABELS[int(torch.softmax(logits, dim=0).argmax())]
19 if energy > ENERGY_THRESHOLD or label == "undetermined":
20 return "undetermined", energy
21 if label == "ur": # Romanized Urdu/Hindi are linguistically identical
22 label = "hi"
23 return label, energy
24
25print(classify("Loan approval")) # ('en', ~ -12.7)
26print(classify("Hey, my card is blocked")) # ('en', ~ -12.9)
27print(classify("namaste")) # ('hi', ~ -11.1)
28print(classify("vanakkam")) # ('ta', ...)
29print(classify("नमस्ते")) # ('hi', ...) — but native-script inputs should ideally be handled by a script-detect short-circuit upstreamDEFAULT_ENERGY_THRESHOLD = -6.2 — calibrated on test_all.csv (n=1882, banking-flavoured): plateau optimum from −6.2 to −4.6 at 95.32% overall accuracy. The bare-noun-phrase and cased-EN training data added in v12-v15 push real banking-phrase energies to −10..−12, well below the threshold, so the gate primarily catches genuine OOD where the argmax is a target language but the logits aren't peaked."loan approval" / "EMI bounce" tripped the energy gate even though softmax preferred en."LOAN APPROVAL" → ml and capital-leading single-word greetings ("Hi", "Hello", "HEY") routing to hi."Accha", "Shukriya") route to hi. Held capital fixes but regressed the dominant lowercase shape ("accha" → en, "Dhanyavaad" → pa)."Hey how are you" and "Hey, my loan approval is pending" routing to hi); revert the en-only guard drop. Lowercase Hindi-Roman shorts back to correct hi; capitalised Hindi-Roman shorts revert to v13 behaviour (acceptable trade-off — capital is rare in real chat input)."Accha", "Shukriya" (rare in real chat) may revert to other Indic labels or get OOD-flagged. Lowercase forms classify correctly.-7.0 increases undetermined rate on short banking-only phrases; loosening reduces OOD recall. Sweep on a representative test set before changing.arxiv:2103.10730).