Это четвертая статья в серии из пяти частей Использование компьютерного зрения и НЛП для подписи рентгеновских снимков.

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

Код размещен и доступен для использования в этом репозитории GitHub.

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

Цель вашей модели машинного обучения

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

Развертывание модели

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

Другой пример — развертывание модели в качестве конечной точки бессерверного API. Не обращая внимания на модные словечки, это просто означает, что модель и ее функция прогнозирования будут поддерживаться в облаке, а конечная точка вместо этого будет просто URL-адресом. Запрос к такому URL-адресу, содержащему некоторые входные данные в качестве полезной нагрузки, вызовет функцию-обработчик, которая объявлена ​​внутри бессерверного интерфейса функции. Этот обработчик в основном реконструирует модель с ее весами, использует входные данные для создания прогноза, а затем возвращает результат. Приложениям, использующим этот подход, как правило, требуется стабильное подключение к Интернету, поскольку он подразумевает выполнение запросов API к конечной точке в облаке. В результате этот путь обычно предполагает высокую задержку при низком использовании памяти. По сравнению со стратегией, описанной в предыдущем абзаце, эта может потребовать более сложной масштабируемости. В принципе, даже несмотря на то, что можно выполнить несколько оптимизаций, несколько запросов к одной и той же конечной точке за короткий период времени могут перегрузить ее память и/или мощность ЦП, что приведет к отклонению запросов.

Экспорт весов модели

Для этой статьи мы решили создать бессерверную конечную точку API для создания подписей из рентгеновских снимков грудной клетки в процессе производства. После обучения модели ее веса и контрольные точки экспортируются. Некоторые случаи более просты, чем другие. Например, существует существенная документация о том, как экспортировать модель Keras и сохранять ее веса после некоторого обучения. Это также применимо для загрузки весов обратно в другой экземпляр модели. Тем не менее, каждый из этих наборов подходов больше подходит для разных случаев. В нашем конкретном сценарии наши модели кодировщика и декодера были подклассами (подмоделями) стандартных моделей Keras (`tensorflow.keras.Model`).

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

decoder.save_weights('/content/drive/My Drive/Colab Notebooks/XRAY/decoderRNN_model/', save_format = 'tf')
encoder.save_weights('/content/drive/My Drive/Colab Notebooks/XRAY/encoderCNN_model/', save_format = 'tf')

Воссоздание модели с экспортированными весами

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

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

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

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

Развертывание модели в облачной функции

Для нашего конкретного проекта мы решили использовать облачные функции Google Cloud Platform (GCP). Есть прилично хороших ресурсов для начала. После создания проекта и запуска облачной функции описанные выше функции можно реализовать в файлах Python (.py). Однако только одна из объявленных функций в файле `main.py` может быть выбрана в качестве точки входа, что по сути является причудливым способом назвать одну функцию, которая будет выполняться, если триггер получит запрос. В нашем случае этот метод является обработчиком, который запускает остальные функции для вывода прогноза, как упоминалось ранее.

Важно отметить, что импортированные библиотеки нужно где-то как-то поддерживать. Что это значит? Среда Python в GCP должна иметь доступ к этим пакетам во время выполнения, и, к сожалению, не все зависимости доступны. Вы можете проверить эту документацию для списка предустановленных пакетов для каждой версии среды выполнения Python. Например, не все версии TensorFlow 2.0 доступны, но поддерживается бета-версия, как показано в этом requirements.txt. Это обходные пути, которые необходимо рассмотреть в идеале перед реализацией самой функции в начале. Поверьте мне, может потребоваться очень много времени, чтобы выполнить весь конвейер машинного обучения только для того, чтобы понять, что есть несколько исправлений, которые нужно сделать просто потому, что конкретная библиотека не поддерживается для развертывания.

Как только функция будет успешно скомпилирована, имя облачной функции появится рядом с зеленой галочкой. Это означает, что пока ошибок не обнаружено. Если щелкнуть раздел TRIGGER вверху, отобразится URL-адрес конечной точки.

Включение триггера в наше приложение

Как только все это будет сделано, вы можете включить POST запрос в сервисы вашего приложения и ожидать предсказания в ответе, как показано в этом примере. Затем просто убедитесь, что сторона HTML отображает ответ на запрос, как показано в примере ниже.

Одним из важных аспектов, о котором следует подумать, является использование общей памяти, используемой функцией. В некоторых случаях ответа не будет, поскольку триггер потребляет больше памяти, чем доступно. Это можно легко настроить в приборной панели функции до 2 ГБ, чего обычно должно быть достаточно. К счастью, GCP Cloud Functions предоставляет панель инструментов для оценки различных показателей, включая использование памяти.

Будущая работа

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

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

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

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

Итак, действуйте и делайте мир лучше с помощью машинного обучения!

Рекомендации