SafeTechDev's picture
Update README.md
12fa79a verified
|
Raw
History Blame Contribute Delete
6.98 kB
---
language:
- ru
license: mit
base_model: DeepPavlov/rubert-base-cased
tags:
- text-classification
- spam-detection
- russian
- telegram-moderation
- bert
pipeline_tag: text-classification
datasets:
- alt-gnome/telegram-spam
metrics:
- f1
- precision
- recall
---
# AIMS-RU-Binary-Spam-Classifier
Бинарный классификатор спама для русскоязычных сообщений, часть проекта **AIMS (AI Moderation System)**.
Модель дообучена поверх [`DeepPavlov/rubert-base-cased`](https://huggingface.co/DeepPavlov/rubert-base-cased) и определяет, является ли сообщение **SPAM** или **SAFE**.
Лёгкая и быстрая модель.
## Обновлено. Фикс некоторых ложных срабатываний
## Обучающие данные
Обучение проводилось на сообщениях, собранных в активных публичных Telegram чатах осенью-весной 2025-2026 года.
## Метрики
Оценка проводилась на внешнем датасете [`alt-gnome/telegram-spam`](https://huggingface.co/datasets/alt-gnome/telegram-spam), не пересекающемся с обучающей выборкой:
| Метрика | Значение |
|-----------|----------|
| F1 | 0.95 |
| Precision | 0.98 |
| Recall | 0.92 |
Высокий precision (0.98) означает низкую долю ложных срабатываний — модель редко помечает безопасные сообщения как спам, что важно для автоматической модерации без риска задеть живых пользователей.
## Архитектура
- Энкодер: `DeepPavlov/rubert-base-cased`
- Голова классификации: `Dropout(0.2) → Linear(hidden_size, 1)`
- Пулинг: эмбеддинг токена `[CLS]`
- Функция потерь при обучении: `BCEWithLogitsLoss` с весом положительного класса (`pos_weight`) для компенсации дисбаланса SAFE/SPAM
- Выход: один логит → `sigmoid` → вероятность класса SPAM
## РЕКОМЕНДАЦИЯ Нормализация текста
Перед подачей в модель рекомендуется нормализовать текст, это использовалось при обучении.
- убирает "разрежённое" написание (`п.р.и.в.е.т.``привет`)
- заменяет гомоглифы (похожие символы из других алфавитов — `ᴀ`, `α`, латиница вместо кириллицы и т.д.) на кириллические эквиваленты
- удаляет ссылки и команды ботов (`/cmd@bot`)
- схлопывает повторяющиеся буквы (`приввееееет``привет`)
- приводит текст к нижнему регистру
## Быстрый запуск
```bash
pip install torch transformers huggingface_hub
```
```python
import re
import json
import torch
import torch.nn as nn
from transformers import AutoTokenizer, AutoModel
from huggingface_hub import hf_hub_download
REPO = "SafeTechDev/AIMS-RU-Binary-Spam-Classifier"
device = "cuda" if torch.cuda.is_available() else "cpu"
# ── Архитектура ──────────────────────────────────────────────────────────
class BinaryModel(nn.Module):
def __init__(self, model_name):
super().__init__()
self.bert = AutoModel.from_pretrained(model_name, low_cpu_mem_usage=True)
hidden = self.bert.config.hidden_size
self.binary = nn.Sequential(
nn.Dropout(0.2),
nn.Linear(hidden, 1)
)
def forward(self, input_ids, attention_mask):
outputs = self.bert(input_ids=input_ids, attention_mask=attention_mask)
pooled = outputs.last_hidden_state[:, 0]
return self.binary(pooled).squeeze(-1)
# ── Загрузка ─────────────────────────────────────────────────────────────
config_path = hf_hub_download(REPO, "config.json")
weights_path = hf_hub_download(REPO, "pytorch_model.bin")
with open(config_path, encoding="utf-8") as f:
cfg = json.load(f)
MAX_LENGTH = cfg.get("max_length", 40)
tokenizer = AutoTokenizer.from_pretrained(REPO)
model = BinaryModel(cfg["model"]).to(device)
model.load_state_dict(torch.load(weights_path, map_location=device, weights_only=True))
model.eval()
# ── Инференс ─────────────────────────────────────────────────────────────
def classify(text: str) -> dict:
enc = tokenizer(
text, truncation=True, padding="max_length",
max_length=MAX_LENGTH, return_tensors="pt"
)
with torch.no_grad():
logits = model(enc["input_ids"].to(device), enc["attention_mask"].to(device))
prob_spam = float(torch.sigmoid(logits).squeeze().cpu().item())
label = "SPAM" if prob_spam >= 0.7 else "SAFE"
return {"label": label, "prob_spam": prob_spam}
print(classify("Дам денег, работу, пишите в лс"))
# {'label': 'SPAM', 'prob_spam': 0.98...}
print(classify("Привет, как дела?"))
# {'label': 'SAFE', 'prob_spam': 0.02...}
```
### Через pipeline (упрощённо, без кастомной нормализации)
Модель хранит веса в формате `pytorch_model.bin` с кастомной головой, поэтому напрямую через `transformers.pipeline("text-classification", ...)` она не запустится — используйте код выше.
## Ограничения
- Модель обучена и валидирована на **русскоязычном** тексте; на других языках качество не гарантируется.
- Порог 0.7 используется по умолчанию для разделения SAFE/SPAM — в проде рекомендуется подбирать порог под свои данные (например, по максимальному F1), т.к. соотношение precision/recall меняется в зависимости от домена.
- Модель не учитывает контекст переписки — классифицируется только отдельное сообщение.
## Автор
[SafeTechDev](https://huggingface.co/SafeTechDev)