Изначально я планировал написать вторую статью из своей серии о Kubeflow. Тем не менее, я увяз в большом количестве работы, и тем временем Oracle разработала новую структуру развертывания модели под названием GraphPipe. Я все еще планирую взглянуть на Kubeflow в какой-то момент, так как он имеет много хороших функций (например, AB-тестирование / обновления многорукого бандита для перенаправления трафика), но я обнаружил, что GraphPipe проще в использовании и, по крайней мере, согласно его веб-сайту. Он намного быстрее, чем API-интерфейсы типа JSON (например, Kubeflow).

В этой статье я собираюсь рассмотреть пример развертывания обученной модели PyTorch с использованием GraphPipe и моей собственной библиотеки, не зависящей от модели (MA) (которая теперь включает поддержку GraphPipe). Для этого примера я выбрал ChexNet (от Rajpurkar et al.) И реализацию от arroweng (т.е. Weng et al.), Которая общедоступна на GitHub.

1. Выполните рефакторинг кода для поддержки обработки «единственного примера» (или, альтернативно, любого режима, который вам нужен для производства).

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

1 (а) Загрузите веса модели

Прежде чем мы даже попытаемся провести рефакторинг, нам нужно убедиться, что мы можем загрузить веса модели (удивительно, что это вызывает гораздо больше проблем, чем вы когда-либо могли бы поверить). Для этого мы создаем подкласс PytorchModel от MA. На данный момент нас не волнуют этапы предварительной обработки и process_result. Вместо этого мы просто сосредоточимся на загрузке весов модели.

Есть несколько способов загрузить модель PyTorch, и MA поддерживает их оба. Первый способ - если вы изначально сохранили полную модель с torch.save(the_model, some_path).. На практике это довольно редко, и вместо этого большую часть времени вы сохраняете только state_dict, а не всю модель (т.е. torch.save(the_model.state_dict(), path)). Здесь arroweng предоставляет сохраненный state_dict, поэтому мы должны внедрить create_model. ChexNet - это, по сути, просто DenseNet121, модифицированный для 14 условий. Поэтому все, что нам нужно сделать в create_model, - это вернуть класс DenseNet121. Остальные MA обрабатывают в PytorchModel, такие как преобразование state_dict в формат, используемый ЦП (или наоборот. Наконец, мы устанавливаем для режима обучения значение false, так как мы хотим, чтобы выполнялась только прямая пропрагментация.

1 (б) Реализовать предварительную обработку и process_result

Чтобы проверить, что эта установка работает, нам нужно запустить созданную модель на некоторых данных. Эти же функции будут использоваться позже при развертывании модели. Так что сейчас самое время похудеть, насколько это возможно. Часто это один из наиболее трудоемких шагов из-за того, что код часто оценивает модель партиями. Кроме того, модель часто имеет загрузчик данных, когда нам нужно, чтобы он запускался на отдельном примере. Таким образом, этот процесс будет значительно отличаться для вашей конкретной модели / варианта использования. Интересно, что для этой конкретной модели arroweng использовала увеличение данных с помощью TenCrop даже во время тестирования. Поэтому в моем методе предварительной обработки я решил использовать параметр увеличения, который пользователь мог бы отметить как истинное или нет.

2. Преобразование модели PyTorch в Caffe2

Эта часть относительно проста и хорошо документирована на веб-сайте PyTorch. По сути, Caffe2 отслеживает выполнение модели в PyTorch.

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

Если все работает, следующий код должен работать без ошибок.

3. Работа с GraphPipe

3 (а) Запустите контейнер докеров GraphPipe.

Теперь возьмите сохраненный файл Caffe ONNX (в данном случае chexnet-py.onnx) и сохраните его либо в облаке, либо в локальном каталоге. Затем запустите следующую команду

docker run -it — rm -e https_proxy=${https_proxy} -p 9000:9000 sleepsonthefloor/graphpipe-onnx:cpu — value-inputs=https://raw.githubusercontent.com/isaacmg/s2i_pytorch_chex/master/value_inputs2.json — model=http://url_to_model.onnx — listen=0.0.0.0:9000`

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

{"0": [1, [1, 3, 224, 224]]}

Итак, в этом примере (если вы планируете не использовать увеличение кадрирования) входными данными будут размер пакета один, три канала (например, RGB) и размер изображения 224x224. Если все идет правильно, в вашем терминале должно быть что-то вроде «INFO [0005] Listening on 0.0.0.0:9000».

3 (b) Определите класс обслуживания GraphPipe

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

Теперь вы можете обернуть этот класс в любой Django или Flask API, чтобы завершить развертывание.

Заключение

Теперь вы можете задаться вопросом, почему это лучше, чем просто запустить PyTorch в REST API Flask / Django. Ответ: (1) этот подход обычно быстрее, поскольку GraphPipe оптимизирует фазу прогнозирования модели (2) этот метод хорошо масштабируется, и (3) этот API может быть вызван любым приложением на любом языке (при условии, что вы можете выполнить эквивалентную предварительную обработку ). На мой взгляд, самое большое преимущество - (2). Поскольку теперь очень легко создавать новые контейнеры Docker, если задержка прогноза становится узким местом приложения.

Готовый продукт доступен на моем GitHub (скоро добавлю все экспортные скрипты). Кроме того, через несколько дней я должен запустить демо-версию модели на Heroku. У меня есть еще пара статей, запланированных для моей серии по развертыванию моделей, включая Kubeflow, GraphPipe, развертывание моделей Tensorflow и развертывание моделей в производственных приложениях Java (с особым упором на предсказания потоковой передачи в реальном времени с помощью Flink). Я не уверен, в каком порядке я буду их публиковать, но я планирую в конце концов добраться до него. Наконец, в какой-то момент я планирую провести тест, чтобы определить, какие методы действительно самые быстрые с точки зрения скорости прогнозирования.

Дополнительные ресурсы

Официальный сайт GraphPipe

Статья о выпуске GraphPipe

Грязный код загрузки модели