newsmode
search
Меню
arrow_back Назад

A Practical Guide to Maintaining Machine Learning in Production

auto_awesomeКраткое саммари

Практическое руководство Eugene Yan по поддержке ML-систем в продакшене, продолжающее его пост о шести малоизвестных проблемах после развёртывания. Автор предлагает около 20 практик, сгруппированных по шести областям: валидация входных данных (схема, распределения, training-serving skew), мониторинг моделей при переобучении (отсев избыточных фич, валидация перед деплоем, shadow-релизы, SHAP/LIME для интерпретируемости), упрощение инженерии (MLflow, Docker-контейнеры, откаты), минимизация feedback loops и bias (позиционные фичи, обучение порогов из данных, периодический аудит выборки), организация команд (end-to-end data scientists по примеру Netflix и Stitch Fix, чёткие интерфейсы между ролями) и краудсорсинг обработки жалоб клиентов через простые UI. В заключение Yan выделяет три обязательные практики (валидация модели перед деплоем, валидация входных данных, простой откат) и три желательные (end-to-end data scientists, инвестиции в инструментарий типа Docker/MLflow/Airflow, инструменты для службы поддержки).

Практическое руководство по поддержке машинного обучения в продакшене

[ machinelearning engineering production ] · 16 мин чтения

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

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

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

С почти 20 рекомендациями всё это может показаться перегруженным. Не волнуйтесь — я выделю три главных must-have и good-to-have практики в конце поста.

Мы пройдёмся по практическим инструментам, которые помогут поддерживать машинное обучение в prod.

Мониторинг обучающих и обслуживающих данных на предмет загрязнения

Валидируйте входящие данные. «Данные — это новая нефть». «Мусор на входе — мусор на выходе». Эти клише подчёркивают: чистые входные данные критически важны для вашей системы. Вот как можно мониторить входящие данные, начиная с самого простого. Эти проверки выявляют ошибки сразу и экономят часы, которые могут уйти на починку пайплайна или очистку feature store.

Проверяйте входящие файлы (если получаете данные через CSV/TSV/JSON-дамп). Не предполагайте, что формат файла будет стабильным — его может создавать ручная задача.

Правильная ли схема? Все ли ожидаемые колонки на месте? Правильный ли формат? (например, парсится ли он как CSV?) Правильная ли кодировка? (например, соответствует ли она UTF-8?) Разумен ли объём данных? Не сильно ли он больше или меньше предыдущих дампов? Если файл зашифрован — не был ли он подменён, например, через man-in-the-middle атаку?

Проверьте общее распределение данных.

Сколько строк? Количество строк не должно скакать день ото дня. Есть ли null'ы в колонках, где их быть не должно? Не появился ли резкий рост (или падение) доли null'ов в какой-либо колонке? Есть ли дубли в первичных ключах (например, ID клиента, ID товара)? (В зависимости от того, как вы делаете join'ы, дубли могут раздуть количество строк)

Проверьте распределения фич.

Для непрерывных фич: разумны ли минимум и максимум? Например, возраст не должен быть ниже 0 или выше разумного порога. Не качаются ли базовые агрегаты (медиана, среднее, межквартильный размах) день ото дня? Для категориальных фич: постоянны ли уникальные значения? Если для пола ожидаются значения Male, Female и Undeclared, то не должно быть дополнительных вроде male или Married. Также — схожа ли доля каждого значения? Для timestamp-фич: тот же ли формат? Это всё ещё dd-mm-yyyy, или какой-то американский DBA изменил его на mm-dd-yyyy? Также разумны ли диапазоны дат? В большинстве случаев у вас не должно быть дат из XVIII века или из будущего.

Если хочется чего-то посерьёзнее — выполняйте статистические проверки

Постоянны ли корреляции между фичами и таргетами? Резкий рост указывает на утечку данных; постепенное снижение — на дрифт данных. Обнаруживайте изменения с помощью тестов однородности, ANOVA и анализа временных рядов. То же ли распределение по полу? Используйте chi-squared test, чтобы (не) подтвердить нулевую гипотезу. (Однако если данных много, статистическая значимость может встречаться часто.)

Вот недавняя статья о том, как Uber мониторит качество данных с помощью многомерных временных рядов и метода главных компонент.

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

В режиме обслуживания логируйте входные данные до и после обработки и выполняйте проверки.

Похожи ли serving-данные на training-данные? Если serving-данные более разреженные, то training-данные могут незаметно обогащаться (например, недостающая демографическая информация о клиенте импьютируется для ежедневных отчётов). Идентична ли обработка фич при обучении и обслуживании? Расхождения возникают, когда при обучении (batch) и обслуживании (отдельный запрос) используется разный код.

Минимизируйте training-serving skew, обучая модель на обслуживаемых фичах. Если вы логируете данные и фичи во время обслуживания, рассмотрите их использование как обучающих данных. Уточним: используйте исторически обработанные фичи (полученные при обслуживании) для обучения модели. Это гарантирует, что модель учится на тех же данных, которые она будет получать и предсказывать в продакшене — никакого training-serving skew.

В качестве бонуса это упрощает и сокращает обучающий пайплайн. Например, прежние ETL-задачи для сшивания кликстримов под training-данные больше не нужны. Просто обучайтесь на обслуживаемых фичах.

Мониторинг моделей на сбои при переобучении

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

Permutation importance — дешёвый способ это сделать: мы просто перемешиваем каждую колонку и оцениваем изменение качества модели. Альтернатива, drop-column importance, итеративно отбрасывает каждую колонку, переобучает и оценивает модель — это дороже, поскольку на каждой итерации модель переобучается, зато точнее.

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

Например, в ранжировщике товаров: как модель ведёт себя на валидационном сете по обычным метрикам ранжирования (AUC, NDCG, recall@k)? И превосходит ли она наивный baseline (например, сортировку товаров по вчерашним продажам)?

Если модель не проходит валидационные проверки, ваш пайплайн должен сломаться и не выпустить модель. Лучше иметь устаревшую модель в продакшене, чем неисправную. Если модель проходит проверки — переобучите её на полном датасете и выкатывайте.

Можно копнуть глубже, сравнив предсказания предыдущей и текущей модели. Если предыдущая модель ранжирует товар на 10 000-м месте, а текущая — на 1-м, что-то не так. Это применимо к разным типам задач ML: ранжирование (разница в ранге), классификация (разница в вероятности), регрессия (разница в численном предсказании).

Делайте shadow-релиз модели. Это можно сделать так: запустите модель в продакшене, пропустите через неё часть боевого трафика и логируйте результаты.

Какова латентность, стабильность и частота ошибок — это покажет, готова ли модель к продакшену (особенно важно при больших изменениях, например, переходе с деревьев решений на нейросети). Как боевые предсказания выглядят по метрикам (recall, precision)? Больше ли false negatives или false positives?

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

Мониторьте здоровье модели. Первый шаг — проверка устаревания модели. Когда вы в последний раз обновляли продакшен-модель?

Затем копайте глубже — проверяйте модель на смещения или некорректное обучение. Сейчас это проще благодаря инструментам интерпретируемости моделей, таким как LIME и SHAP. Если это модель одобрения кредитов — есть ли смещения против определённых полов, возрастных групп или этничностей? (Хотя я бы поспорил, что таких данных вообще не должно быть в расчёте.) Как меняется важность ключевых фич день ото дня? Если важность фичи резко выросла, это может указывать на утечку данных.

Этот SHAP summary plot показывает, что sex, passenger class и age были самыми важными фичами.

Мета-анализ offline-метрик против online-метрик. Насколько ваши offline-метрики коррелируют с online-улучшениями? Приводит ли рост AUC или NDCG при офлайн-оценке к росту CTR или конверсии онлайн?

Например, Etsy обнаружили, что AUC — хорошая метрика для оценки CTR, а в этой статье на KDD были обнаружены большие расхождения между offline- и online-качеством моделей из-за метрик оценки.

Мы принимаем множество решений на основе offline-метрик — например, при экспериментах и валидации модели перед релизом. Инвестиции в поиск надёжных offline-метрик будут окупаться непрерывно.

(К слову: при измерении online-качества фокусируйтесь на том, на что ваша система может напрямую влиять — клики, покупки, bounce rate. Косвенные метрики (например, retention, daily active users) рассматривайте только после того, как разберётесь с прямыми. Избегайте отложенных и общих метрик (удовлетворённость пользователей, рост трафика) — у них может быть много мешающих факторов.)

Упрощение инженерии для снижения операционной нагрузки

Логируйте детали конфигурации. Это касается как экспериментальных, так и продакшен-воркфлоу. Гиперпараметры модели? Логируйте. Порог конвертации вероятностей в бинарные значения? Логируйте. Период исторических обучающих данных? Логируйте. Чёрт возьми, логируйте даже хэш коммита.

Я считаю MLflow лёгкой библиотекой для этой цели. Небольшим объёмом дополнительного кода вы сможете логировать конфигурации, коммиты кода и результаты (метрики оценки, графики, sample CSV). Всё доступно в централизованном дашборде. Вот предыдущий пост об этом.

Обслуживайте модели через контейнеры. Или VM, если вам так больше нравится. Цель — устранить различия между средами обучения и обслуживания. Никаких больше «но у меня на машине работает…».

Docker сейчас де-факто стал контейнерной технологией. Он обеспечивает принцип «собери один раз — запусти везде» и хорошо масштабируется горизонтально. Хорошие статьи про Docker для деплоя машинного обучения здесь и здесь.

Заложите возможность отката. Если по какой-то причине обновлённая модель прошла проверки данных и валидацию, но плохо ведёт себя после деплоя, вы захотите быстро откатиться. Эта возможность отката — ваш страховой полис.

Если вы обслуживаете модели через Docker-контейнеры — это просто: возьмите предыдущий рабочий контейнер из репозитория и задеплойте его взамен неисправной модели. Храните рабочие образы предыдущих деплоев в репозитории — семь или больше, если позволяют ресурсы.

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

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

Когда Instagram купили в 2012-м, у них была команда из 13 человек, обслуживавшая десятки миллионов пользователей. Они масштабировались и удерживали низкую операционную нагрузку на инженера, придерживаясь проверенных технологий вместо новых модных. Пока другие стартапы внедряли модные NoSQL-хранилища и мучились с ними, Instagram оставался поджарым с проверенными в боях и понятными PostgreSQL и Redis.

Для ML-систем начинайте с простых, интерпретируемых моделей, минимального набора фич и без ансамблей. Обновляйте модель с приемлемой частотой (например, еженедельно или ежедневно) — не бросайтесь сразу делать real-time обновления. Начните с общей модели, работающей для большинства пользователей, прежде чем переходить к персонализации.

Полезные практики для минимизации контуров обратной связи и смещений

Используйте позиционные фичи, чтобы избежать контуров обратной связи. Этот изящный приём устраняет значительную часть смещения, при котором взаимодействия пользователя зависят от позиции элемента.

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

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

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

Например, каковы ваши требования продакшена? Нужен ли recall 95%? Или минимум false positives? Или хороший баланс? Оцените, какие пороги (например, в Python — [x/100 for x in range(1, 100, 1)]) удовлетворяют этим требованиям, и используйте их в продакшене.

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

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

Что нужно сделать — взять небольшую выборку отзывов (например, 1–5%) и попросить людей их просмотреть. Есть ли очевидные ошибки или появляются ли новые виды мошенничества? Есть ли общая закономерность? Найдя такие паттерны ошибок, можно по логике или регулярным выражениям отобрать неправильно классифицированные отзывы и переразметить их. После этого можно переразметить другие ошибки через active learning.

Структурирование команд для итераций и инноваций

Пусть data scientists работают end-to-end. Признаю, это непопулярное мнение — большинство технических команд движутся к разделению труда. Но выслушайте меня.

Универсальный (или, если хотите, full-stack) data scientist может выполнять разные функции: общаться со стейкхолдерами, чтобы определить правильную проблему, разрабатывать прототипы и продакшен-код, деплоить и измерять. Это ускоряет обучение, инновации и итерации. Это также поощряет личную ответственность и снижает «размывание ответственности».

У Netflix есть full-cycle разработчики, и это хорошо работает. Stitch Fix начинает с модели full-stack data scientist и переходит к специализации только при необходимости.

Оговорка: Эта практика предполагает наличие хорошего тулинга и инфраструктурной поддержки. Spark-инстансы должны легко поднимать, автоматическое failover и rollback — настроены, A/B-тесты должны запускаться легко. С этим ваши универсальные data scientists могут сосредоточиться на разработке ML-систем.

Если не можете иметь end-to-end data scientists — имейте end-to-end команды. Я понимаю — end-to-end data scientists редки (хотя я бы поспорил, что они не «единороги»; их можно как найти, так и вырастить). Если так — стройте end-to-end команды.

Посадите PM, data scientists и инженеров рядом (после того как пандемия утихнет). Убедитесь, что у команд общие цели быстрых итераций и поставки. Постройте процессы, минимизирующие издержки координации и коммуникации (например, быстрые неформальные обсуждения вместо запланированных митингов).

Определите чёткие интерфейсы между ролями. Если разные команды владеют разными частями ML-процесса, убедитесь, что люди не «перебрасывают код через стену». Установите чёткие ожидания и интерфейсы для поставляемых результатов.

Например, поставка data engineers — это своевременные обновления в БД; это входной интерфейс для data scientists. Data scientists, в свою очередь, строят свои ML-модели и поставляют Docker-контейнер с API model.predict() — это их выходной интерфейс.

Краудсорсинг обработки клиентских жалоб

Облегчите другим возможность действовать. Это касается агентов клиентской поддержки, account-менеджеров и регуляторов. Этого можно добиться через простые интерфейсы (UI), куда можно ввести ID товара и клиента; эти данные затем хранятся в БД.

Клиенты жалуются на неуместные товары в рекомендациях или поиске? Дайте агентам возможность блокировать ID товара через UI. У клиента есть опасения о приватности? Снова — добавляйте его ID через UI. Account-менеджер хочет повысить видимость нового товара? Добавьте ID товара через UI, чтобы временно его бустить (это помогает и с cold-start товарами). А ещё лучше — постройте новый рекламный бизнес и отдайте буст на краудсорсинг продавцам.

Помогите операционному персоналу понимать выводы модели. Когда у ML-решений есть последствия, люди захотят объяснений. Помогите вашим фронтлайн-агентам понимать и объяснять решения клиентам. Я считаю SHAP force plots полезными для этого. LIME тоже хорошая альтернатива.

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

Этот SHAP force plot показывает, что быть female и быть молодой по age повышало выживаемость.

Некоторые (важные) практики, которые я не обсудил

Есть несколько ключевых пунктов, которые я опустил. Они хорошо освещены в других источниках; тем не менее, я подумал, что стоит их кратко упомянуть.

Стандартные инженерные практики: сюда входят code reviews, ваш набор тестов (юнит-тесты, интеграционные, инфраструктурные) и нормальная документация. Я бы расширил это и до методологических ревью. Корректна ли SQL-логика? Был ли train-validation split сделан правильно (без утечек данных)? A/B (и bandit) тестирование: они де-факто для релиза онлайн-продуктов и фич. Не пропускайте их (если только не уверены, что делаете). Усталость от уведомлений: (я не очень понимал, куда это вписать). При нормальном мониторинге команда может начать получать много алертов. Слишком много — и их перестанут замечать, что сводит мониторинг на нет. Подкручивайте баланс precision-recall — приоритизируйте алерты с высокой precision и ценностью (т.е. критически влияющие на клиентский опыт).

Это много; как расставить приоритеты?

Я не планировал делать пост таким перегруженным. Давайте подведу итог тремя главными must-have и good-to-have практиками (оговорка: на это повлиял мой стартап-опыт, и они, скорее всего, субъективны).

ИМХО, это must-have для большинства команд:

Валидация модели перед деплоем: моя любимая практика. Одной проверкой вы устраняете большинство сбоев ML до деплоя. Валидация входных данных: базовые проверки идут далеко — количество строк, наличие ошибочных дубликатов, доля null'ов. Затем — проверка диапазонов числовых и date-колонок, а также уникальных значений категориальных. Простой откат: эта страховка позволяет команде быстро итерироваться и деплоить, прокладывая путь к CI/CD. Деплой сломал prod посреди ночи? Без проблем — откатили и чините утром.

А вот три good-to-have:

Пусть data scientists работают end-to-end: по моему опыту, это сильно сокращает время разработки, ускоряет обучение и инновации и создаёт культуру ответственности. Инвестируйте в data science тулинг: иметь шаблонные Docker-контейнеры для разработки и деплоя ML-моделей. Поднять централизованный MLflow-сервер для шаринга и ревью результатов. Airflow отлично подходит для планирования задач с зависимостями. Инвестируйте в тулинг клиентской поддержки: стройте инструменты, которые дают агентам поддержки возможность решать самые частые задачи (например, блокировка товаров, объяснение исходов). Это сокращает количество ad hoc запросов и тушения пожаров вашей командой.

Источники

Спасибо Yang Xinyi, Marianne Tan и Stew Fortier за прочтение черновиков.

Если это было полезно — пожалуйста, цитируйте этот текст так:

Yan, Ziyou. (May 2020). A Practical Guide to Maintaining Machine Learning in Production. eugeneyan.com. https://eugeneyan.com/writing/practical-guide-to-maintaining-machine-learning/.

или

@article{yan2020maintain, title = {A Practical Guide to Maintaining Machine Learning in Production}, author = {Yan, Ziyou}, journal = {eugeneyan.com}, year = {2020}, month = {May}, url = {https://eugeneyan.com/writing/practical-guide-to-maintaining-machine-learning/} }



Присоединяйтесь к 11 800+ читателям, получающим обновления о машинном обучении, RecSys, LLM и инженерии.