Машинное обучение стало популярной темой в последние годы, причем не только в среде разработчиков, но у широкой общественности. При этом разработка моделей для обучения нейронных сетей требует высокого уровня знаний и опыта в предметной области. Не все, кому она требуется, могут обучить себе модель самостоятельно, а обращаться к сторонним специалистам дорого. Рассказываем о том, как мы создавали сервис по обучению нейронных сетей для бизнес пользователей и разработчиков совместно с AI-стартапом..
Чтобы обучить нейронную сеть, необходимо: собрать данные, на которых модель будет обучаться, сделать препроцессинг этих данных, выбрать фрэймворк для обучения нейронной сети, подобрать архитектуру сети, натренировать ее с использованием GPU ресурсов, а затем запустить весь процесс заново, до тех пор пока не будет достигнута требуемая точность.
Если первый этап еще и можно сделать, не имея специального опыта и знаний, то остальные этапы - никак. Построение модели иногда требует особенных навыков и очень-очень мощное железо, а анализ качества — понимания метрик и умения их применить.
Наш заказчик сам является разработчиком ИИ проектов. В какой-то момент он осознал, что задачи к нему приходят довольно типовые, и все решаются по одному шаблону на ограниченном количестве алгоритмов. А значит, всё это можно автоматизировать.
С этой идеей к нам и обратился AI-стартап - создать сервис, который в автоматическом режиме с минимальными трудозатратами и пониманием позволит бизнес пользователю или разработчику натренировать нейронную сеть и выгрузить ее для использования в необходимой инфраструктуре (мобильное приложение, веб сервис, камера, IoT устройство и пр.).
Система представляет собой платформу для тренировки моделей. Внутри всё группируется по проектам. Проекты делятся на два типа:
APK - готовое android-приложение со встроенной моделью. А APK source code подходит разработчикам мобильных приложений под Android - они могут брать куски кода и вставлять в свои приложения.
Изначально система реализовывалась как serverless, для чего использовали инфраструктуру AWS с Lambda-ми. Для быстрого старта разработки использовался AWS Amplify SDK. А для тренировки моделей у нас был выбор:
Выбрали Amazon Sagemaker , т.к. это самый быстрый путь для старта разработки, а также он позволяет платить деньги только за время тренировок. А AWS - как клауд платформу. В системе мы активно используем сервисы Amazon: AWS Amplify и AWS Lambda.
У системы двухуровневый бэкэнд:
Итак, мы выбрали 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 - такого не было.
Как решили: использовали dedicated instances на GPU для тренировки. То есть, платить дороже, но с гарантией. Плюс, мы получили производительность, которой не было на CPU.
UPD: Пока мы писали эту статью, ситуация еще больше изменилась. Получилось так, что нам перестало хватать dedicated instances на GPU (у Amazon они настолько востребованы, что нам просто не хватало машин с нужной конфигурацией). Поэтому мы сделали динамическую сетку переключения на разные типы инстансов, где в качестве резервного и самого крайнего варианта указали CPU инстанс.
Изначально хотели сделать 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 уровня, который крутится не в лямбдах, а на выделенных серверах. Изначально это был один выделенный сервер, но через какое-то время жизни проекта мы его расширили до трёх серверов.
Изначально бэкенд на питоне только запускал тренировку, пересылая запрос от бэкенда в sagemaker, затем у нас добавился новый функционал виде возможности загрузить модель в разных форматах или возможности проверить модель. А это длительные операции, которые требуют много времени и ресурсов по меркам запрос/ответ. Единственный сервер остается занятым одной из этих двух операций, поэтому одного сервера хватать перестало.
Поэтому нам приходилось расширять архитектуру - мы разделили все ресурсоемкие операции на еще два дополнительных сервера:
Итого - три сервера и оркестрация (очереди задач на старт тренировок, проверки состояния тренировок, симуляцию, билды APK и других артефактов).
Мы давно работаем с Amazon, хорошо его знаем, обычно используем S3 - файловое хранилище. В обычных проектах оно не так активно используется, т.к. в нём хранятся аватары и документы: с такими файлами обычно не так много манипуляций, они меняются раз в год.
Наша платформа в большинстве своем основана на хранении файлов, т.к. датасет - это изображения, тысячи изображений, которые могут занимать много места. Вся работа связана с ними, а также их надо где-то хранить.
Итак, мы храним их на S3, а когда пользователю необходимо начать тренировку нейронной сети, дублируем исходные изображения в другую папку, и уже там проводим на них разметку, добавляем аннотацию и пр. Это небыстрые операции.
Возвращаясь к лямбдам, они имеют ограничение по объему оперативной памяти и времени исполнения. И если датасет состоит из более чем 1000 тяжеловесных картинок, то копирование и подготовка файлов разметки может занимать слишком много времени и потенциально упираться в таймауты, т.к. лямбда не успевает за 15 минут откопировать все картинки из одного места в другое.
Конечно же нехорошо увеличивать таймауты на лямбде, т.к. она должна отрабатывать быстро, минуты исполнения вместо секунд - это не очень хорошая практика для Lambda.
Как решать? С файлами из лямбд не очень удобно работать, т.к. это времязатратно и у них есть лимиты. Надо менять подход в архитектуре - перенести работу с файлами на выделенный сервер, где нет ограничений по времени.
Этапы разработки системы выглядят так:
На данный момент мы закончили 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 человек.
Состав команды: