MosHack-Change 2025 — Анализатор тональности отзывов
Постановка задачи (Правительство Москвы)
- Классифицировать русскоязычные тексты по трем меткам: 0 — отрицательная, 1 — нейтральная, 2 — положительная.
- Веб-интерфейс должен уметь загружать CSV, нормализовать текст, возвращать размеченный CSV и визуализации; по валидационной выборке считать macro‑F1. Дополнительные фичи: поиск/фильтрация по источникам и словам, ручная правка разметки, выбор визуализаций.
- Ограничения: использовать открытые модели/библиотеки, работать на типовом CPU/GPU, обеспечить корректный обмен данными фронтенд
↔ бэкенд.
Датасет
- Исходные файлы:
data/ТОНАЛЬНОСТЬ/train.csv,test.csv,sample_submission.csv(структура из условия:text,label,src, плюсID). - Размеры: train — 232 366 строк, test — 58 092 строк. Распределение классов в train: 0 — 77 243, 1 — 77 494, 2 — 77 629.
- Источники (11): anime, bank, geo, kinopoisk, linis, news, perekrestok, ru-reviews-classification, rureviews, rusentiment, sber.
- Подготовленные выборки:
-
data/processed/train_clean.csv— 209 109 строк,val_clean.csv— 23 235 строк (после очистки/дедупликации). - Финальные сбалансированные:
train_super.csv— 106 311 (по 35 437 на класс),val_super.csv— 11 771 (по ~3.9k на класс),test_super.csv— 58 092. - Ключевые шаги препроцессинга (
notebooks/preprocess.py):- Очистка текста: удаление HTML/URL/email/телефонов, токены для эмодзи/оценок/бранных слов, нормализация пунктуации и растянутых букв, пометки [ALL_CAPS]/[EN].
- Укорачивание длинных текстов до ~900 символов по предложениям с сохранением “сигнальных” фраз (под max_length 256–320 токенов).
- Даунсемплинг до 40 000 примеров на источник; общий лимит не используется; стратифицированный train/val сплит 90/10.
- Мягкие аугментации (word dropout 0.05 + редкий swap, не более 1 аугм./текст) и добавление доменных токенов
[SRC_<источник>]в начало текста.
-
Структура репозитория
-
data/— исходные (ТОНАЛЬНОСТЬ/), подготовленные (processed/), предсчитанные эмбеддинги (embeddings_xlmr/), кеши вероятностей (cache/). -
notebooks/— пайплайны препроцессинга и обучения (RuRoBERTa base/tiny, RuBERT conversational, TF‑IDF baseline, ансамбль BERT+LR, подготовка теста и т.д.). -
models/— сохраненные веса/токенизаторы, истории обучения (training_history_*.csv), конфиги ансамбля. -
src/— скрипты для обучения и инференса (data_utils.py,train_model.py,inference.py,src/models). -
pretrained/— дополнительные артефакты моделей. -
README.md,requirements.txt,environment.yml,ПравительствоМосквы_Hack&Change 2025.pdf.
Пример дерева (обрезано до ключевых узлов):
sentiment_project/
├─ data/
│ ├─ ТОНАЛЬНОСТЬ/ # train.csv, test.csv, sample_submission.csv
│ ├─ processed/ # train_super.csv, val_super.csv, test_super.csv, *_clean.csv
│ ├─ embeddings_xlmr/ # X_train.npy, X_val.npy, y_*.npy
│ └─ cache/ # предсчитанные вероятности для ансамблей
├─ notebooks/
│ ├─ preprocess.py # скрипт подготовки данных
│ ├─ preprocess.ipynb # пошаговый препроцессинг
│ ├─ baseline.ipynb # TF-IDF бэйзлайны (LR, SVC, SVD+HGB)
│ ├─ bert_tf_cv.ipynb # ансамбль BERT + TF-IDF
│ ├─ train_rurorberta_base_manual.ipynb
│ ├─ train_rurorberta_tiny_manual.ipynb
│ ├─ train_rubert_base_conv.ipynb
│ ├─ train_xlmr_base.ipynb
│ └─ eval_model_universal.ipynb
├─ models/
│ ├─ rurorberta_base2_manual/ # веса, токенизатор, история обучения
│ ├─ rurorberta_tiny_manual/
│ ├─ rubert_base_conv_manual/
│ ├─ sentiment_*.joblib # TF-IDF модели
│ └─ ensemble_config_cv*.json # конфиги ансамблей
├─ src/
│ ├─ data_utils.py
│ ├─ train_model.py
│ ├─ inference.py
│ └─ models/
├─ pretrained/
├─ requirements.txt
├─ environment.yml
└─ README.md
Последовательность работы
- Установить окружение:
python -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt(илиconda env create -f environment.yml). - Подготовить данные: из папки
notebooks/запуститьpython preprocess.py— сохранитdata/processed/train_super.csv,val_super.csv,test_super.csv. - (Опц.) Подготовить эмбеддинги/валидацию для классических моделей:
notebooks/baseline.ipynb,bert_tf_cv.ipynb. - Обучить трансформеры: соответствующие ноутбуки (
train_rurorberta_base_manual.ipynb,train_rurorberta_tiny_manual.ipynb,train_rubert_base_conv.ipynb,ubert-base-cased-sentiment-rusentiment.ipynb,train_xlmr_base.ipynb) — читаютdata/processed/*.csv, сохраняют веса/токенизатор вmodels/. - Оценка/ансамбль:
bert_tf_cv.ipynb(считает macro-F1 наval_super, генерирует конфиги ансамбля),eval_model_universal.ipynbдля сводной проверки. - Инференс на тесте/приложении: загрузить обученную модель из
models/и применять тот же препроцесс[SRC_*]/очистку, что вpreprocess.py.
Метрики моделей (macro‑F1 на val_super)
| Модель / пайплайн | Откуда | Macro‑F1 |
|---|---|---|
| blanchefort/rubert-base-cased-sentiment-rusentiment | notebooks/ubert-base-cased-sentiment-rusentiment.ipynb |
0.7561 |
| DeepPavlov/rubert-base-cased-conversational | notebooks/train_rubert_base_conv.ipynb |
0.7347 |
| ai-forever/RuRoBERTa-base (дообученная) |
notebooks/train_rurorberta_base_manual.ipynb (models/rurorberta_base2_manual) |
0.7338 |
| FacebookAI/xlm-roberta-base | ||
| FacebookAI/xlm-roberta-base (дообученная на 30 тысяч данных) | notebooks/train_xlmr_base.ipynb |
0.7213 |
| cointegrated/rubert-tiny2 (дообученная) | notebooks/train_rurorberta_tiny_manual.ipynb |
0.6871 |
| Ансамбль BERT + TF‑IDF+LR | notebooks/bert_tf_cv.ipynb |
0.6642 |
| TF‑IDF + Logistic Regression (Optuna) | notebooks/baseline.ipynb |
0.6222 |
| TF‑IDF + SVD + HistGradientBoosting | notebooks/baseline.ipynb |
0.6101 |
| TF‑IDF + LinearSVC | notebooks/baseline.ipynb |
0.5997 |
Метрики считаются на валидации val_super (стратифицированные 10% после очистки и балансировки). Логи обучения и истории сохранены рядом с соответствующими моделями в models/.