В этой статье мы не будем рассматривать обучение глубокой нейронной сети. Если вам нужно введение в основы DNN / ML / Fastai, вы можете проверить: Очистите его, обучите, разверните, сделайте ML, сложнее, лучше, сильнее, быстрее, быстрее *.

В прошлом я обучал модели, экспериментировал с фреймворками / библиотеками глубокого обучения, такими как Keras, Tensorflow, Fastai и PyTorch. Я обнаружил, что вы можете тратить бесконечное время на сбор данных, тестирование архитектур (если вы начинаете приключения: проектирование собственной архитектуры или адаптация научных статей), обучение различным моделям, но часто в конце процесса все, что у вас есть для ваших усилий это число (набор чисел, если вам особенно повезет) и расплывчатое обещание, что - когда-нибудь это может пригодиться.

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

  1. Нам нужно экспортировать нашу обученную модель + некоторые дополнительные метаданные, мы собираемся использовать это для выполнения логического вывода данных, предоставленных пользователями нашего приложения.
learn.export()

В результате будет создан файл с именем «export.pkl», держите его под рукой, он нам понадобится позже.

2. Создайте код для веб-страницы.

Я не собираюсь признаваться в мошенничестве, все, что я скажу, это то, что мой код в конечном итоге выглядел подозрительно похожим на проект Cougar-or-Not (но хуже) с почетным упоминанием Fastai Model to Production. Минимально жизнеспособный продукт должен иметь возможность принимать HTTP POST, несущий предоставленное пользователем изображение, и иметь возможность возвращать рассчитанный прогноз.

classes = ['foot', 'hand']
defaults.device = torch.device('cpu')
learn = load_learner('models')      #path containing export.pkl
@app.route("/upload", methods=["POST"])
  async def upload(request):    
    data = await request.form()
    bytes = await (data["file"].read())    
    return predict_image_from_bytes(bytes)
def predict_image_from_bytes(input_bytes):
  img = open_image(BytesIO(input_bytes))
  pred_class, pred_idx, losses = learn.predict(img)
  return JSONResponse({"prediction": str(pred_class), "scores": sorted(zip(learn.data.classes, map(float, losses)), key=lambda p: p[1], reverse=True)})

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

3. Разместите свой код в сети.

Я выбрал Heroku. Heroku описывает себя как платформу как услугу (PaaS), и если по какой-либо другой причине ее следует бойкотировать. К сожалению, он оказался идеальным для моего случая использования; вы получаете бесплатный экземпляр, который может запускать контейнеры размером до 500 МБ, он взаимодействует с GitHub и может быть настроен на автоматическую сборку и развертывание кода при совершении новых коммитов (добро CI / CD). Хотя Heroku работает отлично, учитывая время, я бы, вероятно, выбрал одного из более крупных поставщиков облачных сервисов (AWS, GCP, Azure), потому что знание того, как использовать эти сервисы, кажется более полезным. навык на долгий срок.

Если вы решите использовать Heroku, их руководство по началу работы будет отличным, и я рекомендую выполнить все шаги здесь, а затем вернуться к этой статье, когда вы застрянете (потому что вы это сделаете - есть несколько особенностей).

4. После того, как ваш код будет работать локально, я рекомендую поместить его в GitHub, а затем связать Heroku со своей учетной записью GitHub.

5. Готово! Если бы все заработало. Моя - нет. Мы хотим, чтобы это выглядело так:

[ISSUE] Размер ярлыка ›500 МБ

Размер нашего слага должен быть меньше 500 МБ. Если у вас слишком большой, вы включаете слишком много файлов в свой проект. Это все необходимо? Оказывается, базовая установка fastai довольно велика, но большая часть этого объема приходится на поддержку графического процессора CUDA. Heroku не предлагает графический процессор, а логический вывод все равно работает на ЦП, поэтому измените файл «requirements.txt», включив в него следующее:

https://download.pytorch.org/whl/cpu/torch-1.1.0-cp37-cp37m-linux_x86_64.whl
https://download.pytorch.org/whl/cpu/torchvision-0.3.0-cp37-cp37m-linux_x86_64.whl
fastai

Убедитесь, что вы перешли на домашнюю страницу PyTorch, прокрутите вниз до Быстрый запуск локально и выберите параметры, которые подходят для вашей среды. Я выбрал стабильный, linux, pip, python 3.7, CUDA = none, и PyTorch предоставит вам ссылки на файлы .whl, которые вы должны включить в свой файл требований.

[ПРОБЛЕМА] ImportError: libcudart.so.9.0: невозможно открыть файл общих объектов: нет такого файла или каталога

Это вызвало у меня беспокойство.

У меня приложение отлично работало локально, оно успешно строилось в Heroku, но затем журналы показали, что приложение вылетает во время выполнения. Libcudart.so.9.0 - это библиотека CUDA, она нам даже не нужна, потому что мы выполняем вывод только на CPU. В этом весь смысл предыдущего раздела. Честно говоря, ответ приводил в ярость. Heroku использует своего рода кеширование между сборками для экономии ресурсов. Когда я впервые попытался создать приложение, размер слага был слишком велик, поэтому я ввел требования только к ЦП, чтобы предотвратить загрузку fastai больших ненужных библиотек. Оказалось, что там были некоторые остаточные ссылки (вероятно, по дизайну - я просто не знал, что это работает так, я предполагал, что каждая сборка была с нуля).

Если это произойдет с вами, попробуйте создать файл «runtime.txt» в основе рабочего каталога вашего приложения. Heroku по умолчанию использовал python 3.6.x, а мне нужен python 3.7.x, для этого требуется только одна строка в файле времени выполнения:

python-3.7.3

Изменение времени выполнения вызывает очистку кеша сборки, поэтому добавление этой строки устранило мою ошибку libcudart.so.9.0.

Если у вас возникает соблазн подумать: В нем говорится, что файл отсутствует, почему бы мне просто не добавить его, это будет неправильным подходом. Процесс установки набора инструментов CUDA не является тривиальным, если вы решили разветвить buildpack Heroku для python и изменить его, чтобы получить зависимости в слаге, у вас будут плохие времена (скорее, просто значительный список вещей, которым нужно научиться, и когда я так отвлекаюсь, может быть трудно отступить, но если вы пройдете каждую кроличью нору, вы обнаружите, что продвигаетесь медленно).

[ISSUE] Веб-процессу не удалось подключиться к $ PORT в течение 60 секунд после запуска

В server.py

if __name__ == '_main__':
    port1 = int(os.environ.get('PORT', 5000))
    uvicorn.run(app, host='0.0.0.0', port=port1)

Если вы выберете порт и попытаетесь привязаться к нему, это не удастся, потому что Heroku выделит порт во время выполнения. Вам нужно использовать команду os.environ.get (), чтобы получить выбранный порт из переменной среды $ PORT. Я включил резервный порт 5000, который используется, если $ PORT не установлен, это значительно упрощает локальное тестирование.

В теории. Это решение было предложено в Интернете. У меня это не сработало, вероятно, потому, что немного знаний - вещь опасная. Если вы обнаружите, что это тоже не работает, то проблема, скорее всего, связана с вашим Procfile (с учетом регистра!). Procfile содержит команду, используемую Heroku для запуска вашего приложения, введя здесь значение $ PORT, я решил свои проблемы с привязкой к порту:

web: uvicorn server:app --host 0.0.0.0 --port $PORT

Рабочее приложение:

Http://hand-or-foot.herokuapp.com/

Дайте ему немного времени, чтобы развернуться, уровень бесплатного пользования переводит приложение в спящий режим, поэтому, если оно не использовалось какое-то время, потребуется немного времени, чтобы ответить (либо это, либо все это мертво и никогда не будет работать снова, в котором случае, вам просто нужно поверить мне на слово, что он работает, надежен, стабилен с LTS).

Разное и заключение

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

Если вы заглянули так далеко, я настоятельно рекомендую вам уйти и сделать все здесь самостоятельно, от начала до конца. Я потратил некоторое время на чтение историй и подходов других людей, но только когда я вскочил и попробовал это на себе, я действительно начал консолидировать свои знания и навыки (иногда есть разрыв между тем, что мы думаем, что знаем, и тем, что мы можем демонстрируем, что знаем). Несомненно, я столкнулся с проблемами, которые не задокументировал, и вы тоже столкнетесь с ними. Одна из самых важных вещей, которую вы можете изучить / развить, - это настойчивость. Удачи!

Вопросы-Ответы

В. Что дальше?

A. Моя модель все еще довольно вздорная, я нашел примеры ступней, которые явно являются ступнями, и все еще не получается. Почему? Я хочу выяснить, более внимательно изучить свой набор данных на предмет предвзятости, убедиться, что он чистый и что я использую все последние советы по обучению, чтобы максимально использовать имеющиеся у меня небольшие данные.

В. Так больше рук и ног?

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