kalyan-ks/ettin-32m-nemotron-pii
1163
ettin-32m-nemotron-pii model
Light Weight PII Detection Model | Open Source | 32M Parameters | 95.73 F1 Score | Blog Post
Overview
Ettin-32m-nemotron-pii is based on the ettin-encoder-32M model and fine-tuned over the Nemotron PII dataset. This model can detect 50+ PII entities in both structured and unstructured texts across various domains like healthcare, finance, legal, cybersecurity etc. With just 32M parameters, the model achieves a strong F1-score of 95.73.
Key Features
- Achieves strong F1-score of 95.73 with just 32M parameters.
- Outperforms popular LLMs like DeepSeek-V4-Flash (84.89) and GPT-4o-Mini (78.69).
- Detects 50+ PII entities in both structured and unstructured texts.
- Handles text in various domains like healthcare, finance, legal etc.
Supported PII Entity Types
This model can detect the following 55 PII entity types
<details> <summary> PII entity types with description </summary>
</details>
Usage
# First install Hugging Face transformers library
!pip install transformers
# Initialize and run the PII detection pipeline to extract PII entities
from transformers import pipeline
## Initialize the PII detection pipeline
ner = pipeline("ner", model="kalyan-ks/ettin-32m-nemotron-pii", aggregation_strategy="simple")
input_text = "Kalyan KS is from India. His email id is kalyan.ks@yahoo.com"
## Run the PII detection to extract PII entities
pii_entities = ner(input_text)
## Process the extracted PII entities
def format_pii_entities(entities, original_text):
if not entities:
return []
merged_entities = []
entities = sorted(entities, key=lambda x: x['start'])
current_entity = {
'start': entities[0]['start'],
'end': entities[0]['end'],
'label': entities[0]['entity_group'],
'text': entities[0]['word']
}
for next_ent in entities[1:]:
is_same_label = next_ent['entity_group'] == current_entity['label']
is_adjacent = next_ent['start'] <= current_entity['end'] + 1
if is_same_label and is_adjacent:
current_entity['end'] = max(current_entity['end'], next_ent['end'])
current_entity['text'] = original_text[current_entity['start']:current_entity['end']]
else:
merged_entities.append(clean_entity(current_entity))
current_entity = {
'start': next_ent['start'],
'end': next_ent['end'],
'label': next_ent['entity_group'],
'text': next_ent['word']
}
merged_entities.append(clean_entity(current_entity))
return merged_entities
def clean_entity(ent):
raw_text = ent['text']
stripped_text = raw_text.strip()
leading_spaces = len(raw_text) - len(raw_text.lstrip())
return {
'start': ent['start'] + leading_spaces,
'end': ent['start'] + leading_spaces + len(stripped_text),
'text': stripped_text,
'label': ent['label']
}
# Display the extracted PII entities
formatted_entities = format_pii_entities(pii_entities, input_text)
print(formatted_entities)
# Output
[{'start': 0, 'end': 9, 'text': 'Kalyan KS', 'label': 'first_name'}, {'start': 18, 'end': 23, 'text': 'India', 'label': 'country'}, {'start': 41, 'end': 60, 'text': 'kalyan.ks@yahoo.com', 'label': 'email'}]Evaluation
This model is evaluated on a 10k sample test set from Neomotron PII dataset and achieved the following results
Top Performing PII Entity Types
Challenging PII Entity Types
Limitations
- Language: This model works well only for English language texts.
- Challenging PII Entity Types: Some of the entity types like
occupationhas low F1 score.
Citation
@misc{ettin-32m-pii-2026,
title = {ettin-32m-nemotron-pii-2026: PII Detection Model},
author = {Kalyan KS},
year = {2026},
publisher = {Hugging Face},
url = {https://huggingface.co/kalyan-ks/ettin-32m-nemotron-pii}
}