Как мы создавали мощный сервис для обучения нейронных сетей в помощь разработчикам и бизнесу
Машинное обучение стало популярной темой в последние годы, причем не только в среде разработчиков, но у широкой общественности. При этом разработка моделей для обучения нейронных сетей требует высокого уровня знаний и опыта в предметной области. Не все, кому она требуется, могут обучить себе модель самостоятельно, а обращаться к сторонним специалистам дорого. Рассказываем о том, как мы создавали сервис по обучению нейронных сетей для бизнес пользователей и разработчиков совместно с AI-стартапом.
В чём же проблема?
Чтобы обучить нейронную сеть, необходимо: собрать данные, на которых модель будет обучаться, сделать препроцессинг этих данных, выбрать фрэймворк для обучения нейронной сети, подобрать архитектуру сети, натренировать ее с использованием GPU ресурсов, а затем запустить весь процесс заново, до тех пор пока не будет достигнута требуемая точность.
Если первый этап еще и можно сделать, не имея специального опыта и знаний, то остальные этапы - никак. Построение модели иногда требует особенных навыков и очень-очень мощное железо, а анализ качества — понимания метрик и умения их применить.
Как решить данную проблему?
Можно передать обучение модели на аутсорс ИИ разработчикам, которые специализируются на машинлёнинге и нейронках;
Можно нанять ML/DL разработчика в штат;
А можно найти сервис, который позволит натренировать модель, не обращаясь к сторонним разработчикам.
Наш заказчик сам является разработчиком ИИ проектов. В какой-то момент он осознал, что задачи к нему приходят довольно типовые, и все решаются по одному шаблону на ограниченном количестве алгоритмов. А значит, всё это можно автоматизировать.
С этой идеей к нам и обратился AI-стартап - создать сервис, который в автоматическом режиме с минимальными трудозатратами и пониманием позволит бизнес пользователю или разработчику натренировать нейронную сеть и выгрузить ее для использования в необходимой инфраструктуре (мобильное приложение, веб сервис, камера, IoT устройство и пр.).
Дизайн ML системы
Система представляет собой платформу для тренировки моделей. Внутри всё группируется по проектам. Проекты делятся на два типа:
Детекция объектов - детектирование объектов определенного типа;
Классификация объектов - определение типа объекта.
Бизнес-процесс выглядит следующим образом:
Начиная новый проект, пользователь загружает датасет (набор изображений). На этих изображениях будет тренироваться будущая модель.
Далее эти данные нужно подготовить для обучения - разметить лейблами, которые наша система должна распознать.
После этого датасету дается оценка сбалансированности (balancing score) - а именно, каковы у него показатели разметки (сколько объектов, каких видов, сколько размеченных и неразмеченных изображений, оценка качества разметки).
Как только данные подготовлены, можно запускать тренировку модели. Здесь пользователь может согласиться с настройками по-умолчанию, которые подходят для большинства случаев. А может выбрать фреймворк, конфигурацию (Tensorflow или PyTorch), базовую модель и типы аугментации и пр. В системе предусмотрена возможность конфигурации для более продвинутых пользователей.
В процессе тренировки пользователь в реальном времени видит на графиках, как улучшаются показатели точности модели.
Последний шаг - обученную модель можно скачать в виде APK, APK source code или в других форматах (TFLite (Quantized/Non-Quantized, Int8/Float16/Float32, Saved Model (.pb)) или YOLOv5 (.pt)), которые устанавливаются на различные камеры, телефоны, IoT девайсы.
APK - готовое android-приложение со встроенной моделью. А APK source code подходит разработчикам мобильных приложений под Android - они могут брать куски кода и вставлять в свои приложения.
Проблематика и наши решения
Выбор платформы и подхода разработки
Изначально система реализовывалась как serverless, для чего использовали инфраструктуру AWS с Lambda-ми. Для быстрого старта разработки использовался AWS Amplify SDK. А для тренировки моделей у нас был выбор:
Использовать свой собственный environment, арендовать виртуальные машины с GPU, написать кастомный оркестратор, который решал бы, когда поднять/заглушить машину. Поскольку тренировка - это длительный процесс, а пользователей потенциально много, потребуется несколько машин, чтобы в разумное время обслужить всех. Поэтому при кастомном решении нам нужно держать парк машин с GPU. Это возможно, но мы искали другие пути;
Использовать готовый сервис Amazon Sagemaker - платишь деньги, вызываешь запрос к API.
Выбрали Amazon Sagemaker , т.к. это самый быстрый путь для старта разработки, а также он позволяет платить деньги только за время тренировок. А AWS - как клауд платформу. В системе мы активно используем сервисы Amazon: AWS Amplify и AWS Lambda.
У системы двухуровневый бэкэнд:
Первый уровень serverless на джаваскрипте,
Второй с оркестрацией ML процессов на python.
Сложность #1: CPU vs. GPU instances
Итак, мы выбрали Amazon Sagemaker , т.к. это самый быстрый путь для старта разработки (быстро настраивается и платишь только за время тренировок), с помощью которого мы сделали прототип. Пока мы делали прототип, мы выбирали сервера с машинами CPU, т.к. это дешево и заказчик - стартап без большого бюджета. Еще есть GPU машины - более дорогой способ, но вместе с тем и более производительный. А еще у каждого типа машин есть параметр “dedicated instance” и “spot instance”.
Dedicated instance - это когда посылаешь запрос в Sagemaker “начни тренировку”, он ищет у себя свободные машины, находит такую и резервирует ее на весь процесс тренировки, начинает тренировку. Т.е. именно под нашу задачу выделяет машину на время процесса тренировки.
Spot instance - машина выделяется нам, но в процессе работы Amazon может ее прервать, чтобы отдать другому пользователю с бóльшим приоритетом. Такой instance дешевле, можно сэкономить до 70% бюджета, но есть риск неожиданного прерывания тренировки в любой момент.
На Spot instance все работало хорошо, пока тренировались на CPU. У CPU есть проблема - он в разы медленнее, хоть и дешевле. И пока мы делали прототип, конечно же выбирали этот дешевый вариант.
Когда мы ушли в продакшн, то переключились на GPU, чтобы было быстрее. Но здесь возникла еще одна проблема - spot instances на GPU самые дешевые, а значит очень востребованные, и тренировка сеток прерывалась в 50% случаев. Когда работали со spot instances на CPU - такого не было.
Решение #1: CPU, GPU и instances
Как решили: использовали dedicated instances на GPU для тренировки. То есть, платить дороже, но с гарантией. Плюс, мы получили производительность, которой не было на CPU.
UPD: Пока мы писали эту статью, ситуация еще больше изменилась. Получилось так, что нам перестало хватать dedicated instances на GPU (у Amazon они настолько востребованы, что нам просто не хватало машин с нужной конфигурацией). Поэтому мы сделали динамическую сетку переключения на разные типы инстансов, где в качестве резервного и самого крайнего варианта указали CPU инстанс.
Сложность #2: Backend
Изначально хотели сделать serverless архитектуру с помощью AWS Amplify, который позволяет с нуля быстро стартовать проект, не переживая о DevOps. Разработчик садится работать и не думает, как ему поднять виртуальную машину, как её сконфигурировать и т.п. Первоначально мы выбрали JS стек.
Serverless реализуется в Amazon через использование лямбда-функций - мини/микро сервисов, которые по запросу поднимаются, обрабатывают запрос, а затем гасятся. Если пришло много пользователей, например 1000, то Amazon размножает эти кусочки кода по требованию, а мы не переживаем за балансировку нагрузки.
AWS лямбды можно писать на разных языках: java, javascript, python, C# и др. Мы писали на javascript.
Однако с javascript Sagemaker API сложно работать, т.к. он очень не развитый по сравнению, например, с python Sagemaker SDK. Мы попробовали писать лямбду на python. Локально всё работало прекрасно, а в лямбде на сервере - нет. Дело было в том, что у лямбды есть ограничение на объем загружаемого кода. SDK оказалась “тяжелой”, её просто не удалось загрузить.
Лямбда - это маленькая легковесная функция, которая выполняет атомарные операции. Они имеет ограничение по времени (15 минут на запрос) и по объему исходного кода (250 мб). Лямбда на python, при попытке запуска SDK Sagemaker, падала и ругалась, что код весит слишком много.
Мы не сдавались - оптимизировали код. Загрузить смогли, но было понимание, что при дальнейшем расширении кода мы все равно столкнемся с ограничением по объему кода в 250 мб.
Решение #2: Backend
Мы решили эту проблему так: пришлось создать бэкенд 2 уровня, который крутится не в лямбдах, а на выделенных серверах. Изначально это был один выделенный сервер, но через какое-то время жизни проекта мы его расширили до трёх серверов.
Изначально бэкенд на питоне только запускал тренировку, пересылая запрос от бэкенда в sagemaker, затем у нас добавился новый функционал в виде возможности загрузить модель в разных форматах или возможности проверить модель. А это длительные операции, которые требуют много времени и ресурсов по меркам запрос/ответ. Единственный сервер остается занятым одной из этих двух операций, поэтому одного сервера хватать перестало.
Поэтому нам приходилось расширять архитектуру - мы разделили все ресурсоемкие операции на еще два дополнительных сервера:
один отвечает за симуляцию (тестирование моделей на новых данных),
второй отвечает за билды APK,
третий - за старт тренировок и быстрые задачи.
Итого - три сервера и оркестрация (очереди задач на старт тренировок, проверки состояния тренировок, симуляцию, билды APK и других артефактов).
Сложность #3: File storage
Мы давно работаем с Amazon, хорошо его знаем, обычно используем S3 - файловое хранилище. В обычных проектах оно не так активно используется, т.к. в нём хранятся аватары и документы: с такими файлами обычно не так много манипуляций, они меняются раз в год.
Наша платформа в большинстве своем основана на хранении файлов, т.к. датасет - это изображения, тысячи изображений, которые могут занимать много места. Вся работа связана с ними, а также их надо где-то хранить.
Итак, мы храним их на S3, а когда пользователю необходимо начать тренировку нейронной сети, дублируем исходные изображения в другую папку, и уже там проводим на них разметку, добавляем аннотацию и пр. Это небыстрые операции.
Возвращаясь к лямбдам, они имеют ограничение по объему оперативной памяти и времени исполнения. И если датасет состоит из более чем 1000 тяжеловесных картинок, то копирование и подготовка файлов разметки может занимать слишком много времени и потенциально упираться в таймауты, т.к. лямбда не успевает за 15 минут откопировать все картинки из одного места в другое.
Конечно же нехорошо увеличивать таймауты на лямбде, т.к. она должна отрабатывать быстро, минуты исполнения вместо секунд - это не очень хорошая практика для Lambda.
Решение #3: File storage
Как решать? С файлами из лямбд не очень удобно работать, т.к. это времязатратно и у них есть лимиты. Надо менять подход в архитектуре - перенести работу с файлами на выделенный сервер, где нет ограничений по времени.
Этапы внедрения
На данный момент мы закончили 7 этап проекта: сделали систему рабочей и стабильной, подготовили к soft launch на 10 пользователей. Мягкий запуск позволит разрешить проблемы, которые не выявились на данный момент.
Сейчас стадия пересмотра. Мы сделали MVP, который уже в процессе использования. Постепенно появляются первые пожеланию по доработке системы на основе обратной связи от первых пользователей. У клиента в планах уже следующий этап по расширению поддерживаемых типов ml-задач (будем добавлять решения OCR задач и сегментацию изображений).
Также этап доработок будет включать в себя пересмотр архитектуры - уйти от serverless в части работы с картинками. Если бы мы на старте выделили под них отдельный сервер, а не использовали serverless подход, было бы лучше. Пока система справляется, но в процессе развития сервиса и его активной работы, это будет необходимо реализовать.
Стек технологий
AWS Amplify, AWS Lambdas, Amazon Sagemaker, Python, Javascript, React, node.js, Flask, Amazon S3, Amazon Cognito, Amazon SES, Amazon Cloudwatch, Amazon RDS, Tensorflow, PyTorch, Android
Команда и часы работы
Разработка заняла 6 месяцев до первого релиза. Команда состоит из 6 человек.
Состав команды:
2 full stack разработчика (Javascript, React, node.js, AWS DevOps)
2 data scientists (Python)
UX дизайнер
Project manager