Upload README.md with huggingface_hub
Browse files
README.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
language:
|
| 3 |
+
- ru
|
| 4 |
+
license: mit
|
| 5 |
+
tags:
|
| 6 |
+
- text-classification
|
| 7 |
+
- toxicity
|
| 8 |
+
- multi-label-classification
|
| 9 |
+
- multi-task-learning
|
| 10 |
+
- russian
|
| 11 |
+
- bert
|
| 12 |
+
base_model: cointegrated/rubert-tiny2
|
| 13 |
+
---
|
| 14 |
+
|
| 15 |
+
# RU Multi-Task Toxicity Encoder
|
| 16 |
+
|
| 17 |
+
Лёгкая multi-task модель для классификации токсичности русскоязычных текстов
|
| 18 |
+
по трём независимым категориям одновременно.
|
| 19 |
+
|
| 20 |
+
## Описание
|
| 21 |
+
|
| 22 |
+
Модель построена на базе [cointegrated/rubert-tiny2](https://huggingface.co/cointegrated/rubert-tiny2)
|
| 23 |
+
с тремя независимыми классификационными головами поверх эмбеддинга `[CLS]` токена.
|
| 24 |
+
|
| 25 |
+
Каждая голова предсказывает один бинарный класс:
|
| 26 |
+
- **profanity** — ненормативная лексика
|
| 27 |
+
- **threat** — угрозы в адрес пользователя
|
| 28 |
+
- **illegal** — запросы, связанные с нарушением закона
|
| 29 |
+
|
| 30 |
+
## Архитектура
|
| 31 |
+
|
| 32 |
+
```
|
| 33 |
+
Encoder (rubert-tiny2)
|
| 34 |
+
└── [CLS] embedding (312-dim)
|
| 35 |
+
├── Dropout (p=0.2)
|
| 36 |
+
├── Linear(312 → 1) → profanity_logit
|
| 37 |
+
├── Linear(312 → 1) → threat_logit
|
| 38 |
+
└── Linear(312 → 1) → illegal_logit
|
| 39 |
+
```
|
| 40 |
+
|
| 41 |
+
## Метрики (валидационная выборка)
|
| 42 |
+
|
| 43 |
+
| Класс | Порог | Precision | Recall | F1 |
|
| 44 |
+
|------------|----------|-------------|---------|---------|
|
| 45 |
+
| profanity | 0.60 | 0.9454 | 0.9256 | 0.9354 |
|
| 46 |
+
| threat | 0.75 | 1.0000 | 0.9286 | 0.9630 |
|
| 47 |
+
| illegal | 0.16 | 1.0000 | 1.0000 | 1.0000 |
|
| 48 |
+
|
| 49 |
+
> Пороги подобраны индивидуально для каждого класса по максимуму F1-score
|
| 50 |
+
> на валидационной выборке. Классы сильно несбалансированы — это учтено
|
| 51 |
+
> через `pos_weight` в `BCEWithLogitsLoss` при обучении.
|
| 52 |
+
|
| 53 |
+
## Пример использования
|
| 54 |
+
|
| 55 |
+
```python
|
| 56 |
+
import json
|
| 57 |
+
import torch
|
| 58 |
+
import torch.nn as nn
|
| 59 |
+
from transformers import AutoModel, AutoTokenizer
|
| 60 |
+
|
| 61 |
+
# 1. Загрузка токенизатора и конфига
|
| 62 |
+
tokenizer = AutoTokenizer.from_pretrained("AtesiT/ru-multitask-toxicity-encoder")
|
| 63 |
+
|
| 64 |
+
with open("toxicity_config.json") as f:
|
| 65 |
+
config = json.load(f)
|
| 66 |
+
|
| 67 |
+
# 2. Определение архитектуры
|
| 68 |
+
class MultiTaskToxicityEncoder(nn.Module):
|
| 69 |
+
def __init__(self, model_name, hidden_size, dropout=0.2):
|
| 70 |
+
super().__init__()
|
| 71 |
+
self.encoder = AutoModel.from_pretrained(model_name)
|
| 72 |
+
self.dropout = nn.Dropout(dropout)
|
| 73 |
+
self.profanity_head = nn.Linear(hidden_size, 1)
|
| 74 |
+
self.threat_head = nn.Linear(hidden_size, 1)
|
| 75 |
+
self.illegal_head = nn.Linear(hidden_size, 1)
|
| 76 |
+
|
| 77 |
+
def forward(self, input_ids, attention_mask):
|
| 78 |
+
out = self.encoder(input_ids=input_ids, attention_mask=attention_mask)
|
| 79 |
+
cls = self.dropout(out.last_hidden_state[:, 0, :])
|
| 80 |
+
return (
|
| 81 |
+
self.profanity_head(cls),
|
| 82 |
+
self.threat_head(cls),
|
| 83 |
+
self.illegal_head(cls),
|
| 84 |
+
)
|
| 85 |
+
|
| 86 |
+
# 3. Загрузка весов
|
| 87 |
+
model = MultiTaskToxicityEncoder(
|
| 88 |
+
model_name=config["base_model"],
|
| 89 |
+
hidden_size=config["hidden_size"],
|
| 90 |
+
)
|
| 91 |
+
state_dict = torch.load("model_weights.pt", map_location="cpu")
|
| 92 |
+
model.load_state_dict(state_dict)
|
| 93 |
+
model.eval()
|
| 94 |
+
|
| 95 |
+
# 4. Инференс
|
| 96 |
+
thresholds = config["thresholds"]
|
| 97 |
+
|
| 98 |
+
def predict(text):
|
| 99 |
+
enc = tokenizer(
|
| 100 |
+
text, return_tensors="pt",
|
| 101 |
+
padding="max_length", truncation=True,
|
| 102 |
+
max_length=config["max_length"],
|
| 103 |
+
)
|
| 104 |
+
with torch.no_grad():
|
| 105 |
+
p_logit, t_logit, i_logit = model(
|
| 106 |
+
enc["input_ids"], enc["attention_mask"]
|
| 107 |
+
)
|
| 108 |
+
probs = {
|
| 109 |
+
"profanity": torch.sigmoid(p_logit).item(),
|
| 110 |
+
"threat": torch.sigmoid(t_logit).item(),
|
| 111 |
+
"illegal": torch.sigmoid(i_logit).item(),
|
| 112 |
+
}
|
| 113 |
+
labels = {k: int(v >= thresholds[k]) for k, v in probs.items()}
|
| 114 |
+
return {"probs": probs, "labels": labels}
|
| 115 |
+
|
| 116 |
+
print(predict("Ты полный идиот, заткнись!"))
|
| 117 |
+
```
|
| 118 |
+
|
| 119 |
+
## Обучение
|
| 120 |
+
|
| 121 |
+
- **Датасет**: [AtesiT/ru-multitask-toxicity](https://huggingface.co/datasets/AtesiT/ru-multitask-toxicity)
|
| 122 |
+
- **Функция потерь**: `BCEWithLogitsLoss` с `pos_weight` для каждого класса
|
| 123 |
+
- **Оптимизатор**: AdamW (lr=2e-5, weight_decay=0.01)
|
| 124 |
+
- **Early Stopping**: patience=3 по валидационному лоссу
|
| 125 |
+
- **Макс. длина последовательности**: 64 токена
|
| 126 |
+
|
| 127 |
+
## Ограничения
|
| 128 |
+
|
| 129 |
+
- Модель обучена на синтетически аугментированных данных для редких классов
|
| 130 |
+
(`threat`, `illegal`) — качество на реальных данных может отличаться.
|
| 131 |
+
- Короткие тексты (< 5 слов) могут обрабатываться менее точно.
|
| 132 |
+
- Модель не учитывает контекст диалога — только отдельное сообщение.
|
| 133 |
+
|
| 134 |
+
## Лицензия
|
| 135 |
+
|
| 136 |
+
MIT. Создано в учебных целях для курса по трансформерным энкодерам.
|