Модуль машинного обучения для анализа клиентских отзывов:
- Кластеризация текстов (выделение тем: кредитные карты, вклады, мобильное приложение и т.д.).
- Мультилейбл классификация по темам.
- Определение тональности (положительно / нейтрально / отрицательно).
uvicorn app.main:app --host 0.0.0.0 --port 8000 --reloadcurl http://localhost:8000/healthPOST /predict{"data":[{"id":1,"text":"Карта понравилась, но приложение лагает"}]}
curl -s -X POST http://localhost:8000/predict \
-H "Content-Type: application/json" \
-d '{"data":[{"id":1,"text":"Отличное обслуживание, но ужасное мобильное приложение."}]}'Ниже — расширенная документация по обучающему и инференс-пайплайнам (BERTopic + zero-shot классификация на эмбеддингах), а также управлению артефактами через MLflow.
Цель — выделять темы в отзывах клиентов банка и присваивать отзывам бизнес-классы (мультилейбл).
- Этап обучения (train):
- очистка и нормализация текстов (лемматизация RU, унификация англицизмов);
- вычисление эмбеддингов с учётом длинных отзывов (чанкинг + пуллинг);
- кластеризация BERTopic (KMeans/HDBSCAN) по эмбеддингам; улучшение названий тем (MMR);
- zero-shot маппинг тем → бизнес-классы через косинус к прототипам классов;
- zero-shot top‑k классов на уровне документа;
- экспорт артефактов (модель, эмбеддер, векторы классов, отчёты) и логирование в MLflow.
- Этап инференса (predict):
- быстрый zero-shot top‑k классификатор для новых отзывов (эмбеддер + косинус к векторам классов).
banking-topics-mlflow/
MLproject
conda.yaml
src/
final_classes.py # словарь бизнес‑классов (multi‑prototype)
utils_text.py # нормализация/лемматизация, softmax_cos
encode.py # чанкинг + пуллинг эмбеддингов
train_bertopic_and_export.py
predict.py
Актуальные артефакты сохраняются в artifacts/latest/.
Вход: JSON со списком отзывов. Поддерживается корневой ключ reviews.
Минимальные поля: id, title, text.
{
"reviews": [
{"id": 123, "title": "Заголовок", "text": "...", "rating": "5", "city": ""},
{"id": 124, "title": "UnionPay", "text": "..."}
]
}В src/utils_text.py выполняются:
normalize_anglicisms: унификация терминов (кэшбэк, UnionPay, push, Ozon Premium и т.д.);normalize_ru(если доступенpymorphy2): лемматизация, удаление предлогов/союзов/частиц, стоп-слов и чисел; латиница и бренды сохраняются;prepare_text(title, text): сборка и очистка текста для витрины названий тем.
Используются два представления текста:
docs_ctx— «сырые» (title + text),docs_clean— очищенные (леммы) для именования тем.
В src/encode.py:
- Разбиение строки на куски длиной до
max_chars(по умолчанию 1000 символов). - Кодирование каждого кусочка моделью
SentenceTransformer(по умолчаниюBAAI/bge-m3). - Агрегация кусочков (pooling):
max(по умолчанию),meanилиattn_len(взвешивание по длине). - L2‑нормализация итогового вектора.
- Vectorizer (для витрины названий тем):
CountVectorizer(ngram_range=(1,3), min_df=3, max_df=0.4, token_pattern=...)- доменные стоп‑слова (банк, карта, приложение и пр.) для удаления «воды».
- Кластеризация:
- по умолчанию KMeans через аргумент
hdbscan_model=KMeans(...)(особенность API BERTopic 0.17.x); - альтернатива: HDBSCAN; опционально
reduce_outliersдля перераспределения класса-1.
- по умолчанию KMeans через аргумент
- Улучшение представлений тем:
update_topics(..., representation_model=MaximalMarginalRelevance(diversity=0.6))снижает дубли/однокоренные повторы в названиях.
Результаты: topic_info (список тем), doc_info (тема для документа).
В src/final_classes.py задан расширенный словарь: для каждого класса — набор фраз‑прототипов.
- Для каждого класса считаются вектора прототипов (эмбеддер) и усредняются ⇒ вектор класса.
- Для каждой темы кодируются top‑слова темы ⇒ вектор темы.
- Считаются косинусы «тема ↔ класс», берутся top‑k классов для темы.
- Для удобства вероятности аппроксимируются
softmax_cosпо косинусам (температураτ = 0.07).
Для каждого документа берутся его эмбеддинги и косинусы к векторам классов ⇒ top‑k классов на документ. Это быстрый и простой классификатор, используемый на проде.
Скрипт src/train_bertopic_and_export.py сохраняет в artifacts/latest:
bertopic_model/— обученная модель BERTopic;embedder/— сохранённый SentenceTransformer;class_vecs.npy+class_names.json— матрица векторов классов и имена;bertopic_outputs.xlsx— отчёт с листами:topics_summary— перечень тем BERTopic;topics_top3_classes— маппинг тем в бизнес‑классы (top‑3);documents_topk— top‑k классов по документу + тема BERTopic;suspect_topics— темы с низким сходством к top‑1 классу (ниже порога);dist_docs,dist_topics— распределения.
Все артефакты логируются в MLflow.
mlflow run . -e train -P data_path="merged_reviews_filtered.json"Ключевые параметры (см. MLproject):
embedder_model— модель эмбеддингов (напр.,BAAI/bge-m3);pooling∈ {max,mean,attn_len};max_chars— размер чанка для длинных отзывов;use_kmeans,n_clusters,min_topic_size— настройка кластеризации;topk_classes— число классов на документ;suspect_topic_sim— порог отбора «сомнительных» тем.
mlflow run . -e predict \
-P model_dir="artifacts/latest" \
-P input_path="new_reviews.json" \
-P output_path="predictions.xlsx" \
-P topk=3 \
-P pooling=max \
-P max_chars=1000Выход: Excel/CSV с колонками id, top1_class/top1_sim, top2_class/top2_sim, top3_class/top3_sim.
Для изменения доменной таксономии:
- Отредактировать
src/final_classes.py(добавить/изменить фразы‑прототипы). - Перезапустить обучение (train) — пересчитаются векторы классов и отчёты.
- Скорость инференса: вычисление эмбеддинга + косинус к ~10–20 классам (миллисекунды на CPU).
- Длинные тексты: увеличение
max_charsуменьшает число чанков (быстрее, но грубее). - Ускорение: конверсия эмбеддера в ONNX (
onnxruntime) и/или квантование. - Качество: расширять
final_classes.py(синонимы, негативные формулировки), подбиратьpoolingи температуруτвsoftmax_cos. - Пороговая мультилейбл‑селекция: вместо top‑k можно отбирать классы по порогу косинуса.
conda.yamlфиксирует версии Python/пакетов (например,bertopic==0.17.3).- Фиксированные сиды (например,
random_state=42для KMeans). - MLflow логирует параметры и артефакты.
- Передача KMeans: в BERTopic 0.17.x кластеризатор передаётся как
hdbscan_model=KMeans(...). - Предупреждение
TOKENIZERS_PARALLELISM: нормально; можно отключить черезos.environ["TOKENIZERS_PARALLELISM"] = "false". - Малоинформативные названия тем: повышайте
min_df, дополняйте стоп‑слова, используйте MMR (diversity≈0.6). - Много
-1при HDBSCAN: используйте KMeans илиreduce_outliers. - Обновление классов на проде: после правок
final_classes.pyперезапустить train для обновленияclass_vecs.npy.
Основной отчёт: artifacts/latest/bertopic_outputs.xlsx.
Полезные листы:
topics_top3_classes— соответствие тем бизнес‑классам;documents_topk— top‑k классов на документ (для ручной валидации);suspect_topics— кандидаты на ревизию стоп‑слов/лейблов.
Итог: обучение даёт интерпретируемые темы и артефакты, а прод‑инференс работает быстро за счёт zero‑shot мультилейбл‑классификации на эмбеддингах.