Token Classification
Transformers
Safetensors
Malay
Brunei
xlm-roberta
brunei-malay
standard-malay
text-normalization
constrained-editing
Instructions to use ssh2025/brunei-malay-normalizer-v3 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use ssh2025/brunei-malay-normalizer-v3 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("token-classification", model="ssh2025/brunei-malay-normalizer-v3")# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForTokenClassification tokenizer = AutoTokenizer.from_pretrained("ssh2025/brunei-malay-normalizer-v3") model = AutoModelForTokenClassification.from_pretrained("ssh2025/brunei-malay-normalizer-v3", device_map="auto") - Notebooks
- Google Colab
- Kaggle
File size: 4,900 Bytes
a804a2f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | """Hash-verified inference runtime for the public V3 artifact."""
from __future__ import annotations
import hashlib
import json
from pathlib import Path
import threading
from .edit_policy_v3 import inference_policy
from .edit_tags_v3 import render_tag_predictions, tokens
class InputError(ValueError):
"""A safe, user-correctable inference request error."""
def _digest(path: Path) -> str:
value = hashlib.sha256()
with path.open("rb") as stream:
for block in iter(lambda: stream.read(8 * 1024 * 1024), b""):
value.update(block)
return value.hexdigest()
class V3Runtime:
def __init__(self, root: Path, device: str = "cuda:0"):
import torch
from transformers import AutoModelForTokenClassification, AutoTokenizer
root = root.resolve()
manifest = json.loads((root / "release-manifest.json").read_text())
if manifest.get("product_version") != 3 or manifest.get("system_prompt") is not None:
raise RuntimeError("V3 release identity mismatch")
for name, expected in manifest["model_files"].items():
path = root / name
if path.stat().st_size != expected["bytes"] or _digest(path) != expected["sha256"]:
raise RuntimeError(f"V3 model artifact mismatch: {name}")
for name in ("labels.json", "candidate-index.json"):
expected = manifest["runtime_files"][name]
path = root / name
if path.stat().st_size != expected["bytes"] or _digest(path) != expected["sha256"]:
raise RuntimeError(f"V3 runtime artifact mismatch: {name}")
policy_expected = manifest["runtime_files"]["edit_policy_v3.py"]["sha256"]
if _digest(Path(__file__).with_name("edit_policy_v3.py")) != policy_expected:
raise RuntimeError("V3 deployed policy differs from release")
if not torch.cuda.is_available() or not device.startswith("cuda:"):
raise RuntimeError("A CUDA GPU is required for this release")
self.labels = json.loads((root / "labels.json").read_text())
raw_index = json.loads((root / "candidate-index.json").read_text())
self.index = {
first: [(tuple(key), int(label_id)) for key, label_id in values]
for first, values in raw_index.items()
}
self.threshold = float(manifest["selected_threshold"])
self.torch = torch
self.device = device
self.tokenizer = AutoTokenizer.from_pretrained(root, local_files_only=True)
self.model = AutoModelForTokenClassification.from_pretrained(
root, local_files_only=True, torch_dtype=torch.float16,
).to(device).eval()
self.lock = threading.Lock()
self.gpu = f"{device} {torch.cuda.get_device_name(int(device.rsplit(':', 1)[1]))}"
def run(self, text: str) -> dict:
source_tokens = tokens(text)
if not source_tokens:
return {"output": text, "route": "exact_copy", "status": "identity",
"usage": {"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0}}
words = [str(token["text"]) for token in source_tokens]
encoded = self.tokenizer(
words, is_split_into_words=True, return_tensors="pt", truncation=False,
)
if encoded.input_ids.shape[1] > 256:
raise InputError("Input exceeds the verified 256-token budget; nothing was truncated.")
encoded = encoded.to(self.device)
allowed, forced = inference_policy(text, self.index, self.labels)
selected = [self.labels[0]] * len(words)
with self.lock, self.torch.inference_mode():
logits = self.model(**encoded).logits[0]
seen = set()
for token_index, word_id in enumerate(encoded.word_ids()):
if word_id is None or word_id in seen:
continue
seen.add(word_id)
ids = sorted(allowed[word_id])
probabilities = logits[token_index, ids].softmax(-1)
confidence, local_index = probabilities.max(-1)
chosen = forced[word_id] if forced[word_id] is not None else ids[int(local_index)]
if forced[word_id] is None and chosen != 0 and float(confidence) < self.threshold:
chosen = 0
selected[word_id] = chosen if isinstance(chosen, dict) else self.labels[chosen]
output = render_tag_predictions(text, selected)
count = int(encoded.input_ids.shape[1])
return {
"output": output,
"route": "source_conditioned_edit_tagger",
"status": "normalized" if output != text else "identity",
"product_version": 3,
"guard_scope": "licensed source edits plus deterministic semantic and immutable-span policy",
"usage": {"prompt_tokens": count, "completion_tokens": 0, "total_tokens": count},
}
|