Instructions to use schift-io/schift-ko-pii-v4 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use schift-io/schift-ko-pii-v4 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("token-classification", model="schift-io/schift-ko-pii-v4")# Load model directly from transformers import AutoTokenizer, AutoModelForTokenClassification tokenizer = AutoTokenizer.from_pretrained("schift-io/schift-ko-pii-v4") model = AutoModelForTokenClassification.from_pretrained("schift-io/schift-ko-pii-v4", device_map="auto") - Notebooks
- Google Colab
- Kaggle
schift-ko-pii-v4
111M parameter Korean PII detector that outperforms models 3x its size.
Fine-tuned from klue/roberta-base with LoRA on Korean legal, financial, and administrative texts. Distributed as bf16 safetensors (210 MB).
Benchmark
Two benchmark suites are included in this repository under benchmark/.
benchmark_v1 (93 cases)
Same benchmark, same scoring (50% overlap match), no postprocessing on either side.
| Model | Params | micro F1 | strong F1 | Size |
|---|---|---|---|---|
| schift-ko-pii-v4 | 111M | 0.863 | 0.893 | 210 MB (bf16) |
| LFM2.5-PII-Detector | 350M | 0.663 | 0.645 | ~1.4 GB |
benchmark_v2 (253 cases)
Expanded benchmark with harder cases: investigation reports, complex address formats, foreign/Hanja names, mixed-entity documents.
| Model | Params | raw F1 | raw P | raw R |
|---|---|---|---|---|
| LFM2.5-Encoder-350M-PII | 350M | 0.254 | 0.207 | 0.328 |
| schift-ko-pii-v4 | 111M | 0.702 | 0.602 | 0.842 |
With postprocessing enabled (postprocess=True):
| Benchmark | F1 | P | R |
|---|---|---|---|
| v1 (93 cases) | 0.968 | 0.947 | 0.991 |
| v2 (253 cases) | 0.802 | 0.802 | 0.802 |
Category breakdown (benchmark_v1, raw model)
| Category | schift-ko-pii | LFM2.5-PII |
|---|---|---|
| Person (standard) | 1.00 | 0.67 |
| Person (rare surnames) | 1.00 | 0.60 |
| Person (short names) | 1.00 | 0.57 |
| Phone | 0.86 | 0.92 |
| 1.00 | 0.86 | |
| Address (urban) | 1.00 | 0.67 |
| Address (rural) | 1.00 | 0.60 |
| Vehicle plate | 1.00 | 0.00 |
| Date (Korean) | 1.00 | 0.00 |
| Resident ID | 1.00 | 0.75 |
| Passport | 1.00 | 1.00 |
LFM2.5 is a strong multilingual model, but it was not trained on Korean-specific
formats: vehicle plates (52κ°1234), resident registration numbers
(850205-1234567), Korean date expressions (2024λ
3μ 15μΌ), or rare Korean
surnames (ν©λ³΄, λ¨κΆ, λ
κ³ ).
Quick start
pip install schift-ko-pii
from schift_ko_pii import detect, mask, apply
# Detect PII spans (each entity gets a sequential id)
spans = detect("νΌκ³ κΉλ―Όμμ μ νλ²νΈλ 010-1234-5678μ΄λ€.")
# [
# {"id": "person_1", "start": 3, "end": 6, "label": "private_person", ...},
# {"id": "phone_1", "start": 14, "end": 27, "label": "phone_number", ...},
# ]
# Mask: get masked text + entity map in one call
result = mask("νΌμμ κΉμ² μκ° νΌν΄μ λ°μν¬μκ² μμΈμ κ°λ¨κ΅¬μμ κΈνμ μ λ¬νμλ€.")
print(result["masked"])
# νΌμμ [μ¬λ1]κ° νΌν΄μ [μ¬λ2]μκ² [μ£Όμ1]μμ κΈνμ μ λ¬νμλ€.
for e in result["entities"]:
print(f" {e['id']}: {e['text']}")
# person_1: κΉμ² μ
# person_2: λ°μν¬
# address_1: μμΈμ κ°λ¨κ΅¬
# Apply: replace selected entities (user can edit the map before applying)
text = apply(
"νΌμμ κΉμ² μκ° νΌν΄μ λ°μν¬μκ² μμΈμ κ°λ¨κ΅¬μμ κΈνμ μ λ¬νμλ€.",
result["entities"],
replacements={"person_1": "OOO", "person_2": "β³β³β³"}
# address_1 omitted β left unmasked
)
# νΌμμ OOOκ° νΌν΄μ β³β³β³μκ² μμΈμ κ°λ¨κ΅¬μμ κΈνμ μ λ¬νμλ€.
# With postprocessing (regex validation + structured-ID rules)
spans = detect("μ£Όλ―Όλ²νΈ 850205-1234567μ νμΈ.", postprocess=True)
Postprocessing
The postprocess=True flag applies Korean-specific rules:
- Regex validation for structured IDs (resident numbers, passports, vehicle plates, bank accounts)
- Luhn/checksum verification where applicable
- Context-aware span merging
- False-positive suppression for legal case numbers and statute references
API (free)
For production use without managing model files:
from schift import Schift
client = Schift(api_key="...") # free at schift.io
result = client.pii.redact("κΉλ―Όμμ μ νλ²νΈλ 010-1234-5678μ
λλ€.")
# Postprocessing is always enabled on the API.
Labels
| Label | Description | Examples |
|---|---|---|
private_person |
Person names (Korean, Hanja, foreign) | κΉλ―Όμ, ν©λ³΄μν¬, Lee Jenny |
private_phone |
Phone numbers | 010-1234-5678, 02-1234-5678 |
private_email |
Email addresses | user@example.com |
private_address |
Street/postal addresses | μμΈνΉλ³μ κ°λ¨κ΅¬ ν ν€λλ‘ 521 |
private_date |
Dates | 2024λ 3μ 15μΌ, 2024-03-15 |
private_url |
URLs, SNS links, IP addresses | instagram.com/user, 192.168.1.1 |
account_number |
Structured IDs: resident/business/bank/passport/vehicle | 850205-1234567, M12345678 |
secret |
Secrets, API keys, passwords |
Running benchmarks
# Benchmark this model (v1, 93 cases)
python benchmark/run_benchmark.py
# Benchmark v2 (253 cases)
python benchmark/run_benchmark.py --benchmark benchmark/benchmark_v2.jsonl
# With postprocess
python benchmark/run_benchmark.py --postprocess
# Compare any HuggingFace model
python benchmark/run_benchmark.py --hf-model LiquidAI/LFM2.5-Encoder-350M-PII-Detector
Model details
- Base model:
klue/roberta-base(111M params) - Training: LoRA adapter on ~20k Korean legal/financial/admin examples
- Format: safetensors bf16 (210 MB)
- Inference:
transformerspipeline, CPU or GPU - Max length: 512 tokens
- Tagging scheme: BIES (Begin/Inside/End/Single)
License
Schift License v2.0 β Apache 2.0 base with a revenue threshold. Free for everyone under $10M annual revenue. Research, education, and non-profit use always permitted. Companies above the threshold: contact hello@schift.io.
Citation
@software{schift_ko_pii_2026,
author = {Schift Inc.},
title = {schift-ko-pii: Korean PII Detection Model},
year = {2026},
url = {https://huggingface.co/schift-io/schift-ko-pii-v4},
}
- Downloads last month
- 77
Evaluation results
- F1 (raw, no postprocess) on benchmark_v1 (93 cases)self-reported0.863
- F1 (with postprocess) on benchmark_v1 (93 cases)self-reported0.968
- F1 (raw, no postprocess) on benchmark_v2 (253 cases)self-reported0.702
- F1 (with postprocess) on benchmark_v2 (253 cases)self-reported0.802