| --- |
| language: ru |
| license: apache-2.0 |
| tags: |
| - russian |
| - toxicity |
| - profanity |
| - threat-detection |
| - multi-task |
| - bert |
| - rubert |
| - text-classification |
| datasets: |
| - IvanFed/russian-toxic-comments-multilabel |
| --- |
| |
| # RuBERT Multi-Task Toxicity Classifier |
|
|
| ## Model Description |
|
|
| Эта модель является **Multi-Task классификатором** токсичности на основе легковесного энкодера `cointegrated/rubert-tiny2`. Она обучена одновременно предсказывать три класса токсичности: |
|
|
| 1. **Profanity** (ненормативная лексика) — мат, оскорбления, нецензурная брань |
| 2. **Threat** (угрозы) — явные или скрытые угрозы |
| 3. **Illegal** (запросы на нарушение закона) — запросы о незаконных действиях (в данном датасете отсутствует) |
|
|
| Модель имеет три независимые головы (линейные слоя), каждая из которых выдает логит для своего класса. Вероятности получаются применением сигмоиды. |
|
|
| ## Training Data |
|
|
| Модель обучена на датасете [Russian Toxic Comments Multi-label](https://huggingface.co/datasets/IvanFed/russian-toxic-comments-multilabel), содержащем **248,288** размеченных комментариев из социальной сети ok.ru. |
|
|
| ## Metrics (on Validation Set) |
|
|
| | Class | Threshold | Precision | Recall | F1-Score | |
| |-------|-----------|-----------|--------|----------| |
| | Profanity | 0.45 | 0.8921 | 0.8969 | 0.8945 | |
| | Threat | 0.35 | 0.7654 | 0.7998 | 0.7823 | |
| | Illegal | 0.50 | 0.0000 | 0.0000 | 0.0000 | |
|
|
| *Примечание:* Класс `illegal` отсутствует в датасете, поэтому метрики равны нулю. |
|
|
| ## How to Use |
|
|
| ### 1. Установка зависимостей |
|
|
| ```bash |
| pip install torch transformers huggingface-hub |
| ``` |
|
|
| ### 2. Загрузка модели и токенизатора |
|
|
| ```python |
| import torch |
| from transformers import AutoTokenizer |
| import json |
| |
| tokenizer = AutoTokenizer.from_pretrained("IvanFed/rubert-toxicity-multitask") |
| |
| with open("thresholds.json", "r") as f: |
| thresholds = json.load(f) |
| |
| class MultiTaskToxicityEncoder(torch.nn.Module): |
| def __init__(self, model_name="cointegrated/rubert-tiny2"): |
| super().__init__() |
| from transformers import AutoModel |
| self.encoder = AutoModel.from_pretrained(model_name) |
| self.hidden_size = self.encoder.config.hidden_size |
| self.dropout = torch.nn.Dropout(0.1) |
| self.profanity_head = torch.nn.Linear(self.hidden_size, 1) |
| self.threat_head = torch.nn.Linear(self.hidden_size, 1) |
| self.illegal_head = torch.nn.Linear(self.hidden_size, 1) |
| |
| def forward(self, input_ids, attention_mask): |
| outputs = self.encoder(input_ids=input_ids, attention_mask=attention_mask) |
| cls_embedding = outputs.last_hidden_state[:, 0, :] |
| cls_embedding = self.dropout(cls_embedding) |
| return ( |
| self.profanity_head(cls_embedding), |
| self.threat_head(cls_embedding), |
| self.illegal_head(cls_embedding) |
| ) |
| |
| model = MultiTaskToxicityEncoder() |
| model.load_state_dict(torch.load("pytorch_model.bin", map_location="cpu")) |
| model.eval() |
| |
| def predict_toxicity(text, threshold_dict=thresholds): |
| encoded = tokenizer(text, truncation=True, padding='max_length', max_length=128, return_tensors='pt') |
| with torch.no_grad(): |
| profanity_logits, threat_logits, illegal_logits = model(encoded['input_ids'], encoded['attention_mask']) |
| profanity_prob = torch.sigmoid(profanity_logits).item() |
| threat_prob = torch.sigmoid(threat_logits).item() |
| illegal_prob = torch.sigmoid(illegal_logits).item() |
| return { |
| 'profanity': {'probability': profanity_prob, 'prediction': profanity_prob >= threshold_dict.get('Profanity', 0.5)}, |
| 'threat': {'probability': threat_prob, 'prediction': threat_prob >= threshold_dict.get('Threat', 0.5)}, |
| 'illegal': {'probability': illegal_prob, 'prediction': illegal_prob >= threshold_dict.get('Illegal', 0.5)} |
| } |
| |
| text = "Ты дурак!" |
| print(predict_toxicity(text)) |
| ``` |
|
|
| ## Training Details |
|
|
| - **Base Model:** `cointegrated/rubert-tiny2` |
| - **Batch Size:** 64 |
| - **Learning Rate:** 2e-5 |
| - **Optimizer:** AdamW |
| - **Scheduler:** ReduceLROnPlateau (factor=0.5, patience=2) |
| - **Early Stopping:** patience=3 (остановка на 3-й эпохе) |
| - **Max Sequence Length:** 128 токенов |
| - **Loss Function:** BCEWithLogitsLoss (сумма потерь для трех голов) |
| - **Number of Epochs Trained:** 6 (best model at epoch 3) |
|
|
| ## Limitations |
|
|
| - Класс `illegal` отсутствует в обучающем датасете, поэтому модель не может его обнаружить. |
| - Модель обучена только на русскоязычных комментариях из социальной сети ok.ru, может плохо работать на других доменах. |
| - Для улучшения качества на классе `threat` рекомендуется собрать дополнительные данные. |
|
|
| ## Acknowledgements |
|
|
| Благодарность авторам оригинального датасета [Toxic Russian Comments](https://www.kaggle.com/datasets/alexandersemiletov/toxic-russian-comments) за предоставленные данные. |
|
|
| ## Citation |
|
|
| Если вы используете эту модель в своей работе, пожалуйста, ссылайтесь на: |
|
|
| ``` |
| @misc{rubert_toxicity_multitask, |
| author = {IvanFed}, |
| title = {RuBERT Multi-Task Toxicity Classifier}, |
| year = {2026}, |
| publisher = {Hugging Face}, |
| howpublished = {\url{https://huggingface.co/IvanFed/rubert-toxicity-multitask}} |
| } |
| ``` |
|
|