Как мы начали с TensorFlow

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

Answer Bot использует класс современных алгоритмов машинного обучения, известный как глубокое обучение, для определения релевантных статей. Мы используем библиотеку глубокого обучения Google с открытым исходным кодом TensorFlow для создания этих моделей, используя графические процессоры (GPU) для ускорения процесса. Answer Bot - наш первый информационный продукт в Zendesk, использующий Tensorflow. После тяжелых вложений крови, пота и слез наших специалистов по данным, у нас есть модели Tensorflow, которые очень хорошо работают с Answer Bot. Ура!

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

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

Обслуживание моделей TensorFlow

После серии бесед между специалистами по данным и инженерами по данным мы пришли к следующим ключевым требованиям:

  • Низкая задержка при прогнозировании
  • Горизонтально масштабируемый
  • Вписывается в нашу архитектуру микросервисов
  • Возможность A / B тестирования разных версий модели.
  • Совместим с более новыми выпусками TensorFlow
  • Поддерживает другие модели TensorFlow для использования в будущих информационных продуктах

Обслуживание TensorFlow

После некоторого покопания в Интернете, Google TensorFlow Serving стал нашим лучшим выбором для обслуживания моделей. Tensorflow Serving написан на C ++, который поддерживает обслуживание моделей машинного обучения. Готовая установка Tensorflow Serving поддерживает:

  • Обслуживание моделей TensorFlow
  • Сканирование и загрузка моделей TensorFlow из локальной файловой системы

TensorFlow Serving рассматривает каждую модель как обслуживаемый объект. Он периодически сканирует локальную файловую систему, загружая и выгружая модели в зависимости от состояния файловой системы и политики управления версиями модели. Это позволяет легко развернуть обученные модели, скопировав экспортированные модели в указанный путь к файлу, в то время как обслуживание Tensorflow продолжает работать.

Основываясь на тесте, представленном в этом сообщении в блоге Google, они зафиксировали примерно 100 000 запросов в секунду, не считая времени обработки прогнозов TensorFlow и времени сетевого запроса.

Подробнее об архитектуре обслуживания TensorFlow см. В документации TensorFlow Serving.

Протокол связи (gRPC)

TensorFlow Serving предоставляет интерфейс gRPC для вызова прогнозов из моделей. gRPC - это высокопроизводительная среда вызова удаленных процедур (RPC) с открытым исходным кодом, работающая по протоколу HTTP / 2. Пара интересных улучшений HTTP / 2 по сравнению с HTTP / 1.1 включает поддержку мультиплексирования запросов, двунаправленной потоковой передачи и передачи через двоичный, а не текстовый.

По умолчанию gRPC использует Protocol Buffers (Protobuf) в качестве формата обмена сообщениями. Буферы протокола - это механизм Google с открытым исходным кодом для сериализации структурированных данных в эффективный двоичный формат. Он строго типизирован, что снижает вероятность ошибок. Структура данных указывается в файле .proto, который затем может быть скомпилирован в классы запросов gRPC на различных языках, включая Python, Java и C ++. Я впервые работал с gRPC, и мне было любопытно посмотреть, как он работает по сравнению с другими архитектурами API, такими как REST.

Модельная архитектура обучения и обслуживания

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

Модель обучения конвейера

Шаги в обучении модели:

  • наши функции обучения созданы на основе данных, уже предоставленных в Hadoop.
  • созданные функции обучения хранятся в AWS S3.
  • Затем модели TensorFlow обучаются с помощью экземпляров GPU в AWS с использованием пакета обучающих выборок из S3.

После того, как модель построена и проверена, она публикуется в репозитории модели в S3.

Модель конвейера обслуживания

Проверенные модели обслуживаются в производственной среде путем отправки моделей из репозитория моделей в экземпляры обслуживания TensorFlow.

Инфраструктура

Мы запускаем TensorFlow Serving на инстансах AWS EC2. Consul настраивается перед экземплярами для обнаружения служб и распределения трафика. Клиенты подключаются к первому доступному IP-адресу, полученному в результате поиска DNS. В качестве альтернативы можно использовать эластичную балансировку нагрузки для более продвинутой балансировки нагрузки. Поскольку прогнозирование с помощью моделей TensorFlow по своей сути является операцией без сохранения состояния, мы могли бы достичь горизонтальной масштабируемости, развернув больше экземпляров EC2.

Другой вариант - использовать Cloud ML, предлагаемый Google Cloud Platform, который обеспечивает обслуживание моделей Tensorflow как полностью управляемую услугу. Однако служба Cloud ML находилась в альфа-фазе, когда мы развернули TensorFlow Serving примерно в сентябре 2016 года, и ей не хватало функций, необходимых для использования в производственной среде. Поэтому мы выбрали хостинг в наших собственных инстансах AWS EC2, чтобы обеспечить более точный контроль и предсказуемую емкость ресурсов.

Реализация обслуживания моделей

Когда мы впервые развернули TensorFlow Serving в 2016 году, не было возможности напрямую загрузить готовый двоичный файл, и нам пришлось скомпилировать его из исходного кода. В недавнем выпуске TensorFlow Serving v1.0 пользователи могут напрямую установить TF Serving с помощью apt-get install, если вы используете Ubuntu. Дополнительную информацию см. В следующем блоге разработчиков Google.

Вот шаги, которые мы предприняли для развертывания и запуска TensorFlow Serving:

  1. Компиляция обслуживания TensorFlow из исходного кода

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

Предполагая, что у вас установлен Docker, хорошей отправной точкой для компиляции двоичного файла является использование предоставленного Dockerfile. Следуйте инструкциям ниже:

  • Запустите код из этой сути, чтобы создать контейнер докера, подходящий для компиляции TensorFlow Serving.
  • Запустите код в рамках этой сути в работающем контейнере докера, чтобы создать исполняемый двоичный файл.
  • После завершения компиляции исполняемый двоичный файл будет доступен по следующему пути в вашем образе докера: / work / serve / bazel-bin / tensorflow_serving / model_servers / tensorflow_model_server

2. Запуск системы обслуживания моделей

Исполняемый двоичный файл (tensorflow_model_server) может быть развернут в ваших производственных экземплярах. Вы также можете запустить TensorFlow Serving в контейнере докеров, если вы используете платформу оркестровки докеров, такую ​​как Kubernetes или Elastic Container Service.

Предположим, что модель TensorFlow хранится на рабочих хостах в каталоге / work / awesome_model_directory. Вы можете запустить TensorFlow Serving на порту 8999 с вашими моделями TensorFlow с помощью следующей команды:

<path_to_the_binary>/tensorflow_model_server — port=8999 — model_base_path=/work/awesome_model_directory

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

3. Создание заглушек gRPC Python из определений служб

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

pip install tensorflow-serving-api

4. Вызов службы с удаленного хоста

Клиент python может быть создан для вызова вызова gRPC на сервере с использованием скомпилированного определения. См. This, например, где показан клиент Python, который синхронно вызывает TensorFlow Serving.

TensorFlow Serving также поддерживает пакетирование прогнозов в целях оптимизации производительности. Чтобы включить это, вы должны запустить tenorflow_model_server с включенным флагом - enable_batching. См. This на примере асинхронного клиента.

Загрузка моделей из другого хранилища

Что делать, если ваши модели не хранятся в локальной файловой системе? И вы хотите, чтобы TensorFlow Serving читал напрямую из внешней системы хранения, такой как AWS S3 и Google Storage.

В этом случае вам нужно будет расширить TensorFlow Serving для чтения из этих источников через Custom Source. По умолчанию TensorFlow Serving поддерживает загрузку моделей только из файловой системы.

Извлеченные уроки

Мы используем TensorFlow Serving в производстве около полугода, и наш опыт работы с ним был довольно успешным. У него хорошая задержка для времени предсказания. Ниже приведен график 95-го процентиля времени прогнозирования в секундах для наших рабочих экземпляров TensorFlow Serving в течение недели (примерно 20 миллисекунд):

Тем не менее, на пути к производству TensorFlow Serving мы извлекли несколько уроков.

  1. Радость и боль управления версиями моделей

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

1а. Скажите прямо, какая версия вам нужна

Мы нашли простой, но полезный способ предотвращения ошибочных прогнозов - использовать атрибут версий, указанный в определении model.proto, который является необязательным (который скомпилирован в model_pb2.py). Это гарантирует, что вы всегда будете сопоставлять полезные данные вашего запроса с ожидаемой версией модели.

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

1б. Обслуживание нескольких версий моделей

По умолчанию TensorFlow Serving загружает и обслуживает последнюю версию модели.

Когда мы впервые реализовали обслуживание TensorFlow в сентябре 2016 года, он не поддерживал одновременное обслуживание нескольких версий модели. Это означает, что одновременно обслуживается только одна версия модели. Этого было недостаточно для нашего варианта использования, поскольку мы хотели бы обслуживать несколько версий модели для поддержки A / B-тестирования различных архитектур нейронных сетей.

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

  • клиентские приложения (клиент gRPC) должны содержать логику переключения и информацию о том, какой экземпляр TensorFlow Serving вызывать для данной версии. Это усложняет клиентам и не является предпочтительным.
  • реестр, который сопоставляет версию с различными экземплярами TensorFlow Serving.

Более идеальным решением является TensorFlow Serving для обслуживания нескольких версий модели.

Я решил использовать один из лабораторных дней, чтобы расширить TensorFlow Serving для обслуживания нескольких версий модели. В Zendesk существует концепция лабораторного дня, когда мы можем проводить 1 день каждые 2 недели, работая над тем, что нас интересует, пусть это будут инструменты, которые могут улучшить нашу повседневную продуктивность, или новую технологию, которая мы очень хотим учиться. Прошло более восьми лет с тех пор, как я в последний раз работал над кодом C ++. Тем не менее, я впечатлен тем, насколько удобочитаема и чиста кодовая база Tensorflow Serving, что упрощает ее расширение. Были представлены улучшения для поддержки нескольких версий, которые с тех пор были объединены в основную кодовую базу. Сопровождающие TensorFlow Serving довольно оперативно предоставляют отзывы об исправлениях и улучшениях. Из последней основной ветки вы можете запустить TensorFlow Serving для обслуживания нескольких версий модели с дополнительным флагом model_version_policy:

/work/serving/bazel-bin/tensorflow_serving/model_servers/tensorflow_model_server — port=8999 — model_base_path=/work/awesome_model_directory — model_version_policy=ALL_VERSIONS

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

2. Сжатие - ваш друг

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

Родительский каталог, который состоит из номера версии (например, 0000001) и содержит следующие файлы:

  • saved_model.pb - сериализованная модель, которая включает определение (определения) графа модели, а также метаданные модели, такие как подписи.
  • variables - это файлы, содержащие сериализованные переменные графиков.

Чтобы сжать экспортированную модель:

tar -cvzf modelv1.tar.gz 0000001

Зачем сжимать?

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

3. Размер модели имеет значение

Имеющиеся у нас модели TensorFlow довольно большие - от 300 МБ до 1,2 ГБ. Мы заметили, что когда размер модели превышает 64 МБ, мы получим ошибку при попытке обслуживания модели. Это связано с жестко запрограммированным ограничением в 64 Мб для размера сообщения protobuf, как описано в следующей статье Проблема с обслуживанием TensorFlow на Github.

В результате мы применили патч, описанный в проблеме Github, чтобы изменить жестко запрограммированное значение константы. Фу…. :( Это все еще остается для нас загадкой. Сообщите нам, если вам удастся найти альтернативные методы, позволяющие обслуживать модели размером более 64 МБ без изменения жестко запрограммированного источника.

4. Избегайте движения источника под вами

Мы создавали исходный код TensorFlow Serving из основной ветки, так как на момент реализации последняя версия ветки (v0.4) отстает от основной с точки зрения функциональности и исправлений ошибок. Поэтому, если вы создаете исходный код, проверяя только мастера, источник может изменяться под вами всякий раз, когда новые изменения объединяются в мастера. Чтобы гарантировать повторяемость сборки артефакта, мы считаем, что важно проверять конкретные версии фиксации, а не для:

  • Обслуживание TensorFlow и
  • TensorFlow (подмодуль Git в рамках обслуживания TensorFlow)

Список желаний для будущих улучшений

Вот некоторые из функций, которые нам было бы очень интересно увидеть в TensorFlow Serving:

  • методы обслуживания проверки работоспособности
  • возможность поддержки нескольких типов моделей в экземпляре TensorFlow Serving
  • "из коробки" загрузка моделей из распределенных хранилищ, таких как AWS S3 и Google Storage
  • "из коробки" поддержка моделей размером более 64Мб
  • образец клиентов Python, не зависящих от TensorFlow

Благодарим следующих друзей и коллег за то, что нашли время просмотреть этот пост: Soon Ee Cheah, Jeffrey Theobald, Bob Raman, Chris Hausler, Chris Holman, Ryan Seddon и Адель Сми.

Полезные ссылки