💡 На этот пост сильно повлияла статья Скрытый технический долг систем машинного обучения, написанная Google Inc. в 2016 году. Я настоятельно рекомендую вам прочитать оригинальную статью. Я просто перефразирую и пытаюсь добавить полезные пояснения.

Технический долг — это метафора, обозначающая дополнительные затраты, возникающие в долгосрочной перспективе, с которыми сталкивается команда, и результатом которых является выбор простых и быстрых вариантов доставки вместо оптимальной разработки или пропуска важных моментов в действии. Впервые этот термин упомянул Уорд Каннингем в 1992. Каннингем описал аналогию как;

Отправка кода в первый раз — это как влезть в долги. Небольшой долг ускоряет разработку, если он быстро возвращается путем перезаписи.

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

Опасно думать, что быстрые победы в построении сложных систем прогнозирования на основе ML даются бесплатно.

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

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

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

Сложные модели стирают границы

Фридрих Хайек описал абстракцию так: «Это средство справиться со сложностью конкретного, с которым наш разум не в состоянии полностью справиться». в 1973 году абстракция также помогает нам создавать более удобные для сопровождения коды с точки зрения улучшений и исправлений. Несмотря на то, что строгие абстрактные зависимости полезны для согласованной производительности программных систем, они не подходят для систем машинного обучения.

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

запутанность

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

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

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

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

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

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

Незаявленный потребитель

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

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

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

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

Зависимости от данных стоят больше, чем зависимости от кода

Долг зависимостей считается ключевым фактором сложности кода и технического долга в классических настройках разработки программного обеспечения.

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

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

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

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

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

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

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

С недоиспользованными зависимостями можно справиться, используя оценки с исключением одной функции (LOFO). Этот подход экспериментально находит релевантные и полезные функции и выбирает их. Для подхода LOFO существует модуль Python: lofo-importance.

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

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

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

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

Антипаттерны ML-системы

Лишь небольшая часть кода во многих системах машинного обучения фактически посвящена обучению или прогнозированию.

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

Клей Код

Склеивающий код — это тип блока кода, который служит связующим звеном между различным программным обеспечением или библиотеками/пакетами. С точки зрения машинного обучения связующий код используется для соединения моделей, конвейеров ETL и других частей системы. Несмотря на то, что это выглядит полезным для систем ML, это приводит к огромному количеству вспомогательных кодов, которые могут заблокировать систему из-за зависимостей используемого пакета. Использование этих универсальных пакетов также может помешать нам вносить улучшения, потому что нам будет сложнее вносить небольшие изменения без учета ограничений пакета. Одним из полезных решений является включение пакетов черного ящика в API таким образом, чтобы мы могли повторно использовать одни и те же функции и настраивать их для наших ограниченных потребностей.

Зрелая система может в конечном итоге состоять из (максимум) 5% кода машинного обучения и (как минимум) 95% связующего кода, может быть дешевле создать чистое нативное решение, а не повторно использовать общий пакет.

Трубопроводные джунгли

Разработка систем как конвейеров выгодна для развертывания от начала до конца. Конвейерные джунгли обычно появляются в конвейерах ETL и при подготовке данных. Тестирование этих конвейеров требует дорогостоящих сквозных интеграционных тестов. С этими джунглями можно справиться, рассматривая в первую очередь сбор данных и этапы разработки функций как совместные. А затем трубопровод в джунглях следует исследовать и перепроектировать с земли. Этот подход связан с дополнительными инженерными затратами, но если принять во внимание долгосрочные скрытые затраты, в него стоит инвестировать.

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

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

В газете есть пример, я искал его для вас, ребята;

Две существенные технологические ошибки, допущенные Knight Capital, способствовали торговому инциденту 1 августа 2012 года. В 2005 году Knight Capital переместила часть компьютерного кода в автоматическом маршрутизаторе акций на более раннее место в последовательности кодирования, нарушив функциональность маршрутизатора. Найт оставил эту функцию в маршрутизаторе, хотя она и не предназначалась для использования. Из-за этого некоторые ордера, соответствующие требованиям NYSE, вызывали сбои в работе маршрутизатора Knight Capital, из-за чего маршрутизатор не мог определить, был ли исполнен ордер. При попытке выполнить всего 212 заказов клиентов 1 августа в течение первых 45 минут после открытия рынка маршрутизатор Knight Capital быстро отправил на рынок более 4 миллионов заказов и в конечном итоге понес убытки в размере более 460 миллионов долларов США.

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

Абстракция Долг

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

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

Общие запахи

Грязный или нечистый код упоминается как имеющий «запах», который указывает на то, что часть кода должна быть очищена для будущего. Авторы статьи классифицируют несколько типов запахов;

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

Задолженность по конфигурации

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

Авторы предложили несколько принципов хорошей системы конфигурации;

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

Работа с изменениями во внешнем мире

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

Фиксированные пороги в динамических системах

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

Мониторинг и тестирование

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

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

Длинный короткий рассказ,

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

Другие сферы задолженности, связанной с отмыванием денег

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

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

Нижняя граница

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

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

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

Первоначально опубликовано на https://www.goktugocal.com 3 февраля 2023 г.