ML код срещу AWS Lambda граници

Наскоро бях замесен в проект, в който трябваше да решим проблема с включването на използването на ML - затова реших да изпробвам по-модерния подход на „архитектура без сървър“. При подход без сървър всичко, което трябва да направите, е да напишете функция и след това да определите дали нейното име ще се задейства при събитие или заявка за API. Всичко останало, необходимо за създаване на мащабируема инфраструктура на HA, е нещо, което доставчикът на услуги може да реши и AWS има специфична такава услуга, наречена „Lambda“.

От една страна, AWS Lambda изглежда (и е) доста лесно да напишете функционален код, но от друга страна, AWS Lambda също има ограничение в начина на използване на ресурсите.

Трудно е да си представим производствен код без никакви зависимости от трети страни, а зависимостите от ML обикновено са много тежки, така че ограниченията на 250Mb пакетния пакет (включително слоеве) на AWS Lambda може да не са достатъчни, за да поберем всичко, което е необходимо за работа на кода на ML.

Открихме и проблем, при който се задържахме при получаването на грешка при внедряването: „Възникна грешка: Функционалният код, комбиниран със слоеве, надвишава максимално разрешения размер от 262144000 байта.“. Не бихме могли да изоставим употребата на зависимост в полза на някой лек аналог, тъй като леките аналози не са толкова мощни.

За да избегнем ограниченията на размера на пакета, решихме да използваме (базиран на случая) решение, при което AWS Lambda ще се опита да използва отново същия контейнер за включване на функцията - това запазва стартирания контейнер с заредени в памет обекти за няколко минути и едва след това започва нов контейнер.

AWS Lambda предлага да използваме 500 MB съхранение за директорията / tmp и решихме да инсталираме тежки зависимости във време на изпълнение на функцията, в случай че те отсъстват - но инсталирането им от нулата чрез pip може да бъде дълъг процес, тъй като изисква компилация на родните модули в всяка инсталация.

Създадохме zip архив с предварително инсталирани и предварително компилирани зависимости, които AWS Lambda изтегля и разархивира всеки път, когато е необходимо.

Сега, нека да видим как това може да се направи с помощта на библиотеката NLP „spacy“.

На първо място трябва да знаете, че ще трябва да направите архиви в същата среда, използвана от AWS Lambda, тъй като родните модули трябва да бъдат компилирани в същата операционна система, където ще бъдат изпълнявани. Контейнерите за докери AWS Lambda могат да бъдат намерени в „lambci / lambda“.

# стартирайте aws lambda docker
$ docker run --rm -v / tmp / spacy: / spacy -w / spacy -it lambci / lambda: build-python3.7 / bin / bash
# използвайте виртуална среда
bash-4.2 # virtualenv .venv
bash-4.2 #. .venv / хамбар / активиране
# инсталирайте просторен и английски модел
(.venv) bash-4.2 # pip install https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-2.0.0/en_core_web_sm-2.0.0.tar.gz
# премахване на компилирани от python модули
(.venv) bash-4.2 # намери. -name * .pyc -exec rm -f {} \;
(.venv) bash-4.2 # намери. -име __pycache__ -exec rm -rf {} \;
# получите общ размер на зависимостите от пространството
(.venv) bash-4.2 # du -h -d0 .venv / lib / python3.7 / site-пакети /
348M .venv / lib / python3.7 / пакети за сайтове /
# пакетни зависимости за пощенски архив
(.venv) bash-4.2 # cd .venv / lib / python3.7 / site-пакети /
(.venv) bash-4.2 # zip -9r /spacy/deps.zip.
# вземете архива на зависимостите от общия размер
(.venv) bash-4.2 # ls -sh /spacy/deps.zip
97M /spacy/deps.zip

Сега архивът трябва да бъде качен в S3, където от него може да бъде изтеглен в Lambda. Бих препоръчал да автоматизирате тази част с инструментариум „Terraform“ или „serverless“.

Сега нека да видим как може да изглежда кодът за използване в Lambda:

А пространственото активиране е:

Трябва също да се отбележи, че производителността на Lambda зависи от настройките на RAM - по подразбиране 128Mb, но може да бъде увеличена до 3008Mb. CPU, разпределен за функция, е пропорционален на конфигурираната памет.

След няколко експеримента със стойности на RAM установихме, че 2GB прави трика и увеличаването на тази стойност едва се отразява на времето за инсталиране на зависимостите. В момента времето за инсталиране е по-малко от 5 секунди.

Нека да разгледаме диаграмата на продължителността на Ламбда:

Върховете показват смяна на контейнерите Lambda и студения старт на нов. Ако участието се среща често, Lambda използва същия контейнер възможно най-дълго. Само когато работи на празен ход за около 5 минути, той започва нов контейнер, така че открихме, че това решение изглежда разумно за случаите, когато разговорите с функция Lambda се появяват често.

Този метод все още има ограничения за размера на много тежки библиотеки като „tensorflow“, където размерът е близо 500Mb, тъй като 500Mb от / tmp трябва да се поберат с ципирани архивни файлове и разархивирани файлове.

Много кудо за преглед на текст и коментари към Дейвид Лорбике.