Turkish KVKK classifier
turkish-kvkk-classifier is a multi-label model that tells you which kinds of personal data a Turkish text contains. It covers 24 categories: the 14 used in VERBİS, Turkey’s data controller registry, and the 10 special categories in Article 6 of KVKK, the Turkish data protection law. It takes about 22 ms per text on a desktop CPU.
- Size
- 110M parameters
- Base model
dbmdz/bert-base-turkish-cased(BERTurk)- Labels
- 24, multi-label
- Result
- 0.874 micro-F1 on 987 held-out texts
- CPU speed
- about 22 ms per text
- Licence
- MIT
What it does
- Input
hastanın böbrek yetmezliği ilerlemiş, eşi 0532 111 22 33'ten ulaşılabilir- Output
kimlik,iletisim,saglik(special category: yes)
- Input
böbrek yetmezliği farkındalık haftası başladı- Output
- no label
A category is marked only when the text holds that kind of information about a specific person, even an unnamed one such as “the patient” or “the customer”. General information, rules, announcements and statistics get no label. In the first example a patient’s kidney failure is health data. In the second, an awareness week for kidney failure is not about anyone.
The classifier is meant to sit in front of the masking model: classify the text, pick a masking policy, then mask.
Labels
| Label | Covers | F1 |
|---|---|---|
| General categories (VERBİS) | ||
kimlik |
full name, national ID number (TCKN), birth details, age, gender, nationality, marital status, ID document numbers, signature | 0.97 |
iletisim |
phone, email, postal address | 0.97 |
lokasyon |
the person’s location, where they are or are going, route | 0.74 |
ozluk |
an employee’s personnel record: service record, payroll, leave, discipline, social security (SGK) declaration | 0.84 |
hukuki_islem |
lawsuit, debt enforcement, seizure, official notification, power of attorney, formal notice, mediation | 0.89 |
musteri_islem |
order, invoice, subscription, request or complaint, policy or contract transaction | 0.75 |
fiziksel_mekan_guvenligi |
building entry and exit, turnstile, visitor log, security camera | 0.83 |
islem_guvenligi |
IP address, log, device ID, username, password or PIN, session record | 0.83 |
risk_yonetimi |
credit score, risk score, suspicious transaction, blacklist, MASAK (Turkey’s financial crimes investigation board) | 0.82 |
finans |
account, IBAN, card, balance, debt, income or salary, tax number, crypto | 0.85 |
mesleki_deneyim |
workplace, profession, position, diploma, certificate, reference | 0.80 |
pazarlama |
shopping habits, preferences, contact consent, survey answers, cookie or segment data | 0.83 |
gorsel_isitsel |
the person’s photo, voice recording, video, call recording | 0.79 |
arac |
licence plate, chassis number, engine number, registration document | 0.96 |
| Special categories (KVKK Article 6) | ||
saglik |
illness, diagnosis, treatment, medication, disability, blood type, pregnancy | 0.92 |
biyometrik |
fingerprint, face recognition, iris or retina, voiceprint | 0.88 |
genetik |
genetic test, DNA, carrier status | 0.79 |
cinsel_hayat |
sexual orientation, information about sexual life | 0.86 |
ceza_mahkumiyeti |
past offences, criminal record, conviction, security measure | 0.84 |
din_felsefi_inanc |
religion, sect, belief, religious practice | 0.93 |
siyasi_dusunce |
party membership or preference, political opinion, taking part in a protest | 0.85 |
irk_etnik |
race, ethnic origin | 0.82 |
dernek_vakif_sendika |
membership of an association, foundation or trade union | 0.89 |
kilik_kiyafet |
headscarf, choice of religious or cultural dress | 0.91 |
Results
There are two test sets. The main one is an independent held-out set: 1,125 texts written without looking at the training data, then labelled a second time, blind. The 987 texts where both label sets agree exactly are the gold set (87.7% exact agreement, Cohen’s kappa per label between 0.84 and 1.00). The second is a template-disjoint test of 771 examples from 333 templates that were never used in training. On the 987-text gold set, turkish-kvkk-classifier scores 0.874 micro-F1 and 0.856 macro-F1.
| Metric | Held-out 987 texts | Disjoint test 771 examples |
|---|---|---|
| micro-F1 | 0.874 | 0.895 |
| macro-F1 | 0.856 | 0.875 |
| Special category present: precision | 0.960 | 0.955 |
| Special category present: recall | 0.884 | 0.955 |
| Exact match (all labels correct) | 0.717 | 0.733 |
Micro-F1 is F1 computed over all label decisions pooled together. Macro-F1 is the unweighted mean of the per-label F1 scores.
The held-out texts and both label passes were produced with a language model and checked automatically. They were not verified line by line by a person.
Python quick start
import json, torch
from huggingface_hub import hf_hub_download
from transformers import AutoModelForSequenceClassification, AutoTokenizer
MODEL = "halilneed/turkish-kvkk-classifier"
tok = AutoTokenizer.from_pretrained(MODEL)
model = AutoModelForSequenceClassification.from_pretrained(MODEL).eval()
thresholds = json.load(open(hf_hub_download(MODEL, "thresholds.json")))
SPECIAL = {"saglik", "biyometrik", "genetik", "cinsel_hayat", "ceza_mahkumiyeti", "din_felsefi_inanc",
"siyasi_dusunce", "irk_etnik", "dernek_vakif_sendika", "kilik_kiyafet"}
def classify(text):
with torch.inference_mode():
p = torch.sigmoid(model(**tok(text, return_tensors="pt", truncation=True, max_length=320)).logits)[0]
labels = [model.config.id2label[i] for i, v in enumerate(p.tolist()) if v >= thresholds[model.config.id2label[i]]]
return labels, bool(set(labels) & SPECIAL)
print(classify("hastanın böbrek yetmezliği ilerlemiş, eşi 0532 111 22 33'ten ulaşılabilir"))
Per-label thresholds were tuned on the dev set and ship in thresholds.json. For the special categories the threshold never goes above 0.5, which favours recall.
Measured speed: 22 ms per text at batch size one on an Intel i5-12400F with eight threads, for texts of 126 characters on average.
Training
- Base model.
dbmdz/bert-base-turkish-cased(BERTurk, 110M). - Method. Multi-label classification, sigmoid with binary cross-entropy, 5 epochs, learning rate 3e-5, bfloat16, up to 320 tokens.
- Data. 36,000 synthetic examples from 3,276 templates. Most are the masking model’s templates: each PII slot maps to a category by a fixed rule, and each template is also marked for the categories its context adds. The rest are contextual sentences that contain no values. 21% of the examples are traps, texts that should get no label.
- Split. Train, dev and test are separated by template hash.
Limitations
- The training data is synthetic. Measure the model on your own organisation’s text before it goes into a critical pipeline.
- The weakest labels are
lokasyon(F1 0.74),musteri_islem(0.75) andgorsel_isitsel(0.79). All three are inferred from context and have no sharp boundary.genetikalso scores 0.79. - For the question “is there special-category data here?” recall on the held-out set is 0.884, so roughly one such text in nine is missed.
- The output is a category signal, not a legal assessment. The VERBİS inventory and KVKK compliance remain the user’s responsibility.
Türkçe KVKK kategori sınıflandırıcısı
turkish-kvkk-classifier, Türkçe bir metinde hangi kişisel veri kategorilerinin bulunduğunu belirleyen çok etiketli bir sınıflandırıcıdır: 14 VERBİS kategorisi ve KVKK md. 6’daki 10 özel nitelikli veri kategorisi. Maskeleme modelinden önce çalıştırılır: metin önce sınıflandırılır, sonuca göre maskeleme politikası seçilir, ardından metin maskelenir.
Eğitim verisine bakılmadan yazılmış 987 metinlik bağımsız sette micro-F1 0.874, macro-F1 0.856’dır. CPU’da metin başına yaklaşık 22 ms sürer. Çıktı yalnızca bir kategori tahminidir, hukuki nitelendirme değildir.
Links
- Model card and weights
- Evaluation set
- Turkish PII detection and masking
- Turkish BSEBY classifier
- Turkish prompt injection classifier
- Personal data and AI: a short guide for teams on what to mask and what to keep in-house before text reaches a model
- All models