--- language: pl license: cc-by-4.0 tags: - token-classification - ner - pii - polish - onnx - bert base_model: pczarnik/herbert-base-ner datasets: - clarin-pl/kpwr-ner --- # HerBERT NER — Polish PII (ONNX) Fine-tuned [`pczarnik/herbert-base-ner`](https://huggingface.co/pczarnik/herbert-base-ner) for detecting personal data (PII) in Polish text. Detects: **PERSON**, **ADDRESS** (including full address with city, e.g. *ul. Lipowej 7 w Krakowie*). Intended use: Polish web forms — browser-side inference via [`@xenova/transformers`](https://github.com/xenova/transformers.js) + ONNX Runtime Web (WASM), no backend required. ## Training data 4 813 training samples (train/dev/test split): - **KPWr filtered** (3 113 samples) — [clarin-pl/kpwr-ner](https://huggingface.co/datasets/clarin-pl/kpwr-ner) Polish press corpus; LOC-only (geographic) and schematic form-label samples removed. - **LLM-synthetic** (1 700 train samples) — generated with GPT-4o-mini and claude-haiku-4-5, covering ADDRESS with city suffix (*w Mieście*), PERSON in email context, and mixed cases. Fine-tuned for 8 epochs with early stopping (patience=3), best checkpoint selected by **eval F1** (seqeval, micro-averaged over B-PER/I-PER/B-LOC/I-LOC). ## Evaluation (`kpwr_final_test.json`, 615 samples, character-level IoU >= 0.5) | Label | F1 | Prec | Recall | TP | FP | FN | |---------|------:|------:|-------:|-----:|-----:|-----:| | PERSON | 0.922 | 0.885 | 0.962 | 425 | 55 | 17 | | ADDRESS | 0.944 | 0.903 | 0.990 | 102 | 11 | 1 | ADDRESS recall 0.990 — the model captures full addresses including city names. ## Label mapping The model outputs 5 BIO classes: | Model label | Meaning for this use case | |-------------|--------------------------| | `B-PER` / `I-PER` | PERSON | | `B-LOC` / `I-LOC` | ADDRESS | | `O` | not PII | ## Files | File | Format | Notes | |------|--------|-------| | `model.onnx` | FP32 | highest quality | | `model_quantized.onnx` | INT8 | **recommended for browser** | | `onnx/model_quantized.onnx` | INT8 | alias for Transformers.js `dtype:"q8"` | | `config.json` | JSON | label mapping, model config | | `tokenizer.json` | JSON | HerBERT tokenizer | ## Usage ### Python (Transformers) ```python from transformers import pipeline ner = pipeline( "token-classification", model="ArkadiuszPawlak/pczarnik-herbert-ner-polish-pii", aggregation_strategy="simple", ) result = ner("Jan Kowalski mieszka przy ul. Marszałkowskiej 1, 00-001 Warszawa.") # [{"entity_group": "PER", "word": "Jan Kowalski", ...}, # {"entity_group": "LOC", "word": "ul. Marszałkowskiej 1, 00-001 Warszawa", ...}] ``` ### Browser (@xenova/transformers + ONNX Runtime Web) ```js import { pipeline } from "@xenova/transformers"; const ner = await pipeline( "token-classification", "ArkadiuszPawlak/pczarnik-herbert-ner-polish-pii", { aggregation_strategy: "simple" } ); const LABEL_MAP = { PER: "PERSON", LOC: "ADDRESS" }; const raw = await ner("Jan Kowalski mieszka przy ul. Marszałkowskiej 1 w Krakowie."); const entities = raw .filter(e => e.entity_group in LABEL_MAP) .map(e => ({ label: LABEL_MAP[e.entity_group], text: e.word, score: e.score })); console.log(entities); // [{ label: "PERSON", text: "Jan Kowalski", score: 0.99 }, // { label: "ADDRESS", text: "ul. Marszałkowskiej 1 w Krakowie", score: 0.97 }] ```