cbx-pii-extractor-4M
Finds personal information (PII) in English text and returns the exact position of each value with one of 18 labels. 4M parameters (16 MB), about 26 ms per 1,000 tokens on a CPU and 5 ms on a GPU.
This is the smallest and fastest size: 4x smaller than 17M
and about 1.4x faster on CPU, for 4-9 points less accuracy (most of it on names in chat messages). Use 17M when
accuracy matters more than speed and size. Current version: v0.2 (use --revision v0.2 to pin it). Also
available in 17M,
32M and
68M sizes.
How it was made
- Smaller version of cbx-pii-extractor-17M (v0.2). It keeps 4 of the 17M's 7 layers (layers 0, 2, 4 and 6, so the mix of full and local attention stays the same).
- Vocabulary cut to 16,000 tokens (from 50,368): the ones used most in the training data. Any text can still be read; rarer words are split into smaller pieces. Use the tokenizer in this repo, not Ettin's.
- Compressed word table: each token is stored as 112 numbers and expanded to 256 by a shared matrix.
pii.pyin this repo loads it; plainAutoModelloading does not. - Retrained on the same v0.2 data, learning from both the labels and the predictions of cbx-pii-extractor-68M (knowledge distillation).
Labels
| Label | Covers |
|---|---|
| PERSON | Names, including first names only, initials, nicknames and lowercase names |
| DATE_OF_BIRTH | Dates of birth only (other dates are not labelled) |
| Email addresses | |
| PHONE | Phone and fax numbers, including extensions |
| ADDRESS | Full street addresses, with unit, city and postcode (a city or country on its own is not labelled) |
| BANK_ACCOUNT | Bank account numbers and IBANs |
| PAYMENT_CARD | Card numbers, including the last four digits |
| CUSTOMER_ID | Customer, member and policy numbers, and account references (not ticket or order numbers) |
| NATIONAL_ID | Social security and national ID numbers |
| PASSPORT | Passport numbers |
| TAX_ID | Tax IDs |
| DRIVERS_LICENSE | Driving licence numbers |
| USERNAME | Usernames and handles; @ mentions include the @, and Slack mentions include <@ and > |
| URL | Web addresses, with or without https:// |
| IP_ADDRESS | IPv4 and IPv6 addresses |
| SECRET | Passwords, PINs, verification and access codes, API keys and tokens |
| EMPLOYEE_ID | Employee and staff IDs |
| PATIENT_ID | Patient IDs and medical record numbers |
How to use
1. Download and install
pip install -U huggingface_hub
hf download CobuildX-AI/cbx-pii-extractor-4M --revision v0.2 --local-dir cbx-pii-extractor-4M
cd cbx-pii-extractor-4M
pip install -r requirements.txt
2. Use it in your code
PIIExtractor (in pii.py, part of this repo) loads the model once:
from pii import PIIExtractor
pii = PIIExtractor() # uses a GPU if one is available
pii.extract("Hi team, I'm Priya Raman (priya.raman@northwind.com).")
# [{'label': 'PERSON', 'text': 'Priya Raman', 'start': 13, 'end': 24},
# {'label': 'EMAIL', 'text': 'priya.raman@northwind.com', 'start': 26, 'end': 51}]
pii.redact("Hi team, I'm Priya Raman (priya.raman@northwind.com).")
# "Hi team, I'm [PERSON] ([EMAIL])."
pii.extract(text, labels=["PERSON", "EMAIL"]) # keep only some labels
- The model finds the PII.
redact()replaces each value it found with its label, or with your owntemplate. - Context length is 7,999 tokens, read in a single pass. Longer texts are split automatically.
3. Optional: check your setup
python example.py runs four sample texts and prints what it finds.
4. Optional: ONNX Runtime
onnx/model.onnx runs the same model with ONNX Runtime (1.23 or later) and gives the same results. On CPU it is
faster for short texts (2.4 ms against 3.8 ms for 128 tokens, 8 threads) and about the same for 1,000 tokens.
python onnx_example.py shows how to use it with PIIExtractor. It uses ONNX Runtime's fused attention operator
(com.microsoft.MultiHeadAttention), so other ONNX runtimes may not load it.
Results
Exact-match span F1 on three public benchmarks never used for training. A value counts only if its start, end and label are all correct.
| Model | Size | Privacy-Bench docs | Privacy-Bench messages | PII-TRACE | GPU, 1,000 tokens | CPU, 1,000 tokens |
|---|---|---|---|---|---|---|
| cbx-pii-extractor-68M | 68M | 88.1% | 91.7% | 93.2% | 13 ms | 229 ms |
| cbx-pii-extractor-32M | 32M | 88.0% | 87.0% | 93.5% | 8 ms | 78 ms |
| cbx-pii-extractor-17M | 17M | 86.1% | 83.1% | 91.6% | 6 ms | 37 ms |
| cbx-pii-extractor-4M | 4M | 82.0% | 74.3% | 87.7% | 5 ms | 26 ms |
| PII-Tracer | 596M | 86.9% | 82.0% | 92.5% | 160 ms | β |
| GLiNER2-PII | 205M | 80.8% | 86.9% | 66.2% | 91 ms | β |
| Presidio (spaCy lg) | β | 82.4% | 85.8% | 64.7% | β | 85 ms |
- Privacy-Bench docs: 656 human-annotated pages of business documents.
- Privacy-Bench messages: 5,198 chat messages.
- PII-TRACE: 500 conversations. It is PII-Tracer's own benchmark. Most of our remaining gap there is dates other than dates of birth, which we deliberately don't label. Without dates, this model scores 92.1% against 91.9% for PII-Tracer.
On text with no PII at all, this model flags 0.08 false values per 1,000 characters, against 1.6β3.6 for the other models.
How we evaluated
Same runs for every model. We ran every model ourselves, on the same texts, with the same scoring.
Benchmark sizes:
Benchmark Contents Annotated values in the scored types Privacy-Bench docs 656 pages of Word and PDF business documents 8,700 Privacy-Bench messages 5,198 chat messages 6,594 PII-TRACE 500 multi-turn conversations (public subset) 2,442 No overlap with training data. No training text shares a 13-word sequence with any benchmark.
How the benchmarks were used. Half of each benchmark was used to study errors while we designed the training data. Scores on the other half are within 0.8 points of the full-set numbers above.
A prediction counts as correct only when its start, end and type all match the annotation. Each benchmark's types were mapped to ours as below. Every model was scored on the types that both the benchmark and the model support.
| CBX PII Extractor | Privacy-Bench | PII-TRACE |
|---|---|---|
| PERSON | NAME_GIVEN + NAME_FAMILY (one name) | private_person |
| EMAIL_ADDRESS | private_email | |
| PHONE | PHONE_NUMBER | private_phone |
| ADDRESS | LOCATION_ADDRESS | private_address |
| URL | URL | private_url |
| BANK_ACCOUNT, PAYMENT_CARD, CUSTOMER_ID | ACCOUNT_NUMBER | account_number |
| USERNAME | USERNAME | Not annotated |
| EMPLOYEE_ID | EMPLOYEE_ID | Not annotated |
| DATE_OF_BIRTH | Not annotated | private_date |
| SECRET | Not annotated | secret |
Government IDs, IP addresses and patient IDs are not annotated in either benchmark, so this evaluation does not cover them.
Speed. Latency is the median over 50 texts of 1,000 tokens, processed one at a time, end to end (text in, spans out). It was measured on an NVIDIA TITAN RTX GPU (fp16) and an Intel i7-10700 CPU (8 threads), with all models on the same machine. ONNX timings use the same CPU.
Limitations
- English only.
- Less accurate than the larger sizes, most of all on names in casual chat. On chat messages without PII it raises about twice as many false alarms as 17M.
- Sensitive attributes such as health, religion or ethnicity are not detected.
- Account and reference numbers inside long documents, and usernames in documents, are found less reliably than names, emails and phones.
- Addresses are always labelled in full. Benchmarks that mark only the street will count them as boundary errors.
- A detection aid, not a guarantee: keep human review where redaction must be complete.
Training data
The same data as cbx-pii-extractor-17M v0.2:
| Dataset | Licence |
|---|---|
| NVIDIA Nemotron-PII | CC-BY-4.0 |
| Gretel PII masking EN v1 | Apache-2.0 |
| Gretel synthetic PII finance | Apache-2.0 |
| Wismut nym-pii | MIT |
| Kiji PII training data | Apache-2.0 |
| Data we generated | β |
Licence
Apache-2.0. Made from cbx-pii-extractor-17M (base model Ettin, MIT, arXiv:2507.11412), with cbx-pii-extractor-68M as teacher.
- Downloads last month
- 1
Model tree for CobuildX-AI/cbx-pii-extractor-4M
Base model
jhu-clsp/ettin-encoder-17m