Multilingual Toxicity Classifier (XLM-RoBERTa-base V5)

Binary toxicity classifier for Turkish, Arabic, and English text, built on XLM-RoBERTa-base. V5 focuses on real-world chat robustness: Arabic dialects, Arabizi / Franco-Arabic, obfuscation (diacritics, tatweel, elongation, homoglyphs), implicit toxicity, and reduced false positives on dialectal greetings and negation / counter-speech.

Author

Model Details

Property Value
Base Model xlm-roberta-base (280M params)
Task Binary text classification (not-toxic / toxic)
Languages Turkish, Arabic (MSA + dialects), English
Labels 0 = not-toxic, 1 = toxic
Training Focal loss (γ=2) + inverse class weights, bf16, cosine schedule, text normalization

Performance

Metric Score
Validation F1 0.907
Validation Accuracy 0.906

On an internal hard adversarial "frontier" set (dialects, Arabizi, obfuscation, implicit, negation), V5 scores 88% vs 38% for V4 and 41% for V3 — while preserving V4's explicit-toxicity and Arabizi gains.

⚠️ Important: apply the same text normalization at inference

V5 was trained on normalized text (strip Arabic diacritics/tatweel, unify alef/ya, collapse character elongation). You must apply the same normalization before tokenizing, or robustness to diacritics/obfuscation degrades. The text_normalize.py used for training is included in this repo.

import re, unicodedata, torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification

_HARAKAT = re.compile("[ؐ-ًؚ-ٰٟۖ-ۜ۟-۪ۨ-ۭـ]")  # diacritics + tatweel
_ALEF = re.compile("[آأإٱ]")
def normalize_text(t):
    t = unicodedata.normalize("NFKC", t)
    t = _HARAKAT.sub("", t)
    t = _ALEF.sub("ا", t)
    t = t.replace("ى", "ي").replace("ؤ", "و").replace("ئ", "ي")
    t = re.sub(r"(.)\1{2,}", r"\1\1", t)  # collapse 3+ repeats
    return re.sub(r"\s+", " ", t).strip()

name = "gorkem371/toxicity-classifier-xlmr-base-v5"
tok = AutoTokenizer.from_pretrained(name)
model = AutoModelForSequenceClassification.from_pretrained(name).eval()

def classify(text):
    text = normalize_text(text)
    inputs = tok(text, return_tensors="pt", truncation=True, max_length=256)
    with torch.no_grad():
        probs = torch.softmax(model(**inputs).logits, dim=-1)[0]
    label = model.config.id2label[int(probs.argmax())]
    return label, float(probs.max())

print(classify("يا كلب اخرس"))          # ('toxic', ...)
print(classify("this is fucking awesome"))  # ('not-toxic', ...)  (profanity-as-emphasis)
print(classify("lan naber nasılsın"))    # ('not-toxic', ...)

What V5 handles well

  • Arabic dialects: MSA, Egyptian, Levantine, Gulf, Iraqi, Maghrebi, Sudanese, Libyan (toxic + clean greetings)
  • Arabizi / Franco-Arabic (Latin+numbers) in both directions
  • Obfuscation: diacritics (tashkeel), tatweel, character elongation, homoglyphs, dotted/spaced letters, emoji
  • Negation / counter-speech and profanity-as-positive-emphasis (fewer false positives)
  • Self-deprecation and casual interjections (e.g. Turkish "lan")

Known limitations

  • Veiled / polite threats with no explicit words ("I know where you live")
  • Sarcasm / irony where the surface is positive
  • Coded bias / dog-whistles
  • Some benign homographs (e.g. talking about a pet dog/pig can occasionally false-positive)
  • Turkish negation ("X is not stupid") can still false-positive
  • In-group / reclaimed slurs are flagged (a policy gray area)

Training approach

Base data (~100K balanced samples across TR/AR/EN from public datasets) plus iteratively hand-crafted targeted sets that close specific failure modes found by adversarial testing (Arabizi, "يا [insult]" vocative, implicit toxicity, dialect greetings, negation, homographs). Targeted samples are repeated 10× and merged onto the base; all text is normalized at train and inference time.

License

Apache 2.0

Downloads last month
82
Safetensors
Model size
0.3B params
Tensor type
F32
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for gorkem371/toxicity-classifier-xlmr-base-v5

Finetuned
(4121)
this model