15
stars
7
commits
3
repos using this model
1
linked in READMEs
Aug 9, 2026
updated
Use frontier models without giving up your data.
rizzo-pii-0.3B is a lightweight, CPU-friendly, Italian-first token-classification model
(≈0.3B parameters, mmBERT / ModernBERT backbone)
that detects 22 categories of personal data — including the Italian legal identifiers
(codice fiscale, partita IVA, dati catastali) that no other open model covers — to
drive a fully reversible anonymization workflow:
your document → [FULLNAME_1], [IBAN_1], [CF_1] … + local dictionary → closed LLM API → reconstruction
The sensitive values never leave your machine. Only the placeholders go to the API; the local dictionary rebuilds the original from the model's answer. Built for law firms and GDPR compliance.
| 🇮🇹 Italian-first | trained multilingually (8 languages from Ai4Privacy) |
| 🧾 5 IT-legal tags | CF, PIVA, CATASTO, DOCID, PROVINCE — missing from every other PII model |
| 💻 Runs on CPU | ~0.5 GB RAM, no GPU, no API key |
| 🔁 Reversible | designed for anonymize → call LLM → de-anonymize |
| 📦 8192-token context | native (ModernBERT architecture) |
from transformers import pipeline
nlp = pipeline(
"token-classification",
model="rizzoaiacademy/rizzo-pii-0.3B",
aggregation_strategy="simple", # merges B-/I- subwords into whole entities
)
text = ("Mi chiamo Mario Rossi, codice fiscale RSSMRA85M01H501Z, "
"IBAN IT60X0542811101000000123456, email mario.rossi@gmail.com.")
for ent in nlp(text):
print(f"{ent['entity_group']:<14} {ent['word']!r} ({ent['score']:.2f})")
# FULLNAME 'Mario Rossi' (1.00)
# CF 'RSSMRA85M01H501Z' (1.00)
# IBAN 'IT60X0542811101000000123456' (1.00)
# EMAIL 'mario.rossi@gmail.com' (1.00)
def anonymize(text, ents):
"""Replace each entity with a numbered placeholder; keep a reversible dictionary."""
mapping, out, counters = {}, text, {}
for e in sorted(ents, key=lambda x: x["start"], reverse=True):
g = e["entity_group"]
counters[g] = counters.get(g, 0) + 1
tag = f"[{g}_{counters[g]}]"
mapping[tag] = text[e["start"]:e["end"]]
out = out[:e["start"]] + tag + out[e["end"]:]
return out, mapping
anon, table = anonymize(text, nlp(text))
# anon -> "Mi chiamo [FULLNAME_1], codice fiscale [CF_1], IBAN [IBAN_1], email [EMAIL_1]."
# table -> {"[CF_1]": "RSSMRA85M01H501Z", ...} # stays local; use it to rebuild the LLM reply
💡 Production tip: always pair the model with a regex + checksum safety net for structured fields (EMAIL / TELEPHONE / IBAN / CF / PIVA / credit-card / amount / plate). IBAN, CF, PIVA and card numbers are mathematically verifiable — let the checksum override the model when they disagree. This is exactly what the rizzo-pii desktop app does.
| Group | Tags |
|---|---|
| People | FULLNAME, GENDER, AGE |
| Contact | EMAIL, TELEPHONENUM |
| Location | STREET, BUILDINGNUM, CITY, ZIPCODE, PROVINCE |
| Financial | IBAN, CREDITCARDNUMBER, AMOUNT |
| IT-legal identifiers 🇮🇹 | CF (codice fiscale), PIVA (partita IVA), CATASTO (dati catastali), DOCID, ID_DOC |
| Other | ORG, DATE, TIME, TARGA (plate) |
Labels use the BIO scheme → 44 label ids (B-/I- per tag + O).
Full taxonomy and merge rules in the project docs.
Entity-level metrics on a held-out Italian validation set (7,000 real sentences; the 5 IT-legal tags injected into held-out real text — real context, no leakage):
| Metric | Train (eval subset) | Validation (IT) |
|---|---|---|
| Precision | 0.9981 | 0.9876 |
| Recall | 0.9986 | 0.9900 |
| micro-F1 | 0.9984 | 0.9888 |
| Token accuracy | 0.9997 | 0.9985 |
Validation is Italian-only by design (the real use case is the IT legal domain). The training is multilingual, but the other 7 languages are not validated here.
jhu-clsp/mmBERT-base
(multilingual encoder, ModernBERT architecture, native 8192 context). Chosen over vanilla
ModernBERT because the latter is almost English-only.max_len=768, effective batch 32, dynamic padding, group_by_length.Synthetic data is generated by letting an LLM write only the prose with placeholders, while code injects the values. This gives exact BIO labels, mathematically valid checksums (CF/PIVA/IBAN), and guarantees no real PII is ever produced by the LLM.
CATASTO, PROVINCE) —
mitigated with 72 templates, real-text augmentation, and DeepMount real context.FULLNAME ≫ CREDITCARDNUMBER (~66×), so rare tags are noisier.MIT © 2026 Simone Rizzo — Rizzo AI Academy
@software{rizzo_pii_2026,
author = {Simone Rizzo},
title = {rizzo-pii: local reversible PII anonymization for Italian legal text},
year = {2026},
url = {https://huggingface.co/rizzoaiacademy/rizzo-pii-0.3B},
note = {mmBERT/ModernBERT token classification, 22 PII categories}
}
7 commits
15
stars
7
commits
3
repos using this model
1
linked in READMEs
Aug 9, 2026
updated
Use frontier models without giving up your data.
rizzo-pii-0.3B is a lightweight, CPU-friendly, Italian-first token-classification model
(≈0.3B parameters, mmBERT / ModernBERT backbone)
that detects 22 categories of personal data — including the Italian legal identifiers
(codice fiscale, partita IVA, dati catastali) that no other open model covers — to
drive a fully reversible anonymization workflow:
your document → [FULLNAME_1], [IBAN_1], [CF_1] … + local dictionary → closed LLM API → reconstruction
The sensitive values never leave your machine. Only the placeholders go to the API; the local dictionary rebuilds the original from the model's answer. Built for law firms and GDPR compliance.
| 🇮🇹 Italian-first | trained multilingually (8 languages from Ai4Privacy) |
| 🧾 5 IT-legal tags | CF, PIVA, CATASTO, DOCID, PROVINCE — missing from every other PII model |
| 💻 Runs on CPU | ~0.5 GB RAM, no GPU, no API key |
| 🔁 Reversible | designed for anonymize → call LLM → de-anonymize |
| 📦 8192-token context | native (ModernBERT architecture) |
from transformers import pipeline
nlp = pipeline(
"token-classification",
model="rizzoaiacademy/rizzo-pii-0.3B",
aggregation_strategy="simple", # merges B-/I- subwords into whole entities
)
text = ("Mi chiamo Mario Rossi, codice fiscale RSSMRA85M01H501Z, "
"IBAN IT60X0542811101000000123456, email mario.rossi@gmail.com.")
for ent in nlp(text):
print(f"{ent['entity_group']:<14} {ent['word']!r} ({ent['score']:.2f})")
# FULLNAME 'Mario Rossi' (1.00)
# CF 'RSSMRA85M01H501Z' (1.00)
# IBAN 'IT60X0542811101000000123456' (1.00)
# EMAIL 'mario.rossi@gmail.com' (1.00)
def anonymize(text, ents):
"""Replace each entity with a numbered placeholder; keep a reversible dictionary."""
mapping, out, counters = {}, text, {}
for e in sorted(ents, key=lambda x: x["start"], reverse=True):
g = e["entity_group"]
counters[g] = counters.get(g, 0) + 1
tag = f"[{g}_{counters[g]}]"
mapping[tag] = text[e["start"]:e["end"]]
out = out[:e["start"]] + tag + out[e["end"]:]
return out, mapping
anon, table = anonymize(text, nlp(text))
# anon -> "Mi chiamo [FULLNAME_1], codice fiscale [CF_1], IBAN [IBAN_1], email [EMAIL_1]."
# table -> {"[CF_1]": "RSSMRA85M01H501Z", ...} # stays local; use it to rebuild the LLM reply
💡 Production tip: always pair the model with a regex + checksum safety net for structured fields (EMAIL / TELEPHONE / IBAN / CF / PIVA / credit-card / amount / plate). IBAN, CF, PIVA and card numbers are mathematically verifiable — let the checksum override the model when they disagree. This is exactly what the rizzo-pii desktop app does.
| Group | Tags |
|---|---|
| People | FULLNAME, GENDER, AGE |
| Contact | EMAIL, TELEPHONENUM |
| Location | STREET, BUILDINGNUM, CITY, ZIPCODE, PROVINCE |
| Financial | IBAN, CREDITCARDNUMBER, AMOUNT |
| IT-legal identifiers 🇮🇹 | CF (codice fiscale), PIVA (partita IVA), CATASTO (dati catastali), DOCID, ID_DOC |
| Other | ORG, DATE, TIME, TARGA (plate) |
Labels use the BIO scheme → 44 label ids (B-/I- per tag + O).
Full taxonomy and merge rules in the project docs.
Entity-level metrics on a held-out Italian validation set (7,000 real sentences; the 5 IT-legal tags injected into held-out real text — real context, no leakage):
| Metric | Train (eval subset) | Validation (IT) |
|---|---|---|
| Precision | 0.9981 | 0.9876 |
| Recall | 0.9986 | 0.9900 |
| micro-F1 | 0.9984 | 0.9888 |
| Token accuracy | 0.9997 | 0.9985 |
Validation is Italian-only by design (the real use case is the IT legal domain). The training is multilingual, but the other 7 languages are not validated here.
jhu-clsp/mmBERT-base
(multilingual encoder, ModernBERT architecture, native 8192 context). Chosen over vanilla
ModernBERT because the latter is almost English-only.max_len=768, effective batch 32, dynamic padding, group_by_length.Synthetic data is generated by letting an LLM write only the prose with placeholders, while code injects the values. This gives exact BIO labels, mathematically valid checksums (CF/PIVA/IBAN), and guarantees no real PII is ever produced by the LLM.
CATASTO, PROVINCE) —
mitigated with 72 templates, real-text augmentation, and DeepMount real context.FULLNAME ≫ CREDITCARDNUMBER (~66×), so rare tags are noisier.MIT © 2026 Simone Rizzo — Rizzo AI Academy
@software{rizzo_pii_2026,
author = {Simone Rizzo},
title = {rizzo-pii: local reversible PII anonymization for Italian legal text},
year = {2026},
url = {https://huggingface.co/rizzoaiacademy/rizzo-pii-0.3B},
note = {mmBERT/ModernBERT token classification, 22 PII categories}
}
7 commits