Instructions to use e4gl33y3/luganda-pii-dp-v2-eps8 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use e4gl33y3/luganda-pii-dp-v2-eps8 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("token-classification", model="e4gl33y3/luganda-pii-dp-v2-eps8")# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForTokenClassification tokenizer = AutoTokenizer.from_pretrained("e4gl33y3/luganda-pii-dp-v2-eps8") model = AutoModelForTokenClassification.from_pretrained("e4gl33y3/luganda-pii-dp-v2-eps8", device_map="auto") - Notebooks
- Google Colab
- Kaggle
Luganda PII detector trained with differential privacy (ε = 8) — v2
Token-classification model that detects personally identifiable information (PII) in Luganda text: PERSON, USERID (telephone numbers, email addresses, account and ID numbers), LOCATION, DATE, ORG and NORP, in the BILOU scheme.
Developed by Gideon Mpungu for the MSc dissertation Differentially Private Model for PII Detection in Low-Resource Languages (Makerere University, 2026). Code: https://github.com/giddy-mpungu/DP_in_PII_Detection_for_Luganda
Privacy guarantee
This model satisfies (ε, δ) = (7.99, 1e-05)-differential privacy with respect to
each individual sentence of the lg-ner training split (2,085 sentences).
| Mechanism | DP-SGD (Opacus 1.6.0), per-example clipping and Gaussian noise |
| Noise multiplier σ | 1.259 |
| Clipping norm C | 1.0 |
| Sampling | Poisson, rate q = 0.1111 (expected batch 256) |
| Steps | 225 (25 epochs) |
| Accountant | PRV (ε = 7.99, used to calibrate the noise); RDP gives a looser ε = 8.75 |
Before private fine-tuning, the model was trained non-privately on public data only: xlm-roberta-base fine-tuned on the Luganda part of MasakhaNER 2.0 (every sentence sharing an 8-word sequence with any lg-ner sentence removed) plus 3,000 synthetic Luganda PII sentences generated from public name, place, organisation and identifier lists (experiments/synthetic_data.py).
The guarantee therefore covers the lg-ner sentences in full.
Limits of the guarantee: it is per sentence, not per person (a person appearing in k sentences is protected at roughly kε); the learning rate was selected on the validation split without accounting for that selection; and it says nothing about documents the model is applied to: PII that the model misses remains exposed.
Evaluation (lg-ner test split, entity level, exact match)
Micro-F1 0.486 (95% bootstrap CI 0.453–0.516), precision 0.455, recall 0.522, macro-F1 0.486. Membership-inference (loss-threshold) AUC on train vs. test sentences: 0.535 (0.5 = no signal).
| Category | Test mentions | Precision | Recall | F1 |
|---|---|---|---|---|
| PERSON | 412 | 0.413 | 0.510 | 0.456 |
| NORP | 98 | 0.729 | 0.439 | 0.548 |
| DATE | 43 | 0.275 | 0.326 | 0.298 |
| USERID | 22 | 0.514 | 0.818 | 0.632 |
| ORG | 114 | 0.313 | 0.544 | 0.397 |
| LOCATION | 288 | 0.604 | 0.566 | 0.584 |
Results for all privacy levels and seeds are in the dissertation and the code repository. The USERID values in
lg-ner are synthetic (generated in three fixed formats), so the USERID scores above measure those formats, not
identifiers as they occur in real text.
Try it in your browser (nothing you type is uploaded): https://huggingface.co/spaces/e4gl33y3/luganda-pii-dp
Intended use
Assisting human reviewers to find PII in Luganda text before it is shared or analysed. Do not use it as the only safeguard: check the per-category recall above, and combine it with rule-based recognisers for structured identifiers (telephone numbers, NINs, email addresses). Evaluated only on news-style, lower-cased, pre-tokenised text; performance on conversational, SMS or transcribed speech is unknown.
Usage
Labels use the BILOU scheme (B-, I-, L-, U-), which the pipeline's built-in aggregation does not understand, so merge word-level tags into spans yourself:
from transformers import AutoModelForTokenClassification, AutoTokenizer
import torch
tok = AutoTokenizer.from_pretrained("e4gl33y3/luganda-pii-dp-v2-eps8")
model = AutoModelForTokenClassification.from_pretrained("e4gl33y3/luganda-pii-dp-v2-eps8").eval()
def detect_pii(text):
words = text.lower().split() # the training text was lower-cased
enc = tok(words, is_split_into_words=True, return_tensors="pt", truncation=True)
with torch.no_grad():
pred = model(**enc).logits.argmax(-1)[0].tolist()
tags, seen = [], set()
for i, w in enumerate(enc.word_ids()):
if w is not None and w not in seen: # first sub-token of each word
seen.add(w)
tags.append(model.config.id2label[pred[i]])
spans, cur = [], None
for word, tag in zip(words, tags):
prefix, _, typ = tag.partition("-")
if prefix in ("B", "U") or (prefix in ("I", "L") and (cur is None or cur[0] != typ)):
if cur: spans.append(cur)
cur = [typ, [word]]
elif prefix in ("I", "L"):
cur[1].append(word)
else:
if cur: spans.append(cur)
cur = None
if prefix in ("L", "U") and cur:
spans.append(cur); cur = None
if cur: spans.append(cur)
return [(typ, " ".join(ws)) for typ, ws in spans]
print(detect_pii("pulezidenti museveni yasisinkanye abakulembeze b ekibiina kya nrm e kampala ."))
- Downloads last month
- 31
Model tree for e4gl33y3/luganda-pii-dp-v2-eps8
Base model
FacebookAI/xlm-roberta-base