Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

Intent Classification for Customer Support Requests

Учебный 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.

Модели

1. TF-IDF + Logistic Regression

Сильный и интерпретируемый baseline. Сравниваются униграммы, униграммы с биграммами и sublinear TF. Лучшей стала конфигурация с диапазоном (1, 2), min_df=2 и sublinear_tf=True.

2. Many-to-one LSTM + pretrained GloVe

Текст разбивается на последовательность слов и преобразуется в предобученные 50-мерные glove-wiki-gigaword-50 векторы. Они покрывают 97.1% словаря и заморожены во время обучения.

LSTM последовательно читает сообщение, а последнее скрытое состояние передается linear-слою на 77 классов. Padding исключается из вычислений с помощью pack_padded_sequence. Лучшее состояние сохраняется по validation Macro F1.

3. DistilBERT

Используется базовый 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 четвертой эпохи.

Результаты

Validation

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

Official test

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 учитывает порядок, но уступает из-за статических эмбеддингов и необходимости сжимать весь текст в одно последнее скрытое состояние.

Error analysis

Наиболее сложные 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 можно использовать как сигнал для ручной проверки, хотя некоторые двусмысленные ошибки остаются высокоуверенными.

Inference

Notebook содержит функцию:

predict_intent("My card has not arrived yet", top_k=3)

Она проверяет вход, применяет тот же tokenizer и max_length, выполняет inference без градиентов и возвращает top-k intents с softmax-вероятностями. Также модель проверена на 15 собственных запросах о картах, переводах, PIN, возвратах, top-up и верификации.

Что находится в notebook

  1. Постановка задачи и воспроизводимость.
  2. Автоматическая загрузка BANKING77.
  3. Проверка качества и EDA.
  4. Стратифицированный train/validation split.
  5. TF-IDF baseline и анализ ошибок.
  6. LSTM с предобученными GloVe-векторами и learning curves.
  7. Анализ длины токенов и fine-tuning DistilBERT.
  8. Сравнение моделей на validation и test.
  9. Classification report, confused pairs и реальные ошибки.
  10. Confidence и top-3 анализ.
  11. Inference-функция и собственные примеры.
  12. Итоговые выводы с фактическими метриками.

Структура проекта

Text_classification/
├── solution.ipynb    # весь анализ, обучение и результаты
├── README.md         # описание проекта
├── requirements.txt # используемые зависимости
└── artifacts/        # локальные лучшие checkpoints, исключены из Git

Датасет, GloVe и исходные веса DistilBERT скачиваются автоматически и не добавляются в репозиторий.

Запуск

Windows PowerShell

python -m venv .venv
.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
pip install -r requirements.txt
jupyter notebook solution.ipynb

Linux / macOS

python3 -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.

Technology stack

Python, pandas, NumPy, scikit-learn, PyTorch, Hugging Face Datasets/Transformers, Gensim, Matplotlib, Seaborn и Jupyter.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages