6 Little-Known Challenges After Deploying Machine Learning
Юджин Ян описывает шесть малоизвестных проблем, которые возникают уже после деплоя ML-системы, а не до него. Среди них: незаметные изменения схем данных и утечки данных (например, когда поле hospitalization_days перезаписывается с оценочного значения на фактическое), нежелательные взаимодействия между моделями, хаотичная инфраструктура и кодовая база с «магическими» числами и множеством языков, дрейф данных и атаки злоумышленников в реальном мире, организационные конфликты приоритетов и размытая ответственность между командами, а также необходимость поддержки пользователей. Автор приводит реальные примеры — от провала Google Photos с гориллами 2015 года до петель обратной связи в прогнозировании запасов и ранжировании, — и упоминает требования вроде GDPR. Это первая часть; во второй обещан разбор способов решения этих проблем.
6 малоизвестных проблем, возникающих после деплоя машинного обучения
[ machinelearning engineering production ] · чтение на 14 мин
Деплой машинного обучения — это сложно.
Так я думал. А потом понял, что после деплоя становится ещё сложнее.
Да, разработка и деплой по-прежнему остаются для меня вызовом. Проведение ML-экспериментов, написание production-кода, интеграция с инфраструктурой и инженерными системами; ах да, не забудьте про юнит-тесты. Всё это непросто. К счастью, это становится менее болезненным благодаря более удобным инструментам (например, SageMaker, AI Platform, Azure ML) и open-source-библиотекам.
Однако о том, что происходит после деплоя, написано немного. Есть хорошие академические статьи (ссылки ниже), но они менее доступны для непосвящённых. Чтобы это исправить, я поделюсь своим опытом на реальных примерах. Это работа в процессе и не исчерпывающий список, но я надеюсь, что она повысит осведомлённость о жизни ML после деплоя.
Я буду разбирать это снизу вверх: начиная с данных, затем модели и инженерия, а затем аспекты, внешние по отношению к системе (то есть реальный мир, структура организации, пользователи).
Схемы меняются, когда не должны (и наоборот) Нежелательные взаимодействия моделей (внутренние и внешние) Инфраструктура и кодовая база захламлены (читай: хаотичны) Смещение реального мира и приход злоумышленников Организационные проблемы — столкновение приоритетов; размытая ответственность С пользователями приходится оказывать клиентскую поддержку
Можете смело перематывать вперёд. В следующем посте мы обсудим, как справляться с этими проблемами.
Продолжение: A Practical Guide to Maintaining Machine Learning
Как только вы развернули систему в prod, она не имеет права ломаться. В отличие от dev.
1: Схемы меняются, когда не должны (и наоборот)
ML-системы зависят от данных. Нестабильные данные на входе скажутся на производительности вашей системы. Часть таких проблем — это просто раздражающие сбои или задержки, требующие ручного перезапуска пайплайна. Другие наносят больший ущерб и труднее обнаруживаются.
Вот пример: представьте, что у вас есть колонка gender с двумя значениями, male и female. Чтобы быть политкорректнее, фронтенд добавляет в выпадающий список Transgender, Other и Prefer not to say. Заодно меняют male -> Male и female -> Female. Теперь в production-базе появились эти новые — ранее невиданные — значения.
Ваши пайплайны данных работают без нареканий. Ваши кодировщики признаков присваивают этим неизвестным значениям null. Ваши модели устойчивы к тому, что вся колонка gender становится null, и не ломаются. Однако онлайн-производительность вашей системы деградирует, особенно в сценариях, где пол важен (например, сегментация клиентов, персонализированные рекомендатели и т. д.)
(Неожиданные) потребители пайплайна могут навязывать ограничения. Ваши пайплайны хранят промежуточно обработанные данные в таблицах, которые вы делаете доступными всей организации. По мере итераций вы добавляете колонки данных, улучшающие производительность ML, и удаляете избыточные. Однажды вы получаете гневное письмо с вопросом, почему (удалённая) колонка больше недоступна, — оно от ранее неизвестного потребителя ваших данных.
Быстрое краткосрочное решение — восстановить эту колонку и успокоить разгневанного потребителя. Однако это добавляет дополнительное время вычислений и затраты в ваш пайплайн — без всякой пользы для ваших систем! Теперь в ежедневном обновлении вашей модели возникают задержки, а вашей команде приходится нести дополнительные расходы.
В масштабе картины ваши пайплайны (и ML-система) теперь переплетены. Потребители ваших данных навязали ограничения — у вас больше нет полной автономии в обновлении пайплайнов. Более того, все системы, опирающиеся на ваш пайплайн, включая вашу, оказываются застрявшими в плохом общем локальном оптимуме.
«All your (data)base are belong to us» — Eugene Yan
Появляются утечки данных. Утечка данных происходит, когда некая форма метки (то есть целевой переменной) «просачивается» в данные признаков. Это приводит к искусственно хорошим результатам при офлайн-оценке, но плохой производительности в боевой среде.
Предположим, вы строите модель для оценки больничного счёта пациента. Пациенты запрашивают оценку в момент поступления (или когда сравнивают варианты). Ключевой признак вашей модели — предполагаемое hospitalization_days (которое указывает принимающий врач); оно хранится в production-базе. Однажды кто-то решает обновить колонку hospitalization_days фактическим числом дней госпитализации.
Теперь ваша модель обучается на фактической длительности пребывания, которая никогда не была бы доступна в момент поступления, — это утечка данных. Во время обучения модель присваивает (фактическому) hospitalization_days высокий вес, переобучается и хорошо показывает себя в офлайн-оценке. Во время работы она продолжает придавать большой вес (предполагаемому) hospitalization_days, что приводит к низкой точности в production. Такие утечки данных и расхождение между обучением и инференсом (training-serving skew) бывает трудно обнаружить.
2: Нежелательные взаимодействия моделей (внутренние и внешние)
Слишком много признаков усложняет сопровождение модели. После запуска прототипа лёгкий путь к улучшению производительности — добавить больше признаков; это обычно повышает точность. Мы редко переоцениваем, все ли признаки по-прежнему полезны. Со временем многие признаки становятся избыточными, с добавлением других признаков (или без него).
Сопровождение пайплайнов данных для этих избыточных признаков может обходиться дорого. Эти избыточности также добавляют ненужные зависимости и сложность вашей модели, затрудняя её сопровождение и доработку.
Другие модели влияют на производительность вашей модели. Часто ваша модель показывается клиентам вместе с несколькими другими моделями.
Возьмём, к примеру, главную страницу приложения электронной коммерции. Ваш рекомендатель — один из множества виджетов на ней. Есть ещё и общий ранжировщик виджетов, который определяет, какому виджету достаётся больше видимости. Виджеты, повышающие определённые метрики (например, кликабельность, конверсию, выручку), отображаются ближе к верху.
В последнее время производительность вашего рекомендателя ухудшилась. Почему? Деградирует ли он сам по себе? Другие рекомендатели работают лучше и оттягивают вовлечённость? Или изменился алгоритм ранжировщика виджетов? Эти эффекты взаимодействия затрудняют понимание онлайн-производительности модели и её улучшение.
3: Инфраструктура и кодовая база захламлены (читай: хаотичны)
В ML-системах часто плохие инженерные практики. Признаюсь честно: если я строю ML-систему от начала до конца, мои практики кодирования будут не настолько «best practice», как у моих собратьев по оружию из инженерии.
Плохие инженерные практики «пахнут» по-разному. Glue-код (склеивающий код) — один из таких запахов: он выполняет разовые задачи вроде выгрузки данных из S3 в вашу базу или наоборот. Моя кодовая база также пахнет несколькими языками программирования. Python — де-факто стандарт для машинного обучения, а Scala (и Spark) — для обработки больших данных. Тут и там разбросаны кусочки SQL. А ещё есть легаси UI-инструменты, слишком плотно вплетённые внутрь.
Эти разные языки и кодовые базы требуют разной инфраструктуры и наборов навыков для поддержки. В долгосрочной перспективе их становится дорого сопровождать и улучшать. С другой стороны, попытка переписать всё на Java или другом enterprise-языке — заведомо безнадёжна. Я всё ещё пытаюсь нащупать этот баланс.
Конфигурационный код часто захламлён или вовсе отсутствует. По мере разработки ML-системы вы обнаруживаете необходимость добавлять «магические» числа. Какие тут примеры? threshold (порог) для преобразования вероятностей в единицы и нули в классификации. Число days исторических данных, на которых обучается модель. И, конечно, все оптимизированные гиперпараметры (params) машинного обучения.
В худшем случае эти магические числа разбросаны по production-коду. Небольшое улучшение — вынести их в конфигурационные файлы. Или же вы можете использовать MLflow для управления ими. По мере роста вашей ML-системы конфигурационный код разрастается больше, чем сам ML-код.
Как управлять этими объёмными конфигами? Как вводить в них нового человека? Когда мы вносим изменения, как убедиться, что они корректны (и не сломают prod)? Это более серьёзный вызов, чем кажется.
«Данные созревают как вино, приложения — как рыба» — James Governor
Инфраструктурные окружения не сотрудничают. Вы попробовали новую ML-библиотеку, и результаты офлайн-оценки потрясающие. К тому же новый релиз Spark 2.x устраняет ключевую боль, и вы хотите начать им пользоваться как можно скорее. (Например, до Spark 2.3 сырые вероятности предсказаний были недоступны для некоторых реализаций моделей.)
К сожалению, ваша инфраструктурная команда не может удовлетворить ваши запросы. Чтобы запустить вашу новую ML-библиотеку в prod, им нужно обновить API-серверы. Чтобы использовать Spark 2.x, им нужно дождаться, пока их облачный/Hadoop-дистрибутив начнёт его поддерживать. И обновить кластер. И провести регрессионное тестирование. На это уйдёт пара дней (читай: недель).
Но, эй, это не так уж плохо. Могло быть и хуже. Вы могли бы обновить код, задеплоить его и сломать всё на день-два. Вы могли вызвать сбой уровня P0, при котором уведомляют CEO и все бросают всё ради отката.
Короче говоря, как только ваша система в production, вам придётся полагаться на окружение prod и больше нельзя ковбойствовать в dev.
4: Смещение реального мира и приход злоумышленников
Данные реального мира не сотрудничают. Они меняются. Сравните это с вашей ML-моделью. После обучения ML-модели статичны (если только их не обновляют через онлайн-обучение). Они усваивают (фиксированные) предположения о мире — на основе обучающих данных — и не меняют их.
Что происходит, когда эти предположения перестают выполняться? Дрейф данных. Он возникает, когда ваши входные данные (во время предсказания) со временем всё сильнее отличаются от обучающих. Данные реального мира динамичны, а ваша модель статична.
Мы уже видели пример структурного дрейфа (например, изменение схемы); он произошёл, когда обновилась колонка gender. Пример с hospitalization_days, где значение меняется с предполагаемого на фактическое, демонстрирует семантический дрейф — смысл данных изменился, а структура (то есть схема) нет.
В безобидных случаях производительность модели деградирует и CTR немного падает. Куда более разрушительно, если это ведёт к потере денег или, того хуже, жизней.
Петли обратной связи могут запустить порочный круг. В production ваша модель влияет на реальный мир, который влияет на вашу модель, которая влияет на реальный мир… вы поняли, о чём я. (Да, Minority Report)
Вот пример: модель прогнозирования предсказывает, сколько запасов сети супермаркетов следует держать каждую неделю. Модель штрафуется за избыточные запасы, поэтому она стабильно занижает прогноз. В результате магазины часто продают спрогнозированный объём и оказываются без товара. ML-модель учится на (снижающихся) данных о продажах и продолжает занижать. Но на бумаге она выглядит очень точной.
Ещё пример. Рассмотрим систему ранжирования. Товары, которые сегодня ранжируются высоко, получают высокую вовлечённость. Поскольку у них была высокая вовлечённость, завтра они продолжают ранжироваться высоко. Из-за этого новым товарам почти невозможно получить трафик. Такие петли обратной связи трудно обнаружить и контролировать при обучении модели.
Противники (академический термин для злоумышленников). Противники будут прощупывать и пытаться обмануть вашу модель, если это выгодно. В системе ранжирования продавцы будут пытаться вывести контрафактные или некачественные товары в топ, доходя даже до скупки собственных товаров. Фишеры пытаются обойти детекторы спама в почте. Мошенники пытаются перехитрить системы противодействия отмыванию денег.
Эти противники будут реверс-инжинирить ваши модели и отслеживать, какие из их попыток сработали. Прощупывая систему, они также (намеренно) подсовывают данные, на которых ваша модель будет обучаться. В результате обучающие данные загрязняются, и производительность в production падает.
5: Организационные проблемы — столкновение приоритетов; размытая ответственность
Подключается больше команд (с конфликтующими приоритетами). Как часть data science вы хотите внедрять инновации и развёртывать самое производительное (и, вероятно, наиболее затратное по вычислениям) машинное обучение. Инженерия хочет стабильности и меньшей стоимости сопровождения. Бизнес хочет результатов быстро (читай: сегодня, а в идеале — вчера), ограничивая время и ресурсы, доступные для долгосрочных инноваций (лёгкое преувеличение).
Вам придётся учитывать общую картину, итерируя над вашей ML-системой, которая теперь в prod. Это означает отказ от самой навороченной, самой производительной модели, потому что она требует в 10 раз больше вычислений ради 0,5% прироста. Это означает выпуск за 2–3 месяца вместо 2–3 лет. Балансировать эти разные приоритеты стейкхолдеров в вашем роадмапе будет непросто.
Теперь на каждое совещание по обновлению требуется больше людей. Когда кто-то сообщал о баге в исходном production-прототипе, вы в одиночку исправляли его за день. Теперь, чтобы исправить баг или добавить новую функцию, вам нужно совещание с продакт-менеджером, дата-инженером, инженером-программистом и QA — и если повезёт, это совещание состоится в течение нескольких дней.
В большинстве зрелых организаций работа разделена между специализированными ролями. Рассмотрим это в контексте машинного обучения. Чтобы добавить колонки входных данных:
Дата-инженеру нужно обновить пайплайны данных и feature store. Затем дата-сайентист обновляет ML-код и запускает офлайн-оценку. Далее инженер «продакшенизирует» код (нельзя же позволить дата-сайентистам сломать prod!). Наконец, специалист по контролю качества (QA) запускает набор тестов и стресс-тесты.
Это разделение труда приводит к росту координационных издержек и времени ожидания, поскольку задачи передаются от одного человека к другому. Результат? Возросшее трение, сниженная скорость разработки и деплоя. Из-за этого быстро итерировать после выхода в production становится непросто.
«То, что один программист может сделать за один месяц, два программиста сделают за два месяца» — Frederick P. Brooks
6: С пользователями приходится оказывать клиентскую поддержку
Пользователи заметят недостатки и потребуют их исправить. Поскольку у вашего продукта так много пользователей, недостатки машинного обучения быстро становятся очевидными. Большинство приложений машинного обучения приближаются к человеческому уровню способностей — и ошибок — но в гораздо большем масштабе. Всё может рвануть быстро.
Один печально известный пример — «горилла» от Google. В 2015 году фотоклассификатор Google по ошибке пометил чернокожих людей как горилл. Два года спустя Google так и не нашёл удовлетворительного решения — GG. Я сталкивался с похожими инцидентами, когда клиентам на страницах товаров рекомендовали секс-игрушки (не спрашивайте как, модель обучена на данных о поведении пользователей). Это вызывало беспокойство, особенно в консервативных мусульманских странах, особенно у родителей.
При миллионах пользователей (завидно низкие) 0,001% ошибок затрагивают тысячи. Вы получите подарок в виде обратной связи и ожидание быстрого исправления.
Людям нужно знать почему. Сначала оговорюсь: в большинстве сценариев этого, скорее всего, не случится. Прогнозы погоды, рекомендации фильмов, прокладка маршрутов — мы пользуемся ими ежедневно и не ставим их под сомнение. Мы привыкаем к ML-приложениям тем сильнее, чем чаще ими пользуемся, особенно если польза высока, а последствия незначительны.
Однако есть случаи, когда нам нужно объяснение.
Представьте, что вы приходите в больницу за стандартной процедурой на сердечном клапане. Ваш google-jitsu подсказывает, что это обычно стоит 60 тысяч. Однако (непрозрачный) алгоритм больницы оценивает счёт втрое выше. Стоп, погодите, почему?! Модель предвидит осложнения? Дело в моём возрасте или истории болезни? В том, что я курю?
Люди не могут не волноваться, даже если это всего лишь оценка и она никак не влияет на итоговый счёт. Сравните это с алгоритмами машинного обучения, которые действительно влияют на жизни людей, — например, отказ в кредите или страховке. В таких случаях потребность знать почему гораздо сильнее, и наши ML-системы должны уметь это объяснять.
Людям важна приватность и то, как используются их данные. Чем больше данных у ML-систем, тем лучше они обучаются и тем лучше обслуживают. С другой стороны, люди хотят контролировать свои данные. Они не хотят, чтобы их персональные данные использовались для дискриминации или таргетинга (например, рекламой). Они не хотят, чтобы неловкие подробности были в сети.
Это приводит к регуляциям, таким как Общий регламент по защите данных ЕС (GDPR). Он призван дать людям контроль над их персональными данными и влияет на работу многих отраслей, особенно социальных сетей и онлайн-рекламы. Если среди ваших пользователей есть жители ЕС, вы тоже столкнётесь с этим вызовом в своих ML-операциях.
Куда двигаться дальше?
В начале этого поста вы, вероятно, думали одно из следующего:
«Деплой был самой сложной частью». «Деплой — это только начало».
К какой бы группе вы ни принадлежали, надеюсь, это повысило вашу осведомлённость о проблемах машинного обучения после деплоя. Я провёл годы над этими вопросами и (к счастью) нашёл несколько простых способов их исправить — или, во многих случаях, предотвратить. Подробнее в следующем посте.
Ссылки
Machine Learning: The High Interest Credit Card of Technical Debt Rules of Machine Learning: Best Practices for ML Engineering Hidden Technical Debt in Machine Learning Systems On Challenges in Machine Learning Model Management Data Lifecycle Challenges in Production Machine Learning: A Survey Continuous Delivery for Machine Learning Why Machine Learning Models Degrade In Production Versioning for End-to-End Machine Learning Pipelines
Спасибо Yang Xinyi, Stew Fortier, Richie Bonilla и Joel Christiansen за прочтение черновиков.
Если это оказалось полезным, пожалуйста, цитируйте эту статью так:
Yan, Ziyou. (May 2020). 6 Little-Known Challenges After Deploying Machine Learning. eugeneyan.com. https://eugeneyan.com/writing/challenges-after-deploying-machine-learning/.
или
@article{yan2020challenge, title = {6 Little-Known Challenges After Deploying Machine Learning}, author = {Yan, Ziyou}, journal = {eugeneyan.com}, year = {2020}, month = {May}, url = {https://eugeneyan.com/writing/challenges-after-deploying-machine-learning/} }
Присоединяйтесь к 11 800+ читателям, получающим обновления о машинном обучении, RecSys, LLM и инженерии.