Sinhala N-gram Language Model
A token-level 5-gram language model for Sinhala, trained on 180K sentences (8.7M tokens). Uses Stupid Backoff scoring. Pure Python implementation.
Files
| File | Description |
|---|---|
sinhala_5gram.json.gz |
Compressed 5-gram model (gzipped JSON, 13 MB) |
tokenizer/vocab.json |
Sinlib tokenizer vocabulary (850 subword tokens) |
tokenizer/config.json |
Tokenizer configuration |
Model Stats
| Metric | Value |
|---|---|
| Order | 5 |
| Vocabulary | 850 phonological subword tokens |
| Training tokens | 8,681,739 |
| Unique 1-grams | 847 |
| Unique 2-grams | 63,325 |
| Unique 3-grams | 409,674 |
| Unique 4-grams | 927,050 |
| Unique 5-grams | 1,341,620 |
Usage
Loading the model
import gzip
import json
import math
class NgramLM:
\"\"\"Lightweight n-gram LM with Stupid Backoff scoring.\"\"\"
def __init__(self, path: str):
with gzip.open(path, "rt", encoding="utf-8") as f:
data = json.load(f)
self.order = data["order"]
self.total_unigrams = data["total_unigrams"]
self.counts = [{}] * (self.order + 1)
for n_str, ngram_counts in data["counts"].items():
n = int(n_str)
self.counts[n] = {
tuple(k.split(" ")): v for k, v in ngram_counts.items()
}
def score(self, context: list[str], token: str) -> float:
\"\"\"Return log10 P(token | context) using Stupid Backoff.\"\"\"
for n in range(min(len(context) + 1, self.order), 0, -1):
if n == 1:
count = self.counts[1].get((token,), 0)
if count > 0:
return math.log10(count / self.total_unigrams)
return math.log10(1.0 / (self.total_unigrams + 1))
ngram = tuple(context[-(n - 1):]) + (token,)
ctx = tuple(context[-(n - 1):])
nc = self.counts[n].get(ngram, 0)
cc = self.counts[n - 1].get(ctx, 0)
if nc > 0 and cc > 0:
return math.log10(nc / cc)
return math.log10(1.0 / (self.total_unigrams + 1))
def score_sequence(self, tokens: list[str]) -> float:
\"\"\"Score a full token sequence. Returns sum of log10 probs.\"\"\"
context = ["<s>"]
total = 0.0
for t in tokens:
total += self.score(context, t)
context.append(t)
return total
Scoring a token sequence
lm = NgramLM("sinhala_5gram.json.gz")
# Tokens are string representations of sinlib token IDs
tokens = ["166", "96", "433", "28"]
log_prob = lm.score_sequence(tokens)
print(f"Sequence log10-prob: {log_prob:.4f}")
# Score next token given context
context = ["<s>", "166", "96"]
next_token_score = lm.score(context, "433")
print(f"P(433 | context): {10**next_token_score:.6f}")
Tokenizing text with sinlib
from sinlib import Tokenizer
tokenizer = Tokenizer.from_pretrained("Ransaka/sinlib")
encoding = tokenizer("සිංහල වාක්\u200dය", add_bos_token=False, truncate_and_pad=False)
token_ids = [str(tid) for tid in encoding.input_ids]
score = lm.score_sequence(token_ids)
Training Details
- Tokenizer: sinlib phonological subword tokenizer
- Scoring: Stupid Backoff (Brants et al., 2007)
- Implementation: Python
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support