MLOps

8 опасностей, угрожающих системам машинного обучения в производстве

На что следует обращать внимание при обслуживании систем машинного обучения

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

Затраты на обслуживание систем машинного обучения, то есть время, которое инженеры тратят на поддержание работоспособности и исправности систем, в некоторых случаях могут стать непомерными. В статье Google« Скрытый технический долг в системах машинного обучения » авторы указывают несколько причин, по которым это может иметь место, и предлагают способы смягчения некоторых проблем. Давайте подробнее рассмотрим некоторые из них.

1. Запутанность

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

Все компоненты системы машинного обучения взаимозависимы. Изменение чего-либо меняет все.

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

Допустим, вы обнаружили ошибку в конвейере предварительной обработки данных. Что-то явно, объективно неверное: например, две разные категории категориальной переменной рассматриваются как одна из-за ошибки в коде. Стоит ли это исправить? Что произойдет, если вы это сделаете? Модель внезапно получит это новое значение функции, которого она никогда не видела во время обучения. Это называется дрейфом данных . Дрейф может возникнуть естественным образом и обычно вызывает беспокойство, но здесь он вносится нами и нашим исправлением обработки данных. Как это повлияет на производительность модели? Добро пожаловать в мир CACE: никто не может сказать. Он может расти или падать, или оставаться неизменным.

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



2. Каскады коррекции

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

Однажды я работал над проблемой прогнозирования ежедневного количества заказов в некоторых ресторанах. После того, как модель была развернута, клиент попросил другую, чтобы спрогнозировать количество заказов на вынос / доставку. Заказы на доставку составляют небольшую часть от общего количества заказов, и они, как правило, сильно взаимосвязаны. Поскольку существующая модель для общих заказов работала очень хорошо, можно было подумать, что лучший или самый простой способ прогнозирования заказов на доставку - это построить простую модель, скажем, с двумя функциями: прогнозированием общего количества заказов и индикатором плохой погоды (когда холодно или дождливо, люди предпочитают заказывать еду домой, а не выходить на улицу). Это просто? Конечно. Будет ли это точно? Скорее всего так. Стоит ли нам это делать? Конечно нет!

В этом примере применяется только одно исправление, но представьте, что клиент просит затем спрогнозировать количество заказов на доставку стоимостью более 15 долларов. Заманчиво взять прогнозы заказов на доставку и изучить на их основе модель. Таким образом, небольшие исправления будут быстро вводиться каскадом. Почему это так опасно?

Построение новых моделей поверх существующих может привести к тупикам при улучшении.

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

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

3. Незаявленные потребители

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

Представьте, что в ваше хранилище S3 регулярно поступают новые данные в виде фрагментированных файлов. Возможно, вы захотите настроить задание cron, которое берет все новые файлы, появившиеся с момента его предыдущего запуска, очищает их и вставляет выходные данные в базу данных. Затем у вас будет процедура предварительной обработки данных, которая будет считывать данные из базы данных и выполнять вменение недостающих данных, проектирование функций и т. Д. И выгружать предварительно обработанные данные обратно в S3. Затем вам понадобится тренажер моделей, который считывает предварительно обработанные данные, обучает модель машинного обучения и где-то ее сохраняет. Последним шагом будет микросервис с API для обслуживания прогнозов модели.

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

Незаявленные потребители создают скрытые зависимости между, казалось бы, несвязанными системами.

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

4. Нестабильные зависимости данных.

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

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

Управление версиями выходных данных всех подсистем защищает вас от потребления мусора из-за нестабильной зависимости.

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

5. Недостаточно используемые зависимости данных

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

Существует четыре основных источника недостаточно используемых данных в системах машинного обучения:

  • Унаследованные функции, которые были полезны на ранних этапах разработки модели, но позже были сделаны избыточными и не были удалены по надзору.
  • Объединенные функции, то есть функции, которые каким-то образом связаны, влияние которых на производительность модели оценивалось для всего пакета. Некоторые из них могут и не понадобиться.
  • Ɛ-особенности, то есть особенности, которые дают очень небольшой выигрыш для модели. Их удаление может не сильно повредить модель и может быть лучшим решением, чем их сохранение и обслуживание.
  • Коррелированные признаки, которые различаются очень похожим образом, можно считать почти дубликатами. Если можно определить на основе знания предметной области, какое из них оказывает причинное влияние на цель, следует сохранить только это.

Сохраняйте в модели только те функции, которые способствуют ее хорошей производительности. Отбрось остальное.

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

6. Петли обратной связи

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

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

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

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

7. Код на клей

Большинство систем машинного обучения в значительной степени полагаются на пакеты с открытым исходным кодом, будь то библиотеки общего назначения для моделей обучения, такие как scikit-learn или TensorFlow, или пакеты для конкретных предметных областей для обработки данных. Это часто приводит к созданию тонны связующего кода, который поддерживает код, используемый для преобразования, повторного выражения, изменения формы, сжатия, распространения, перегруппировки или иной обработки данных, чтобы вводить и выводить их из всех этих пакеты.

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

Общие API-интерфейсы для внешних пакетов предотвращают использование связующего кода и делают систему более модульной.

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

8. Мертвые экспериментальные кодовые пути

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

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

Не экспериментируйте в производственном коде. Настройте отдельный фреймворк для экспериментов.

Лучше всего иметь отдельную платформу для экспериментов, чтобы экспериментировать с идеями и настраивать модели. Если это невозможно, регулярно просматривайте и удаляйте мертвые экспериментальные пути кода из рабочего кода. Каждый эксперимент должен заканчиваться либо внедрением нового решения в производство, либо отказом от него. Вы всегда можете вернуться к старому экспериментальному коду, если используете систему контроля версий, такую ​​как git. Нет необходимости хранить его в производственной базе кода.

Выводы

  1. Все компоненты системы машинного обучения взаимозависимы. Изменение чего-либо меняет все. Настройте мониторинг и оповещения, чтобы своевременно обнаруживать любые неожиданные изменения в поведении модели.
  2. Каскадирование моделей или построение новых моделей поверх существующих может привести к тупикам в улучшении. Лучше дополнить существующие модели, чтобы изучить новые задачи или построить отдельную модель для каждой задачи.
  3. Незаявленные потребители создают скрытые зависимости между, казалось бы, несвязанными системами. Всегда устанавливайте ограничения доступа, чтобы знать, какие системы от каких входов зависят.
  4. Всегда обновляйте выходные данные всех подсистем, чтобы защитить последующие системы от потребления мусора из-за нестабильной зависимости.
  5. Сохраняйте в модели только те функции, которые способствуют ее хорошей производительности. Отбрось остальное.
  6. Всегда следите за тем, чтобы на данные тренировки не влияла сама модель. Такие петли обратной связи мешают модели узнать о реальном мире.
  7. Общие API-интерфейсы для внешних пакетов предотвращают использование связующего кода и делают систему более модульной.
  8. Не экспериментируйте в производственном коде. Настройте отдельный фреймворк для экспериментов. Если это невозможно, регулярно просматривайте и удаляйте мертвые экспериментальные пути кода из рабочего кода.

Источники

Скалли, Д и Холт, Гэри и Головин, Дэниел и Давыдов, Юджин и Филлипс, Тодд и Эбнер, Дитмар и Чаудхари, Виней и Янг, Майкл и Деннисон, Дэн. (2015). Скрытый технический долг в системах машинного обучения. НИПС. 2494–2502. ["ССЫЛКА НА САЙТ"]

Спасибо за чтение!

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

Нужна консультация? Вы можете спросить меня о чем угодно или заказать меня со счетом 1: 1 здесь.

Вы также можете попробовать одну из других моих статей. Не можете выбрать? Выберите один из них: