В сегодняшнем материале рассказывается про Neuropod, движок вывода глубокого обучения с открытым исходным кодом от Uber ATG. Это слой абстракции над фреймворками глубокого обучения, решающий проблему быстрой замены написанных на разных фреймворках моделей и проблему адаптации модели для производственных сред, помогающий построить единый и оптимизированный конвейер входных данных. Подробности, как обычно, под катом.
В Uber Advanced Technologies Group (ATG) глубокое обучение используется, чтобы предоставить безопасную и надежную технологию беспилотного вождения. Используя глубокое обучение, мы можем создавать и обучать модели для решения таких задач, как обработка входных данных датчиков, идентификация объектов и прогнозирование их возможного перемещения. По мере развития нашего ПО для беспилотного вождения, мы постоянно ищем новые способы улучшения моделей, иногда это означает эксперименты с различными фреймворками глубокого обучения (далее DL). По мере выпуска новых фреймворков DL и развития существующих, например, TensorFlow или PyTorch мы хотим предоставить инженерам и ученым гибкость в использовании инструментов, лучше всего подходящих для решения задач. К сожалению, добавление поддержки новой платформы глубокого обучения во всем стеке машинного обучения ресурсоемко и трудозатратно. В ATG мы потратили много времени на упрощение процесса. Сегодня мы открываем исходный код Neuropod — плода наших усилий. Neuropod — это слой абстракции поверх существующих фреймворков глубокого обучения, который предоставляет единый интерфейс для запуска моделей DL. Neuropod позволяет исследователям легко строить модели на выбранном фреймворке, а также внедрять модели в производственную среду.
Использование нескольких фреймворков глубокого обучения
DL развивается очень быстро и разные фреймворки эффективны в решении разных задач. Это означает, что в Uber ATG за последние несколько лет мы использовали несколько фреймворков DL. В 2016 году Caffe2 был основной платформой глубокого обучения, а в начале 2017 года мы проделали значительную работу по интеграции TensorFlow (о том, как получить сертификат разработчика TensorFlow, был материал вот тут). В этой работе мы столкнулись с серьезными препятствиями при интеграции с CUDA и cuDNN, конфликтами между зависимостями Caffe2 и TensorFlow, проблемами загрузки библиотек и многими другими проблемами. В конце 2017 года мы начали разрабатывать больше моделей в PyTorch. Для преобразования этих моделей в производственные также потребовалось много работы. Мы видели проблемы повреждения памяти при работе вместе с TensorFlow и несколько других трудно отлаживаемых проблем. Затем был выпущен TorchScript, и мы снова прошли подобный процесс.
На протяжении многих лет Uber ATG развивала собственный подход к машинному обучению, используя различные популярные фреймворки DL
С 2018 года открыт исходный код нескольких фреймворков DL, включая созданный в Uber Ludwig, JAX, Trax, Flax, Haiku и RLax. Даже если исследователю легко экспериментировать с новыми фреймворками, добавление поддержки производственной среды для нового фреймворка во все наши системы и процессы — задача не из легких. Одна из трудностей: требуется интеграция и оптимизация работы для каждой части инфраструктуры и инструментов.
Трудно добавить поддержку для новой структуры, потому что каждый элемент инфраструктуры, который запускает модель, должен поддерживать все фреймворки. Компонентами инфраструктуры могут быть конвейеры метрик, подача моделей или другие производственные и тестовые среды
В конце 2018 года Uber ATG начала создавать несколько моделей, по-разному решавших одну и ту же проблему. Например, обнаружение трехмерных объектов с помощью лидара может выполняться в горизонтальной плоскости или с высоты птичьего полета. Оба подхода корректны и у них разные достоинства и недостатки. Кроме того, построенные разными командами модели иногда реализовывались на разных фреймворках. Для упрощения производства мы хотели иметь возможность легко заменять модели, решающие одну и ту же проблему, даже когда они реализованы на разных фреймворках. Мы также видели некоторые случаи, когда новые исследования выходили с кодом PyTorch и хотели быстро сравнить модель с существующими моделями TensorFlow. Сделать это было трудно: у нас были конвейеры метрик на уровне конкретного фреймворка и каждой модели. Чтобы развернуть модель на новом фреймворке, нужно было перестроить конвейеры метрик на уровне модели, интегрировать фреймворк во все наши системы и процессы, а затем выполнить дополнительную оптимизацию, чтобы гарантировать эффективный запуск модели в рамках бюджета. Хотя эти шаги могут показаться простыми, проблемы, подобные описанным выше, (повреждение памяти, конфликты зависимостей и т.д.), заставили нас потратить значительные усилия на решение проблем интеграции вместо того, чтобы сосредоточиться на разработке модели. Нам нужен был способ максимально увеличить гибкость во время исследований без необходимости переделывать работу на других этапах процесса.
Введение в Neuropod
Решением проблемы стал Neuropod: библиотека с открытым исходным кодом, которая делает фреймворки DL одинаковыми, когда модель выполняется. Теперь добавить поддержку нового фреймворка во все ваши инструменты и инфраструктуру так же просто, как добавить ее в Neuropod.
Neuropod-это уровень абстракции, который обеспечивает единый интерфейс для запуска моделей глубокого обучения из нескольких фреймворков
На момент публикации статьи Neuropod поддерживает несколько фреймворков, включая TensorFlow, PyTorch, Keras, TorchScript и упрощает добавление новых фреймворков. Neuropod с момента его внутреннего релиза в начале 2019 года важен в быстром развертывании новых моделей в Uber. За последний год мы внедрили сотни моделей Neuropod в Uber ATG, Uber AI и основной бизнес Uber. Это модели прогнозирования спроса, прогноз расчетного времени прибытия (ETA) для поездок, транскрипция меню Uber Eats и модели обнаружения объектов для самоуправляемых транспортных средств. Мы надеемся, что открытие исходного кода Neuropod, принесет пользу сообществу машинного обучения.
Обзор
Neuropod начинает с формального описания решаемой задачи для моделей. В этом контексте проблемой может быть что-то вроде семантической сегментации изображений или перевода текста с одного языка на другой. Формально определив проблему, мы можем рассматривать ее как интерфейс и абстрагироваться от конкретных реализаций. Каждая модель Neuropod реализует определение проблемы. В результате любые решающие одну и ту же задачу модели взаимозаменяемы, даже когда используют разные фреймворки. Neuropod работает путем упаковки существующих моделей в пакет neuropod (или «нейропод» для краткости). Этот пакет содержит исходную модель вместе с метаданными, тестовыми данными и пользовательскими операциями, если они есть. С помощью Neuropod любая модель может выполняться на любом поддерживаемом языке. Например, когда пользователь хочет запустить модель PyTorch из C++, Neuropod развертывает интерпретатор Python под капотом и свяжется с ним, чтобы запустить модель. Это необходимо потому, что модели PyTorch требуют запуска интерпретатора python. Такая возможность позволяет быстро протестировать модели PyTorch до попыток их преобразования в TorchScript. TorchScript, в свою очередь, может изначально запускаться из C++. Neuropod на момент публикации статьи поддерживает запуск моделей на Python и C++. Дополнительные языковые привязки для библиотеки пишутся легко. Например, платформа ML Uber Michelangelo использует Neuropod как основной формат модели DL и реализует привязку Go для запуска производственных моделей на Go.
Neuropod имеет специфичный для фреймворка API упаковки и независимый от фреймворка API вывода
Обзор вывода
Прежде чем мы углубимся в принцип работы Neuropod, давайте посмотрим, как модели глубокого обучения интегрируются в приложения традиционно:
Обычно приложения взаимодействуют с системой глубокого обучения напрямую на протяжении всего процесса вывода
На рисунке выше приложение непосредственно взаимодействует с API TensorFlow на всех этапах вывода. С Neuropod приложение взаимодействует только с независимым от фреймворка API (все фиолетовым цветом ниже), и Neuropod переводит эти независимые от фреймворка вызовы в вызовы нижележащего фреймворка. Мы делаем это эффективно, используя операции без копирования из одной области памяти в другую, когда это возможно. Для получения более подробной информации смотрите раздел «оптимизация» ниже.
С Neuropod приложения взаимодействуют с независимым от фреймворка API, а Neuropod взаимодействует с нижележащим фреймворком
Neuropod имеет подключаемый внутренний слой, и каждый поддерживаемый фреймворк имеет свою собственную реализацию. Именно это упрощает добавление новых фреймворков в Neuropod.
Глубокое обучение с помощью Neuropod
Давайте посмотрим на весь процесс глубокого обучения с помощью Neuropod, чтобы увидеть, как он помогает упростить эксперименты, развертывание и итерацию.
Постановка задачи
Для создания нейропода нужно формально описать задачу. Как упоминалось выше, это каноническое описание входных и выходных данных решаемой задачи. Оно включает имена, типы данных и формы всех входных и выходных тензоров. Например, определение задачи обнаружения двумерных объектов может выглядеть примерно так:
Обратите внимание: в приведенном выше определении используются «сущности» определения форм (
num_classes
и num_detections
). Каждый экземпляр сущности должен разрешать одно и то же значение во время выполнения. Так предоставляется более надежный способ ограничения форм, чем просто установка значения элементов формы в None
. В приведенном выше примере num_detections должны быть одинаковыми для всех боксов и object_class_probability
. Ради простоты мы решим элементарную задачу: сложение.Фрагмент кода выше также определяет тестовые входные и выходные данные, они обсуждаются ниже.
Генерация модели-заполнителя
Сразу после формального определения задачи мы можем использовать Neuropod для автоматической генерации модели-заполнителя, которая реализует спецификацию проблемы. Это позволяет начать интеграцию без реальной модели. Сгенерированная модель принимает входные данные из спецификации и возвращает случайные данные, соответствующие выходной спецификации.
Построение модели
После установления определение проблемы (и, возможно, генерации модели-заполнителя) мы можем построить нашу модель. Для этого пройдем все обычные шаги по созданию и обучению модели, но теперь добавим шаг экспорта Neuropod к концу процесса:
В коде выше модель экспортируется как нейропод вместе с дополнительными тестовыми данными. Если тестовые данные предоставлены, библиотека запускает самотестирование модели сразу после экспорта. Параметры create_tensorflow_neuropod и всех других упаковщиков хорошо задокументированы.
Строим конвейер метрик
Теперь, когда у нас есть модель, мы можем построить конвейер метрик для задачи на Python. Единственное отличие от того, как если бы мы делали это без Neuropod: вместо специфичных платформам API мы для запуска модели работаем с Neuropod на Python.
Документация Neuropod содержит более подробную информацию о load_neuropod и infer. Любые построенные с помощью Neuropod конвейеры метрик должны строиться один раз для каждой задачи, таким образом становясь источником истины при сравнении моделей (даже между различными фреймворками).
Интеграция
Теперь мы можем интегрировать модель в производственную систему C++. В примере ниже показано крайне упрощенное применение C++ API Neuropod, но библиотека поддерживает применение сложнее, позволяя выполнять эффективные операции без копирования из одной области памяти в другую и оборачивая существующую память.
В отличие от интеграции без Neuropod, этот шаг выполняется один раз для каждой проблемы, но не один раз для каждой платформы. Пользователям не нужно разбираться в тонкостях TensorFlow или C ++ API Torch, но они все же могут обеспечить большую гибкость, когда исследователи решают, какой фреймворк хотят использовать. Кроме того, поскольку ядро библиотеки Neuropod написано на C++, возможно написать привязки для других языков: Go, Java и т.д.
Оптимизация
Требования к задержке в Uber ATG довольно строгие, поэтому многие операции осуществляются без копирования из одной области памяти в другую. Мы много работали над профилированием и оптимизацией, и теперь Neuropod может стать центральным местом для реализации оптимизации вывода, применяемой ко всем моделям. В рамках этой работы каждый коммит Neuropod тестируется на наших конвейерах непрерывной интеграции для платформ:
- Mac, Linux, Linux (GPU)
- 5 версий Python
- 5 версий каждой поддерживаемой платформы DL
Ознакомьтесь с документацией для получения актуального списка поддерживаемых платформ и фреймворков. В Neuropod есть способ запуска моделей в процессах-воркерах с применением высокопроизводительного моста с общей памятью. Такой подход позволяет изолировать модели друг от друга без значительных потерь времени. Подробнее об этом мы поговорим в конце статьи.
Итерация
После построения и интеграции первой версии модели мы можем итеративно улучшать решение. В рамках улучшения, когда мы хотим попробовать модель TorchScript вместо созданной выше модели TensorFlow, мы просто заменяем модель.
Без Neuropod пришлось бы повторять многие шаги. С Neuropod взаимозаменяемы любые модели, реализующие одну и ту же спецификацию задачи. Мы можем повторно использовать созданный ранее конвейер метрик вместе со всей проделанной в разрезе интеграции работой. Все запускающие модель системы и процессы становятся независимыми от платформы, что обеспечивает гораздо большую гибкость при построении модели. Neuropod позволяет пользователям сосредоточиться на решаемой проблеме, а не на используемой при решении технологии.
Независимые от проблемы инструменты
Хотя Neuropod начинает с фокусировки на «задаче» (например, на обнаружении двухмерных объектов на изображении, анализе тональности текста и т.д.), мы можем создать независимые от фреймворка и проблемы инструменты поверх Neuropod. Это позволяет построить общую и работающую с любой моделью инфраструктуру.
Канонические конвейеры построения ввода
Интересный независимый от задач вариант применения Neuropod — канонические конвейеры для создания входных данных. В ATG есть определенный формат/спецификация представления входных данных в тензорах. Это касается данных с датчиков, включая изображения LiDAR, радаров и камер, а также другую информацию, такую как карты с высоким разрешением. Определение стандартного формата упрощает управление очень большими наборами данных во время обучения. Так мы быстро создаем модели, поскольку многие из них работают с подмножеством этих входных данных (например, модель, работающая только с камерой и LiDAR). Комбинируя общий формат ввода с Neuropod, мы можем построить единый оптимизированный конвейер построения ввода, работающий со всеми нашими моделями независимо от фреймворка реализации. Построитель ввода не зависит от задачи, пока каждая модель работает с подмножеством одного и того же набора признаков. Любые оптимизации в построителе ввода помогают улучшить все наши модели.
Система Neuropod позволяет построить единый оптимизированный канал ввода-вывода, который работает со многими моделями, вместо того, чтобы строить отдельный канал для каждой модели или каждого фреймворка
Подача моделей
Еще одна полезная часть независимой от проблемы инфраструктуры — это подача моделей. В Uber ATG некоторые модели довольно тяжелые: они требуют больших затрат и они большие сами по себе. Некоторые из этих моделей невозможно запустить на центральном процессоре в таких задачах, как автономное моделирование. Включение графических процессоров во все наши кластерные машины не имеет смысла с точки зрения эффективности использования ресурсов, поэтому вместо этого у нас есть служба, позволяющая пользователям запускать модели на удаленных графических процессорах. Это очень похоже на обслуживание модели на основе gRPC. Без Neuropod платформа обслуживания моделей должна была бы хорошо справляться с удаленными запусками Keras, TensorFlow, PyTorch, TorchScript и т.д. Возможно, потребуется реализовать сериализацию, десериализацию, взаимодействие с API C++ и оптимизацию для каждого фреймворка. Все приложения также должны уметь запускать модели из всех этих фреймворков локально. Поскольку локальный и удаленный запуски реализованы по-разному, система в целом должна учитывать 2n случаев. Однако с помощью Neuropod служба подачи моделей может действительно хорошо работать с нейроподами удаленно, а Neuropod может действительно хорошо работать с моделями на нескольких фреймворкоах. При разделении проблем количество случаев, которые система должна учитывать, масштабируется сложением (2 + n), а не умножением — 2n фреймворков. Эта разница становится более заметной по мере роста числа поддерживаемых фреймворков. Но ее можно сделать еще заметнее, если добавить подачу моделей как серверную часть Neuropod, тогда любая часть инфраструктуры сможет легко запускать модели удаленно.
Добавление подачи моделей в качестве бэкенда Neuropod позволяет любому приложению, использующему Neuropod для удаленного запуска моделей, выполнять модели без существенных изменений. Под капотом это может выглядеть примерно так:
Приложения могут использовать Neuropod как прокси для выполнения модели на удаленной машине
Это решение не специфично для конкретной задачи или платформы и обеспечивает использующим Neuropod приложениям еще большую гибкость.
Выполнение из процесса
Neuropod включает поддержку запуска моделей в изолированных рабочих процессах с применением моста общей памяти с низкой задержкой
Входные данные Uber ATG, как правило, имеют большой размер и мы чувствительны к задержкам, поэтому локальный gRPC — не идеальный способ изолировать модели. Вместо этого мы можем использовать выполнение из процесса (OPE) на основе избегающей копирования данных и оптимизированной общей памяти. Это позволяет изолировать модели друг от друга без возникновения значительных потерь времени. Такая изоляция важна потому, что в прошлом мы видели конфликты работающих в одном процессе фреймворков, включая трудно обнаруживаемые ошибки CUDA и повреждения памяти. Все эти проблемы действительно сложно отследить. Изоляция также полезна для повышения производительности при запуске моделей на Python, поскольку позволяет пользователям избежать использования общего GIL для всех моделей. Запуск каждой модели в отдельном рабочем процессе также включает некоторые дополнительные функции, подробности об этом читайте в разделе «Дальнейшие шаги».
Дальнейшие шаги
Neuropod позволил Uber быстро создавать и развертывать новые модели глубокого обучения, но это только начало.
Вот некоторые вещи, над которыми мы активно работаем:
- Выбор версии: эта функция дает пользователям возможность при экспорте модели указать требуемый диапазон версий платформы. Например, для модели может потребоваться TensorFlow 1.13.1, и Neuropod автоматически запустит модель через OPE и с правильной версией платформы. Так пользователи могут применять несколько платформ и несколько версий каждой платформы в одном приложении.
- Запечатывание операций. Эта функция позволяет приложениям с помощью тензора указывать, когда они «выполнены». После того, как тензор запечатан, Neuropod может асинхронно транспортировать данные в нужное место назначения, например, на графический процессор локально, в процесс-воркер и т.д. до запуска логического вывода. Это помогает пользователям распараллеливать передачу данных и вычисления.
- Докеризация процессов-воркеров: позволяет обеспечить еще большую изоляцию моделей друг от друга. Например, с помощью этой функции в одном приложении могут работать даже модели, требующие разных версий CUDA.
По мере работы над Neuropod, улучшая текущие функции и вводя новые, мы с нетерпением ждем возможности работать с сообществом Open Source, чтобы сделать библиотеку лучше. Neuropod оказался очень полезным для множества команд глубокого обучения в Uber, и мы надеемся, что инструмент принесет пользу и другим людям и командам. Пожалуйста попробуйте Neuropod и расскажите нам, что вы думаете.
Особая благодарность Евгению Литвину, который способствовал успеху Neuropod.
В UBER сделали нейропод, а мы, для тех кто хочет развиваться в области ML и DL, сделали промокод HABR, дающий дополнительную скидку 10% к скидке указанной на баннере.
- Курс по Machine Learning
- Курс «Математика и Machine Learning для Data Science»
- Продвинутый курс «Machine Learning Pro + Deep Learning»
- Обучение профессии Data Science с нуля
- Онлайн-буткемп по Data Science
- Обучение профессии Data Analyst с нуля
- Онлайн-буткемп по Data Analytics
- Курс «Python для веб-разработки»
Eще курсы