SyntaxError commited on
Commit
4dcc6f7
·
verified ·
1 Parent(s): 612495c

Upload 9 files

Browse files
README.md ADDED
@@ -0,0 +1,238 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language:
3
+ - ru
4
+ tags:
5
+ - text-classification
6
+ - moderation
7
+ - toxicity
8
+ - spam-detection
9
+ - toxic-detection
10
+ - cyberbullying-detection
11
+ - russian
12
+ - cyberbullying
13
+ - bert
14
+ - NLP
15
+ - rubert
16
+ license: mit
17
+ base_model: DeepPavlov/rubert-base-cased
18
+ ---
19
+
20
+ # AIMS — AI Moderation System
21
+
22
+ **AIMS** — многоклассовая модель классификации текста для автоматической модерации русскоязычных чатов. Определяет токсичный контент, спам, коммерческие объявления и другие нарушения.
23
+
24
+ Модель построена на базе [`DeepPavlov/rubert-base-cased`](https://huggingface.co/DeepPavlov/rubert-base-cased) с дополнительной головой классификатора (multi-head pooling: CLS + mean + max).
25
+ Модель может использоваться для автоматической модерации русскоязычных онлайн-сообществ.
26
+
27
+ ---
28
+
29
+ ## Классы
30
+
31
+ | Класс | Описание |
32
+ |---|---|
33
+ | `SAFE` | Безопасное сообщение, нарушений не обнаружено |
34
+ | `OSK` | Оскорбления — кибербуллинг, агрессия, унижение |
35
+ | `RUDELY_OSK` | Грубые оскорбления — мат в адрес родственников, несколько оскорблений в одном сообщении |
36
+ | `SPAM` | Спам — реклама, предложения работы, навязчивые рассылки |
37
+ | `SELL` | Коммерция — объявления о покупке/продаже, обмене |
38
+ | `ADULT` | Сексуальный контент — текстовые предложения интима, различные грубые выражения |
39
+ | `PLS` | Попрошайничество - навязчивые просьбы о денежном вознаграждении *(бета-тест)* |
40
+
41
+ > ⚠️ Модель работает **исключительно с русскоязычным текстом**.
42
+
43
+ ---
44
+
45
+ ## Характеристики
46
+
47
+ | Параметр | Значение |
48
+ |---|---|
49
+ | Базовая модель | `DeepPavlov/rubert-base-cased` |
50
+ | Архитектура | BERT + multi-head pooling + Linear classifier |
51
+ | Макс. длина токенов | 40 |
52
+ | Количество классов | 7 |
53
+ | Язык | Русский |
54
+ | Источник данных | Активные Telegram-чаты |
55
+
56
+ ---
57
+
58
+ ## Датасет
59
+
60
+ Модель обучена на собственном датасете из **27 000 примеров**, собранных в русскоязычных Telegram-чатах летом и осенью 2025 года.
61
+
62
+ - Разметка: частично выполнена вручную человеком, частично с помощью **DeepSeek**
63
+ - Источник: живые сообщения из публичных Telegram-чатов
64
+ - Баланс классов: компенсируется оверсэмплингом редких классов и взвешенным `CrossEntropyLoss`
65
+
66
+ ---
67
+
68
+ ## Метрики
69
+
70
+ Тестирование проводилось на внешних датасетах с HuggingFace с бинарной разметкой (плохое/хорошее). Оценивалась способность модели детектировать целевой класс среди немеченых плохих сообщений.
71
+
72
+ Все метрики приведены для порога уверенности **≥ 90%** (рекомендуемый порог уверенности модели).
73
+
74
+ ### Токсичность (OSK + RUDELY_OSK)
75
+
76
+ Для оценки эффективности модели использовались открытые наборы данных, охватывающие различные задачи автоматической модерации русскоязычного контента.
77
+
78
+ Тестирование проводилось на следующих датасетах:
79
+
80
+ - **AlexSham/Toxic_Russian_Comments** — набор данных, содержащий русскоязычные комментарии с разметкой токсичности. Использовался для оценки качества обнаружения токсичных высказываний.
81
+
82
+ Тест на датасете с оскорбительными сообщениями (Взятый обьем: 22 000 примеров, ~18 000 SAFE / ~4 000 BAD). **AlexSham/Toxic_Russian_Comments**
83
+
84
+ | Метрика | Значение |
85
+ |---|---|
86
+ | **Precision** | 91.3% |
87
+ | **Recall** | 95.7% |
88
+ | **F1-score** | 93.5% |
89
+
90
+
91
+
92
+ ### Спам (SPAM)
93
+
94
+ - **alt-gnome/telegram-spam** — набор сообщений из Telegram с разметкой на спам и легитимные сообщения. Использовался для оценки качества обнаружения спам-контента в условиях, приближенных к реальной эксплуатации.
95
+
96
+
97
+ Тест на датасете спам сообщений (Взятый обьем: 15 000 примеров, ~10 000 SAFE / ~5 000 BAD).
98
+
99
+ | Метрика | Значение |
100
+ |---|---|
101
+ | **Precision** | 93.6% |
102
+ | **Recall** | 96.8% |
103
+ | **F1-score** | 95.2% |
104
+
105
+
106
+
107
+
108
+ ---
109
+
110
+ ## Использование
111
+
112
+ ### Установка зависимостей
113
+
114
+ ```bash
115
+ pip install torch transformers
116
+ ```
117
+
118
+ ### Быстрый старт
119
+
120
+ ```python
121
+ import torch
122
+ import torch.nn as nn
123
+ import pickle
124
+ import json
125
+ import numpy as np
126
+ from transformers import AutoTokenizer, AutoModel
127
+
128
+ MODEL_DIR = "path/to/aims-model"
129
+ DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
130
+
131
+ # Загрузка конфига
132
+ with open(f"{MODEL_DIR}/config.json") as f:
133
+ config = json.load(f)
134
+
135
+ with open(f"{MODEL_DIR}/label_encoder.pkl", "rb") as f:
136
+ label_encoder = pickle.load(f)
137
+
138
+ # Определение архитектуры
139
+ class AIMSModel(nn.Module):
140
+ def __init__(self, model_name, num_classes):
141
+ super().__init__()
142
+ self.encoder = AutoModel.from_pretrained(model_name, low_cpu_mem_usage=True)
143
+ hidden = self.encoder.config.hidden_size
144
+ self.classifier = nn.Sequential(
145
+ nn.Dropout(0.2),
146
+ nn.Linear(hidden * 3, 512),
147
+ nn.GELU(),
148
+ nn.Dropout(0.1),
149
+ nn.Linear(512, num_classes)
150
+ )
151
+
152
+ def forward(self, input_ids, attention_mask):
153
+ hs = self.encoder(input_ids=input_ids, attention_mask=attention_mask).last_hidden_state
154
+ cls_p = hs[:, 0]
155
+ mask = attention_mask.unsqueeze(-1).float()
156
+ mean_p = (hs * mask).sum(1) / mask.sum(1).clamp(min=1e-9)
157
+ max_p = hs.masked_fill(attention_mask.unsqueeze(-1) == 0, float('-inf')).max(dim=1).values
158
+ return self.classifier(torch.cat([cls_p, mean_p, max_p], dim=-1))
159
+
160
+ # Загрузка модели
161
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_DIR)
162
+ model = AIMSModel(config["model"], config["num_classes"]).to(DEVICE)
163
+ model.load_state_dict(torch.load(f"{MODEL_DIR}/pytorch_model.bin", map_location=DEVICE, weights_only=True))
164
+ model.eval()
165
+
166
+ # Инференс
167
+ def predict(text: str) -> dict:
168
+ enc = tokenizer(text, truncation=True, padding="max_length",
169
+ max_length=config["max_length"], return_tensors="pt")
170
+ with torch.no_grad():
171
+ logits = model(enc["input_ids"].to(DEVICE), enc["attention_mask"].to(DEVICE))
172
+ probs = torch.softmax(logits, dim=-1).squeeze().cpu().numpy()
173
+ idx = int(np.argmax(probs))
174
+ return {
175
+ "label": label_encoder.classes_[idx],
176
+ "confidence": float(probs[idx]),
177
+ "probs": dict(zip(label_encoder.classes_, probs.tolist()))
178
+ }
179
+
180
+ # Пример
181
+ result = predict("продам аккаунт за 500 звёзд, пишите в лс")
182
+ print(result)
183
+ # {'label': 'SELL', 'confidence': 0.99, 'probs': {...}}
184
+ ```
185
+
186
+ ### Рекомендуемая логика принятия решения
187
+
188
+ ```python
189
+ FINAL_THRESHOLD = 0.90 # окончательное решение
190
+ WARNING_THRESHOLD = 0.80 # предупреждение, требуется проверка
191
+
192
+ def moderate(text: str) -> dict:
193
+ result = predict(text)
194
+ conf = result["confidence"]
195
+ label = result["label"]
196
+
197
+ if label == "SAFE":
198
+ verdict = "safe"
199
+ elif conf >= FINAL_THRESHOLD:
200
+ verdict = "block" # высокая уверенность — блокировать
201
+ elif conf >= WARNING_THRESHOLD:
202
+ verdict = "review" # средняя уверенность — на проверку модератору
203
+ else:
204
+ verdict = "safe" # низкая уверенность — пропустить
205
+
206
+ return {"verdict": verdict, "label": label, "confidence": conf}
207
+ ```
208
+
209
+ > **Рекомендация:** используйте порог **90-95%**- как границу для автоматической блокировки. При уверенности 80–90% — передавайте сообщение на ручную проверку. Ниже 80% — считайте сообщение безопасным.
210
+
211
+ ---
212
+
213
+ ## Ограничения
214
+
215
+ - Модель оптимизирована для **коротких сообщений** (до 40 токенов). Длинные тексты обрезаются.
216
+ - Класс `PLS` (попрошайничество) находится в **бета-тестировании** — точность ниже остальных классов из-за малого количества обучающих примеров.
217
+ - Модель не адаптирована для официальных текстов или новостных материалов.
218
+ - Возможны ложные срабатывания на текстах с нецензурной лексикой в нейтральном контексте (цитаты, художественные тексты).
219
+
220
+ ---
221
+
222
+ ## Лицензия
223
+
224
+ MIT
225
+
226
+ ---
227
+
228
+ ## Цитирование
229
+
230
+ ```bibtex
231
+ @misc{aims2025,
232
+ author = {JustDev23},
233
+ title = {AIMS: AI Moderation System},
234
+ year = {2025},
235
+ publisher = {Hugging Face},
236
+ note = {Trained on proprietary Telegram dataset collected during summer--autumn 2025}
237
+ }
238
+ ```
category_weights.json ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "ADULT": 0.9465142488479614,
3
+ "OSK": 0.3675874173641205,
4
+ "PLS": 4.7165961265563965,
5
+ "RUDELY_OSK": 5.732478618621826,
6
+ "SELL": 3.0709707736968994,
7
+ "SPAM": 0.6618314385414124
8
+ }
config.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "DeepPavlov/rubert-base-cased",
3
+ "max_length": 40,
4
+ "categories": [
5
+ "ADULT",
6
+ "SELL",
7
+ "PLS",
8
+ "OSK",
9
+ "SPAM",
10
+ "RUDELY_OSK"
11
+ ],
12
+ "num_categories": 6,
13
+ "binary_threshold": 0.8
14
+ }
label_encoder.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:bf44244dcaab267692e01178502f3ffa1b6411f24a27a3732aef5f62484c08c7
3
+ size 476
pytorch_model.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:27af36db14abfdde83ce13f0465c7ad18a62294ddecd167edec67443c7a9523e
3
+ size 718586783
special_tokens_map.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "cls_token": "[CLS]",
3
+ "mask_token": "[MASK]",
4
+ "pad_token": "[PAD]",
5
+ "sep_token": "[SEP]",
6
+ "unk_token": "[UNK]"
7
+ }
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "added_tokens_decoder": {
3
+ "0": {
4
+ "content": "[PAD]",
5
+ "lstrip": false,
6
+ "normalized": false,
7
+ "rstrip": false,
8
+ "single_word": false,
9
+ "special": true
10
+ },
11
+ "100": {
12
+ "content": "[UNK]",
13
+ "lstrip": false,
14
+ "normalized": false,
15
+ "rstrip": false,
16
+ "single_word": false,
17
+ "special": true
18
+ },
19
+ "101": {
20
+ "content": "[CLS]",
21
+ "lstrip": false,
22
+ "normalized": false,
23
+ "rstrip": false,
24
+ "single_word": false,
25
+ "special": true
26
+ },
27
+ "102": {
28
+ "content": "[SEP]",
29
+ "lstrip": false,
30
+ "normalized": false,
31
+ "rstrip": false,
32
+ "single_word": false,
33
+ "special": true
34
+ },
35
+ "103": {
36
+ "content": "[MASK]",
37
+ "lstrip": false,
38
+ "normalized": false,
39
+ "rstrip": false,
40
+ "single_word": false,
41
+ "special": true
42
+ }
43
+ },
44
+ "clean_up_tokenization_spaces": true,
45
+ "cls_token": "[CLS]",
46
+ "do_basic_tokenize": true,
47
+ "do_lower_case": false,
48
+ "extra_special_tokens": {},
49
+ "mask_token": "[MASK]",
50
+ "model_max_length": 1000000000000000019884624838656,
51
+ "never_split": null,
52
+ "pad_token": "[PAD]",
53
+ "sep_token": "[SEP]",
54
+ "strip_accents": null,
55
+ "tokenize_chinese_chars": true,
56
+ "tokenizer_class": "BertTokenizer",
57
+ "unk_token": "[UNK]"
58
+ }
vocab.txt ADDED
The diff for this file is too large to render. See raw diff