Шесть лет назад я занимался стартапом FscoreLab, мы разрабатывали ML-системы для кредитного скоринга. Тогда я ещё слыхом не слыхивал о термине MLOps, да я и не уверен, что он вообще существовал. Однако, необходимость определённых практик и процессов, которые сейчас относят к MLOps, стала быстро понятна уже тогда. Один из самых важных уроков того времени - если модель обучить, задеплоить и отправить в свободное плавание, то рано или поздно, постепенно или внезапно, но случится что-то не очень хорошее. Да, сейчас от этого "откровения" хочется зевать - написана тонна книг и статей, запилена куча полезных инструментов, но в то время пришлось собирать систему ML-мониторинга опытным путём из подручных материалов. Состояла она из следующих компонентов:
Flask-SQLAlchemy для записи в БД информации о запросах и предиктах
Dash для создания удобного браузера для БД с фильтрами и поиском, доступного даже с телефона ночью (с некоторыми клиентами у меня была разница во времени в 10 часов)
Flask-Mail и cron для отправки ежедневных и еженедельных отчётов о сделанных предсказаниях и полученных запросах
Sentry, засылающий алерты об ошибках в Слак
Jupyter-ноутбучек, в котором раз в какое-то время забирались данные из БД и в pandas-датафрейме прогонялось несколько простых ассертов (например, что не появилось новых, неизвестных значений в какой-то колонке) и строилось несколько графиков. Впоследствии этот процесс был автоматизирован
Материал является адаптированной версией с моего ТГ-канала Варим ML
Эта с виду шаткая конструкция нормально справлялась со своими задачами, много лет служила верой и правдой и спасла нас от немалого количества фейлов, а наших клиентов - от некорректных предиктов и потерянных денег. В Цельсе мы долгое время были заняты гонкой за метриками и выходом хоть в какой-нибудь прод, поэтому понадобилось немало времени, прежде чем мы привели нашу систему мониторинга в порядок, а некоторых важных компонентов в ней не хватает до сих пор. Да, материалов про мониторинг много, но личный опыт и конкретные инструменты - это всегда приятно, да и многие статьи написаны вендорами MLOps-решений и не всегда объективны ?
Чем отличается мониторинг ML-систем?
Систему ML-мониторинга часто изображают в виде подобной пирамиды:
Логично, что в основе лежит классический софтверный мониторинг, ведь любая ИИ-система - это софтверная система. А вот дальше начинаются интересности, которые я подробно разберу в следующих секциях.
Глобально у ML-систем есть несколько нюансов, осложняющих их мониторинг:
В ходе своей работы они производят огромное количество фичей, которые потенциально можно мониторить - различные статистики и мета-информация по входным данным, промежуточные и конечные предсказания, сгенерированные фичи и многое другое. Корректно настроить автоматический мониторинг всех нужных параметров непросто - скорее всего, поначалу у нас будет много ложных алертов, а оптимальные настройки и трешхолды ещё и могут меняться во времени.
ML-системы производят много скрытых внутренних преобразований - препроцессинг, feature engineering, постпроцессинг, и проблемы с данными и предиктами могут проявиться где-то внутри этих компонентов.
Мониторинг качества работы ML-систем часто затруднён из-за delayed target - ведь чтобы узнать правильность предсказания нужно либо дождаться ground truth (например, вернул ли человек займ вовремя), либо разметить данные.
Часто ML-метрики тяжело привязать к бизнес-метрикам. Например, система может выдавать достаточно точные предикты, но если ей никто не пользуется или пользуется не так, как задумывалось, то бизнес-эффект будет сведён на нет.
Какие-то показатели, которые хочется мониторить (например, медиана или мода тензора), не вычисляются в ходе работы системы. Чтобы не замедлять работу системы, их расчёт нужно производить в отдельных пайплайнах, что усложняет архитектуру системы.
Различных ML-систем и моделей существует огромное множество - даже внутри одной компании, и требования к их мониторингу могут сильно разниться. Давайте на примерах из медицины разберём, какие факторы могут влиять на сложность и важность системы мониторинга:
Скорость изменений и нестабильность среды - как часто к нашей системе подключаются новые медицинские учреждения, появляются ли в популяции новые заболевания?
Разнообразие входных данных - сколько производителей рентген-аппаратов есть, много ли у них настроек, как сильно друг от друга визуально отличаются исследования разных людей?
Критичность решений, которые принимаются с помощью ML-системы - система предназначена для детекции рака или определения степени плоскостопия?
Автономность системы - каково участие системы в процессе постановки диагноза?
Количество, разнообразие и стабильность внешних источников входных данных - используем ли мы для предсказания какую-то внешнюю информацию о пациенте (возраст, пол, вес)? Откуда она приходит, сообщат ли нам об изменениях?
Новизна и степень решённости задачи - детекция лиц персонала на проходной больницы или детекция новообразований мозга?
Сложность системы и количество компонентов - есть ли у нас каскад моделей, которые зависят друг от друга?
Тип входных данных - табличные, текстовые, картинки, видео, звук?
Возраст ML-системы - был ли недавно новый большой релиз, сколько уже времени система работает в продакшне?
Давайте перейдём к более подробному обзору видов мониторинга ML-систем.
Классический мониторинг
Это показатели, связанные с инфраструктурой и корректной работой приложения:
Ошибки выполнения кода
Нагрузка - количество запросов во времени
Скорость работы - latency, throughput
Утилизация ресурсов - CPU, GPU, RAM, жёсткий диск, сеть
Error rates - проценты запросов с разными типами ошибок (не смогли найти целевой орган, не смогли прочитать DICOM-файл и другие)
Для классического мониторинга в Цельсе мы используем Sentry с алертами в Mattermost, Grafana, даш Кубернетеса, телеграм-бот для алертов инфры и другие известные всем инструменты.
Мониторинг данных
Техническое качество входных данных
Входные данные постоянно меняются, и очень часто это происходит по сугубо техническим причинам:
Изменение схемы данных - внешний источник обновил схему или формат данных
Источник данных сломался - поступают неверные данные, например, NaNы
Сломался предыдущий компонент в каскаде - другая ML-модель отдаёт неверный предикт или неверно работает препроцессинг изображений
Неверный инпут от пользователей - опечатка в тексте, которую мы не провалидировали
Рано или поздно эти проблемы начнут сказываться на качестве работы модели, поэтому лучше обнаружить их как можно быстрее:
Валидировать схему и формат входных данных. Это включает в себя как простые проверки типа отсутствия NaN-значений, так и более сложные доменные вещи - например, проверка, что размер целевого органа на исследовании лежит в заданных пределах. Для создания таких "ожиданий" от данных можно использовать либу Great Expectations.
"Ожидания" можно формировать и для батча данных (например, все запросы за день) - если какая-то фича константная или процент пропущенных значений превышает порог, можно триггернуть алерт.
Дрифты
Наверное, каждый так или иначе слышал о пресловутых data drifts:
Дрифты обычно делят на три типа:
Covariate drift - изменение распределения фичей, может происходить по естественным причинам (подключилась новая больница) и по техническим (изменился формат входных данных).
Target drift - изменение распределения целевой переменной. Например, изменился баланс классов "норма" и "патология" из-за начала эпидемии.
Concept drift - изменение связи между фичами и таргетами, оно может случаться постепенно, резко или с определённой периодичностью.
Тема дрифтов очень обширна и явно выходит за рамки этого поста, но один нюанс я хочу упомянуть. На мой взгляд, основная сложность детекции дрифтов состоит в огромном разнообразии методов, способов и настроек:
Мониторинг дрифтов можно осуществлять по сырым данным, их статистикам (например, средняя интенсивность пикселей), по промежуточным или финальным предсказаниям системы.
Дрифты можно детектировать по каждой фиче независимо (univariate) или по всему множеству сразу (multivariate). Во втором случае перед проведением стат-теста часто ещё проводят процедуру dimensionality reduction, а это можно делать тысячей разных способов.
Дрифты отличаются по степени воздействия на качество модели. Распределение фичи может измениться, но если она не особо значима для предсказания, то переобучение модели может не потребоваться.
Для детекции дрифта нужно определиться со стратегией выбора референс-сета (с чем сравниваем) и тест-сета (что сравниваем). Подробнее о разных способах выбора тест-сета можно посмотреть здесь, а вот выбор референс-сета в основном зависит от задачи и цели. Можно использовать обучающую или тестовую выборку, а можно предыдущий период работы модели.
Наконец, дрифт может происходить только на конкретной подвыборке данных с определёнными характеристиками, что затрудняет его детекцию.
На данный момент ни одно из специализированных решений (EvidentlyAI, alibi-detect, TorchDrift) для детекции дрифтов у нас не используется, но это прям в ближайших планах. Сейчас мы узнаём о каких-то изменениях входного потока данных:
Из бизнес-эвентов. Чаще всего мы заранее знаем о подключении новой больницы или региона от наших сейлов или продактов и можем вручную помониторить поток запросов. Очень важно помнить о том, что такие знания важно использовать и не полагаться только на автоматический мониторинг.
С помощью чайка-мониторинга. По аналогии с чайка-менеджментом и чайка-код-ревью чайка-мониторинг - это рандомный ручной мониторинг. Лень кодить или пилить таски?Мможно посмотреть на случайные исследования из потока и предсказания наших систем.
Out-of-Distribution & Anomaly Detection
Часто в нашу систему залетают снимки, которые являются явными аномалиями. В своих выступлениях я рассказывал про рентген-снимки ножниц и канистр, есть и менее необычные случаи - сильные артефакты, стенты, грудные импланты. Если подобных исследований не было в обучающей выборке, или просто по объективным причинам (плохое качество изображения) система не сможет сделать корректное предсказание, было бы здорово уметь это детектировать:
Во многих случаях лучше вообще не отдавать предсказание, чем отдавать мусор.
Это помогает искать необычные примеры, которые нужно изучить или доразметить.
Это помогает быстрее детектировать технические проблемы во входных данных - например, неверная настройка аппарата.
Как и в случае с дрифтами, OoD-детекция и anomaly detection - это слишком обширные темы, чтобы адекватно их покрыть в рамках поста про мониторинг. Одна из важных особенностей - это разнообразие типов аномалий. К примеру, подключение новой больницы с другим рентген-аппаратом, скорее всего, относится к классу clustered, а пациент с необычной анатомией - к global. Естественно, для детекции разных типов аномалий могут потребоваться разные методы.
На данный момент для детекции выбросов мы используем:
ML-методы - отдельная модель для определения качества изображения или обрезки целевого органа или uncertainty-методы, часто используемые для активного обучения (confidence branch, learning loss, энтропия предсказаний).
Экстремальные значения. Наши ML-системы логируют информацию о запросах (например, свойства картинок, промежуточные и финальные предсказания) в ElasticSearch, откуда их легко достать в те же pandas-датафреймы. Затем можно посмотреть глазами на исследования с экстремально низкими или высокими значениями различных показателей. В ближайшем будущем мы планируем также попробовать специальные библиотеки типа PyOD или той же alibi-detect.
Мониторинг качества
Пользователям наших систем и бизнесу не очень интересно слушать про какие-то аут-оф-дистрибьюшны, имадж кволити и дрифты - им нужны МЕТРИКИ. На темы тестирования и измерения качества ML-систем я уже делал пару докладов - раз и два, а в рамках разговора про мониторинг главной особенностью оценки является тот самый delayed target, про который я писал выше. У нас эта проблема решается следующим образом:
Если есть доступ к финальному текстовому заключению врача, либо его фидбек в формате "лайк-дизлайк" (human-in-the-loop формат), это позволяет без сильной задержки считать часть классификационных метрик.
Часть обработанных исследований сэмплируется и размечается нашими врачами уже более детально, что позволяет рассчитывать полный комплекс локализационных ML-метрик. В планах автоматизировать эту процедуру, чтоб публиковать динамику метрик на дашборд без нашего вмешательства.
Хочется в будущем добавить возможность одним кликом отправить на разметку конкретный спорный пример или подвыборку данных, а затем получить оповещение и метрику, когда разметка закончена.
В некоторых случаях (как в кредитном скоринге) "разметку" за нас осуществляет окружающий мир - по истечении срока займа человек возвращает его или нет. Это создаёт довольно большой лаг между предсказанием и расчётом метрик. В данном случае стоит обратить своё внимание на стабильность предсказаний (есть ли сильные сдвиги во времени или по сравнению с предыдущими версиями системы и бейзлайнами). Ещё можно попробовать оценить изменение метрики в зависимости от изменения распределения данных. Например, если на определённом сегменте данных на тестах модель показывает не очень хорошие результаты, и доля этого сегмента при этом растёт, то мы можем ожидать снижение метрики.
Работа с инцидентами
Напоследок поговорим про инциденты, ведь одна из основных задач системы мониторинга - как раз детекция инцидентов. Про общую практику выстраивания системы реагирования и разрешения можно почитать, например, здесь, а я попробую описать стадии инцидента с помощью ML-примеров:
Предварительная - что создало условия для инцидента, какие архитектурные и организационные решения? Анализ этой стадии предстоит провести на пост-мортеме. Может быть, мы раскатываем релизы новых моделей вручную без полного набора тестов или у нас слишком длинный релизный цикл из-за долгой разметки данных?
Триггер - основное событие, которое вызвало инцидент. Например, мы раскатили неверную версию модели, или модель начал использовать новый клиент с другим распределением данных.
Начало инцидента - момент, когда часть или все пользователи системы оказались затронуты инцидентом. Для ML-систем конкретный момент иногда определить очень сложно - например, в инцидентах, связанных с дрифтом данных.
Обнаружение - проблема обнаружена с помощью ручного/автоматического мониторинга или после жалобы от пользователей.
Поиск прямых причин - поиск триггера. Здесь нам весьма помогут логи и удобные инструменты для визуализации данных.
Краткосрочное решение - максимально быстро минимизируем ущерб для пользователей. Например, отключаем ML-систему, откатываемся на предыдущую версию или бейзлайн, релизим хот-фикс, оповещаем пользователей.
Долгосрочное решение - например, переобучаем модель на новых данных.
Пост-мортем - анализируем корневые причины инцидента и принимаем меры для недопущения или более скорого обнаружения подобных кейсов в будущем. К примеру, добавляем инструмент мониторинга, автоматический тест или изменяем наши процессы.
В зависимости от типа, причины и триггера инцидента в его разрешении могут принимать участие люди из разных команд - ML, бэк, инфраструктура и так далее. Для ML-систем очень важно не ограждать ML-команду разработки модели от процесса разрешения инцидентов, особенно если проблемы связаны с данными или работой модели.
Как вы уже, наверное, поняли из всего поста, главная особенность ML-инцидентов - их "тихость". Система продолжит работать как обычно, но будет отдавать неверные предсказания из-за неверного конфига, бага, дрифта данных, изменения внешнего источника данных. Дополнительно осложняет ситуацию, что это может затронуть только часть пользователей, и в стандартных метриках мы не увидим особой просадки. Часто в таких случаях мы узнаём о проблемах случайно (привет, чайка-мониторинг) или после жалоб от пользователей.
Дополнительные материалы
Кое-какие дополнительные материалы для изучения:
Видео Monitoring and explainability of models in production и статья-компаньон
Data Distribution Shifts and Monitoring от Chip Huyen
Если вы хотите узнать ещё больше об организации процессов ML-разработки, подписывайтесь на наш Телеграм-канал Варим ML
Monitoring от MadeWithML