Учебный NLP-проект по автоматической классификации обращений клиентов банка. По короткому англоязычному сообщению модель определяет один из 77 intents: например, проблему со снятием наличных, статус перевода, доставку карты или возврат платежа.
Основная цель проекта — последовательно сравнить три поколения методов классификации текста на одинаковых данных:
- классический TF-IDF + Logistic Regression;
- many-to-one LSTM с предобученными GloVe-эмбеддингами;
- fine-tuning компактного Transformer
distilbert-base-uncased.
Весь анализ — от загрузки данных и EDA до обучения, error analysis и inference — находится в одном воспроизводимом Jupyter Notebook: solution.ipynb.
Intent classification помогает автоматически определять тему обращения пользователя. Такая модель может быть первым этапом системы поддержки: сгруппировать запросы, предложить подходящий сценарий ответа или передать неоднозначное сообщение специалисту.
Это multiclass classification: каждому тексту назначается ровно один из 77 классов. Главной метрикой выбрана Macro F1, поскольку она одинаково учитывает качество каждого intent, независимо от его размера в обучающей выборке.
Используется PolyAI/BANKING77 с Hugging Face:
- 10 003 train-сообщения;
- 3 080 test-сообщений;
- 77 банковских intent-классов;
- английский язык;
- короткие пользовательские запросы: медиана — 10 слов.
Датасет автоматически скачивается вызовом:
dataset = load_dataset("PolyAI/banking77", trust_remote_code=True)Отдельный CSV в репозитории не хранится. После первого запуска данные остаются в локальном кэше Hugging Face и повторно используются следующими запусками.
Проверка качества данных показала отсутствие пропусков, пустых строк и одинаковых текстов с конфликтующими labels. Между официальными train и test найдено шесть точных совпадений текста — этот факт отмечен при интерпретации результата.
Официальный train разделен на 8 002 train- и 2 001 validation-пример со стратификацией и random_state=42. Все три модели получают одинаковое разбиение.
Официальный test не используется для выбора признаков, гиперпараметров или checkpoint. Модели сначала сравниваются по validation Macro F1, после чего их финальные версии один раз оцениваются на test.
Используемые метрики:
- Accuracy;
- Macro F1 — главная метрика;
- Weighted F1.
Сильный и интерпретируемый baseline. Сравниваются униграммы, униграммы с биграммами и sublinear TF. Лучшей стала конфигурация с диапазоном (1, 2), min_df=2 и sublinear_tf=True.
Текст разбивается на последовательность слов и преобразуется в предобученные 50-мерные glove-wiki-gigaword-50 векторы. Они покрывают 97.1% словаря и заморожены во время обучения.
LSTM последовательно читает сообщение, а последнее скрытое состояние передается linear-слою на 77 классов. Padding исключается из вычислений с помощью pack_padded_sequence. Лучшее состояние сохраняется по validation Macro F1.
Используется базовый distilbert-base-uncased, который заранее не обучался на BANKING77. После анализа WordPiece-длин выбрано max_length=64: 99% train-сообщений короче 51 токена, поэтому обрезается только 0.30% примеров.
Fine-tuning выполняется пять эпох с learning rate 5e-5, weight decay 0.01 и выбором лучшего checkpoint по validation Macro F1. Победил checkpoint четвертой эпохи.
| Model | Accuracy | Macro F1 | Weighted F1 |
|---|---|---|---|
| DistilBERT | 0.9040 | 0.9013 | 0.9041 |
| TF-IDF + Logistic Regression | 0.8746 | 0.8698 | 0.8747 |
| LSTM + pretrained GloVe | 0.7836 | 0.7763 | 0.7817 |
| Model | Accuracy | Macro F1 | Weighted F1 |
|---|---|---|---|
| DistilBERT | 0.9159 | 0.9161 | 0.9161 |
| TF-IDF + Logistic Regression | 0.8812 | 0.8815 | 0.8815 |
| LSTM + pretrained GloVe | 0.7841 | 0.7820 | 0.7820 |
DistilBERT улучшил test Macro F1 baseline на 0.0346. При этом TF-IDF остается сильным: короткие банковские запросы часто содержат характерные слова и биграммы. LSTM учитывает порядок, но уступает из-за статических эмбеддингов и необходимости сжимать весь текст в одно последнее скрытое состояние.
Наиболее сложные intents для DistilBERT:
pending_transfer— F1 0.7765;balance_not_updated_after_bank_transfer— F1 0.7901;topping_up_by_card— F1 0.8052.
Ошибки в основном возникают между семантически близкими категориями:
card_arrivalиcard_delivery_estimate;why_verify_identityиverify_my_identity;- разные состояния переводов: pending, failed и not received;
fiat_currency_supportиexchange_via_app.
У правильных ответов средняя confidence равна 0.916, у ошибок — 0.603. Поэтому низкую confidence можно использовать как сигнал для ручной проверки, хотя некоторые двусмысленные ошибки остаются высокоуверенными.
Notebook содержит функцию:
predict_intent("My card has not arrived yet", top_k=3)Она проверяет вход, применяет тот же tokenizer и max_length, выполняет inference без градиентов и возвращает top-k intents с softmax-вероятностями. Также модель проверена на 15 собственных запросах о картах, переводах, PIN, возвратах, top-up и верификации.
- Постановка задачи и воспроизводимость.
- Автоматическая загрузка BANKING77.
- Проверка качества и EDA.
- Стратифицированный train/validation split.
- TF-IDF baseline и анализ ошибок.
- LSTM с предобученными GloVe-векторами и learning curves.
- Анализ длины токенов и fine-tuning DistilBERT.
- Сравнение моделей на validation и test.
- Classification report, confused pairs и реальные ошибки.
- Confidence и top-3 анализ.
- Inference-функция и собственные примеры.
- Итоговые выводы с фактическими метриками.
Text_classification/
├── solution.ipynb # весь анализ, обучение и результаты
├── README.md # описание проекта
├── requirements.txt # используемые зависимости
└── artifacts/ # локальные лучшие checkpoints, исключены из Git
Датасет, GloVe и исходные веса DistilBERT скачиваются автоматически и не добавляются в репозиторий.
python -m venv .venv
.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
pip install -r requirements.txt
jupyter notebook solution.ipynbpython3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
pip install -r requirements.txt
jupyter notebook solution.ipynbПосле открытия выполнить Restart Kernel → Run All. Первый запуск требует интернет для загрузки BANKING77, GloVe и DistilBERT.
Notebook автоматически использует CUDA, если она доступна, иначе переходит на CPU. Для локального fine-tuning рекомендуется GPU с 6–8 ГБ VRAM. CUDA-сборку PyTorch следует устанавливать по официальной инструкции для конкретной системы.
- seed зафиксирован равным 42 для Python, NumPy и PyTorch;
- split одинаков для всех моделей;
- версии
datasetsиtransformersзафиксированы вrequirements.txt; - лучший checkpoint выбирается только по validation Macro F1;
- notebook проверен полным выполнением сверху вниз без ошибок.
Небольшие расхождения последних знаков метрик возможны между разными GPU и версиями CUDA.
- сообщения короткие и иногда не содержат достаточного контекста для однозначного intent;
- часть категорий отличается только стадией одной операции;
- softmax confidence не откалибрована;
- проект работает только с английским языком и банковским доменом.
Возможные продолжения: анализ и аугментация сложных пар, confidence threshold для ручной проверки, BERT-base/RoBERTa, contrastive learning или иерархическая классификация intents.
Python, pandas, NumPy, scikit-learn, PyTorch, Hugging Face Datasets/Transformers, Gensim, Matplotlib, Seaborn и Jupyter.