| --- |
| language: |
| - ru |
| license: mit |
| tags: |
| - text-classification |
| - toxicity |
| - multi-label-classification |
| - multi-task-learning |
| - russian |
| - bert |
| base_model: cointegrated/rubert-tiny2 |
| --- |
| |
| # RU Multi-Task Toxicity Encoder |
|
|
| Лёгкая multi-task модель для классификации токсичности русскоязычных текстов |
| по трём независимым категориям одновременно. |
|
|
| ## Описание |
|
|
| Модель построена на базе [cointegrated/rubert-tiny2](https://huggingface.co/cointegrated/rubert-tiny2) |
| с тремя независимыми классификационными головами поверх эмбеддинга `[CLS]` токена. |
|
|
| Каждая голова предсказывает один бинарный класс: |
| - **profanity** — ненормативная лексика |
| - **threat** — угрозы в адрес пользователя |
| - **illegal** — запросы, связанные с нарушением закона |
|
|
| ## Архитектура |
|
|
| ``` |
| Encoder (rubert-tiny2) |
| └── [CLS] embedding (312-dim) |
| ├── Dropout (p=0.2) |
| ├── Linear(312 → 1) → profanity_logit |
| ├── Linear(312 → 1) → threat_logit |
| └── Linear(312 → 1) → illegal_logit |
| ``` |
|
|
| ## Метрики (валидационная выборка) |
|
|
| | Класс | Порог | Precision | Recall | F1 | |
| |------------|----------|-------------|---------|---------| |
| | profanity | 0.60 | 0.9454 | 0.9256 | 0.9354 | |
| | threat | 0.75 | 1.0000 | 0.9286 | 0.9630 | |
| | illegal | 0.16 | 1.0000 | 1.0000 | 1.0000 | |
|
|
| > Пороги подобраны индивидуально для каждого класса по максимуму F1-score |
| > на валидационной выборке. Классы сильно несбалансированы — это учтено |
| > через `pos_weight` в `BCEWithLogitsLoss` при обучении. |
| |
| ## Пример использования |
| |
| ```python |
| import json |
| import torch |
| import torch.nn as nn |
| from transformers import AutoModel, AutoTokenizer |
| |
| # 1. Загрузка токенизатора и конфига |
| tokenizer = AutoTokenizer.from_pretrained("AtesiT/ru-multitask-toxicity-encoder") |
|
|
| with open("toxicity_config.json") as f: |
| config = json.load(f) |
| |
| # 2. Определение архитектуры |
| class MultiTaskToxicityEncoder(nn.Module): |
| def __init__(self, model_name, hidden_size, dropout=0.2): |
| super().__init__() |
| self.encoder = AutoModel.from_pretrained(model_name) |
| self.dropout = nn.Dropout(dropout) |
| self.profanity_head = nn.Linear(hidden_size, 1) |
| self.threat_head = nn.Linear(hidden_size, 1) |
| self.illegal_head = nn.Linear(hidden_size, 1) |
| |
| def forward(self, input_ids, attention_mask): |
| out = self.encoder(input_ids=input_ids, attention_mask=attention_mask) |
| cls = self.dropout(out.last_hidden_state[:, 0, :]) |
| return ( |
| self.profanity_head(cls), |
| self.threat_head(cls), |
| self.illegal_head(cls), |
| ) |
| |
| # 3. Загрузка весов |
| model = MultiTaskToxicityEncoder( |
| model_name=config["base_model"], |
| hidden_size=config["hidden_size"], |
| ) |
| state_dict = torch.load("model_weights.pt", map_location="cpu") |
| model.load_state_dict(state_dict) |
| model.eval() |
| |
| # 4. Инференс |
| thresholds = config["thresholds"] |
|
|
| def predict(text): |
| enc = tokenizer( |
| text, return_tensors="pt", |
| padding="max_length", truncation=True, |
| max_length=config["max_length"], |
| ) |
| with torch.no_grad(): |
| p_logit, t_logit, i_logit = model( |
| enc["input_ids"], enc["attention_mask"] |
| ) |
| probs = { |
| "profanity": torch.sigmoid(p_logit).item(), |
| "threat": torch.sigmoid(t_logit).item(), |
| "illegal": torch.sigmoid(i_logit).item(), |
| } |
| labels = {k: int(v >= thresholds[k]) for k, v in probs.items()} |
| return {"probs": probs, "labels": labels} |
| |
| print(predict("Ты полный идиот, заткнись!")) |
| ``` |
| |
| ## Обучение |
| |
| - **Датасет**: [AtesiT/ru-multitask-toxicity](https://huggingface.co/datasets/AtesiT/ru-multitask-toxicity) |
| - **Функция потерь**: `BCEWithLogitsLoss` с `pos_weight` для каждого класса |
| - **Оптимизатор**: AdamW (lr=2e-5, weight_decay=0.01) |
| - **Early Stopping**: patience=3 по валидационному лоссу |
| - **Макс. длина последовательности**: 64 токена |
| |
| ## Ограничения |
| |
| - Модель обучена на синтетически аугментированных данных для редких классов |
| (`threat`, `illegal`) — качество на реальных данных может отличаться. |
| - Короткие тексты (< 5 слов) могут обрабатываться менее точно. |
| - Модель не учитывает контекст диалога — только отдельное сообщение. |
| |
| ## Лицензия |
| |
| MIT. Создано в учебных целях для курса по трансформерным энкодерам. |
| |