Hebrew Toxicity Detector

A fine-tuned BERT-based model for detecting toxic and offensive text, with a focus on Hebrew social media comments.

Project Context

This model was developed as part of my final Computer Science project.
The goal is to improve automatic detection of harmful, offensive, and toxic comments, especially in Hebrew, where existing toxicity models often perform less accurately.

Model Description

The model is based on a Transformer text-classification architecture and was fine-tuned on a custom dataset of toxic and non-toxic examples.

It is designed to classify short user-generated text such as:

  • YouTube comments
  • Social media posts
  • Informal Hebrew text
  • Offensive slang and insults

Intended Use

This model is used as part of a browser extension that helps reduce direct exposure to harmful comments by blurring content detected as toxic.

Files

  • model.safetensors โ€” fine-tuned model weights (fp32)
  • model.int8.onnx โ€” the same model quantized to INT8 for CPU inference with ONNX Runtime (see INT8 version)
  • config.json โ€” model configuration
  • tokenizer.json โ€” tokenizer file
  • tokenizer_config.json โ€” tokenizer configuration
  • quantize/export_and_quantize.py โ€” the script that produced model.int8.onnx

Usage

from transformers import pipeline

model_path = "BAR-ILAN/hebrew-toxicity-detector-INT8"

classifier = pipeline(
    "text-classification",
    model=model_path,
    tokenizer=model_path
)

result = classifier("ืืชื” ืคืฉื•ื˜ ืžื’ืขื™ืœ")
print(result)

INT8 version

model.int8.onnx is the fp32 model exported to ONNX and quantized with ONNX Runtime dynamic quantization:

  • The weights of every linear layer are INT8, quantized per channel (74 MatMul ops: 72 in the encoder, plus the pooler and the classifier).
  • The word embeddings stay fp32, so the file is 434 MB, compared with 679 MB for the fp32 weights.
  • No calibration data was needed.

Usage

Run one text per call. Dynamic quantization picks one activation scale for the whole input, so in a batch a comment's score depends on the other comments in it and on their padding. In our tests, the same comment scored 0.54 alone and 0.74 or 0.94 inside two different batches. One text per call is also faster on CPU, because no time is spent on padding.

import numpy as np
import onnxruntime as ort
from huggingface_hub import hf_hub_download
from transformers import AutoConfig, AutoTokenizer

model_id = "BAR-ILAN/hebrew-toxicity-detector-INT8"
tokenizer = AutoTokenizer.from_pretrained(model_id)
id2label = AutoConfig.from_pretrained(model_id).id2label
session = ort.InferenceSession(hf_hub_download(model_id, "model.int8.onnx"), providers=["CPUExecutionProvider"])

def classify(text):
    encoded = tokenizer(text, truncation=True, max_length=512, return_tensors="np")
    inputs = {i.name: encoded[i.name].astype(np.int64) for i in session.get_inputs()}
    logits = session.run(None, inputs)[0][0]
    probabilities = np.exp(logits - logits.max()) / np.exp(logits - logits.max()).sum()
    best = int(probabilities.argmax())
    return {"label": id2label[best], "score": float(probabilities[best])}

print(classify("ืืชื” ืคืฉื•ื˜ ืžื’ืขื™ืœ"))

fp32 vs INT8

The two models were evaluated on the same comments:

  • fp32: transformers pipeline, batches of 8
  • INT8: ONNX Runtime, one text per call

Both used the thresholds of the server that runs the model: P(toxic) โ‰ฅ 0.65 for Hebrew and mixed text, and โ‰ฅ 0.85 for English. The times are for a full CPU run on one laptop (Intel Core, 12 threads).

Dataset Model Precision Recall F1 AUC Time
Hebrew: textdetox he split (2,011, 807 toxic) fp32 89.35% 87.36% 88.35% 0.9623 112.5 s
INT8 89.38% 88.60% 88.99% 0.9614 37.3 s
English: textdetox en split (5,000, 2,500 toxic) fp32 99.19% 98.40% 98.80% 0.9976 168.0 s
INT8 98.95% 98.36% 98.66% 0.9977 66.4 s
Team-collected YouTube-style comments (326, 257 toxic) fp32 93.61% 79.77% 86.13% 0.8657 10.5 s
INT8 93.72% 81.32% 87.08% 0.8723 4.2 s

How far each comment's result moved between fp32 and INT8:

Dataset Decisions that flipped Mean change in P(toxic) 99th percentile Max
Hebrew textdetox 21 (1.04%) 0.014 0.22 0.66
English textdetox 11 (0.22%) 0.003 0.06 0.62
YouTube-style comments 8 (2.45%) 0.022 0.25 0.63
  • Accuracy is unchanged. F1 moves by less than 1 point on every set, and AUC by less than 0.001 on the benchmarks.
  • INT8 is 2.5โ€“3ร— faster on CPU.
  • Most flipped decisions sit near a threshold. On Hebrew, 15 of the 21 flips were corrections.
  • English false positives rose from 20 to 26. Most of the new ones are harmless comments that mention an identity group, such as "Some are just great black mothers" and "Salute to every SIKH". The fp32 model already scores these 0.57โ€“0.85, and INT8 pushes them over the 0.85 English threshold.
  • A few single comments move a lot, up to 0.66 in P(toxic). This is rare: 99% of comments move by less than 0.25.

Reproducing the export

pip install torch transformers onnx onnxruntime onnxscript
python quantize/export_and_quantize.py

The script exports the fp32 model to ONNX and quantizes it. It then prints the fp32 vs INT8 scores for a few sample comments and the file sizes. The export uses torch.onnx.export(..., dynamo=True), because the older exporter can't trace the attention-mask code in transformers 5.

Downloads last month
78
Safetensors
Model size
0.2B params
Tensor type
F32
ยท
Inference Providers NEW
This model isn't deployed by any Inference Provider. ๐Ÿ™‹ Ask for provider support