«Обучил, запустил и забыл» — плохая стратегия работы с ML‑моделями, но она часто встречается после удачного тестирования. Качество моделей может незаметно снижаться, и если пропустить этот момент — последствия могут дорого стоить. Когда мы начали задумываться о системе мониторинга, одна из наших моделей начала выдавать предсказания, которые требовали незамедлительного вмешательства в выстроенную работу. Но разум подсказывал, что проблема не в процессе, а в модели. О том, каким трудоемким оказалось наше расследование, и как мы восстанавливали и изучали каждую составляющую процесса почти вслепую, читайте по ссылке.

Быть детективами нам понравилось, но вкладывать столько усилий в каждый подобный случай не хочется. Мы поняли, что нужно научиться контролировать работу модели так, чтобы своевременно находить проблему и чинить ее, используя минимальное количество ресурсов. В серии из двух статей расскажу, как мы построили систему мониторинга ML‑моделей силами одного человека за несколько месяцев. 

Формулируем требования для системы мониторинга

Кейс выше подсветил нам важность комплексного мониторинга, поэтому не было сомнений в том, нужен ли он нам. Но откуда его взять и как его настроить понимания не было. Поэтому начали с простого — предложили себе ответить на вопросы: «Что мы хотим получить от мониторинга? Каким критериям он должен соответствовать?». Поняли, что наш идеальный мониторинг:

  1. Предоставляет информацию: предлагает как общую сводку о состоянии, так и детальные данные для глубокого анализа проблем.

  2. Удобен в использовании: визуализирует данные, выделяя ключевое, и объединяет всё в едином интерфейсе.

  3. Работает проактивно: привлекает внимание при необходимости.

  4. Дает уверенность: подтверждает корректность работы модели.

  5. Масштабируется: легко адаптировать для новых моделей.

Пожелания сформированы, теперь нужно понять, что необходимо проанализировать, чтобы получить желаемое. Выстроим упрощенную цепочку событий:

Нереальный рисунок карандашом
Нереальный рисунок карандашом

В модель подаются данные, с которыми могло что‑то произойти: от банальной потери части информации до структурных изменений в источниках. Некачественные данные на входе автоматически ставят под сомнение любые выходы модели. Поэтому первый рубеж защиты — это тесты на целостность и согласованность данных.

Предположим, данные прошли первую проверку. Следующий критически важный этап — убедиться, что статистические свойства фичей соответствуют тем, на которых модель была обучена. Если распределения признаков изменились (например, из‑за сдвига в поведении пользователей или обновления процесса сбора данных), модель окажется в новой, незнакомой ей реальности. Этот дрифт данных почти гарантированно приведет к деградации качества предсказаний.

Конечно, не стоит забывать и про показатели, которые замеряют качество модели. Для этого, нужно выделить ключевые метрики и отслеживать их поведение. И важно следить за предсказаниями модели: они должны рассчитываться в полном объеме и в соответствии с запланированным сценарием (по расписанию или по запросу в сервис).

Если все проверки будут пройдены — данные качественны, дрифта нет, метрики в порядке, предсказания отдаются с заданной регулярностью — мы сможем с уверенностью полагаться на выводы модели. 

В итоге, от желания «иметь мониторинг» пришли к требованиям для будущей системы. Мы поняли, что будем отслеживать и зачем. Этот фундамент позволил нам перейти к практической части — к выбору инструментов для реализации.

Выбор инструментов

Для выстраивания системы мониторинга можно пойти двумя путями: использовать готовое решение или собрать свой «велосипед». 

После анализа рынка мы решили создать собственную платформу путём интеграции существующих инстру��ентов.

Момент понимания собственной крутости
Момент понимания собственной крутости

Преимущества такого решения:

  • Кастомизация. Возможность тонкой настройки под наши нужды. Мы сами решаем, что и как отслеживать. Написать свои методы часто быстрее и надёжнее, чем переписывать реализацию чужих решений.

  • Экономическая эффективность. Минимизация финансовых вложений за счёт использования открытых или уже оплаченных инструментов.

  • Знакомый инструментарий. Сотрудникам не требуется осваивать новые инструменты, что ускоряет внедрение.

Недостатки:

  • Решение придётся собрать самостоятельно. Требуются ресурсы на разработку и отладку взаимодействия между компонентами системы.

Недостатки не звучат как что‑то невероятное. По нашим оценкам, для реализации хватило бы всего одиного специалиста. А позитивные аргументы выглядят весьма привлекательно. 

Следующий шаг — выбор технологического стека. Мы руководствовались не личными предпочтениями, а внутренними стандартами компании. Важно было использовать популярные и хорошо поддерживаемые инструменты, чтобы система не устарела и была понятна коллегам. Так мы остановились на:

  • Обработка данных: Python, в основном pandas и numpy.

  • Хранение: Реляционная база данных.

  • Оркестрация: Airflow.

  • Визуализация: Power BI.

Выбрав инструменты, мы приступили к воплощению задуманного.

Индикаторы и возможные проблемы при проверке данных

По совокупности получаемых данных:

  • Количество строк: резкое уменьшение говорит о возможной потере данных или сбоях, а внезапный рост — о наплыве пользователей и потенциальных проблемах с масштабированием.

  • Дубликаты: могут означать, что сервис, в который было внедрено ML‑решение, отправляет одни и те же данные несколько раз.

Индивидуально по признакам:

  • Колонка начала принимать константное значение — данные могли перестать обновляться, либо в выборку начали попадать значения только из одной группы (например, только определённый сегмент клиентов).

  • Колонка начала принимать только пустые значения — сигнализирует о возможных изменениях в источнике или ошибках обработки.

  • Появление новых значений или исчезновение известных — это может означать изменения в источнике. Стоит уточнить, произошли ли какие‑то изменения в бизнес‑логике сборки признака: например, условия агрегации значений. 

  • Содержание конкретного значения — если ожидаемая доля какого‑то значения изменилась, это повод проверить, что поведение/характеристики пользователей сохраняются.

Реализация большинства тестов сводится к расчёту двух значений простой функцией (например: cur_data[column].nunique()) и сравнению их между собой.

Обработка пропусков

Отдельно выделим работу с пропусками. Постепенное исчезновение данных также снижает качество предсказаний. К тому же, не всегда очевидно, почему это происходит — до нас не доходит часть информации или признак становится неактуальным?

Нехватка данных понятна и котику
Нехватка данных понятна и котику

Как можно обрабатывать пропуски:

  1. Заполнить каким‑либо значением. Это может быть ноль, среднее, медиана… или значение, которое естественным образом не может оказаться в наборе. Подменяя пустоты, мы должны помнить, что это наше действие, а не возможная ошибка в данных. Также, при таком подходе мы рискуем оказаться в ситуации, когда количество искусственных значений недостаточно, чтобы указать на проблему с пропусками, и при этом оно дает ложное представление о распределении данных. Мы либо зря отвлекаемся на изучение вопроса, либо пропускаем смещение показателей. Не рекомендовали бы данный подход для сервиса мониторинга.

  2. Оставить без изменений, если расчёт выбранных статистик не требует заполнения пропусков. Обработка пропущенных значений не вызывает трудностей, и при этом не возникает дополнительной путаницы.

Мы использовали второй вариант.

Для определения проблемы с пропусками нужно посчитать долю пустых значений в исходном наборе, который участвовал в обучении/тестировании модели, и в текущих данных. Способы анализа:

  1. Задать порог.
    Устанавливаем границу, ниже которой данные считаются проблемными, а выше — допустимыми. Производим сравнение порога с текущей долей пропусков. 

    Достоинства: Легко внедрить и объяснить.

    Недостатки: Порог — это гиперпараметр, который подбирается для каждого признака. Слишком низкий порог не покажет исчезновение данных, слишком высокий приведёт к ложным срабатываниям.

  2. Значение по исходным данным.
    Рассчитываем порог относительно эталонного набора данных. Можно задавать её абсолютным значением, добавляя фиксированную величину, а можно относительным, используя процент. Например, у нас доля непустых данных 0.9. Используя абсолютное значение 0.1, получим границу в 0.8, а используя относительное 10%, получим порог уже в 0.82.

    Достоинства: Легче адаптировать под любой набор данных.

    Недостатки: Могут возникнуть трудности с подбором границы интервала и допустимым размером погрешности.

  3. Статистический анализ.
    Можно на это взглянуть, как на пропорции, с которыми нам уже поможет разобраться z‑тест.

    Достоинства: Строгий контроль качества, возможность обнаружить проблему на раннем этапе.

    Недостатки: Повышается частота ложных срабатываний.

Идеального решения нет, поэтому важно использовать гибридный подход. Для критичных признаков используйте статистический тест, для остальных — относительные пороги. Главное — не дать данным тихо исчезнуть.

Выбор статистического теста для обнаружения дрифта данных — это поиск баланса между чувствительностью и устойчивостью. PSI‑тест можно назвать стандартом в этом вопросе, он идеально подходит для роли основного индикатора. Его принцип работы — сравнение распределений через разбиение на интервалы (бины). Так он оценивает общую картину изменений, а не только смещение среднего. Это делает PSI устойчивым к незначительным колебаниям, которые не несут реальных угроз. Рекомендуем использовать именно его.

Если нужна более тонкая диагностика, можно считать дистанцию Вассерштейна или дивергенцию Кульбака‑Лейблера. Главное — не перестараться! Больше двух тестов на один признак не повысят качество мониторинга, но гарантированно усложнят анализ. Оптимальная стратегия — один основной и один вспомогательный для проверки критически важных признаков. Любой используемый тест исследуйте, посмотрите как его правильно применять, проводите эксперименты со своими данными, изучите на предмет нюансов.

У себя мы используем PSI‑тест как основной индикатор, а в качестве вспомогательного применяем bootstrap.

Контроль качества предсказания моделей

Один котик вышел грустным, почему?
Один котик вышел грустным, почему?

Из всего множества показателей (Precision, Recall, ROC‑AUC и пр.) нужно выбрать один‑три ключевых, которые напрямую влияют на решение о дальнейших действиях с моделью. Именно их изменение должно запускать процесс исследования, а все остальные показатели (какими бы интересными они ни были) — поясняющие и служат для диагностики. Наша цель — не каталог с тысячей и одной метрикой, а полезный и информативный инструмент. 

По каким метрикам мы оцениваем качество модели? По каким метрикам понимаем, что модель даёт нужный результат? Именно эти метрики и нужно мониторить, обозначив допустимый диапазон колебаний значений:

  1. От бизнес‑требований. Прописываем оценку нашего принятия решения, ниже которой считаем, что модель теряет ценность. Также не стоит выпускать из внимания слишком высокий результат метрики.
    Пример: нижняя граница метрики precision выставлена на 0.7, а верхняя на 0.95, значит нас устроит любое значение в диапазоне 0.7-0.95.

  2. Построение интервала с использованием абсолютных погрешностей от значений по исходным данным (например, падение ROC‑AUC на 0.05).

  3. Построение интервала с использованием относительных погрешностей от значений по исходным данным (например, рост LogLoss на 15%).

Откуда брать тесты

Стало ясно, какие тесты нужны, но откуда их взять? Можно пойти двумя путями: использовать готовые библиотеки (например: evidently ai, great expectations…) или написать функции реализации расчётов проверок самостоятельно. 

Сперва мы пошли первым пут��м. Выбрали библиотеку, включающую в себя обширную коллекцию тестов и метрик для разных моделей, что избавляет от необходимости создавать их с нуля. Это казалось идеальным решением, просто делай импорт библиотеки и доставай всё необходимое. Но позже нам пришлось столкнуться с минусами.

В надежде на быстрый результат
В надежде на быстрый результат

Опытным путем мы обнаружили, что инструмент был эффективен на малых объёмах данных — для первой модели нужно было обрабатывать всего 5 тысяч строк. Переход на 500 тысяч строк обернулся тем, что некоторые наши тесты стали выполняться дольше 15 минут. В итоге мы перешли на стандартные библиотеки: sklearn, scipy; а логику тестов полностью переписали. Это позволило сократить суммарное время обработки данных до 15 минут. 

Когда вы решаете, использовать ли сторонние библиотеки, обращайте внимание на то, как они реализованы, как часто они обновляются и когда это было в последний раз, есть ли люди, поддерживающие их. Изучите. как и что вы будете подавать им на вход. Предварительно ознакомьтесь с проблемами, с которыми встречаются пользователи, оцените, насколько они для вас будут критичны.

Подбирая всё необходимое для анализа данных, не забывайте о работоспособности всего выстроенного пайплайна. Надёжность мониторинга определяется не только качеством метрик, но и устойчивостью системы. Каждый тест и метрика должны быть обработаны на предмет крайних случаев, способных вызвать падение всей системы. Согласитесь, будет обидно, если ошибка в одном вычислении сломает всю сборку данных. Необходимо предусмотреть обработку исключений и добавить для каждого проверяемого сценария секцию с возможными ошибками. Таким образом, тесты должны возвращать не только статусы «успех» или «неуспех», но и состояние «ошибка», что позволяет изолировать проблему и сохранить работоспособность остальных компонентов мониторинга.

Куда смотреть? А куда жмать?
Куда смотреть? А куда жмать?

Мы собрали большое количество факторов, на которые можно смотреть, и кажется, что всё под контролем — но в этом и проблема. Если что‑то сломается, то непонятно, а что нужно делать, критично это или надо дальше наблюдать. Чтобы не потеряться в потоке цифр, введём систему приоритетов. В её основу заложим важность фичей и их группировку, а также нашу оценку критичности.

  1. Определить самые важные фичи модели. Они почти полностью определяют поведение модели. Не стоит выделять 100–200 фичей — это бессмысленно. Обратите внимание на топ из 10–20 признаков, отсортированных по важности. Допустимо добавить ещё 1–3 фичи, которым необходимо уделить повышенное внимание: например, если есть влияние на бизнес‑логику.

  2. Сгруппировать все фичи. Это поможет определить, является ли проблема, обнаруженная в нескольких фичах, случайной или общей. Выделим два вида группировок. 

    1. По источнику данных. Быстро отреагируем на изменения в источнике или возникшие проблемы с обработкой данных. 

    2. По смысловым блокам. Отловим изменения в бизнес‑процессах и сможем вовремя подстроиться. Имейте ввиду, такая группировка, обычно, требует ручной разметки, и вызывает трудности при масштабировании.

  3. Выделить тесты. Среди настроенных тестов следует расставить приоритеты — выделить до 30 штук, результат которых наиболее критичен. Рекомендуем включить сюда тесты на показатели качества моделей и состояние важных фичей.

  4. Установить пороги критичности. Чтобы однозначно интерпретировать сигналы от мониторинга, мы должны их классифицировать.

  • Критическая проблема: аномалии затрагивают >N важных показателей ИЛИ >X% фичей в одном смысловом блоке.

  • Требует наблюдения: единичные срабатывания в менее важных случаях.

Правильная расстановка приоритетов позволяет перейти от реакции на шум к анализу системных сбоев, отвечая на вопрос «что сломалось?» и «насколько это серьёзно?» до того, как будут затрачены ресурсы на исследование.

Заключение

Мы определились с набором компонент и тем, как из них выделить главное, чтобы собрать эффективную систему мониторинга.

В следующей статье мы поговорим о том, как не превратить ваш безупречный мониторинг в свалку бессмысленных дашбордов, как не утонуть в водопаде ложных срабатываний алертов, и как сделать систему масштабируемой, понятной и действительно полезной.

Автор: 

  • Татьяна Бородина, аналитик данных.

Комментарии (0)